UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

126 lines 26.7 kB
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { CountdownIntervalComponent } from '@c8y/ngx-components'; import { cloneDeep } from 'lodash-es'; import { Subject } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; import { ClusterMapComponent } from './cluster-map.component'; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "ngx-bootstrap/tooltip"; export class MapStatusComponent { constructor() { this.configChange = new EventEmitter(); this.onUnfollow = new EventEmitter(); this.buttonsConfig = {}; this.centerMapButtonDisabled = true; this.refreshPaused = false; this.destroy$ = new Subject(); } ngOnInit() { this.initConfig = cloneDeep(this.config); this.buttonsConfig = Object.assign(this.defaultButtonsConfig(), this.buttonsConfig); } ngAfterViewInit() { if (!this.config.widgetInstanceGlobalAutoRefreshContext) { this.clusterMap.countdownIntervalComp = this.countdownIntervalComp; } } ngOnChanges(changes) { if (changes.clusterMap?.previousValue !== changes.clusterMap?.currentValue) { this.checkIfMapIsAlreadyCentered(); } } center() { this.clusterMap.center(); } reload() { this.clusterMap.reload(); } cancelReload() { this.clusterMap.cancelReload(); } toggleRealtime() { this.config = { ...this.config, realtime: !this.config.realtime }; this.configChange.emit(this.config); } toggleAutoRefresh($event) { $event.preventDefault(); $event.stopPropagation(); this.refreshPaused = !this.refreshPaused; if (this.refreshPaused) { this.countdownIntervalComp.stop(true); } else { this.countdownIntervalComp.start(); } } unfollow() { this.config = { ...this.clusterMap.config, follow: false }; this.configChange.emit(this.config); this.onUnfollow.emit(this.config); } follow() { this.config = { ...this.config, follow: true }; this.configChange.emit(this.config); } ngOnDestroy() { this.destroy$.next(); } checkIfMapIsAlreadyCentered() { this.clusterMap.mapChange.pipe(takeUntil(this.destroy$)).subscribe((event) => { if (this.config?.center && event.sourceTarget?.getBounds) { const bounds = event.sourceTarget.getBounds(); this.centerMapButtonDisabled = this.shouldDisableCenterButton(bounds); } }); } /** * Checks if Center button should be disabled according to provided bounds. * Provided bounds contain coordinates of current map rectangle corners. * Center button should be disabled if distance between center coordinates (from config) and center of current bounds * is less than 1/4 of bounds dimensions. * To achieve it we just need to check if center coordinates (from config) are contained in the boundaries of * current bounds shrunk by 25%. * @param bounds Current map view boundaries. * @returns True if distance between config center and current boundaries center is bigger than 1/4 of boundaries dimensions */ shouldDisableCenterButton(bounds) { const shrunkBounds = bounds.pad(-0.25); return shrunkBounds.contains(this.config.center); } defaultButtonsConfig() { return { realtime: { show: this.config.realtime || this.clusterMap.config.follow, disabled: false } }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MapStatusComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MapStatusComponent, selector: "c8y-map-status", inputs: { config: "config", clusterMap: "clusterMap", buttonsConfig: "buttonsConfig" }, outputs: { configChange: "configChange", onUnfollow: "onUnfollow" }, viewQueries: [{ propertyName: "countdownIntervalComp", first: true, predicate: CountdownIntervalComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"c8y-map-status\">\n <div class=\"leaflet-touch\">\n <div\n class=\"leaflet-bar\"\n role=\"group\"\n >\n <button\n class=\"c8y-realtime\"\n title=\"{{ 'Realtime' | translate }}\"\n type=\"button\"\n *ngIf=\"buttonsConfig.realtime.show\"\n (click)=\"toggleRealtime()\"\n [disabled]=\"buttonsConfig.realtime.disabled\"\n >\n <span\n class=\"c8y-pulse\"\n [ngClass]=\"{\n active: clusterMap?.config.realtime,\n inactive: !clusterMap?.config.realtime\n }\"\n ></span>\n </button>\n\n <label\n class=\"toggle-countdown vertical\"\n [attr.aria-label]=\"\n refreshPaused ? ('Enable auto refresh' | translate) : ('Disable auto refresh' | translate)\n \"\n [tooltip]=\"\n refreshPaused ? ('Enable auto refresh' | translate) : ('Disable auto refresh' | translate)\n \"\n placement=\"left\"\n *ngIf=\"\n !config.widgetInstanceGlobalAutoRefreshContext &&\n clusterMap?.config.refreshInterval &&\n !clusterMap?.config.follow\n \"\n [adaptivePosition]=\"false\"\n [container]=\"'body'\"\n [delay]=\"1000\"\n >\n <input\n type=\"checkbox\"\n (click)=\"toggleAutoRefresh($event)\"\n />\n <c8y-countdown-interval\n [hidden]=\"refreshPaused\"\n [countdownInterval]=\"clusterMap?.config.refreshInterval\"\n ></c8y-countdown-interval>\n <i\n c8yIcon=\"pause\"\n *ngIf=\"refreshPaused\"\n ></i>\n </label>\n\n <button\n title=\"{{ 'Cancel reload' | translate }}\"\n type=\"button\"\n *ngIf=\"(clusterMap?.isLoading$ | async) && !config.widgetInstanceGlobalAutoRefreshContext\"\n (click)=\"cancelReload()\"\n >\n <i\n class=\"icon-spin\"\n c8yIcon=\"refresh\"\n ></i>\n </button>\n <button\n [title]=\"'Reload' | translate\"\n type=\"button\"\n *ngIf=\"\n !clusterMap?.config.realtime &&\n !clusterMap?.assets &&\n !(clusterMap?.isLoading$ | async) &&\n !config.widgetInstanceGlobalAutoRefreshContext\n \"\n (click)=\"reload()\"\n >\n <i c8yIcon=\"refresh\"></i>\n </button>\n <button\n title=\"{{ 'Center map' | translate }}\"\n type=\"button\"\n (click)=\"center()\"\n [disabled]=\"centerMapButtonDisabled || clusterMap?.config.follow\"\n >\n <i c8yIcon=\"target1\"></i>\n </button>\n <button\n title=\"{{ 'Unfollow' | translate }}\"\n type=\"button\"\n *ngIf=\"clusterMap?.config.follow\"\n (click)=\"unfollow()\"\n >\n <i c8yIcon=\"marker-off\"></i>\n </button>\n\n <button\n title=\"{{ 'Follow' | translate }}\"\n type=\"button\"\n *ngIf=\"initConfig.follow && !clusterMap?.config.follow\"\n (click)=\"follow()\"\n >\n <i c8yIcon=\"marker\"></i>\n </button>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "component", type: i2.CountdownIntervalComponent, selector: "c8y-countdown-interval", inputs: ["countdownInterval"], outputs: ["countdownEnded"] }, { kind: "directive", type: i3.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MapStatusComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-map-status', template: "<div class=\"c8y-map-status\">\n <div class=\"leaflet-touch\">\n <div\n class=\"leaflet-bar\"\n role=\"group\"\n >\n <button\n class=\"c8y-realtime\"\n title=\"{{ 'Realtime' | translate }}\"\n type=\"button\"\n *ngIf=\"buttonsConfig.realtime.show\"\n (click)=\"toggleRealtime()\"\n [disabled]=\"buttonsConfig.realtime.disabled\"\n >\n <span\n class=\"c8y-pulse\"\n [ngClass]=\"{\n active: clusterMap?.config.realtime,\n inactive: !clusterMap?.config.realtime\n }\"\n ></span>\n </button>\n\n <label\n class=\"toggle-countdown vertical\"\n [attr.aria-label]=\"\n refreshPaused ? ('Enable auto refresh' | translate) : ('Disable auto refresh' | translate)\n \"\n [tooltip]=\"\n refreshPaused ? ('Enable auto refresh' | translate) : ('Disable auto refresh' | translate)\n \"\n placement=\"left\"\n *ngIf=\"\n !config.widgetInstanceGlobalAutoRefreshContext &&\n clusterMap?.config.refreshInterval &&\n !clusterMap?.config.follow\n \"\n [adaptivePosition]=\"false\"\n [container]=\"'body'\"\n [delay]=\"1000\"\n >\n <input\n type=\"checkbox\"\n (click)=\"toggleAutoRefresh($event)\"\n />\n <c8y-countdown-interval\n [hidden]=\"refreshPaused\"\n [countdownInterval]=\"clusterMap?.config.refreshInterval\"\n ></c8y-countdown-interval>\n <i\n c8yIcon=\"pause\"\n *ngIf=\"refreshPaused\"\n ></i>\n </label>\n\n <button\n title=\"{{ 'Cancel reload' | translate }}\"\n type=\"button\"\n *ngIf=\"(clusterMap?.isLoading$ | async) && !config.widgetInstanceGlobalAutoRefreshContext\"\n (click)=\"cancelReload()\"\n >\n <i\n class=\"icon-spin\"\n c8yIcon=\"refresh\"\n ></i>\n </button>\n <button\n [title]=\"'Reload' | translate\"\n type=\"button\"\n *ngIf=\"\n !clusterMap?.config.realtime &&\n !clusterMap?.assets &&\n !(clusterMap?.isLoading$ | async) &&\n !config.widgetInstanceGlobalAutoRefreshContext\n \"\n (click)=\"reload()\"\n >\n <i c8yIcon=\"refresh\"></i>\n </button>\n <button\n title=\"{{ 'Center map' | translate }}\"\n type=\"button\"\n (click)=\"center()\"\n [disabled]=\"centerMapButtonDisabled || clusterMap?.config.follow\"\n >\n <i c8yIcon=\"target1\"></i>\n </button>\n <button\n title=\"{{ 'Unfollow' | translate }}\"\n type=\"button\"\n *ngIf=\"clusterMap?.config.follow\"\n (click)=\"unfollow()\"\n >\n <i c8yIcon=\"marker-off\"></i>\n </button>\n\n <button\n title=\"{{ 'Follow' | translate }}\"\n type=\"button\"\n *ngIf=\"initConfig.follow && !clusterMap?.config.follow\"\n (click)=\"follow()\"\n >\n <i c8yIcon=\"marker\"></i>\n </button>\n </div>\n </div>\n</div>\n" }] }], propDecorators: { config: [{ type: Input }], configChange: [{ type: Output }], onUnfollow: [{ type: Output }], clusterMap: [{ type: Input }], buttonsConfig: [{ type: Input }], countdownIntervalComp: [{ type: ViewChild, args: [CountdownIntervalComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFwLXN0YXR1cy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9tYXAvbWFwLXN0YXR1cy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi9tYXAvbWFwLXN0YXR1cy5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFpQixTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDakcsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUN0QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQzs7Ozs7QUFPOUQsTUFBTSxPQUFPLGtCQUFrQjtJQUovQjtRQVNFLGlCQUFZLEdBQUcsSUFBSSxZQUFZLEVBQW9CLENBQUM7UUFHcEQsZUFBVSxHQUFHLElBQUksWUFBWSxFQUFvQixDQUFDO1FBS3pDLGtCQUFhLEdBQW9DLEVBQUUsQ0FBQztRQUU3RCw0QkFBdUIsR0FBRyxJQUFJLENBQUM7UUFJL0Isa0JBQWEsR0FBRyxLQUFLLENBQUM7UUFDZCxhQUFRLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztLQW9HeEM7SUFsR0MsUUFBUTtRQUNOLElBQUksQ0FBQyxVQUFVLEdBQUcsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN6QyxJQUFJLENBQUMsYUFBYSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFFRCxlQUFlO1FBQ2Is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O0lBQ0sseUJBQXlCLENBQUMsTUFBc0I7UUFDdEQsTUFBTSxZQUFZLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLE9BQU8sWUFBWSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFFTyxvQkFBb0I7UUFDMUIsT0FBTztZQUNMLFFBQVEsRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsUUFBUSxFQUFFLEtBQUssRUFBRTtTQUMzRixDQUFDO0lBQ0osQ0FBQzsrR0F2SFUsa0JBQWtCO21HQUFsQixrQkFBa0IsMFFBZ0JsQiwwQkFBMEIscUVDNUJ2QyxzbUdBMkdBOzs0RkQvRmEsa0JBQWtCO2tCQUo5QixTQUFTOytCQUNFLGdCQUFnQjs4QkFLMUIsTUFBTTtzQkFETCxLQUFLO2dCQUlOLFlBQVk7c0JBRFgsTUFBTTtnQkFJUCxVQUFVO3NCQURULE1BQU07Z0JBSVAsVUFBVTtzQkFEVCxLQUFLO2dCQUdHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBR2lDLHFCQUFxQjtzQkFBM0QsU0FBUzt1QkFBQywwQkFBMEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIEV2ZW50RW1pdHRlciwgSW5wdXQsIE91dHB1dCwgU2ltcGxlQ2hhbmdlcywgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb3VudGRvd25JbnRlcnZhbENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IENsdXN0ZXJNYXBDb21wb25lbnQgfSBmcm9tICcuL2NsdXN0ZXItbWFwLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBDbHVzdGVyTWFwQ29uZmlnLCBNYXBTdGF0dXNCdXR0b25zQ29uZmlnIH0gZnJvbSAnLi9tYXAubW9kZWwnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktbWFwLXN0YXR1cycsXG4gIHRlbXBsYXRlVXJsOiAnLi9tYXAtc3RhdHVzLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBNYXBTdGF0dXNDb21wb25lbnQge1xuICBASW5wdXQoKVxuICBjb25maWc6IENsdXN0ZXJNYXBDb25maWc7XG5cbiAgQE91dHB1dCgpXG4gIGNvbmZpZ0NoYW5nZSA9IG5ldyBFdmVudEVtaXR0ZXI8Q2x1c3Rlck1hcENvbmZpZz4oKTtcblxuICBAT3V0cHV0KClcbiAgb25VbmZvbGxvdyA9IG5ldyBFdmVudEVtaXR0ZXI8Q2x1c3Rlck1hcENvbmZpZz4oKTtcblxuICBASW5wdXQoKVxuICBjbHVzdGVyTWFwOiBDbHVzdGVyTWFwQ29tcG9uZW50O1xuXG4gIEBJbnB1dCgpIGJ1dHRvbnNDb25maWc6IFBhcnRpYWw8TWFwU3RhdHVzQnV0dG9uc0NvbmZpZz4gPSB7fTtcblxuICBjZW50ZXJNYXBCdXR0b25EaXNhYmxlZCA9IHRydWU7XG4gIEBWaWV3Q2hpbGQoQ291bnRkb3duSW50ZXJ2YWxDb21wb25lbnQpIGNvdW50ZG93bkludGVydmFsQ29tcDogQ291bnRkb3duSW50ZXJ2YWxDb21wb25lbnQ7XG5cbiAgaW5pdENvbmZpZzogQ2x1c3Rlck1hcENvbmZpZztcbiAgcmVmcmVzaFBhdXNlZCA9IGZhbHNlO1xuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmluaXRDb25maWcgPSBjbG9uZURlZXAodGhpcy5jb25maWcpO1xuICAgIHRoaXMuYnV0dG9uc0NvbmZpZyA9IE9iamVjdC5hc3NpZ24odGhpcy5kZWZhdWx0QnV0dG9uc0NvbmZpZygpLCB0aGlzLmJ1dHRvbnNDb25maWcpO1xuICB9XG5cbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xuICAgIGlmICghdGhpcy5jb25maWcud2lkZ2V0SW5zdGFuY2VHbG9iYWxBdXRvUmVmcmVzaENvbnRleHQpIHtcbiAgICAgIHRoaXMuY2x1c3Rlck1hcC5jb3VudGRvd25JbnRlcnZhbENvbXAgPSB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcDtcbiAgICB9XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgaWYgKGNoYW5nZXMuY2x1c3Rlck1hcD8ucHJldmlvdXNWYWx1ZSAhPT0gY2hhbmdlcy5jbHVzdGVyTWFwPy5jdXJyZW50VmFsdWUpIHtcbiAgICAgIHRoaXMuY2hlY2tJZk1hcElzQWxyZWFkeUNlbnRlcmVkKCk7XG4gICAgfVxuICB9XG5cbiAgY2VudGVyKCkge1xuICAgIHRoaXMuY2x1c3Rlck1hcC5jZW50ZXIoKTtcbiAgfVxuXG4gIHJlbG9hZCgpIHtcbiAgICB0aGlzLmNsdXN0ZXJNYXAucmVsb2FkKCk7XG4gIH1cblxuICBjYW5jZWxSZWxvYWQoKSB7XG4gICAgdGhpcy5jbHVzdGVyTWFwLmNhbmNlbFJlbG9hZCgpO1xuICB9XG5cbiAgdG9nZ2xlUmVhbHRpbWUoKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICAuLi50aGlzLmNvbmZpZyxcbiAgICAgIHJlYWx0aW1lOiAhdGhpcy5jb25maWcucmVhbHRpbWVcbiAgICB9O1xuICAgIHRoaXMuY29uZmlnQ2hhbmdlLmVtaXQodGhpcy5jb25maWcpO1xuICB9XG5cbiAgdG9nZ2xlQXV0b1JlZnJlc2goJGV2ZW50OiBNb3VzZUV2ZW50KSB7XG4gICAgJGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIHRoaXMucmVmcmVzaFBhdXNlZCA9ICF0aGlzLnJlZnJlc2hQYXVzZWQ7XG4gICAgaWYgKHRoaXMucmVmcmVzaFBhdXNlZCkge1xuICAgICAgdGhpcy5jb3VudGRvd25JbnRlcnZhbENvbXAuc3RvcCh0cnVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5jb3VudGRvd25JbnRlcnZhbENvbXAuc3RhcnQoKTtcbiAgICB9XG4gIH1cblxuICB1bmZvbGxvdygpIHtcbiAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgIC4uLnRoaXMuY2x1c3Rlck1hcC5jb25maWcsXG4gICAgICBmb2xsb3c6IGZhbHNlXG4gICAgfTtcbiAgICB0aGlzLmNvbmZpZ0NoYW5nZS5lbWl0KHRoaXMuY29uZmlnKTtcbiAgICB0aGlzLm9uVW5mb2xsb3cuZW1pdCh0aGlzLmNvbmZpZyk7XG4gIH1cblxuICBmb2xsb3coKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICAuLi50aGlzLmNvbmZpZyxcbiAgICAgIGZvbGxvdzogdHJ1ZVxuICAgIH07XG4gICAgdGhpcy5jb25maWdDaGFuZ2UuZW1pdCh0aGlzLmNvbmZpZyk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcbiAgfVxuXG4gIHByaXZhdGUgY2hlY2tJZk1hcElzQWxyZWFkeUNlbnRlcmVkKCkge1xuICAgIHRoaXMuY2x1c3Rlck1hcC5tYXBDaGFuZ2UucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZSgoZXZlbnQ6IEwuTGVhZmxldEV2ZW50KSA9PiB7XG4gICAgICBpZiAodGhpcy5jb25maWc/LmNlbnRlciAmJiBldmVudC5zb3VyY2VUYXJnZXQ/LmdldEJvdW5kcykge1xuICAgICAgICBjb25zdCBib3VuZHM6IEwuTGF0TG5nQm91bmRzID0gZXZlbnQuc291cmNlVGFyZ2V0LmdldEJvdW5kcygpO1xuICAgICAgICB0aGlzLmNlbnRlck1hcEJ1dHRvbkRpc2FibGVkID0gdGhpcy5zaG91bGREaXNhYmxlQ2VudGVyQnV0dG9uKGJvdW5kcyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2tzIGlmIENlbnRlciBidXR0b24gc2hvdWxkIGJlIGRpc2FibGVkIGFjY29yZGluZyB0byBwcm92aWRlZCBib3VuZHMuXG4gICAqIFByb3ZpZGVkIGJvdW5kcyBjb250YWluIGNvb3JkaW5hdGVzIG9mIGN1cnJlbnQgbWFwIHJlY3RhbmdsZSBjb3JuZXJzLlxuICAgKiBDZW50ZXIgYnV0dG9uIHNob3VsZCBiZSBkaXNhYmxlZCBpZiBkaXN0YW5jZSBiZXR3ZWVuIGNlbnRlciBjb29yZGluYXRlcyAoZnJvbSBjb25maWcpIGFuZCBjZW50ZXIgb2YgY3VycmVudCBib3VuZHNcbiAgICogaXMgbGVzcyB0aGFuIDEvNCBvZiBib3VuZHMgZGltZW5zaW9ucy5cbiAgICogVG8gYWNoaWV2ZSBpdCB3ZSBqdXN0IG5lZWQgdG8gY2hlY2sgaWYgY2VudGVyIGNvb3JkaW5hdGVzIChmcm9tIGNvbmZpZykgYXJlIGNvbnRhaW5lZCBpbiB0aGUgYm91bmRhcmllcyBvZlxuICAgKiBjdXJyZW50IGJvdW5kcyBzaHJ1bmsgYnkgMjUlLlxuICAgKiBAcGFyYW0gYm91bmRzIEN1cnJlbnQgbWFwIHZpZXcgYm91bmRhcmllcy5cbiAgICogQHJldHVybnMgVHJ1ZSBpZiBkaXN0YW5jZSBiZXR3ZWVuIGNvbmZpZyBjZW50ZXIgYW5kIGN1cnJlbnQgYm91bmRhcmllcyBjZW50ZXIgaXMgYmlnZ2VyIHRoYW4gMS80IG9mIGJvdW5kYXJpZXMgZGltZW5zaW9uc1xuICAgKi9cbiAgcHJpdmF0ZSBzaG91bGREaXNhYmxlQ2VudGVyQnV0dG9uKGJvdW5kczogTC5MYXRMbmdCb3VuZHMpOiBib29sZWFuIHtcbiAgICBjb25zdCBzaHJ1bmtCb3VuZHMgPSBib3VuZHMucGFkKC0wLjI1KTtcbiAgICByZXR1cm4gc2hydW5rQm91bmRzLmNvbnRhaW5zKHRoaXMuY29uZmlnLmNlbnRlcik7XG4gIH1cblxuICBwcml2YXRlIGRlZmF1bHRCdXR0b25zQ29uZmlnKCk6IE1hcFN0YXR1c0J1dHRvbnNDb25maWcge1xuICAgIHJldHVybiB7XG4gICAgICByZWFsdGltZTogeyBzaG93OiB0aGlzLmNvbmZpZy5yZWFsdGltZSB8fCB0aGlzLmNsdXN0ZXJNYXAuY29uZmlnLmZvbGxvdywgZGlzYWJsZWQ6IGZhbHNlIH1cbiAgICB9O1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwiYzh5LW1hcC1zdGF0dXNcIj5cbiAgPGRpdiBjbGFzcz1cImxlYWZsZXQtdG91Y2hcIj5cbiAgICA8ZGl2XG4gICAgICBjbGFzcz1cImxlYWZsZXQtYmFyXCJcbiAgICAgIHJvbGU9XCJncm91cFwiXG4gICAgPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBjbGFzcz1cImM4eS1yZWFsdGltZVwiXG4gICAgICAgIHRpdGxlPVwie3sgJ1JlYWx0aW1lJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAqbmdJZj1cImJ1dHRvbnNDb25maWcucmVhbHRpbWUuc2hvd1wiXG4gICAgICAgIChjbGljayk9XCJ0b2dnbGVSZWFsdGltZSgpXCJcbiAgICAgICAgW2Rpc2FibGVkXT1cImJ1dHRvbnNDb25maWcucmVhbHRpbWUuZGlzYWJsZWRcIlxuICAgICAgPlxuICAgICAgICA8c3BhblxuICAgICAgICAgIGNsYXNzPVwiYzh5LXB1bHNlXCJcbiAgICAgICAgICBbbmdDbGFzc109XCJ7XG4gICAgICAgICAgICBhY3RpdmU6IGNsdXN0ZXJNYXA/LmNvbmZpZy5yZWFsdGltZSxcbiAgICAgICAgICAgIGluYWN0aXZlOiAhY2x1c3Rlck1hcD8uY29uZmlnLnJlYWx0aW1lXG4gICAgICAgICAgfVwiXG4gICAgICAgID48L3NwYW4+XG4gICAgICA8L2J1dHRvbj5cblxuICAgICAgPGxhYmVsXG4gICAgICAgIGNsYXNzPVwidG9nZ2xlLWNvdW50ZG93biB2ZXJ0aWNhbFwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiXG4gICAgICAgICAgcmVmcmVzaFBhdXNlZCA/ICgnRW5hYmxlIGF1dG8gcmVmcmVzaCcgfCB0cmFuc2xhdGUpIDogKCdEaXNhYmxlIGF1dG8gcmVmcmVzaCcgfCB0cmFuc2xhdGUpXG4gICAgICAgIFwiXG4gICAgICAgIFt0b29sdGlwXT1cIlxuICAgICAgICAgIHJlZnJlc2hQYXVzZWQgPyAoJ0VuYWJsZSBhdXRvIHJlZnJlc2gnIHwgdHJhbnNsYXRlKSA6ICgnRGlzYWJsZSBhdXRvIHJlZnJlc2gnIHwgdHJhbnNsYXRlKVxuICAgICAgICBcIlxuICAgICAgICBwbGFjZW1lbnQ9XCJsZWZ0XCJcbiAgICAgICAgKm5nSWY9XCJcbiAgICAgICAgICAhY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsQXV0b1JlZnJlc2hDb250ZXh0ICYmXG4gICAgICAgICAgY2x1c3Rlck1hcD8uY29uZmlnLnJlZnJlc2hJbnRlcnZhbCAmJlxuICAgICAgICAgICFjbHVzdGVyTWFwPy5jb25maWcuZm9sbG93XG4gICAgICAgIFwiXG4gICAgICAgIFthZGFwdGl2ZVBvc2l0aW9uXT1cImZhbHNlXCJcbiAgICAgICAgW2NvbnRhaW5lcl09XCInYm9keSdcIlxuICAgICAgICBbZGVsYXldPVwiMTAwMFwiXG4gICAgICA+XG4gICAgICAgIDxpbnB1dFxuICAgICAgICAgIHR5cGU9XCJjaGVja2JveFwiXG4gICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZUF1dG9SZWZyZXNoKCRldmVudClcIlxuICAgICAgICAvPlxuICAgICAgICA8Yzh5LWNvdW50ZG93bi1pbnRlcnZhbFxuICAgICAgICAgIFtoaWRkZW5dPVwicmVmcmVzaFBhdXNlZFwiXG4gICAgICAgICAgW2NvdW50ZG93bkludGVydmFsXT1cImNsdXN0ZXJNYXA/LmNvbmZpZy5yZWZyZXNoSW50ZXJ2YWxcIlxuICAgICAgICA+PC9jOHktY291bnRkb3duLWludGVydmFsPlxuICAgICAgICA8aVxuICAgICAgICAgIGM4eUljb249XCJwYXVzZVwiXG4gICAgICAgICAgKm5nSWY9XCJyZWZyZXNoUGF1c2VkXCJcbiAgICAgICAgPjwvaT5cbiAgICAgIDwvbGFiZWw+XG5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdGl0bGU9XCJ7eyAnQ2FuY2VsIHJlbG9hZCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgKm5nSWY9XCIoY2x1c3Rlck1hcD8uaXNMb2FkaW5nJCB8IGFzeW5jKSAmJiAhY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsQXV0b1JlZnJlc2hDb250ZXh0XCJcbiAgICAgICAgKGNsaWNrKT1cImNhbmNlbFJlbG9hZCgpXCJcbiAgICAgID5cbiAgICAgICAgPGlcbiAgICAgICAgICBjbGFzcz1cImljb24tc3BpblwiXG4gICAgICAgICAgYzh5SWNvbj1cInJlZnJlc2hcIlxuICAgICAgICA+PC9pPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIFt0aXRsZV09XCInUmVsb2FkJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAqbmdJZj1cIlxuICAgICAgICAgICFjbHVzdGVyTWFwPy5jb25maWcucmVhbHRpbWUgJiZcbiAgICAgICAgICAhY2x1c3Rlck1hcD8uYXNzZXRzICYmXG4gICAgICAgICAgIShjbHVzdGVyTWFwPy5pc0xvYWRpbmckIHwgYXN5bmMpICYmXG4gICAgICAgICAgIWNvbmZpZy53aWRnZXRJbnN0YW5jZUdsb2JhbEF1dG9SZWZyZXNoQ29udGV4dFxuICAgICAgICBcIlxuICAgICAgICAoY2xpY2spPVwicmVsb2FkKClcIlxuICAgICAgPlxuICAgICAgICA8aSBjOHlJY29uPVwicmVmcmVzaFwiPjwvaT5cbiAgICAgIDwvYnV0dG9uPlxuICAgICAgPGJ1dHRvblxuICAgICAgICB0aXRsZT1cInt7ICdDZW50ZXIgbWFwJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAoY2xpY2spPVwiY2VudGVyKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwiY2VudGVyTWFwQnV0dG9uRGlzYWJsZWQgfHwgY2x1c3Rlck1hcD8uY29uZmlnLmZvbGxvd1wiXG4gICAgICA+XG4gICAgICAgIDxpIGM4eUljb249XCJ0YXJnZXQxXCI+PC9pPlxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHRpdGxlPVwie3sgJ1VuZm9sbG93JyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAqbmdJZj1cImNsdXN0ZXJNYXA/LmNvbmZpZy5mb2xsb3dcIlxuICAgICAgICAoY2xpY2spPVwidW5mb2xsb3coKVwiXG4gICAgICA+XG4gICAgICAgIDxpIGM4eUljb249XCJtYXJrZXItb2ZmXCI+PC9pPlxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdGl0bGU9XCJ7eyAnRm9sbG93JyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAqbmdJZj1cImluaXRDb25maWcuZm9sbG93ICYmICFjbHVzdGVyTWFwPy5jb25maWcuZm9sbG93XCJcbiAgICAgICAgKGNsaWNrKT1cImZvbGxvdygpXCJcbiAgICAgID5cbiAgICAgICAgPGkgYzh5SWNvbj1cIm1hcmtlclwiPjwvaT5cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19