UNPKG

@agm/core

Version:

Angular components for Google Maps

630 lines 74.6 kB
import { isPlatformServer } from '@angular/common'; import { Component, ContentChildren, Directive, ElementRef, EventEmitter, Inject, Input, NgZone, Output, PLATFORM_ID } from '@angular/core'; import { FitBoundsService } from '../services/fit-bounds'; import { GoogleMapsAPIWrapper } from '../services/google-maps-api-wrapper'; import { CircleManager } from '../services/managers/circle-manager'; import { InfoWindowManager } from '../services/managers/info-window-manager'; import { LayerManager } from '../services/managers/layer-manager'; import { MarkerManager } from '../services/managers/marker-manager'; import { PolygonManager } from '../services/managers/polygon-manager'; import { PolylineManager } from '../services/managers/polyline-manager'; import { RectangleManager } from '../services/managers/rectangle-manager'; import { DataLayerManager } from './../services/managers/data-layer-manager'; import { KmlLayerManager } from './../services/managers/kml-layer-manager'; export class AgmMapControl { } AgmMapControl.decorators = [ { type: Directive } ]; AgmMapControl.propDecorators = { position: [{ type: Input }] }; export class AgmFullscreenControl extends AgmMapControl { getOptions() { return { fullscreenControl: true, fullscreenControlOptions: { position: this.position && google.maps.ControlPosition[this.position], }, }; } } AgmFullscreenControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-fullscreen-control', providers: [{ provide: AgmMapControl, useExisting: AgmFullscreenControl }], },] } ]; export class AgmMapTypeControl extends AgmMapControl { getOptions() { return { mapTypeControl: true, mapTypeControlOptions: { position: this.position && google.maps.ControlPosition[this.position], style: this.style && google.maps.MapTypeControlStyle[this.style], mapTypeIds: this.mapTypeIds && this.mapTypeIds.map(mapTypeId => google.maps.MapTypeId[mapTypeId]), }, }; } } AgmMapTypeControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-map-type-control', providers: [{ provide: AgmMapControl, useExisting: AgmMapTypeControl }], },] } ]; AgmMapTypeControl.propDecorators = { mapTypeIds: [{ type: Input }], style: [{ type: Input }] }; export class AgmPanControl extends AgmMapControl { getOptions() { return { panControl: true, panControlOptions: { position: this.position && google.maps.ControlPosition[this.position], }, }; } } AgmPanControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-pan-control', providers: [{ provide: AgmMapControl, useExisting: AgmPanControl }], },] } ]; export class AgmRotateControl extends AgmMapControl { getOptions() { return { rotateControl: true, rotateControlOptions: { position: this.position && google.maps.ControlPosition[this.position], }, }; } } AgmRotateControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-rotate-control', providers: [{ provide: AgmMapControl, useExisting: AgmRotateControl }], },] } ]; export class AgmScaleControl extends AgmMapControl { getOptions() { return { scaleControl: true, }; } } AgmScaleControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-scale-control', providers: [{ provide: AgmMapControl, useExisting: AgmScaleControl }], },] } ]; export class AgmStreetViewControl extends AgmMapControl { getOptions() { return { streetViewControl: true, streetViewControlOptions: { position: this.position && google.maps.ControlPosition[this.position], }, }; } } AgmStreetViewControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-street-view-control', providers: [{ provide: AgmMapControl, useExisting: AgmStreetViewControl }], },] } ]; export class AgmZoomControl extends AgmMapControl { getOptions() { return { zoomControl: true, zoomControlOptions: { position: this.position && google.maps.ControlPosition[this.position], style: this.style && google.maps.ZoomControlStyle[this.style], }, }; } } AgmZoomControl.decorators = [ { type: Directive, args: [{ selector: 'agm-map agm-zoom-control', providers: [{ provide: AgmMapControl, useExisting: AgmZoomControl }], },] } ]; AgmZoomControl.propDecorators = { style: [{ type: Input }] }; /** * AgmMap renders a Google Map. * **Important note**: To be able see a map in the browser, you have to define a height for the * element `agm-map`. * * ### Example * ```typescript * import { Component } from '@angular/core'; * * @Component({ * selector: 'my-map-cmp', * styles: [` * agm-map { * height: 300px; * } * `], * template: ` * <agm-map [latitude]="lat" [longitude]="lng" [zoom]="zoom"> * </agm-map> * ` * }) * ``` */ export class AgmMap { constructor(_elem, _mapsWrapper, // tslint:disable-next-line: ban-types _platformId, _fitBoundsService, _zone) { this._elem = _elem; this._mapsWrapper = _mapsWrapper; this._platformId = _platformId; this._fitBoundsService = _fitBoundsService; this._zone = _zone; /** * The longitude that defines the center of the map. */ this.longitude = 0; /** * The latitude that defines the center of the map. */ this.latitude = 0; /** * The zoom level of the map. The default zoom level is 8. */ this.zoom = 8; /** * Enables/disables if map is draggable. */ // tslint:disable-next-line:no-input-rename this.draggable = true; /** * Enables/disables zoom and center on double click. Enabled by default. */ this.disableDoubleClickZoom = false; /** * Enables/disables all default UI of the Google map. Please note: When the map is created, this * value cannot get updated. */ this.disableDefaultUI = false; /** * If false, disables scrollwheel zooming on the map. The scrollwheel is enabled by default. */ this.scrollwheel = true; /** * If false, prevents the map from being controlled by the keyboard. Keyboard shortcuts are * enabled by default. */ this.keyboardShortcuts = true; /** * Styles to apply to each of the default map types. Note that for Satellite/Hybrid and Terrain * modes, these styles will only apply to labels and geometry. */ this.styles = []; /** * When true and the latitude and/or longitude values changes, the Google Maps panTo method is * used to * center the map. See: https://developers.google.com/maps/documentation/javascript/reference#Map */ this.usePanning = false; /** * Sets the viewport to contain the given bounds. * If this option to `true`, the bounds get automatically computed from all elements that use the {@link AgmFitBounds} directive. */ this.fitBounds = false; /** * The map mapTypeId. Defaults to 'roadmap'. */ this.mapTypeId = 'ROADMAP'; /** * When false, map icons are not clickable. A map icon represents a point of interest, * also known as a POI. By default map icons are clickable. */ this.clickableIcons = true; /** * A map icon represents a point of interest, also known as a POI. * When map icons are clickable by default, an info window is displayed. * When this property is set to false, the info window will not be shown but the click event * will still fire */ this.showDefaultInfoWindow = true; /** * This setting controls how gestures on the map are handled. * Allowed values: * - 'cooperative' (Two-finger touch gestures pan and zoom the map. One-finger touch gestures are not handled by the map.) * - 'greedy' (All touch gestures pan or zoom the map.) * - 'none' (The map cannot be panned or zoomed by user gestures.) * - 'auto' [default] (Gesture handling is either cooperative or greedy, depending on whether the page is scrollable or not. */ this.gestureHandling = 'auto'; /** * Controls the automatic switching behavior for the angle of incidence of * the map. The only allowed values are 0 and 45. The value 0 causes the map * to always use a 0° overhead view regardless of the zoom level and * viewport. The value 45 causes the tilt angle to automatically switch to * 45 whenever 45° imagery is available for the current zoom level and * viewport, and switch back to 0 whenever 45° imagery is not available * (this is the default behavior). 45° imagery is only available for * satellite and hybrid map types, within some locations, and at some zoom * levels. Note: getTilt returns the current tilt angle, not the value * specified by this option. Because getTilt and this option refer to * different things, do not bind() the tilt property; doing so may yield * unpredictable effects. (Default of AGM is 0 (disabled). Enable it with value 45.) */ this.tilt = 0; this._observableSubscriptions = []; /** * This event emitter gets emitted when the user clicks on the map (but not when they click on a * marker or infoWindow). */ // tslint:disable-next-line: max-line-length this.mapClick = new EventEmitter(); /** * This event emitter gets emitted when the user right-clicks on the map (but not when they click * on a marker or infoWindow). */ this.mapRightClick = new EventEmitter(); /** * This event emitter gets emitted when the user double-clicks on the map (but not when they click * on a marker or infoWindow). */ this.mapDblClick = new EventEmitter(); /** * This event emitter is fired when the map center changes. */ this.centerChange = new EventEmitter(); /** * This event is fired when the viewport bounds have changed. */ this.boundsChange = new EventEmitter(); /** * This event is fired when the mapTypeId property changes. */ this.mapTypeIdChange = new EventEmitter(); /** * This event is fired when the map becomes idle after panning or zooming. */ this.idle = new EventEmitter(); /** * This event is fired when the zoom level has changed. */ this.zoomChange = new EventEmitter(); /** * This event is fired when the google map is fully initialized. * You get the google.maps.Map instance as a result of this EventEmitter. */ this.mapReady = new EventEmitter(); /** * This event is fired when the visible tiles have finished loading. */ this.tilesLoaded = new EventEmitter(); } /** @internal */ ngAfterContentInit() { if (isPlatformServer(this._platformId)) { // The code is running on the server, do nothing return; } // todo: this should be solved with a new component and a viewChild decorator const container = this._elem.nativeElement.querySelector('.agm-map-container-inner'); this._initMapInstance(container); } _initMapInstance(el) { this._mapsWrapper.createMap(el, { center: { lat: this.latitude || 0, lng: this.longitude || 0 }, zoom: this.zoom, minZoom: this.minZoom, maxZoom: this.maxZoom, controlSize: this.controlSize, disableDefaultUI: this.disableDefaultUI, disableDoubleClickZoom: this.disableDoubleClickZoom, scrollwheel: this.scrollwheel, backgroundColor: this.backgroundColor, draggable: this.draggable, draggableCursor: this.draggableCursor, draggingCursor: this.draggingCursor, keyboardShortcuts: this.keyboardShortcuts, styles: this.styles, mapTypeId: this.mapTypeId.toLocaleLowerCase(), clickableIcons: this.clickableIcons, gestureHandling: this.gestureHandling, tilt: this.tilt, restriction: this.restriction, }) .then(() => this._mapsWrapper.getNativeMap()) .then(map => this.mapReady.emit(map)); // register event listeners this._handleMapCenterChange(); this._handleMapZoomChange(); this._handleMapMouseEvents(); this._handleBoundsChange(); this._handleMapTypeIdChange(); this._handleTilesLoadedEvent(); this._handleIdleEvent(); this._handleControlChange(); } /** @internal */ ngOnDestroy() { // unsubscribe all registered observable subscriptions this._observableSubscriptions.forEach((s) => s.unsubscribe()); // remove all listeners from the map instance this._mapsWrapper.clearInstanceListeners(); if (this._fitBoundsSubscription) { this._fitBoundsSubscription.unsubscribe(); } } /* @internal */ ngOnChanges(changes) { this._updateMapOptionsChanges(changes); this._updatePosition(changes); } _updateMapOptionsChanges(changes) { const options = {}; const optionKeys = Object.keys(changes).filter(k => AgmMap._mapOptionsAttributes.indexOf(k) !== -1); optionKeys.forEach((k) => { options[k] = changes[k].currentValue; }); this._mapsWrapper.setMapOptions(options); } /** * Triggers a resize event on the google map instance. * When recenter is true, the of the google map gets called with the current lat/lng values or fitBounds value to recenter the map. * Returns a promise that gets resolved after the event was triggered. */ triggerResize(recenter = true) { // Note: When we would trigger the resize event and show the map in the same turn (which is a // common case for triggering a resize event), then the resize event would not // work (to show the map), so we trigger the event in a timeout. return new Promise((resolve) => { setTimeout(() => { return this._mapsWrapper.triggerMapEvent('resize').then(() => { if (recenter) { this.fitBounds != null ? this._fitBounds() : this._setCenter(); } resolve(); }); }); }); } _updatePosition(changes) { // tslint:disable: no-string-literal if (changes['latitude'] == null && changes['longitude'] == null && !changes['fitBounds']) { // no position update needed return; } // tslint:enable: no-string-literal // we prefer fitBounds in changes if ('fitBounds' in changes) { this._fitBounds(); return; } if (typeof this.latitude !== 'number' || typeof this.longitude !== 'number') { return; } this._setCenter(); } _setCenter() { const newCenter = { lat: this.latitude, lng: this.longitude, }; if (this.usePanning) { this._mapsWrapper.panTo(newCenter); } else { this._mapsWrapper.setCenter(newCenter); } } _fitBounds() { switch (this.fitBounds) { case true: this._subscribeToFitBoundsUpdates(); break; case false: if (this._fitBoundsSubscription) { this._fitBoundsSubscription.unsubscribe(); } break; default: if (this._fitBoundsSubscription) { this._fitBoundsSubscription.unsubscribe(); } this._updateBounds(this.fitBounds, this.fitBoundsPadding); } } _subscribeToFitBoundsUpdates() { this._zone.runOutsideAngular(() => { this._fitBoundsSubscription = this._fitBoundsService.getBounds$().subscribe(b => { this._zone.run(() => this._updateBounds(b, this.fitBoundsPadding)); }); }); } _updateBounds(bounds, padding) { if (!bounds) { return; } if (this._isLatLngBoundsLiteral(bounds) && typeof google !== 'undefined' && google && google.maps && google.maps.LatLngBounds) { const newBounds = new google.maps.LatLngBounds(); newBounds.union(bounds); bounds = newBounds; } if (this.usePanning) { this._mapsWrapper.panToBounds(bounds, padding); return; } this._mapsWrapper.fitBounds(bounds, padding); } _isLatLngBoundsLiteral(bounds) { return bounds != null && bounds.extend === undefined; } _handleMapCenterChange() { const s = this._mapsWrapper.subscribeToMapEvent('center_changed').subscribe(() => { this._mapsWrapper.getCenter().then((center) => { this.latitude = center.lat(); this.longitude = center.lng(); this.centerChange.emit({ lat: this.latitude, lng: this.longitude }); }); }); this._observableSubscriptions.push(s); } _handleBoundsChange() { const s = this._mapsWrapper.subscribeToMapEvent('bounds_changed').subscribe(() => { this._mapsWrapper.getBounds().then((bounds) => { this.boundsChange.emit(bounds); }); }); this._observableSubscriptions.push(s); } _handleMapTypeIdChange() { const s = this._mapsWrapper.subscribeToMapEvent('maptypeid_changed').subscribe(() => { this._mapsWrapper.getMapTypeId().then((mapTypeId) => { this.mapTypeIdChange.emit(mapTypeId); }); }); this._observableSubscriptions.push(s); } _handleMapZoomChange() { const s = this._mapsWrapper.subscribeToMapEvent('zoom_changed').subscribe(() => { this._mapsWrapper.getZoom().then((z) => { this.zoom = z; this.zoomChange.emit(z); }); }); this._observableSubscriptions.push(s); } _handleIdleEvent() { const s = this._mapsWrapper.subscribeToMapEvent('idle').subscribe(() => { this.idle.emit(void 0); }); this._observableSubscriptions.push(s); } _handleTilesLoadedEvent() { const s = this._mapsWrapper.subscribeToMapEvent('tilesloaded').subscribe(() => this.tilesLoaded.emit(void 0)); this._observableSubscriptions.push(s); } _handleMapMouseEvents() { const events = [ { name: 'click', emitter: this.mapClick }, { name: 'rightclick', emitter: this.mapRightClick }, { name: 'dblclick', emitter: this.mapDblClick }, ]; events.forEach(e => { const s = this._mapsWrapper.subscribeToMapEvent(e.name).subscribe(([event]) => { // the placeId will be undefined in case the event was not an IconMouseEvent (google types) if (event.placeId && !this.showDefaultInfoWindow) { event.stop(); } e.emitter.emit(event); }); this._observableSubscriptions.push(s); }); } _handleControlChange() { this._setControls(); this.mapControls.changes.subscribe(() => this._setControls()); } _setControls() { const controlOptions = { fullscreenControl: !this.disableDefaultUI, mapTypeControl: false, panControl: false, rotateControl: false, scaleControl: false, streetViewControl: !this.disableDefaultUI, zoomControl: !this.disableDefaultUI, }; this._mapsWrapper.getNativeMap().then(() => { this.mapControls.forEach(control => Object.assign(controlOptions, control.getOptions())); this._mapsWrapper.setMapOptions(controlOptions); }); } } /** * Map option attributes that can change over time */ AgmMap._mapOptionsAttributes = [ 'disableDoubleClickZoom', 'scrollwheel', 'draggable', 'draggableCursor', 'draggingCursor', 'keyboardShortcuts', 'styles', 'zoom', 'minZoom', 'maxZoom', 'mapTypeId', 'clickableIcons', 'gestureHandling', 'tilt', 'restriction', ]; AgmMap.decorators = [ { type: Component, args: [{ selector: 'agm-map', providers: [ CircleManager, DataLayerManager, DataLayerManager, FitBoundsService, GoogleMapsAPIWrapper, InfoWindowManager, KmlLayerManager, LayerManager, MarkerManager, PolygonManager, PolylineManager, RectangleManager, ], template: ` <div class='agm-map-container-inner sebm-google-map-container-inner'></div> <div class='agm-map-content'> <ng-content></ng-content> </div> `, styles: [` .agm-map-container-inner { width: inherit; height: inherit; } .agm-map-content { display:none; } `] },] } ]; AgmMap.ctorParameters = () => [ { type: ElementRef }, { type: GoogleMapsAPIWrapper }, { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] }, { type: FitBoundsService }, { type: NgZone } ]; AgmMap.propDecorators = { longitude: [{ type: Input }], latitude: [{ type: Input }], zoom: [{ type: Input }], minZoom: [{ type: Input }], maxZoom: [{ type: Input }], controlSize: [{ type: Input }], draggable: [{ type: Input, args: ['mapDraggable',] }], disableDoubleClickZoom: [{ type: Input }], disableDefaultUI: [{ type: Input }], scrollwheel: [{ type: Input }], backgroundColor: [{ type: Input }], draggableCursor: [{ type: Input }], draggingCursor: [{ type: Input }], keyboardShortcuts: [{ type: Input }], styles: [{ type: Input }], usePanning: [{ type: Input }], fitBounds: [{ type: Input }], fitBoundsPadding: [{ type: Input }], mapTypeId: [{ type: Input }], clickableIcons: [{ type: Input }], showDefaultInfoWindow: [{ type: Input }], gestureHandling: [{ type: Input }], tilt: [{ type: Input }], restriction: [{ type: Input }], mapClick: [{ type: Output }], mapRightClick: [{ type: Output }], mapDblClick: [{ type: Output }], centerChange: [{ type: Output }], boundsChange: [{ type: Output }], mapTypeIdChange: [{ type: Output }], idle: [{ type: Output }], zoomChange: [{ type: Output }], mapReady: [{ type: Output }], tilesLoaded: [{ type: Output }], mapControls: [{ type: ContentChildren, args: [AgmMapControl,] }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvY29yZS9zcmMvbGliL2RpcmVjdGl2ZXMvbWFwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFBb0IsU0FBUyxFQUFFLGVBQWUsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBd0IsTUFBTSxFQUFFLFdBQVcsRUFBNEIsTUFBTSxlQUFlLENBQUM7QUFHOU0sT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDMUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDM0UsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHFDQUFxQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBQzdFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxvQ0FBb0MsQ0FBQztBQUNsRSxPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDcEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBQ3RFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx3Q0FBd0MsQ0FBQztBQUMxRSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUM3RSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sMENBQTBDLENBQUM7QUFLM0UsTUFBTSxPQUFnQixhQUFhOzs7WUFEbEMsU0FBUzs7O3VCQUVQLEtBQUs7O0FBUVIsTUFBTSxPQUFPLG9CQUFxQixTQUFRLGFBQWE7SUFDckQsVUFBVTtRQUNSLE9BQU87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S0FBSzs2QkFRTCxLQUFLO2dDQU1MLEtBQUs7cUJBTUwsS0FBSzt5QkFPTCxLQUFLO3dCQU1MLEtBQUs7K0JBS0wsS0FBSzt3QkFLTCxLQUFLOzZCQU1MLEtBQUs7b0NBUUwsS0FBSzs4QkFVTCxLQUFLO21CQWdCTCxLQUFLOzBCQU1MLEtBQUs7dUJBbUJMLE1BQU07NEJBTU4sTUFBTTswQkFNTixNQUFNOzJCQUtOLE1BQU07MkJBS04sTUFBTTs4QkFLTixNQUFNO21CQUtOLE1BQU07eUJBS04sTUFBTTt1QkFNTixNQUFNOzBCQUtOLE1BQU07MEJBRU4sZUFBZSxTQUFDLGFBQWEiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc1BsYXRmb3JtU2VydmVyIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEFmdGVyQ29udGVudEluaXQsIENvbXBvbmVudCwgQ29udGVudENoaWxkcmVuLCBEaXJlY3RpdmUsIEVsZW1lbnRSZWYsIEV2ZW50RW1pdHRlciwgSW5qZWN0LCBJbnB1dCwgTmdab25lLCBPbkNoYW5nZXMsIE9uRGVzdHJveSwgT3V0cHV0LCBQTEFURk9STV9JRCwgUXVlcnlMaXN0LCBTaW1wbGVDaGFuZ2VzIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgRml0Qm91bmRzU2VydmljZSB9IGZyb20gJy4uL3NlcnZpY2VzL2ZpdC1ib3VuZHMnO1xuaW1wb3J0IHsgR29vZ2xlTWFwc0FQSVdyYXBwZXIgfSBmcm9tICcuLi9zZXJ2aWNlcy9nb29nbGUtbWFwcy1hcGktd3JhcHBlcic7XG5pbXBvcnQgeyBDaXJjbGVNYW5hZ2VyIH0gZnJvbSAnLi4vc2VydmljZXMvbWFuYWdlcnMvY2lyY2xlLW1hbmFnZXInO1xuaW1wb3J0IHsgSW5mb1dpbmRvd01hbmFnZXIgfSBmcm9tICcuLi9zZXJ2aWNlcy9tYW5hZ2Vycy9pbmZvLXdpbmRvdy1tYW5hZ2VyJztcbmltcG9ydCB7IExheWVyTWFuYWdlciB9IGZyb20gJy4uL3NlcnZpY2VzL21hbmFnZXJzL2xheWVyLW1hbmFnZXInO1xuaW1wb3J0IHsgTWFya2VyTWFuYWdlciB9IGZyb20gJy4uL3NlcnZpY2VzL21hbmFnZXJzL21hcmtlci1tYW5hZ2VyJztcbmltcG9ydCB7IFBvbHlnb25NYW5hZ2VyIH0gZnJvbSAnLi4vc2VydmljZXMvbWFuYWdlcnMvcG9seWdvbi1tYW5hZ2VyJztcbmltcG9ydCB7IFBvbHlsaW5lTWFuYWdlciB9IGZyb20gJy4uL3NlcnZpY2VzL21hbmFnZXJzL3BvbHlsaW5lLW1hbmFnZXInO1xuaW1wb3J0IHsgUmVjdGFuZ2xlTWFuYWdlciB9IGZyb20gJy4uL3NlcnZpY2VzL21hbmFnZXJzL3JlY3RhbmdsZS1tYW5hZ2VyJztcbmltcG9ydCB7IERhdGFMYXllck1hbmFnZXIgfSBmcm9tICcuLy4uL3NlcnZpY2VzL21hbmFnZXJzL2RhdGEtbGF5ZXItbWFuYWdlcic7XG5pbXBvcnQgeyBLbWxMYXllck1hbmFnZXIgfSBmcm9tICcuLy4uL3NlcnZpY2VzL21hbmFnZXJzL2ttbC1sYXllci1tYW5hZ2VyJztcblxuZXhwb3J0IHR5cGUgQ29udHJvbFBvc2l0aW9uID0ga2V5b2YgdHlwZW9mIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvbjtcblxuQERpcmVjdGl2ZSgpXG5leHBvcnQgYWJzdHJhY3QgY2xhc3MgQWdtTWFwQ29udHJvbCB7XG4gIEBJbnB1dCgpIHBvc2l0aW9uOiBDb250cm9sUG9zaXRpb247XG4gIGFic3RyYWN0IGdldE9wdGlvbnMoKTogUGFydGlhbDxnb29nbGUubWFwcy5NYXBPcHRpb25zPjtcbn1cblxuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnYWdtLW1hcCBhZ20tZnVsbHNjcmVlbi1jb250cm9sJyxcbiAgcHJvdmlkZXJzOiBbeyBwcm92aWRlOiBBZ21NYXBDb250cm9sLCB1c2VFeGlzdGluZzogQWdtRnVsbHNjcmVlbkNvbnRyb2wgfV0sXG59KVxuZXhwb3J0IGNsYXNzIEFnbUZ1bGxzY3JlZW5Db250cm9sIGV4dGVuZHMgQWdtTWFwQ29udHJvbCB7XG4gIGdldE9wdGlvbnMoKTogUGFydGlhbDxnb29nbGUubWFwcy5NYXBPcHRpb25zPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGZ1bGxzY3JlZW5Db250cm9sOiB0cnVlLFxuICAgICAgZnVsbHNjcmVlbkNvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuQERpcmVjdGl2ZSh7XG4gIHNlbGVjdG9yOiAnYWdtLW1hcCBhZ20tbWFwLXR5cGUtY29udHJvbCcsXG4gIHByb3ZpZGVyczogW3sgcHJvdmlkZTogQWdtTWFwQ29udHJvbCwgdXNlRXhpc3Rpbmc6IEFnbU1hcFR5cGVDb250cm9sIH1dLFxufSlcbmV4cG9ydCBjbGFzcyBBZ21NYXBUeXBlQ29udHJvbCBleHRlbmRzIEFnbU1hcENvbnRyb2wge1xuICBASW5wdXQoKSBtYXBUeXBlSWRzOiAoa2V5b2YgdHlwZW9mIGdvb2dsZS5tYXBzLk1hcFR5cGVJZClbXTtcbiAgQElucHV0KCkgc3R5bGU6IGtleW9mIHR5cGVvZiBnb29nbGUubWFwcy5NYXBUeXBlQ29udHJvbFN0eWxlO1xuXG4gIGdldE9wdGlvbnMoKTogUGFydGlhbDxnb29nbGUubWFwcy5NYXBPcHRpb25zPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIG1hcFR5cGVDb250cm9sOiB0cnVlLFxuICAgICAgbWFwVHlwZUNvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgICAgc3R5bGU6IHRoaXMuc3R5bGUgJiYgZ29vZ2xlLm1hcHMuTWFwVHlwZUNvbnRyb2xTdHlsZVt0aGlzLnN0eWxlXSxcbiAgICAgICAgbWFwVHlwZUlkczogdGhpcy5tYXBUeXBlSWRzICYmIHRoaXMubWFwVHlwZUlkcy5tYXAobWFwVHlwZUlkID0+IGdvb2dsZS5tYXBzLk1hcFR5cGVJZFttYXBUeXBlSWRdKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwIGFnbS1wYW4tY29udHJvbCcsXG4gIHByb3ZpZGVyczogW3sgcHJvdmlkZTogQWdtTWFwQ29udHJvbCwgdXNlRXhpc3Rpbmc6IEFnbVBhbkNvbnRyb2wgfV0sXG59KVxuZXhwb3J0IGNsYXNzIEFnbVBhbkNvbnRyb2wgZXh0ZW5kcyBBZ21NYXBDb250cm9sIHtcbiAgZ2V0T3B0aW9ucygpOiBQYXJ0aWFsPGdvb2dsZS5tYXBzLk1hcE9wdGlvbnM+IHtcbiAgICByZXR1cm4ge1xuICAgICAgcGFuQ29udHJvbDogdHJ1ZSxcbiAgICAgIHBhbkNvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwIGFnbS1yb3RhdGUtY29udHJvbCcsXG4gIHByb3ZpZGVyczogW3sgcHJvdmlkZTogQWdtTWFwQ29udHJvbCwgdXNlRXhpc3Rpbmc6IEFnbVJvdGF0ZUNvbnRyb2wgfV0sXG59KVxuZXhwb3J0IGNsYXNzIEFnbVJvdGF0ZUNvbnRyb2wgZXh0ZW5kcyBBZ21NYXBDb250cm9sIHtcbiAgZ2V0T3B0aW9ucygpOiBQYXJ0aWFsPGdvb2dsZS5tYXBzLk1hcE9wdGlvbnM+IHtcbiAgICByZXR1cm4ge1xuICAgICAgcm90YXRlQ29udHJvbDogdHJ1ZSxcbiAgICAgIHJvdGF0ZUNvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwIGFnbS1zY2FsZS1jb250cm9sJyxcbiAgcHJvdmlkZXJzOiBbeyBwcm92aWRlOiBBZ21NYXBDb250cm9sLCB1c2VFeGlzdGluZzogQWdtU2NhbGVDb250cm9sIH1dLFxufSlcbmV4cG9ydCBjbGFzcyBBZ21TY2FsZUNvbnRyb2wgZXh0ZW5kcyBBZ21NYXBDb250cm9se1xuICBnZXRPcHRpb25zKCk6IFBhcnRpYWw8Z29vZ2xlLm1hcHMuTWFwT3B0aW9ucz4ge1xuICAgIHJldHVybiB7XG4gICAgICBzY2FsZUNvbnRyb2w6IHRydWUsXG4gICAgfTtcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwIGFnbS1zdHJlZXQtdmlldy1jb250cm9sJyxcbiAgcHJvdmlkZXJzOiBbeyBwcm92aWRlOiBBZ21NYXBDb250cm9sLCB1c2VFeGlzdGluZzogQWdtU3RyZWV0Vmlld0NvbnRyb2wgfV0sXG59KVxuZXhwb3J0IGNsYXNzIEFnbVN0cmVldFZpZXdDb250cm9sIGV4dGVuZHMgQWdtTWFwQ29udHJvbCB7XG4gIGdldE9wdGlvbnMoKTogUGFydGlhbDxnb29nbGUubWFwcy5NYXBPcHRpb25zPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN0cmVldFZpZXdDb250cm9sOiB0cnVlLFxuICAgICAgc3RyZWV0Vmlld0NvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuXG5ARGlyZWN0aXZlKHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwIGFnbS16b29tLWNvbnRyb2wnLFxuICBwcm92aWRlcnM6IFt7IHByb3ZpZGU6IEFnbU1hcENvbnRyb2wsIHVzZUV4aXN0aW5nOiBBZ21ab29tQ29udHJvbCB9XSxcbn0pXG5leHBvcnQgY2xhc3MgQWdtWm9vbUNvbnRyb2wgZXh0ZW5kcyBBZ21NYXBDb250cm9se1xuICBASW5wdXQoKSBzdHlsZToga2V5b2YgdHlwZW9mIGdvb2dsZS5tYXBzLlpvb21Db250cm9sU3R5bGU7XG4gIGdldE9wdGlvbnMoKTogUGFydGlhbDxnb29nbGUubWFwcy5NYXBPcHRpb25zPiB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHpvb21Db250cm9sOiB0cnVlLFxuICAgICAgem9vbUNvbnRyb2xPcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uICYmIGdvb2dsZS5tYXBzLkNvbnRyb2xQb3NpdGlvblt0aGlzLnBvc2l0aW9uXSxcbiAgICAgICAgc3R5bGU6IHRoaXMuc3R5bGUgJiYgZ29vZ2xlLm1hcHMuWm9vbUNvbnRyb2xTdHlsZVt0aGlzLnN0eWxlXSxcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxufVxuXG4vKipcbiAqIEFnbU1hcCByZW5kZXJzIGEgR29vZ2xlIE1hcC5cbiAqICoqSW1wb3J0YW50IG5vdGUqKjogVG8gYmUgYWJsZSBzZWUgYSBtYXAgaW4gdGhlIGJyb3dzZXIsIHlvdSBoYXZlIHRvIGRlZmluZSBhIGhlaWdodCBmb3IgdGhlXG4gKiBlbGVtZW50IGBhZ20tbWFwYC5cbiAqXG4gKiAjIyMgRXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG4gKlxuICogQENvbXBvbmVudCh7XG4gKiAgc2VsZWN0b3I6ICdteS1tYXAtY21wJyxcbiAqICBzdHlsZXM6IFtgXG4gKiAgICBhZ20tbWFwIHtcbiAqICAgICAgaGVpZ2h0OiAzMDBweDtcbiAqICAgIH1cbiAqIGBdLFxuICogIHRlbXBsYXRlOiBgXG4gKiAgICA8YWdtLW1hcCBbbGF0aXR1ZGVdPVwibGF0XCIgW2xvbmdpdHVkZV09XCJsbmdcIiBbem9vbV09XCJ6b29tXCI+XG4gKiAgICA8L2FnbS1tYXA+XG4gKiAgYFxuICogfSlcbiAqIGBgYFxuICovXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdhZ20tbWFwJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgQ2lyY2xlTWFuYWdlcixcbiAgICBEYXRhTGF5ZXJNYW5hZ2VyLFxuICAgIERhdGFMYXllck1hbmFnZXIsXG4gICAgRml0Qm91bmRzU2VydmljZSxcbiAgICBHb29nbGVNYXBzQVBJV3JhcHBlcixcbiAgICBJbmZvV2luZG93TWFuYWdlcixcbiAgICBLbWxMYXllck1hbmFnZXIsXG4gICAgTGF5ZXJNYW5hZ2VyLFxuICAgIE1hcmtlck1hbmFnZXIsXG4gICAgUG9seWdvbk1hbmFnZXIsXG4gICAgUG9seWxpbmVNYW5hZ2VyLFxuICAgIFJlY3RhbmdsZU1hbmFnZXIsXG4gIF0sXG4gIHN0eWxlczogW2BcbiAgICAuYWdtLW1hcC1jb250YWluZXItaW5uZXIge1xuICAgICAgd2lkdGg6IGluaGVyaXQ7XG4gICAgICBoZWlnaHQ6IGluaGVyaXQ7XG4gICAgfVxuICAgIC5hZ20tbWFwLWNvbnRlbnQge1xuICAgICAgZ