@ng-maps/core
Version:
**@ng-maps/core** is a simple, modular and tree-shakable library for displaying google-maps inside an angular application
534 lines • 62.7 kB
JavaScript
import { Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewChild, } from '@angular/core';
import { Subscription } from 'rxjs';
import { FitBoundsService } from '../services/fit-bounds';
import { MapsApiWrapper } from '../services/maps-api-wrapper';
import * as i0 from "@angular/core";
import * as i1 from "../services/maps-api-wrapper";
import * as i2 from "../services/fit-bounds";
/**
* NgMapsViewComponent renders a Google Map.
* **Important note**: To be able see a map in the browser, you have to define a height for the
* element `map-view`.
*
* @example
* <map-view [latitude]="lat" [longitude]="lng" [zoom]="zoom"></map-view>
*/
export class NgMapsViewComponent {
constructor(_mapsWrapper, _fitBoundsService, _zone) {
this._mapsWrapper = _mapsWrapper;
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.
*/
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;
/**
* The enabled/disabled state of the Zoom control.
*/
this.zoomControl = 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 NgMapsFitBounds} directive.
*/
this.fitBounds = false;
/**
* The initial enabled/disabled state of the Scale control. This is disabled by default.
*/
this.scaleControl = true;
/**
* The initial enabled/disabled state of the Map type control.
*/
this.mapTypeControl = true;
/**
* The initial enabled/disabled state of the Pan control.
*/
this.panControl = false;
/**
* The initial enabled/disabled state of the Rotate control.
*/
this.rotateControl = false;
/**
* The initial enabled/disabled state of the Fullscreen control.
*/
this.fullscreenControl = false;
/**
* The map mapTypeId. Defaults to 'roadmap'.
*/
this.mapTypeId = 'roadmap';
this._layerInstance = new Map();
/**
* 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;
/**
* 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.subscription = new Subscription();
/**
* This event emitter gets emitted when the user clicks on the map (but not when they click on a
* marker or infoWindow).
*/
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();
}
/**
* Map option attributes that can change over time
*/
static { this._mapOptionsAttributes = [
'disableDoubleClickZoom',
'scrollwheel',
'draggable',
'draggableCursor',
'draggingCursor',
'keyboardShortcuts',
'zoomControl',
'zoomControlOptions',
'styles',
'streetViewControl',
'streetViewControlOptions',
'zoom',
'mapTypeControl',
'mapTypeControlOptions',
'minZoom',
'maxZoom',
'panControl',
'panControlOptions',
'rotateControl',
'rotateControlOptions',
'fullscreenControl',
'fullscreenControlOptions',
'scaleControl',
'scaleControlOptions',
'mapTypeId',
'clickableIcons',
'gestureHandling',
'tilt',
]; }
/** @internal */
ngOnInit() {
this._initMapInstance(this.container?.nativeElement);
}
async _initMapInstance(el) {
await this._mapsWrapper.createMap(el, { lat: this.latitude || 0, lng: this.longitude || 0 }, {
zoom: this.zoom,
minZoom: this.minZoom,
maxZoom: this.maxZoom,
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,
zoomControl: this.zoomControl,
zoomControlOptions: this.zoomControlOptions,
streetViewControl: this.streetViewControl,
streetViewControlOptions: this.streetViewControlOptions,
scaleControl: this.scaleControl,
scaleControlOptions: this.scaleControlOptions,
mapTypeControl: this.mapTypeControl,
mapTypeControlOptions: this.mapTypeControlOptions,
panControl: this.panControl,
panControlOptions: this.panControlOptions,
rotateControl: this.rotateControl,
rotateControlOptions: this.rotateControlOptions,
fullscreenControl: this.fullscreenControl,
fullscreenControlOptions: this.fullscreenControlOptions,
mapTypeId: this.mapTypeId,
clickableIcons: this.clickableIcons,
gestureHandling: this.gestureHandling,
tilt: this.tilt,
});
const map = await this._mapsWrapper.getNativeMap();
this.mapReady.emit(map);
// register event listeners
this._handleMapCenterChange();
this._handleMapZoomChange();
this._handleMapMouseEvents();
this._handleBoundsChange();
this._handleMapTypeIdChange();
this._handleTilesLoadedEvent();
this._handleIdleEvent();
}
_handleIdleEvent() {
throw new Error('Method not implemented.');
}
_handleTilesLoadedEvent() {
throw new Error('Method not implemented.');
}
_handleMapTypeIdChange() {
throw new Error('Method not implemented.');
}
_handleBoundsChange() {
throw new Error('Method not implemented.');
}
_handleMapMouseEvents() {
throw new Error('Method not implemented.');
}
_handleMapZoomChange() {
throw new Error('Method not implemented.');
}
_handleMapCenterChange() {
throw new Error('Method not implemented.');
}
/** @internal */
ngOnDestroy() {
// unsubscribe all registered observable subscriptions
this.subscription.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);
this._layerChanges(changes);
}
_updateMapOptionsChanges(changes) {
const options = {};
const optionKeys = Object.keys(changes).filter((k) => NgMapsViewComponent._mapOptionsAttributes.includes(k));
optionKeys.forEach((k) => {
options[k] = changes[k].currentValue;
});
return this._mapsWrapper.setMapOptions(options);
}
/**
* @todo google specific
* @param changes
* @protected
*/
async _layerChanges(changes) {
if (changes.layers) {
const map = await this._mapsWrapper.getNativeMap();
const layers = Array.isArray(this.layers) ? this.layers : [this.layers];
layers.forEach((layer) => {
if (layer && !this._layerInstance.has(layer)) {
const i = new google.maps[layer]();
// @todo typings
i.setMap(map);
this._layerInstance.set(layer, i);
}
});
Array.from(this._layerInstance.keys()).forEach((layer) => {
if (!layers.includes(layer)) {
const i = this._layerInstance.get(layer);
i?.setMap(null);
this._layerInstance.delete(layer);
}
});
}
}
/**
* 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(async () => {
await this._mapsWrapper.triggerMapEvent('resize');
if (recenter) {
this.fitBounds != null ? this._fitBounds() : this._setCenter();
}
resolve();
});
});
}
async _updatePosition(changes) {
if (changes.latitude == null &&
changes.longitude == null &&
!changes.fitBounds) {
// no position update needed
return;
}
// we prefer fitBounds in changes
if ('fitBounds' in changes) {
await this._fitBounds();
return;
}
if (typeof this.latitude === 'string') {
this.latitude = parseFloat(this.latitude);
}
if (typeof this.longitude === 'string') {
this.longitude = parseFloat(this.longitude);
}
const center = await this._mapsWrapper.getCenter();
if (!(typeof this.latitude !== 'number' || typeof this.longitude !== 'number') &&
this.latitude !== center?.lat &&
this.longitude !== center?.lng) {
await this._setCenter();
return;
}
}
_setCenter() {
const newCenter = {
lat: this.latitude,
lng: this.longitude,
};
if (this.usePanning) {
return this._mapsWrapper.panTo(newCenter);
}
else {
return this._mapsWrapper.setCenter(newCenter);
}
}
async _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();
}
return this._updateBounds(this.fitBounds);
}
}
_subscribeToFitBoundsUpdates() {
this._zone.runOutsideAngular(() => {
this._fitBoundsSubscription = this._fitBoundsService
.getBounds$()
.subscribe((b) => this._zone.run(() => this._updateBounds(b)));
});
}
async _updateBounds(bounds) {
if (bounds != null) {
/**
* await map to not update bounds till map is initialized
*/
await this._mapsWrapper.getNativeMap();
if (this.usePanning) {
return this._mapsWrapper.panToBounds(bounds, this.boundsPadding);
}
else {
return this._mapsWrapper.fitBounds(bounds, this.boundsPadding);
}
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsViewComponent, deps: [{ token: i1.MapsApiWrapper }, { token: i2.FitBoundsService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.8", type: NgMapsViewComponent, selector: "ng-component", inputs: { longitude: "longitude", latitude: "latitude", zoom: "zoom", minZoom: "minZoom", maxZoom: "maxZoom", draggable: "draggable", disableDoubleClickZoom: "disableDoubleClickZoom", disableDefaultUI: "disableDefaultUI", scrollwheel: "scrollwheel", backgroundColor: "backgroundColor", draggableCursor: "draggableCursor", draggingCursor: "draggingCursor", keyboardShortcuts: "keyboardShortcuts", zoomControl: "zoomControl", zoomControlOptions: "zoomControlOptions", styles: "styles", usePanning: "usePanning", streetViewControl: "streetViewControl", streetViewControlOptions: "streetViewControlOptions", fitBounds: "fitBounds", boundsPadding: "boundsPadding", scaleControl: "scaleControl", scaleControlOptions: "scaleControlOptions", mapTypeControl: "mapTypeControl", mapTypeControlOptions: "mapTypeControlOptions", panControl: "panControl", panControlOptions: "panControlOptions", rotateControl: "rotateControl", rotateControlOptions: "rotateControlOptions", fullscreenControl: "fullscreenControl", fullscreenControlOptions: "fullscreenControlOptions", mapTypeId: "mapTypeId", layers: "layers", clickableIcons: "clickableIcons", gestureHandling: "gestureHandling", tilt: "tilt" }, outputs: { mapClick: "mapClick", mapRightClick: "mapRightClick", mapDblClick: "mapDblClick", centerChange: "centerChange", boundsChange: "boundsChange", mapTypeIdChange: "mapTypeIdChange", idle: "idle", zoomChange: "zoomChange", mapReady: "mapReady", tilesLoaded: "tilesLoaded" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: `
<div class="map-container-inner" #container></div>
<div class="map-content">
<ng-content></ng-content>
</div>
`, isInline: true, styles: [".map-container-inner{width:inherit;height:inherit}.map-content{display:none}\n"] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.8", ngImport: i0, type: NgMapsViewComponent, decorators: [{
type: Component,
args: [{ template: `
<div class="map-container-inner" #container></div>
<div class="map-content">
<ng-content></ng-content>
</div>
`, styles: [".map-container-inner{width:inherit;height:inherit}.map-content{display:none}\n"] }]
}], ctorParameters: () => [{ type: i1.MapsApiWrapper }, { type: i2.FitBoundsService }, { type: i0.NgZone }], propDecorators: { longitude: [{
type: Input
}], latitude: [{
type: Input
}], zoom: [{
type: Input
}], minZoom: [{
type: Input
}], maxZoom: [{
type: Input
}], draggable: [{
type: Input
}], disableDoubleClickZoom: [{
type: Input
}], disableDefaultUI: [{
type: Input
}], scrollwheel: [{
type: Input
}], backgroundColor: [{
type: Input
}], draggableCursor: [{
type: Input
}], draggingCursor: [{
type: Input
}], keyboardShortcuts: [{
type: Input
}], zoomControl: [{
type: Input
}], zoomControlOptions: [{
type: Input
}], styles: [{
type: Input
}], usePanning: [{
type: Input
}], streetViewControl: [{
type: Input
}], streetViewControlOptions: [{
type: Input
}], fitBounds: [{
type: Input
}], boundsPadding: [{
type: Input
}], scaleControl: [{
type: Input
}], scaleControlOptions: [{
type: Input
}], mapTypeControl: [{
type: Input
}], mapTypeControlOptions: [{
type: Input
}], panControl: [{
type: Input
}], panControlOptions: [{
type: Input
}], rotateControl: [{
type: Input
}], rotateControlOptions: [{
type: Input
}], fullscreenControl: [{
type: Input
}], fullscreenControlOptions: [{
type: Input
}], mapTypeId: [{
type: Input
}], layers: [{
type: Input
}], clickableIcons: [{
type: Input
}], gestureHandling: [{
type: Input
}], tilt: [{
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
}], container: [{
type: ViewChild,
args: ['container', { static: true }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFwLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vbGlicy9jb3JlL3NyYy9saWIvZGlyZWN0aXZlcy9tYXAudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLEtBQUssRUFDTCxNQUFNLEVBSU4sTUFBTSxFQUVOLFNBQVMsR0FDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBT3BDLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzFELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQzs7OztBQUU5RDs7Ozs7OztHQU9HO0FBcUJILE1BQU0sT0FBTyxtQkFBbUI7SUFHOUIsWUFDWSxZQUErQixFQUMvQixpQkFBbUMsRUFDbkMsS0FBYTtRQUZiLGlCQUFZLEdBQVosWUFBWSxDQUFtQjtRQUMvQixzQkFBaUIsR0FBakIsaUJBQWlCLENBQWtCO1FBQ25DLFVBQUssR0FBTCxLQUFLLENBQVE7UUFvQ3pCOztXQUVHO1FBQ2EsY0FBUyxHQUFXLENBQUMsQ0FBQztRQUV0Qzs7V0FFRztRQUNhLGFBQVEsR0FBVyxDQUFDLENBQUM7UUFFckM7O1dBRUc7UUFDYSxTQUFJLEdBQVcsQ0FBQyxDQUFDO1FBY2pDOztXQUVHO1FBQ2EsY0FBUyxHQUFZLElBQUksQ0FBQztRQUUxQzs7V0FFRztRQUNhLDJCQUFzQixHQUFZLEtBQUssQ0FBQztRQUV4RDs7O1dBR0c7UUFDYSxxQkFBZ0IsR0FBWSxLQUFLLENBQUM7UUFFbEQ7O1dBRUc7UUFDYSxnQkFBVyxHQUFZLElBQUksQ0FBQztRQXdCNUM7OztXQUdHO1FBQ2Esc0JBQWlCLEdBQVksSUFBSSxDQUFDO1FBRWxEOztXQUVHO1FBQ2EsZ0JBQVcsR0FBWSxJQUFJLENBQUM7UUFPNUM7OztXQUdHO1FBQ2EsV0FB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Z0JBTUEsVUFBVTtzQkFEaEIsTUFBTTtnQkFPVSxRQUFRO3NCQUF4QixNQUFNO2dCQUtVLFdBQVc7c0JBQTNCLE1BQU07Z0JBRTBDLFNBQVM7c0JBQXpELFNBQVM7dUJBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgTmdab25lLFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdDaGlsZCxcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJzY3JpcHRpb24gfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgQm91bmRzTGl0ZXJhbCB9IGZyb20gJy4uL2ludGVyZmFjZS9ib3VuZHMnO1xuaW1wb3J0IHsgR2VvUG9pbnQgfSBmcm9tICcuLi9pbnRlcmZhY2UvZ2VvLXBvaW50JztcbmltcG9ydCB7IExheWVyVHlwZXMgfSBmcm9tICcuLi9pbnRlcmZhY2UvbGF5ZXJzJztcbmltcG9ydCB7IE1hcE9wdGlvbnMgfSBmcm9tICcuLi9pbnRlcmZhY2UvbWFwLW9wdGlvbnMnO1xuaW1wb3J0IHsgUGFkZGluZyB9IGZyb20gJy4uL2ludGVyZmFjZS9wYWRkaW5nJztcbmltcG9ydCB7IEZpdEJvdW5kc1NlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9maXQtYm91bmRzJztcbmltcG9ydCB7IE1hcHNBcGlXcmFwcGVyIH0gZnJvbSAnLi4vc2VydmljZXMvbWFwcy1hcGktd3JhcHBlcic7XG5cbi8qKlxuICogTmdNYXBzVmlld0NvbXBvbmVudCByZW5kZXJzIGEgR29vZ2xlIE1hcC5cbiAqICoqSW1wb3J0YW50IG5vdGUqKjogVG8gYmUgYWJsZSBzZWUgYSBtYXAgaW4gdGhlIGJyb3dzZXIsIHlvdSBoYXZlIHRvIGRlZmluZSBhIGhlaWdodCBmb3IgdGhlXG4gKiBlbGVtZW50IGBtYXAtdmlld2AuXG4gKlxuICogQGV4YW1wbGVcbiAqIDxtYXAtdmlldyBbbGF0aXR1ZGVdPVwibGF0XCIgW2xvbmdpdHVkZV09XCJsbmdcIiBbem9vbV09XCJ6b29tXCI+PC9tYXAtdmlldz5cbiAqL1xuQENvbXBvbmVudCh7XG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIC5tYXAtY29udGFpbmVyLWlubmVyIHtcbiAgICAgICAgd2lkdGg6IGluaGVyaXQ7XG4gICAgICAgIGhlaWdodDogaW5oZXJpdDtcbiAgICAgIH1cblxuICAgICAgLm1hcC1jb250ZW50IHtcbiAgICAgICAgZGlzcGxheTogbm9uZTtcbiAgICAgIH1cbiAgICBgLFxuICBdLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJtYXAtY29udGFpbmVyLWlubmVyXCIgI2NvbnRhaW5lcj48L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwibWFwLWNvbnRlbnRcIj5cbiAgICAgIDxuZy1jb250ZW50PjwvbmctY29udGVudD5cbiAgICA8L2Rpdj5cbiAgYCxcbn0pXG5leHBvcnQgY2xhc3MgTmdNYXBzVmlld0NvbXBvbmVudDxUPlxuICBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25Jbml0LCBPbkRlc3Ryb3ksIE1hcE9wdGlvbnNcbntcbiAgY29uc3RydWN0b3IoXG4gICAgcHJvdGVjdGVkIF9tYXBzV3JhcHBlcjogTWFwc0FwaVdyYXBwZXI8VD4sXG4gICAgcHJvdGVjdGVkIF9maXRCb3VuZHNTZXJ2aWNlOiBGaXRCb3VuZHNTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCBfem9uZTogTmdab25lLFxuICApIHt9XG5cbiAgLyoqXG4gICAqIE1hcCBvcHRpb24gYXR0cmlidXRlcyB0aGF0IGNhbiBjaGFuZ2Ugb3ZlciB0aW1lXG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBfbWFwT3B0aW9uc0F0dHJpYnV0ZXM6IEFycmF5PHN0cmluZz4gPSBbXG4gICAgJ2Rpc2FibGVEb3VibGVDbGlja1pvb20nLFxuICAgICdzY3JvbGx3aGVlbCcsXG4gICAgJ2RyYWdnYWJsZScsXG4gICAgJ2RyYWdnYWJsZUN1cnNvcicsXG4gICAgJ2RyYWdnaW5nQ3Vyc29yJyxcbiAgICAna2V5Ym9hcmRTaG9ydGN1dHMnLFxuICAgICd6b29tQ29udHJvbCcsXG4gICAgJ3pvb21Db250cm9sT3B0aW9ucycsXG4gICAgJ3N0eWxlcycsXG4gICAgJ3N0cmVldFZpZXdDb250cm9sJyxcbiAgICAnc3RyZWV0Vmlld0NvbnRyb2xPcHRpb25zJyxcbiAgICAnem9vbScsXG4gICAgJ21hcFR5cGVDb250cm9sJyxcbiAgICAnbWFwVHlwZUNvbnRyb2xPcHRpb25zJyxcbiAgICAnbWluWm9vbScsXG4gICAgJ21heFpvb20nLFxuICAgICdwYW5Db250cm9sJyxcbiAgICAncGFuQ29udHJvbE9wdGlvbnMnLFxuICAgICdyb3RhdGVDb250cm9sJyxcbiAgICAncm90YXRlQ29udHJvbE9wdGlvbnMnLFxuICAgICdmdWxsc2NyZWVuQ29udHJvbCcsXG4gICAgJ2Z1bGxzY3JlZW5Db250cm9sT3B0aW9ucycsXG4gICAgJ3NjYWxlQ29udHJvbCcsXG4gICAgJ3NjYWxlQ29udHJvbE9wdGlvbnMnLFxuICAgICdtYXBUeXBlSWQnLFxuICAgICdjbGlja2FibGVJY29ucycsXG4gICAgJ2dlc3R1cmVIYW5kbGluZycsXG4gICAgJ3RpbHQnLFxuICBdO1xuICAvKipcbiAgICogVGhlIGxvbmdpdHVkZSB0aGF0IGRlZmluZXMgdGhlIGNlbnRlciBvZiB0aGUgbWFwLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIGxvbmdpdHVkZTogbnVtYmVyID0gMDtcblxuICAvKipcbiAgICogVGhlIGxhdGl0dWRlIHRoYXQgZGVmaW5lcyB0aGUgY2VudGVyIG9mIHRoZSBtYXAuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgbGF0aXR1ZGU6IG51bWJlciA9IDA7XG5cbiAgLyoqXG4gICAqIFRoZSB6b29tIGxldmVsIG9mIHRoZSBtYXAuIFRoZSBkZWZhdWx0IHpvb20gbGV2ZWwgaXMgOC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyB6b29tOiBudW1iZXIgPSA4O1xuXG4gIC8qKlxuICAgKiBUaGUgbWluaW1hbCB6b29tIGxldmVsIG9mIHRoZSBtYXAgYWxsb3dlZC4gV2hlbiBub3QgcHJvdmlkZWQsIG5vIHJlc3RyaWN0aW9ucyB0byB0aGUgem9vbSBsZXZlbFxuICAgKiBhcmUgZW5mb3JjZWQuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgbWluWm9vbT86IG51bWJlcjtcblxuICAvKipcbiAgICogVGhlIG1heGltYWwgem9vbSBsZXZlbCBvZiB0aGUgbWFwIGFsbG93ZWQuIFdoZW4gbm90IHByb3ZpZGVkLCBubyByZXN0cmljdGlvbnMgdG8gdGhlIHpvb20gbGV2ZWxcbiAgICogYXJlIGVuZm9yY2VkLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIG1heFpvb20/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIEVuYWJsZXMvZGlzYWJsZXMgaWYgbWFwIGlzIGRyYWdnYWJsZS5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBkcmFnZ2FibGU6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKlxuICAgKiBFbmFibGVzL2Rpc2FibGVzIHpvb20gYW5kIGNlbnRlciBvbiBkb3VibGUgY2xpY2suIEVuYWJsZWQgYnkgZGVmYXVsdC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBkaXNhYmxlRG91YmxlQ2xpY2tab29tOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIEVuYWJsZXMvZGlzYWJsZXMgYWxsIGRlZmF1bHQgVUkgb2YgdGhlIEdvb2dsZSBtYXAuIFBsZWFzZSBub3RlOiBXaGVuIHRoZSBtYXAgaXMgY3JlYXRlZCwgdGhpc1xuICAgKiB2YWx1ZSBjYW5ub3QgZ2V0IHVwZGF0ZWQuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgZGlzYWJsZURlZmF1bHRVSTogYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBJZiBmYWxzZSwgZGlzYWJsZXMgc2Nyb2xsd2hlZWwgem9vbWluZyBvbiB0aGUgbWFwLiBUaGUgc2Nyb2xsd2hlZWwgaXMgZW5hYmxlZCBieSBkZWZhdWx0LlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIHNjcm9sbHdoZWVsOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKipcbiAgICogQ29sb3IgdXNlZCBmb3IgdGhlIGJhY2tncm91bmQgb2YgdGhlIE1hcCBkaXYuIFRoaXMgY29sb3Igd2lsbCBiZSB2aXNpYmxlIHdoZW4gdGlsZXMgaGF2ZSBub3RcbiAgICogeWV0IGxvYWRlZCBhcyB0aGUgdXNlciBwYW5zLiBUaGlzIG9wdGlvbiBjYW4gb25seSBiZSBzZXQgd2hlbiB0aGUgbWFwIGlzIGluaXRpYWxpemVkLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIGJhY2tncm91bmRDb2xvcj86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIG5hbWUgb3IgdXJsIG9mIHRoZSBjdXJzb3IgdG8gZGlzcGxheSB3aGVuIG1vdXNpbmcgb3ZlciBhIGRyYWdnYWJsZSBtYXAuIFRoaXMgcHJvcGVydHkgdXNlc1xuICAgKiB0aGUgY3NzICAqIGN1cnNvciBhdHRyaWJ1dGUgdG8gY2hhbmdlIHRoZSBpY29uLiBBcyB3aXRoIHRoZSBjc3MgcHJvcGVydHksIHlvdSBtdXN0IHNwZWNpZnkgYXRcbiAgICogbGVhc3Qgb25lIGZhbGxiYWNrIGN1cnNvciB0aGF0IGlzIG5vdCBhIFVSTC4gRm9yIGV4YW1wbGU6XG4gICAqIFtkcmFnZ2FibGVDdXJzb3JdPVwiJ3VybChodHRwOi8vd3d3LmV4YW1wbGUuY29tL2ljb24ucG5nKSwgYXV0bzsnXCJcbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBkcmFnZ2FibGVDdXJzb3I/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9yIHVybCBvZiB0aGUgY3Vyc29yIHRvIGRpc3BsYXkgd2hlbiB0aGUgbWFwIGlzIGJlaW5nIGRyYWdnZWQuIFRoaXMgcHJvcGVydHkgdXNlcyB0aGVcbiAgICogY3NzIGN1cnNvciBhdHRyaWJ1dGUgdG8gY2hhbmdlIHRoZSBpY29uLiBBcyB3aXRoIHRoZSBjc3MgcHJvcGVydHksIHlvdSBtdXN0IHNwZWNpZnkgYXQgbGVhc3RcbiAgICogb25lIGZhbGxiYWNrIGN1cnNvciB0aGF0IGlzIG5vdCBhIFVSTC4gRm9yIGV4YW1wbGU6XG4gICAqIFtkcmFnZ2luZ0N1cnNvcl09XCIndXJsKGh0dHA6Ly93d3cuZXhhbXBsZS5jb20vaWNvbi5wbmcpLCBhdXRvOydcIlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIGRyYWdnaW5nQ3Vyc29yPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJZiBmYWxzZSwgcHJldmVudHMgdGhlIG1hcCBmcm9tIGJlaW5nIGNvbnRyb2xsZWQgYnkgdGhlIGtleWJvYXJkLiBLZXlib2FyZCBzaG9ydGN1dHMgYXJlXG4gICAqIGVuYWJsZWQgYnkgZGVmYXVsdC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBrZXlib2FyZFNob3J0Y3V0czogYm9vbGVhbiA9IHRydWU7XG5cbiAgLyoqXG4gICAqIFRoZSBlbmFibGVkL2Rpc2FibGVkIHN0YXRlIG9mIHRoZSBab29tIGNvbnRyb2wuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgem9vbUNvbnRyb2w6IGJvb2xlYW4gPSB0cnVlO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciB0aGUgWm9vbSBjb250cm9sLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIHpvb21Db250cm9sT3B0aW9ucz86IGdvb2dsZS5tYXBzLlpvb21Db250cm9sT3B0aW9ucztcblxuICAvKipcbiAgICogU3R5bGVzIHRvIGFwcGx5IHRvIGVhY2ggb2YgdGhlIGRlZmF1bHQgbWFwIHR5cGVzLiBOb3RlIHRoYXQgZm9yIFNhdGVsbGl0ZS9IeWJyaWQgYW5kIFRlcnJhaW5cbiAgICogbW9kZXMsIHRoZXNlIHN0eWxlcyB3aWxsIG9ubHkgYXBwbHkgdG8gbGFiZWxzIGFuZCBnZW9tZXRyeS5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBzdHlsZXM6IEFycmF5PGdvb2dsZS5tYXBzLk1hcFR5cGVTdHlsZT4gPSBbXTtcblxuICAvKipcbiAgICogV2hlbiB0cnVlIGFuZCB0aGUgbGF0aXR1ZGUgYW5kL29yIGxvbmdpdHVkZSB2YWx1ZXMgY2hhbmdlcywgdGhlIEdvb2dsZSBNYXBzIHBhblRvIG1ldGhvZCBpc1xuICAgKiB1c2VkIHRvXG4gICAqIGNlbnRlciB0aGUgbWFwLiBTZWU6IGh0dHBzOi8vZGV2ZWxvcGVycy5nb29nbGUuY29tL21hcHMvZG9jdW1lbnRhdGlvbi9qYXZhc2NyaXB0L3JlZmVyZW5jZSNNYXBcbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyB1c2VQYW5uaW5nOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIFRoZSBpbml0aWFsIGVuYWJsZWQvZGlzYWJsZWQgc3RhdGUgb2YgdGhlIFN0cmVldCBWaWV3IFBlZ21hbiBjb250cm9sLlxuICAgKiBUaGlzIGNvbnRyb2wgaXMgcGFydCBvZiB0aGUgZGVmYXVsdCBVSSwgYW5kIHNob3VsZCBiZSBzZXQgdG8gZmFsc2Ugd2hlbiBkaXNwbGF5aW5nIGEgbWFwIHR5cGVcbiAgICogb24gd2hpY2ggdGhlIFN0cmVldCBWaWV3IHJvYWQgb3ZlcmxheSBzaG91bGQgbm90IGFwcGVhciAoZS5nLiBhIG5vbi1FYXJ0aCBtYXAgdHlwZSkuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgc3RyZWV0Vmlld0NvbnRyb2w/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciB0aGUgU3RyZWV0IFZpZXcgY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBzdHJlZXRWaWV3Q29udHJvbE9wdGlvbnM/OiBnb29nbGUubWFwcy5TdHJlZXRWaWV3Q29udHJvbE9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIHZpZXdwb3J0IHRvIGNvbnRhaW4gdGhlIGdpdmVuIGJvdW5kcy5cbiAgICogSWYgdGhpcyBvcHRpb24gdG8gYHRydWVgLCB0aGUgYm91bmRzIGdldCBhdXRvbWF0aWNhbGx5IGNvbXB1dGVkIGZyb20gYWxsIGVsZW1lbnRzIHRoYXQgdXNlIHRoZSB7QGxpbmsgTmdNYXBzRml0Qm91bmRzfSBkaXJlY3RpdmUuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgZml0Qm91bmRzOiBCb3VuZHNMaXRlcmFsIHwgYm9vbGVhbiA9IGZhbHNlO1xuXG4gIC8qKlxuICAgKiBQYWRkaW5nIGFtb3VudCBmb3IgYm91bmRzLiBUaGlzIG9wdGlvbmFsIHBhcmFtZXRlciBpcyB1bmRlZmluZWQgYnkgZGVmYXVsdC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBib3VuZHNQYWRkaW5nPzogbnVtYmVyIHwgUGFkZGluZztcblxuICAvKipcbiAgICogVGhlIGluaXRpYWwgZW5hYmxlZC9kaXNhYmxlZCBzdGF0ZSBvZiB0aGUgU2NhbGUgY29udHJvbC4gVGhpcyBpcyBkaXNhYmxlZCBieSBkZWZhdWx0LlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIHNjYWxlQ29udHJvbDogYm9vbGVhbiA9IHRydWU7XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIHRoZSBzY2FsZSBjb250cm9sLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIHNjYWxlQ29udHJvbE9wdGlvbnM/OiBnb29nbGUubWFwcy5TY2FsZUNvbnRyb2xPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCBlbmFibGVkL2Rpc2FibGVkIHN0YXRlIG9mIHRoZSBNYXAgdHlwZSBjb250cm9sLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIG1hcFR5cGVDb250cm9sOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKipcbiAgICogT3B0aW9ucyBmb3IgdGhlIE1hcCB0eXBlIGNvbnRyb2wuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgbWFwVHlwZUNvbnRyb2xPcHRpb25zPzogZ29vZ2xlLm1hcHMuTWFwVHlwZUNvbnRyb2xPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCBlbmFibGVkL2Rpc2FibGVkIHN0YXRlIG9mIHRoZSBQYW4gY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBwYW5Db250cm9sOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIHRoZSBQYW4gY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBwYW5Db250cm9sT3B0aW9ucz86IGdvb2dsZS5tYXBzLlBhbkNvbnRyb2xPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCBlbmFibGVkL2Rpc2FibGVkIHN0YXRlIG9mIHRoZSBSb3RhdGUgY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyByb3RhdGVDb250cm9sOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIHRoZSBSb3RhdGUgY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyByb3RhdGVDb250cm9sT3B0aW9ucz86IGdvb2dsZS5tYXBzLlJvdGF0ZUNvbnRyb2xPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCBlbmFibGVkL2Rpc2FibGVkIHN0YXRlIG9mIHRoZSBGdWxsc2NyZWVuIGNvbnRyb2wuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgZnVsbHNjcmVlbkNvbnRyb2w6IGJvb2xlYW4gPSBmYWxzZTtcblxuICAvKipcbiAgICogT3B0aW9ucyBmb3IgdGhlIEZ1bGxzY3JlZW4gY29udHJvbC5cbiAgICovXG4gIEBJbnB1dCgpXG4gIHB1YmxpYyBmdWxsc2NyZWVuQ29udHJvbE9wdGlvbnM/OiBnb29nbGUubWFwcy5GdWxsc2NyZWVuQ29udHJvbE9wdGlvbnM7XG5cbiAgLyoqXG4gICAqIFRoZSBtYXAgbWFwVHlwZUlkLiBEZWZhdWx0cyB0byAncm9hZG1hcCcuXG4gICAqL1xuICBASW5wdXQoKSBwdWJsaWMgbWFwVHlwZUlkOlxuICAgIHwgJ3JvYWRtYXAnXG4gICAgfCAnaHlicmlkJ1xuICAgIHwgJ3NhdGVsbGl0ZSdcbiAgICB8ICd0ZXJyYWluJ1xuICAgIHwgc3RyaW5nXG4gICAgfCBnb29nbGUubWFwcy5NYXBUeXBlSWQgPSAncm9hZG1hcCc7XG5cbiAgLyoqXG4gICAqIEFkZCBsYXllcnMgaHR0cHM6Ly9kZXZlbG9wZXJzLmdvb2dsZS5jb20vbWFwcy9kb2N1bWVudGF0aW9uL2phdmFzY3JpcHQvdHJhZmZpY2xheWVyIHRvIG1hcFxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIGxheWVycz86IEFycmF5PExheWVyVHlwZXM+IHwgTGF5ZXJUeXBlcztcblxuICBwcml2YXRlIF9sYXllckluc3RhbmNlOiBNYXA8XG4gICAgTGF5ZXJUeXBlcyxcbiAgICB8IGdvb2dsZS5tYXBzLlRyYWZmaWNMYXllclxuICAgIHwgZ29vZ2xlLm1hcHMuVHJhbnNpdExheWVyXG4gICAgfCBnb29nbGUubWFwcy5CaWN5Y2xpbmdMYXllclxuICA+ID0gbmV3IE1hcCgpO1xuXG4gIC8qKlxuICAgKiBXaGVuIGZhbHNlLCBtYXAgaWNvbnMgYXJlIG5vdCBjbGlja2FibGUuIEEgbWFwIGljb24gcmVwcmVzZW50cyBhIHBvaW50IG9mIGludGVyZXN0LFxuICAgKiBhbHNvIGtub3duIGFzIGEgUE9JLiBCeSBkZWZhdWx0IG1hcCBpY29ucyBhcmUgY2xpY2thYmxlLlxuICAgKi9cbiAgQElucHV0KCkgcHVibGljIGNsaWNrYWJsZUljb25zOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKipcbiAgICogVGhpcyBzZXR0aW5nIGNvbnRyb2xzIGhvdyBnZXN0dXJlcyBvbiB0aGUgbWFwIGFyZSBoYW5kbGVkLlxuICAgKiBBbGxvd2VkIHZhbHVlczpcbiAgICogLSAnY29vcGVyYXRpdmUnIChUd28tZmluZ2VyIHRvdWNoIGdlc3R1cmVzIHBhbiBhbmQgem9vbSB0aGUgbWFwLiBPbmUtZmluZ2VyIHRvdWNoIGdlc3R1cmVzIGFyZSBub3QgaGFuZGxlZCBieSB0aGUgbWFwLilcbiAgICogLSAnZ3JlZWR5JyAgICAgIChBbGwgdG91Y2ggZ2VzdHVyZXMgcGFuIG9yIHpvb20gdGhlIG1hcC4pXG4gICAqIC0gJ25vbmUnICAgICAgICAoVGhlIG1hcCBjYW5ub3QgYmUgcGFubmVkIG9yIHpvb21lZCBieSB1c2VyIGdlc3R1cmVzLilcbiAgICogLSAnYXV0bycgICAgICAgIFtkZWZhdWx0XSAoR2VzdHVyZSBoYW5kbGluZyBpcyBlaXRoZXIgY29vcGVyYXRpdmUgb3IgZ3JlZWR5LCBkZXBlbmRpbmcgb24gd2hldGhlciB0aGUgcGFnZSBpcyBzY3JvbGxhYmxlIG9yIG5vdC5cbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyBnZXN0dXJlSGFuZGxpbmc6ICdjb29wZXJhdGl2ZScgfCAnZ3JlZWR5JyB8ICdub25lJyB8ICdhdXRvJyA9XG4gICAgJ2F1dG8nO1xuXG4gIC8qKlxuICAgKiBDb250cm9scyB0aGUgYXV0b21hdGljIHN3aXRjaGluZyBiZWhhdmlvciBmb3IgdGhlIGFuZ2xlIG9mIGluY2lkZW5jZSBvZlxuICAgKiB0aGUgbWFwLiBUaGUgb25seSBhbGxvd2VkIHZhbHVlcyBhcmUgMCBhbmQgNDUuIFRoZSB2YWx1ZSAwIGNhdXNlcyB0aGUgbWFwXG4gICAqIHRvIGFsd2F5cyB1c2UgYSAwwrAgb3ZlcmhlYWQgdmlldyByZWdhcmRsZXNzIG9mIHRoZSB6b29tIGxldmVsIGFuZFxuICAgKiB2aWV3cG9ydC4gVGhlIHZhbHVlIDQ1IGNhdXNlcyB0aGUgdGlsdCBhbmdsZSB0byBhdXRvbWF0aWNhbGx5IHN3aXRjaCB0b1xuICAgKiA0NSB3aGVuZXZlciA0NcKwIGltYWdlcnkgaXMgYXZhaWxhYmxlIGZvciB0aGUgY3VycmVudCB6b29tIGxldmVsIGFuZFxuICAgKiB2aWV3cG9ydCwgYW5kIHN3aXRjaCBiYWNrIHRvIDAgd2hlbmV2ZXIgNDXCsCBpbWFnZXJ5IGlzIG5vdCBhdmFpbGFibGVcbiAgICogKHRoaXMgaXMgdGhlIGRlZmF1bHQgYmVoYXZpb3IpLiA0NcKwIGltYWdlcnkgaXMgb25seSBhdmFpbGFibGUgZm9yXG4gICAqIHNhdGVsbGl0ZSBhbmQgaHlicmlkIG1hcCB0eXBlcywgd2l0aGluIHNvbWUgbG9jYXRpb25zLCBhbmQgYXQgc29tZSB6b29tXG4gICAqIGxldmVscy4gTm90ZTogZ2V0VGlsdCByZXR1cm5zIHRoZSBjdXJyZW50IHRpbHQgYW5nbGUsIG5vdCB0aGUgdmFsdWVcbiAgICogc3BlY2lmaWVkIGJ5IHRoaXMgb3B0aW9uLiBCZWNhdXNlIGdldFRpbHQgYW5kIHRoaXMgb3B0aW9uIHJlZmVyIHRvXG4gICAqIGRpZmZlcmVudCB0aGluZ3MsIGRvIG5vdCBiaW5kKCkgdGhlIHRpbHQgcHJvcGVydHk7IGRvaW5nIHNvIG1heSB5aWVsZFxuICAgKiB1bnByZWRpY3RhYmxlIGVmZmVjdHMuIChEZWZhdWx0IG9mIEFHTSBpcyAwIChkaXNhYmxlZCkuIEVuYWJsZSBpdCB3aXRoIHZhbHVlIDQ1LilcbiAgICovXG4gIEBJbnB1dCgpIHB1YmxpYyB0aWx0OiBudW1iZXIgPSAwO1xuXG4gIHByb3RlY3RlZCBzdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbiA9IG5ldyBTdWJzY3JpcHRpb24oKTtcbiAgcHJvdGVjdGVkIF9maXRCb3VuZHNTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb247XG5cbiAgLyoqXG4gICAqIFRoaXMgZXZlbnQgZW1pdHRlciBnZXRzIGVtaXR0ZWQgd2hlbiB0aGUgdXNlciBjbGlja3Mgb24gdGhlIG1hcCAoYnV0IG5vdCB3aGVuIHRoZXkgY2xpY2sgb24gYVxuICAgKiBtYXJrZXIgb3IgaW5mb1dpbmRvdykuXG4gICAqL1xuICBAT3V0cHV0KClcbiAgcHVibGljIG1hcENsaWNrOiBFdmVudEVtaXR0ZXI8Z29vZ2xlLm1hcHMuTWFwTW91c2VFdmVudD4gPVxuICAgIG5ldyBFdmVudEVtaXR0ZXI8Z29vZ2xlLm1hcHMuTWFwTW91c2VFdmVudD4oKTtcblxuICAvKipcbiAgICogVGhpcyBldmVudCBlbWl0dGVyIGdldHMgZW1pdHRlZCB3aGVuIHRoZSB1c2VyIHJpZ2h0LWNsaWNrcyBvbiB0aGUgbWFwIChidXQgbm90IHdoZW4gdGhleSBjbGlja1xuICAgKiBvbiBhIG1hcmtlciBvciBpbmZvV2luZG93KS5cbiAgICovXG4gIEBPdXRwdXQoKVxuICBwdWJsaWMgbWFwUmlnaHRDbGljazogRXZlbnRFbWl0dGVyPGdvb2dsZS5tYXBzLk1hcE1vdXNlRXZlbnQ+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPGdvb2dsZS5tYXBzLk1hcE1vdXNlRXZlbnQ+KCk7XG5cbiAgLyoqXG4gICAqIFRoaXMgZXZlbnQgZW1pdHRlciBnZXRzIGVtaXR0ZWQgd