@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
265 lines • 39.7 kB
JavaScript
import { Component, EventEmitter, Inject, Input, IterableDiffers, Output, SimpleChange } from '@angular/core';
import { ColorService, DatePipe, GeoService, ManagedObjectRealtimeService, WidgetGlobalAutoRefreshService, globalAutoRefreshLoading } from '@c8y/ngx-components';
import { TranslateService } from '@ngx-translate/core';
import { BehaviorSubject, EMPTY, Observable, combineLatest, from, fromEvent, merge, of } from 'rxjs';
import { catchError, debounceTime, mergeMap, skip, switchMap, takeUntil, tap } from 'rxjs/operators';
import { ClusterMap } from './cluster-map';
import { MapComponent } from './map.component';
import { ClusterSize, MAP_DEFAULT_CONFIG, MAP_TILE_LAYER } from './map.model';
import { MapService } from './map.service';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components";
import * as i2 from "./map.service";
import * as i3 from "@ngx-translate/core";
import * as i4 from "rxjs";
export class ClusterMapComponent extends MapComponent {
constructor(moRealtimeService, mapService, layers$, defaultConfig$, translateService, widgetGlobalAutoRefreshService, iterable, colorService, geo, datePipe) {
super(moRealtimeService, mapService, layers$, defaultConfig$, translateService, geo, datePipe, widgetGlobalAutoRefreshService);
this.moRealtimeService = moRealtimeService;
this.mapService = mapService;
this.layers$ = layers$;
this.defaultConfig$ = defaultConfig$;
this.translateService = translateService;
this.widgetGlobalAutoRefreshService = widgetGlobalAutoRefreshService;
this.iterable = iterable;
this.colorService = colorService;
this.isLoading$ = new BehaviorSubject(false);
this.showClusterColor = false;
this.mapChange = new EventEmitter();
this.errorNotifier = new BehaviorSubject(null);
this.reloadTrigger$ = new BehaviorSubject(false);
this.clusters = [];
this.EVENT_THROTTLE_TIME = 750;
}
async ngOnChanges(changes) {
if (changes.config?.firstChange) {
return;
}
if (changes.rootNode?.previousValue !== changes.rootNode?.currentValue) {
this.changeRootNode(changes.rootNode.currentValue);
}
if (changes.config?.currentValue) {
this.changeConfig(changes.config);
}
}
changeConfig(change) {
// on following, cancel reload to avoid stale state
if (change.currentValue.follow === true) {
this.cancelReload();
this.isLoading$.next(false);
}
if (change.currentValue.refreshInterval !== change.previousValue.refreshInterval) {
this.reload();
}
super.changeConfig(change);
}
async ngAfterViewInit() {
if (!this.leaflet) {
this.leaflet = await this.mapService.getLeaflet();
}
if (this.config.widgetInstanceGlobalAutoRefreshContext) {
this.handleGlobalRefreshLoading();
}
combineLatest([this.layers$, this.defaultConfig$])
.pipe(takeUntil(this.unsubscribeTrigger$))
.subscribe(([layers, defaultConfig]) => {
this.initMap(layers, defaultConfig);
this.changeRootNode(this.rootNode);
this.changeConfig(new SimpleChange({}, this.config, false));
});
}
async reset() {
this.ngOnDestroy();
await this.ngAfterViewInit();
}
reload() {
this.reloadTrigger$.next(true);
}
cancelReload() {
this.reloadTrigger$.next(false);
}
listenToClusterAndIntervalChanges() {
const countdownEnded$ = this.config.widgetInstanceGlobalAutoRefreshContext
? this.widgetGlobalAutoRefreshService.countdownActions.countdownEnded$.pipe(takeUntil(this.destroy$))
: this.countdownIntervalComp
? this.countdownIntervalComp.countdownEnded.pipe(takeUntil(this.unsubscribeTrigger$))
: EMPTY;
const mapChange$ = this.getMapChangeObservable();
merge(this.reloadTrigger$, mapChange$, countdownEnded$)
.pipe(tap(value => {
if (this.config.widgetInstanceGlobalAutoRefreshContext) {
!this.isLeafletEventInterface(value) && this.isLoading$.next(true);
return;
}
this.isLoading$.next(true);
this.countdownIntervalComp?.stop(true);
}), switchMap(value => value === false
? of([])
: from(this.mapService.getClusterSize(this.map.getBounds())).pipe(mergeMap((clusterSize) => this.getClusterRects(clusterSize, this.map.getBounds())), mergeMap(rects => this.createOrUpdateCluster(rects)), catchError(error => {
this.errorNotifier.next(error);
return of([]);
}))), takeUntil(this.unsubscribeTrigger$))
.subscribe((clusters) => {
clusters.forEach(cluster => cluster.render(this.map));
this.isLoading$.next(false);
if (this.config.widgetInstanceGlobalAutoRefreshContext) {
return;
}
this.countdownIntervalComp?.start();
});
}
listenToClusterMapChanges() {
this.getMapChangeObservable().subscribe();
}
refreshMarkers() {
if (this.assets) {
super.refreshMarkers();
return;
}
this.clusters.forEach(cluster => {
cluster.clear(this.map);
});
this.reload();
}
changeRootNode(mo) {
this.unsubscribeAllListeners();
this.clearMarkers();
this.clearClusters();
const isPositionDevice = mo?.c8y_Position && mo?.c8y_IsDevice;
if (isPositionDevice) {
this.assets = mo;
this.refreshMarkers();
this.listenToClusterMapChanges();
}
else {
this.assets = null;
this.listenToClusterAndIntervalChanges();
this.reload();
}
}
async getClusterRects(levelThreshold = ClusterSize.FOUR, viewBounds, level = 0) {
let rects = [];
if (levelThreshold === ClusterSize.NONE) {
const rect = await this.getRect(viewBounds);
rects.push(rect);
return rects;
}
if (level >= levelThreshold) {
return rects;
}
level++;
const { lat: x1, lng: y1 } = viewBounds.getSouthWest();
const { lat: x2, lng: y2 } = viewBounds.getNorthEast();
const newX2 = (x1 + x2) / 2;
const newY2 = (y1 + y2) / 2;
const bounds = [
[
[x1, y1],
[newX2, newY2]
],
[
[newX2, newY2],
[x2, y2]
],
[
[x1, newY2],
[newX2, y2]
],
[
[newX2, y1],
[x2, newY2]
]
];
for (const bound of bounds) {
const latLngBound = this.leaflet.latLngBounds(bound);
const rect = await this.getRect(latLngBound);
rects = [...rects, ...(await this.getClusterRects(levelThreshold, latLngBound, level))];
if (level === levelThreshold) {
rects.push(rect);
}
}
return rects;
}
async getRect(latLngBound) {
let color = 'none';
if (this.showClusterColor) {
color = await this.colorService.generateColor(latLngBound.toBBoxString());
}
const rect = this.leaflet.rectangle(latLngBound, {
color,
weight: color === 'none' ? 0 : 1,
interactive: false
});
return rect;
}
clearClusters() {
this.clusters.forEach(cluster => {
cluster.clear(this.map);
});
this.clusters = [];
}
async updateCluster(cluster) {
const clusterCount = await this.mapService.getPositionMOsFromBoundCount(cluster.rect.getBounds(), this.rootNode);
if (clusterCount > this.mapService.MAX_DEVICE_PER_CLUSTER) {
cluster.setClusterToBigMarker(this.map, clusterCount, this.leaflet);
cluster.positions = [];
return cluster;
}
cluster.removeClusterToBigMarker();
cluster.positions = await this.mapService.getPositionMOsFromBound(cluster.rect.getBounds(), this.rootNode);
return cluster;
}
createOrUpdateCluster(rects) {
const isNew = rects.length !== this.clusters.length;
if (isNew) {
this.clearClusters();
}
const updatePromise = rects.map((rect, index) => {
if (isNew) {
const cluster = new ClusterMap(this.iterable, asset => this.getAssetMarker(asset), this.translateService);
this.clusters.push(cluster);
}
this.clusters[index].rect = rect;
return this.updateCluster(this.clusters[index]);
});
return Promise.all(updatePromise);
}
getMapChangeObservable() {
return merge(fromEvent(this.map, 'move'), fromEvent(this.map, 'moveend')).pipe(debounceTime(this.EVENT_THROTTLE_TIME), tap(event => this.mapChange.emit(event)), takeUntil(this.unsubscribeTrigger$));
}
isLeafletEventInterface(LeafletEventObject) {
return LeafletEventObject?.type !== undefined;
}
handleGlobalRefreshLoading() {
this.isLoading$
.pipe(skip(1), globalAutoRefreshLoading(this.widgetGlobalAutoRefreshService), takeUntil(this.destroy$))
.subscribe();
this.destroy$.subscribe({
complete: () => this.isLoading$.value && this.widgetGlobalAutoRefreshService.decrementLoading()
});
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClusterMapComponent, deps: [{ token: i1.ManagedObjectRealtimeService }, { token: i2.MapService }, { token: MAP_TILE_LAYER }, { token: MAP_DEFAULT_CONFIG }, { token: i3.TranslateService }, { token: i1.WidgetGlobalAutoRefreshService }, { token: i0.IterableDiffers }, { token: i1.ColorService }, { token: i1.GeoService }, { token: i1.DatePipe }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: ClusterMapComponent, selector: "c8y-cluster-map", inputs: { config: "config", rootNode: "rootNode", assets: ["asset", "assets"], showClusterColor: "showClusterColor" }, outputs: { mapChange: "mapChange" }, providers: [ManagedObjectRealtimeService], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<div class=\"c8y-map\">\n <div #map></div>\n</div>\n<ng-content></ng-content>\n" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClusterMapComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-cluster-map', providers: [ManagedObjectRealtimeService], template: "<div class=\"c8y-map\">\n <div #map></div>\n</div>\n<ng-content></ng-content>\n" }]
}], ctorParameters: () => [{ type: i1.ManagedObjectRealtimeService }, { type: i2.MapService }, { type: i4.Observable, decorators: [{
type: Inject,
args: [MAP_TILE_LAYER]
}] }, { type: i4.Observable, decorators: [{
type: Inject,
args: [MAP_DEFAULT_CONFIG]
}] }, { type: i3.TranslateService }, { type: i1.WidgetGlobalAutoRefreshService }, { type: i0.IterableDiffers }, { type: i1.ColorService }, { type: i1.GeoService }, { type: i1.DatePipe }], propDecorators: { config: [{
type: Input
}], rootNode: [{
type: Input
}], assets: [{
type: Input,
args: ['asset']
}], showClusterColor: [{
type: Input
}], mapChange: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3Rlci1tYXAuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vbWFwL2NsdXN0ZXItbWFwLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL21hcC9jbHVzdGVyLW1hcC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUNMLGVBQWUsRUFDZixNQUFNLEVBQ04sWUFBWSxFQUViLE1BQU0sZUFBZSxDQUFDO0FBR3ZCLE9BQU8sRUFDTCxZQUFZLEVBRVosUUFBUSxFQUNSLFVBQVUsRUFDViw0QkFBNEIsRUFDNUIsOEJBQThCLEVBQzlCLHdCQUF3QixFQUd6QixNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRXZELE9BQU8sRUFDTCxlQUFlLEVBQ2YsS0FBSyxFQUNMLFVBQVUsRUFDVixhQUFhLEVBQ2IsSUFBSSxFQUNKLFNBQVMsRUFDVCxLQUFLLEVBQ0wsRUFBRSxFQUNILE1BQU0sTUFBTSxDQUFDO0FBQ2QsT0FBTyxFQUNMLFVBQVUsRUFDVixZQUFZLEVBQ1osUUFBUSxFQUNSLElBQUksRUFDSixTQUFTLEVBQ1QsU0FBUyxFQUNULEdBQUcsRUFDSixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFFTCxXQUFXLEVBQ1gsa0JBQWtCLEVBQ2xCLGNBQWMsRUFFZixNQUFNLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOzs7Ozs7QUFPM0MsTUFBTSxPQUFPLG1CQUFvQixTQUFRLFlBQVk7SUEwQm5ELFlBQ1ksaUJBQStDLEVBQy9DLFVBQXNCLEVB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RW1pdHRlcixcbiAgSW5qZWN0LFxuICBJbnB1dCxcbiAgSXRlcmFibGVEaWZmZXJzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZSxcbiAgU2ltcGxlQ2hhbmdlc1xufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IElNYW5hZ2VkT2JqZWN0IH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHR5cGUgeyBNYXBEZWZhdWx0Q29uZmlnLCBNYXBUaWxlTGF5ZXIgfSBmcm9tICdAYzh5L29wdGlvbnMnO1xuaW1wb3J0IHtcbiAgQ29sb3JTZXJ2aWNlLFxuICBDb3VudGRvd25JbnRlcnZhbENvbXBvbmVudCxcbiAgRGF0ZVBpcGUsXG4gIEdlb1NlcnZpY2UsXG4gIE1hbmFnZWRPYmplY3RSZWFsdGltZVNlcnZpY2UsXG4gIFdpZGdldEdsb2JhbEF1dG9SZWZyZXNoU2VydmljZSxcbiAgZ2xvYmFsQXV0b1JlZnJlc2hMb2FkaW5nLFxuICBEeW5hbWljQ29tcG9uZW50LFxuICBEeW5hbWljQ29tcG9uZW50QWxlcnRBZ2dyZWdhdG9yXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHR5cGUgKiBhcyBMIGZyb20gJ2xlYWZsZXQnO1xuaW1wb3J0IHtcbiAgQmVoYXZpb3JTdWJqZWN0LFxuICBFTVBUWSxcbiAgT2JzZXJ2YWJsZSxcbiAgY29tYmluZUxhdGVzdCxcbiAgZnJvbSxcbiAgZnJvbUV2ZW50LFxuICBtZXJnZSxcbiAgb2Zcbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBjYXRjaEVycm9yLFxuICBkZWJvdW5jZVRpbWUsXG4gIG1lcmdlTWFwLFxuICBza2lwLFxuICBzd2l0Y2hNYXAsXG4gIHRha2VVbnRpbCxcbiAgdGFwXG59IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IENsdXN0ZXJNYXAgfSBmcm9tICcuL2NsdXN0ZXItbWFwJztcbmltcG9ydCB7IE1hcENvbXBvbmVudCB9IGZyb20gJy4vbWFwLmNvbXBvbmVudCc7XG5pbXBvcnQge1xuICBDbHVzdGVyTWFwQ29uZmlnLFxuICBDbHVzdGVyU2l6ZSxcbiAgTUFQX0RFRkFVTFRfQ09ORklHLFxuICBNQVBfVElMRV9MQVlFUixcbiAgUG9zaXRpb25NYW5hZ2VkT2JqZWN0XG59IGZyb20gJy4vbWFwLm1vZGVsJztcbmltcG9ydCB7IE1hcFNlcnZpY2UgfSBmcm9tICcuL21hcC5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWNsdXN0ZXItbWFwJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2NsdXN0ZXItbWFwLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbTWFuYWdlZE9iamVjdFJlYWx0aW1lU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgQ2x1c3Rlck1hcENvbXBvbmVudCBleHRlbmRzIE1hcENvbXBvbmVudCBpbXBsZW1lbnRzIER5bmFtaWNDb21wb25lbnQge1xuICBpc0xvYWRpbmckID0gbmV3IEJlaGF2aW9yU3ViamVjdChmYWxzZSk7XG4gIGNvdW50ZG93bkludGVydmFsQ29tcDogQ291bnRkb3duSW50ZXJ2YWxDb21wb25lbnQ7XG5cbiAgQElucHV0KClcbiAgY29uZmlnOiBDbHVzdGVyTWFwQ29uZmlnO1xuXG4gIEBJbnB1dCgpXG4gIHJvb3ROb2RlOiBJTWFuYWdlZE9iamVjdDtcblxuICBASW5wdXQoJ2Fzc2V0JylcbiAgYXNzZXRzOiBQb3NpdGlvbk1hbmFnZWRPYmplY3Q7XG5cbiAgQElucHV0KClcbiAgc2hvd0NsdXN0ZXJDb2xvciA9IGZhbHNlO1xuXG4gIEBPdXRwdXQoKVxuICBtYXBDaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyPEwuTGVhZmxldEV2ZW50PigpO1xuXG4gIGFsZXJ0czogRHluYW1pY0NvbXBvbmVudEFsZXJ0QWdncmVnYXRvcjtcblxuICBlcnJvck5vdGlmaWVyID0gbmV3IEJlaGF2aW9yU3ViamVjdChudWxsKTtcbiAgcHJpdmF0ZSByZWxvYWRUcmlnZ2VyJCA9IG5ldyBCZWhhdmlvclN1YmplY3QoZmFsc2UpO1xuICBwcml2YXRlIGNsdXN0ZXJzOiBDbHVzdGVyTWFwW10gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBFVkVOVF9USFJPVFRMRV9USU1FID0gNzUwO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByb3RlY3RlZCBtb1JlYWx0aW1lU2VydmljZTogTWFuYWdlZE9iamVjdFJlYWx0aW1lU2VydmljZSxcbiAgICBwcm90ZWN0ZWQgbWFwU2VydmljZTogTWFwU2VydmljZSxcbiAgICBASW5qZWN0KE1BUF9USUxFX0xBWUVSKSBwcm90ZWN0ZWQgbGF5ZXJzJDogT2JzZXJ2YWJsZTxNYXBUaWxlTGF5ZXJbXT4sXG4gICAgQEluamVjdChNQVBfREVGQVVMVF9DT05GSUcpXG4gICAgcHJvdGVjdGVkIGRlZmF1bHRDb25maWckOiBPYnNlcnZhYmxlPE1hcERlZmF1bHRDb25maWc+LFxuICAgIHByb3RlY3RlZCB0cmFuc2xhdGVTZXJ2aWNlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgIHByb3RlY3RlZCB3aWRnZXRHbG9iYWxBdXRvUmVmcmVzaFNlcnZpY2U6IFdpZGdldEdsb2JhbEF1dG9SZWZyZXNoU2VydmljZSxcbiAgICBwcml2YXRlIGl0ZXJhYmxlOiBJdGVyYWJsZURpZmZlcnMsXG4gICAgcHJpdmF0ZSBjb2xvclNlcnZpY2U6IENvbG9yU2VydmljZSxcbiAgICBnZW86IEdlb1NlcnZpY2UsXG4gICAgZGF0ZVBpcGU6IERhdGVQaXBlXG4gICkge1xuICAgIHN1cGVyKFxuICAgICAgbW9SZWFsdGltZVNlcnZpY2UsXG4gICAgICBtYXBTZXJ2aWNlLFxuICAgICAgbGF5ZXJzJCxcbiAgICAgIGRlZmF1bHRDb25maWckLFxuICAgICAgdHJhbnNsYXRlU2VydmljZSxcbiAgICAgIGdlbyxcbiAgICAgIGRhdGVQaXBlLFxuICAgICAgd2lkZ2V0R2xvYmFsQXV0b1JlZnJlc2hTZXJ2aWNlXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpIHtcbiAgICBpZiAoY2hhbmdlcy5jb25maWc/LmZpcnN0Q2hhbmdlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGNoYW5nZXMucm9vdE5vZGU/LnByZXZpb3VzVmFsdWUgIT09IGNoYW5nZXMucm9vdE5vZGU/LmN1cnJlbnRWYWx1ZSkge1xuICAgICAgdGhpcy5jaGFuZ2VSb290Tm9kZShjaGFuZ2VzLnJvb3ROb2RlLmN1cnJlbnRWYWx1ZSk7XG4gICAgfVxuXG4gICAgaWYgKGNoYW5nZXMuY29uZmlnPy5jdXJyZW50VmFsdWUpIHtcbiAgICAgIHRoaXMuY2hhbmdlQ29uZmlnKGNoYW5nZXMuY29uZmlnKTtcbiAgICB9XG4gIH1cblxuICBjaGFuZ2VDb25maWcoY2hhbmdlOiBTaW1wbGVDaGFuZ2UpIHtcbiAgICAvLyBvbiBmb2xsb3dpbmcsIGNhbmNlbCByZWxvYWQgdG8gYXZvaWQgc3RhbGUgc3RhdGVcbiAgICBpZiAoY2hhbmdlLmN1cnJlbnRWYWx1ZS5mb2xsb3cgPT09IHRydWUpIHtcbiAgICAgIHRoaXMuY2FuY2VsUmVsb2FkKCk7XG4gICAgICB0aGlzLmlzTG9hZGluZyQubmV4dChmYWxzZSk7XG4gICAgfVxuXG4gICAgaWYgKGNoYW5nZS5jdXJyZW50VmFsdWUucmVmcmVzaEludGVydmFsICE9PSBjaGFuZ2UucHJldmlvdXNWYWx1ZS5yZWZyZXNoSW50ZXJ2YWwpIHtcbiAgICAgIHRoaXMucmVsb2FkKCk7XG4gICAgfVxuICAgIHN1cGVyLmNoYW5nZUNvbmZpZyhjaGFuZ2UpO1xuICB9XG5cbiAgYXN5bmMgbmdBZnRlclZpZXdJbml0KCkge1xuICAgIGlmICghdGhpcy5sZWFmbGV0KSB7XG4gICAgICB0aGlzLmxlYWZsZXQgPSBhd2FpdCB0aGlzLm1hcFNlcnZpY2UuZ2V0TGVhZmxldCgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmNvbmZpZy53aWRnZXRJbnN0YW5jZUdsb2JhbEF1dG9SZWZyZXNoQ29udGV4dCkge1xuICAgICAgdGhpcy5oYW5kbGVHbG9iYWxSZWZyZXNoTG9hZGluZygpO1xuICAgIH1cbiAgICBjb21iaW5lTGF0ZXN0KFt0aGlzLmxheWVycyQsIHRoaXMuZGVmYXVsdENvbmZpZyRdKVxuICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMudW5zdWJzY3JpYmVUcmlnZ2VyJCkpXG4gICAgICAuc3Vic2NyaWJlKChbbGF5ZXJzLCBkZWZhdWx0Q29uZmlnXSkgPT4ge1xuICAgICAgICB0aGlzLmluaXRNYXAobGF5ZXJzLCBkZWZhdWx0Q29uZmlnKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VSb290Tm9kZSh0aGlzLnJvb3ROb2RlKTtcbiAgICAgICAgdGhpcy5jaGFuZ2VDb25maWcobmV3IFNpbXBsZUNoYW5nZSh7fSwgdGhpcy5jb25maWcsIGZhbHNlKSk7XG4gICAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIHJlc2V0KCkge1xuICAgIHRoaXMubmdPbkRlc3Ryb3koKTtcbiAgICBhd2FpdCB0aGlzLm5nQWZ0ZXJWaWV3SW5pdCgpO1xuICB9XG5cbiAgcmVsb2FkKCkge1xuICAgIHRoaXMucmVsb2FkVHJpZ2dlciQubmV4dCh0cnVlKTtcbiAgfVxuXG4gIGNhbmNlbFJlbG9hZCgpIHtcbiAgICB0aGlzLnJlbG9hZFRyaWdnZXIkLm5leHQoZmFsc2UpO1xuICB9XG5cbiAgbGlzdGVuVG9DbHVzdGVyQW5kSW50ZXJ2YWxDaGFuZ2VzKCkge1xuICAgIGNvbnN0IGNvdW50ZG93bkVuZGVkJCA9IHRoaXMuY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsQXV0b1JlZnJlc2hDb250ZXh0XG4gICAgICA/IHRoaXMud2lkZ2V0R2xvYmFsQXV0b1JlZnJlc2hTZXJ2aWNlLmNvdW50ZG93bkFjdGlvbnMuY291bnRkb3duRW5kZWQkLnBpcGUoXG4gICAgICAgICAgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpXG4gICAgICAgIClcbiAgICAgIDogdGhpcy5jb3VudGRvd25JbnRlcnZhbENvbXBcbiAgICAgICAgPyB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcC5jb3VudGRvd25FbmRlZC5waXBlKHRha2VVbnRpbCh0aGlzLnVuc3Vic2NyaWJlVHJpZ2dlciQpKVxuICAgICAgICA6IEVNUFRZO1xuXG4gICAgY29uc3QgbWFwQ2hhbmdlJCA9IHRoaXMuZ2V0TWFwQ2hhbmdlT2JzZXJ2YWJsZSgpO1xuICAgIG1lcmdlKHRoaXMucmVsb2FkVHJpZ2dlciQsIG1hcENoYW5nZSQsIGNvdW50ZG93bkVuZGVkJClcbiAgICAgIC5waXBlKFxuICAgICAgICB0YXAodmFsdWUgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmNvbmZpZy53aWRnZXRJbnN0YW5jZUdsb2JhbEF1dG9SZWZyZXNoQ29udGV4dCkge1xuICAgICAgICAgICAgIXRoaXMuaXNMZWFmbGV0RXZlbnRJbnRlcmZhY2UodmFsdWUpICYmIHRoaXMuaXNMb2FkaW5nJC5uZXh0KHRydWUpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cbiAgICAgICAgICB0aGlzLmlzTG9hZGluZyQubmV4dCh0cnVlKTtcbiAgICAgICAgICB0aGlzLmNvdW50ZG93bkludGVydmFsQ29tcD8uc3RvcCh0cnVlKTtcbiAgICAgICAgfSksXG4gICAgICAgIHN3aXRjaE1hcCh2YWx1ZSA9PlxuICAgICAgICAgIHZhbHVlID09PSBmYWxzZVxuICAgICAgICAgICAgPyBvZihbXSlcbiAgICAgICAgICAgIDogZnJvbSh0aGlzLm1hcFNlcnZpY2UuZ2V0Q2x1c3RlclNpemUodGhpcy5tYXAuZ2V0Qm91bmRzKCkpKS5waXBlKFxuICAgICAgICAgICAgICAgIG1lcmdlTWFwKChjbHVzdGVyU2l6ZTogQ2x1c3RlclNpemUpID0+XG4gICAgICAgICAgICAgICAgICB0aGlzLmdldENsdXN0ZXJSZWN0cyhjbHVzdGVyU2l6ZSwgdGhpcy5tYXAuZ2V0Qm91bmRzKCkpXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBtZXJnZU1hcChyZWN0cyA9PiB0aGlzLmNyZWF0ZU9yVXBkYXRlQ2x1c3RlcihyZWN0cykpLFxuICAgICAgICAgICAgICAgIGNhdGNoRXJyb3IoZXJyb3IgPT4ge1xuICAgICAgICAgICAgICAgICAgdGhpcy5lcnJvck5vdGlmaWVyLm5leHQoZXJyb3IpO1xuXG4gICAgICAgICAgICAgICAgICByZXR1cm4gb2YoW10pO1xuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgIClcbiAgICAgICAgKSxcbiAgICAgICAgdGFrZVVudGlsKHRoaXMudW5zdWJzY3JpYmVUcmlnZ2VyJClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKGNsdXN0ZXJzOiBDbHVzdGVyTWFwW10pID0+IHtcbiAgICAgICAgY2x1c3RlcnMuZm9yRWFjaChjbHVzdGVyID0+IGNsdXN0ZXIucmVuZGVyKHRoaXMubWFwKSk7XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nJC5uZXh0KGZhbHNlKTtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLndpZGdldEluc3RhbmNlR2xvYmFsQXV0b1JlZnJlc2hDb250ZXh0KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY291bnRkb3duSW50ZXJ2YWxDb21wPy5zdGFydCgpO1xuICAgICAgfSk7XG4gIH1cblxuICBsaXN0ZW5Ub0NsdXN0ZXJNYXBDaGFuZ2VzKCkge1xuICAgIHRoaXMuZ2V0TWFwQ2hhbmdlT2JzZXJ2YWJsZSgpLnN1YnNjcmliZSgpO1xuICB9XG5cbiAgcmVmcmVzaE1hcmtlcnMoKSB7XG4gICAgaWYgKHRoaXMuYXNzZXRzKSB7XG4gICAgICBzdXBlci5yZWZyZXNoTWFya2VycygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmNsdXN0ZXJzLmZvckVhY2goY2x1c3RlciA9PiB7XG4gICAgICBjbHVzdGVyLmNsZWFyKHRoaXMubWFwKTtcbiAgICB9KTtcbiAgICB0aGlzLnJlbG9hZCgpO1xuICB9XG5cbiAgcHJpdmF0ZSBjaGFuZ2VSb290Tm9kZShtbzogSU1hbmFnZWRPYmplY3QpIHtcbiAgICB0aGlzLnVuc3Vic2NyaWJlQWxsTGlzdGVuZXJzKCk7XG4gICAgdGhpcy5jbGVhck1hcmtlcnMoKTtcbiAgICB0aGlzLmNsZWFyQ2x1c3RlcnMoKTtcblxuICAgIGNvbnN0IGlzUG9zaXRpb25EZXZpY2UgPSBtbz8uYzh5X1Bvc2l0aW9uICYmIG1vPy5jOHlfSXNEZXZpY2U7XG4gICAgaWYgKGlzUG9zaXRpb25EZXZpY2UpIHtcbiAgICAgIHRoaXMuYXNzZXRzID0gbW8gYXMgUG9zaXRpb25NYW5hZ2VkT2JqZWN0O1xuICAgICAgdGhpcy5yZWZyZXNoTWFya2VycygpO1xuICAgICAgdGhpcy5saXN0ZW5Ub0NsdXN0ZXJNYXBDaGFuZ2VzKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuYXNzZXRzID0gbnVsbDtcbiAgICAgIHRoaXMubGlzdGVuVG9DbHVzdGVyQW5kSW50ZXJ2YWxDaGFuZ2VzKCk7XG4gICAgICB0aGlzLnJlbG9hZCgpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0Q2x1c3RlclJlY3RzKFxuICAgIGxldmVsVGhyZXNob2xkOiBDbHVzdGVyU2l6ZSA9IENsdXN0ZXJTaXplLkZPVVIsXG4gICAgdmlld0JvdW5kczogTC5MYXRMbmdCb3VuZHMsXG4gICAgbGV2ZWwgPSAwXG4gICk6IFByb21pc2U8TC5SZWN0YW5nbGVbXT4ge1xuICAgIGxldCByZWN0cyA9IFtdO1xuXG4gICAgaWYgKGxldmVsVGhyZXNob2xkID09PSBDbHVzdGVyU2l6ZS5OT05FKSB7XG4gICAgICBjb25zdCByZWN0ID0gYXdhaXQgdGhpcy5nZXRSZWN0KHZpZXdCb3VuZHMpO1xuICAgICAgcmVjdHMucHVzaChyZWN0KTtcbiAgICAgIHJldHVybiByZWN0cztcbiAgICB9XG5cbiAgICBpZiAobGV2ZWwgPj0gbGV2ZWxUaHJlc2hvbGQpIHtcbiAgICAgIHJldHVybiByZWN0cztcbiAgICB9XG4gICAgbGV2ZWwrKztcblxuICAgIGNvbnN0IHsgbGF0OiB4MSwgbG5nOiB5MSB9ID0gdmlld0JvdW5kcy5nZXRTb3V0aFdlc3QoKTtcbiAgICBjb25zdCB7IGxhdDogeDIsIGxuZzogeTIgfSA9IHZpZXdCb3VuZHMuZ2V0Tm9ydGhFYXN0KCk7XG4gICAgY29uc3QgbmV3WDIgPSAoeDEgKyB4MikgLyAyO1xuICAgIGNvbnN0IG5ld1kyID0gKHkxICsgeTIpIC8gMjtcblxuICAgIGNvbnN0IGJvdW5kczogW1tudW1iZXIsIG51bWJlcl0sIFtudW1iZXIsIG51bWJlcl1dW10gPSBbXG4gICAgICBbXG4gICAgICAgIFt4MSwgeTFdLFxuICAgICAgICBbbmV3WDIsIG5ld1kyXVxuICAgICAgXSxcbiAgICAgIFtcbiAgICAgICAgW25ld1gyLCBuZXdZMl0sXG4gICAgICAgIFt4MiwgeTJdXG4gICAgICBdLFxuICAgICAgW1xuICAgICAgICBbeDEsIG5ld1kyXSxcbiAgICAgICAgW25ld1gyLCB5Ml1cbiAgICAgIF0sXG4gICAgICBbXG4gICAgICAgIFtuZXdYMiwgeTFdLFxuICAgICAgICBbeDIsIG5ld1kyXVxuICAgICAgXVxuICAgIF07XG4gICAgZm9yIChjb25zdCBib3VuZCBvZiBib3VuZHMpIHtcbiAgICAgIGNvbnN0IGxhdExuZ0JvdW5kID0gdGhpcy5sZWFmbGV0LmxhdExuZ0JvdW5kcyhib3VuZCk7XG4gICAgICBjb25zdCByZWN0ID0gYXdhaXQgdGhpcy5nZXRSZWN0KGxhdExuZ0JvdW5kKTtcbiAgICAgIHJlY3RzID0gWy4uLnJlY3RzLCAuLi4oYXdhaXQgdGhpcy5nZXRDbHVzdGVyUmVjdHMobGV2ZWxUaHJlc2hvbGQsIGxhdExuZ0JvdW5kLCBsZXZlbCkpXTtcblxuICAgICAgaWYgKGxldmVsID09PSBsZXZlbFRocmVzaG9sZCkge1xuICAgICAgICByZWN0cy5wdXNoKHJlY3QpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZWN0cztcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZ2V0UmVjdChsYXRMbmdCb3VuZDogTC5MYXRMbmdCb3VuZHMpIHtcbiAgICBsZXQgY29sb3IgPSAnbm9uZSc7XG4gICAgaWYgKHRoaXMuc2hvd0NsdXN0ZXJDb2xvcikge1xuICAgICAgY29sb3IgPSBhd2FpdCB0aGlzLmNvbG9yU2VydmljZS5nZW5lcmF0ZUNvbG9yKGxhdExuZ0JvdW5kLnRvQkJveFN0cmluZygpKTtcbiAgICB9XG4gICAgY29uc3QgcmVjdCA9IHRoaXMubGVhZmxldC5yZWN0YW5nbGUobGF0TG5nQm91bmQsIHtcbiAgICAgIGNvbG9yLFxuICAgICAgd2VpZ2h0OiBjb2xvciA9PT0gJ25vbmUnID8gMCA6IDEsXG4gICAgICBpbnRlcmFjdGl2ZTogZmFsc2VcbiAgICB9KTtcbiAgICByZXR1cm4gcmVjdDtcbiAgfVxuXG4gIHByaXZhdGUgY2xlYXJDbHVzdGVycygpIHtcbiAgICB0aGlzLmNsdXN0ZXJzLmZvckVhY2goY2x1c3RlciA9PiB7XG4gICAgICBjbHVzdGVyLmNsZWFyKHRoaXMubWFwKTtcbiAgICB9KTtcbiAgICB0aGlzLmNsdXN0ZXJzID0gW107XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHVwZGF0ZUNsdXN0ZXIoY2x1c3RlcjogQ2x1c3Rlck1hcCkge1xuICAgIGNvbnN0IGNsdXN0ZXJDb3VudCA9IGF3YWl0IHRoaXMubWFwU2VydmljZS5nZXRQb3NpdGlvbk1Pc0Zyb21Cb3VuZENvdW50KFxuICAgICAgY2x1c3Rlci5yZWN0LmdldEJvdW5kcygpLFxuICAgICAgdGhpcy5yb290Tm9kZVxuICAgICk7XG4gICAgaWYgKGNsdXN0ZXJDb3VudCA+IHRoaXMubWFwU2VydmljZS5NQVhfREVWSUNFX1BFUl9DTFVTVEVSKSB7XG4gICAgICBjbHVzdGVyLnNldENsdXN0ZXJUb0JpZ01hcmtlcih0aGlzLm1hcCwgY2x1c3RlckNvdW50LCB0aGlzLmxlYWZsZXQpO1xuICAgICAgY2x1c3Rlci5wb3NpdGlvbnMgPSBbXTtcbiAgICAgIHJldHVybiBjbHVzdGVyO1xuICAgIH1cblxuICAgIGNsdXN0ZXIucmVtb3ZlQ2x1c3RlclRvQmlnTWFya2VyKCk7XG4gICAgY2x1c3Rlci5wb3NpdGlvbnMgPSBhd2FpdCB0aGlzLm1hcFNlcnZpY2UuZ2V0UG9zaXRpb25NT3NGcm9tQm91bmQoXG4gICAgICBjbHVzdGVyLnJlY3QuZ2V0Qm91bmRzKCksXG4gICAgICB0aGlzLnJvb3ROb2RlXG4gICAgKTtcbiAgICByZXR1cm4gY2x1c3RlcjtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlT3JVcGRhdGVDbHVzdGVyKHJlY3RzOiBMLlJlY3RhbmdsZTx1bmtub3duPltdKSB7XG4gICAgY29uc3QgaXNOZXcgPSByZWN0cy5sZW5ndGggIT09IHRoaXMuY2x1c3RlcnMubGVuZ3RoO1xuICAgIGlmIChpc05ldykge1xuICAgICAgdGhpcy5jbGVhckNsdXN0ZXJzKCk7XG4gICAgfVxuICAgIGNvbnN0IHVwZGF0ZVByb21pc2UgPSByZWN0cy5tYXAoKHJlY3QsIGluZGV4KSA9PiB7XG4gICAgICBpZiAoaXNOZXcpIHtcbiAgICAgICAgY29uc3QgY2x1c3RlciA9IG5ldyBDbHVzdGVyTWFwKFxuICAgICAgICAgIHRoaXMuaXRlcmFibGUsXG4gICAgICAgICAgYXNzZXQgPT4gdGhpcy5nZXRBc3NldE1hcmtlcihhc3NldCksXG4gICAgICAgICAgdGhpcy50cmFuc2xhdGVTZXJ2aWNlXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuY2x1c3RlcnMucHVzaChjbHVzdGVyKTtcbiAgICAgIH1cbiAgICAgIHRoaXMuY2x1c3RlcnNbaW5kZXhdLnJlY3QgPSByZWN0O1xuICAgICAgcmV0dXJuIHRoaXMudXBkYXRlQ2x1c3Rlcih0aGlzLmNsdXN0ZXJzW2luZGV4XSk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gUHJvbWlzZS5hbGwodXBkYXRlUHJvbWlzZSk7XG4gIH1cblxuICBwcml2YXRlIGdldE1hcENoYW5nZU9ic2VydmFibGUoKSB7XG4gICAgcmV0dXJuIG1lcmdlKFxuICAgICAgZnJvbUV2ZW50PEwuTGVhZmxldEV2ZW50Pih0aGlzLm1hcCwgJ21vdmUnKSxcbiAgICAgIGZyb21FdmVudDxMLkxlYWZsZXRFdmVudD4odGhpcy5tYXAsICdtb3ZlZW5kJylcbiAgICApLnBpcGUoXG4gICAgICBkZWJvdW5jZVRpbWUodGhpcy5FVkVOVF9USFJPVFRMRV9USU1FKSxcbiAgICAgIHRhcChldmVudCA9PiB0aGlzLm1hcENoYW5nZS5lbWl0KGV2ZW50KSksXG4gICAgICB0YWtlVW50aWwodGhpcy51bnN1YnNjcmliZVRyaWdnZXIkKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGlzTGVhZmxldEV2ZW50SW50ZXJmYWNlKFxuICAgIExlYWZsZXRFdmVudE9iamVjdDogTC5MZWFmbGV0RXZlbnQgfCBib29sZWFuIHwgdm9pZFxuICApOiBMZWFmbGV0RXZlbnRPYmplY3QgaXMgTC5MZWFmbGV0RXZlbnQge1xuICAgIHJldHVybiAoTGVhZmxldEV2ZW50T2JqZWN0IGFzIEwuTGVhZmxldEV2ZW50KT8udHlwZSAhPT0gdW5kZWZpbmVkO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVHbG9iYWxSZWZyZXNoTG9hZGluZygpOiB2b2lkIHtcbiAgICB0aGlzLmlzTG9hZGluZyRcbiAgICAgIC5waXBlKFxuICAgICAgICBza2lwKDEpLFxuICAgICAgICBnbG9iYWxBdXRvUmVmcmVzaExvYWRpbmcodGhpcy53aWRnZXRHbG9iYWxBdXRvUmVmcmVzaFNlcnZpY2UpLFxuICAgICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95JClcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUoKTtcblxuICAgIHRoaXMuZGVzdHJveSQuc3Vic2NyaWJlKHtcbiAgICAgIGNvbXBsZXRlOiAoKSA9PlxuICAgICAgICB0aGlzLmlzTG9hZGluZyQudmFsdWUgJiYgdGhpcy53aWRnZXRHbG9iYWxBdXRvUmVmcmVzaFNlcnZpY2UuZGVjcmVtZW50TG9hZGluZygpXG4gICAgfSk7XG4gIH1cbn1cbiIsIjxkaXYgY2xhc3M9XCJjOHktbWFwXCI+XG4gIDxkaXYgI21hcD48L2Rpdj5cbjwvZGl2PlxuPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuIl19