UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

88 lines 27.6 kB
import { Component, ViewChild } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { ActionBarModule, ContextRouteService, CoreModule, EventRealtimeService, TimeIntervalComponent } from '@c8y/ngx-components'; import { MapComponent, MapModule } from '@c8y/ngx-components/map'; import { TrackingMarkerPopupComponent } from './tracking-marker-popup.component'; import { TrackingService } from './tracking.service'; import * as i0 from "@angular/core"; import * as i1 from "./tracking.service"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "@angular/router"; import * as i4 from "@c8y/ngx-components/map"; import * as i5 from "@angular/common"; export class TrackingComponent { constructor(service, realtime, contextRouteService, activatedRoute) { this.service = service; this.realtime = realtime; this.contextRouteService = contextRouteService; this.activatedRoute = activatedRoute; this.dateRangePickerConfig = { adaptivePosition: true, showPreviousMonth: true, preventChangeToNextMonth: true }; this.config = { realtime: true, follow: false, zoomLevel: 12, fitBoundsOptions: { padding: [50, 50] } }; this.maxDate = new Date(); this.activeMarkers = {}; this.realtimeDisabled = false; } async ngOnInit() { const { contextData } = this.contextRouteService.getContextData(this.activatedRoute); this.device = contextData; } async ngAfterViewInit() { this.service.setDeviceId(this.device.id); this.togglePositionRealtime(this.realtime.active); } toggleMarker(event) { let marker = this.map.findMarker(event); if (marker) { this.map.removeMarker(marker); delete this.activeMarkers[`p${event.id}`]; } else { marker = this.map.getTrackingMarker(event); this.map.addMarkerToMap(marker); this.activeMarkers[`p${event.id}`] = true; } } togglePositionRealtime(active) { this.config = { ...this.config, realtime: active }; } toggleRealtime(interval) { const currentTimeInRange = Date.now() <= interval?.dateTo?.getTime(); this.togglePositionRealtime(currentTimeInRange); this.realtimeDisabled = !currentTimeInRange; if (currentTimeInRange) { this.realtime.start(); } else { this.realtime.stop(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingComponent, deps: [{ token: i1.TrackingService }, { token: i2.EventRealtimeService }, { token: i2.ContextRouteService }, { token: i3.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TrackingComponent, isStandalone: true, selector: "c8y-tracking", providers: [EventRealtimeService], viewQueries: [{ propertyName: "map", first: true, predicate: MapComponent, descendants: true }], ngImport: i0, template: "<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n>\n <c8y-realtime-btn\n [service]=\"realtime\"\n [disabled]=\"realtimeDisabled\"\n (onToggle)=\"togglePositionRealtime($event)\"\n ></c8y-realtime-btn>\n</c8y-action-bar-item>\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"60\"\n>\n <c8y-time-interval\n [maxCustomDate]=\"maxDate\"\n [dateRangePickerConfig]=\"dateRangePickerConfig\"\n (interval)=\"service.setInterval($event); toggleRealtime($event)\"\n ></c8y-time-interval>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid content-fullpage d-grid grid__col--8-4--md\">\n <div class=\"bg-white p-relative\">\n <c8y-map\n [config]=\"config\"\n [assets]=\"device\"\n [polyline$]=\"service.polyline$\"\n [polylineOptions]=\"{ color: 'darkblue' }\"\n >\n <div *c8yMapPopup=\"let context\">\n <c8y-tracking-marker-popup [context]=\"context\"></c8y-tracking-marker-popup>\n </div>\n </c8y-map>\n </div>\n\n <div class=\"d-flex d-col bg-inherit content-fullpage bg-gray-white\">\n <div class=\"card-header large-padding separator sticky-top\">\n <span\n class=\"card-title\"\n translate\n >\n Tracking events\n </span>\n </div>\n <div class=\"inner-scroll\">\n <c8y-list-group class=\"c8y-list__group--strip\">\n <ng-template\n c8yFor\n let-event\n [c8yForOf]=\"service.events$\"\n [c8yForPipe]=\"service.pipe\"\n [c8yForRealtime]=\"realtime\"\n [c8yForRealtimeOptions]=\"{ entityOrId: device }\"\n [c8yForLoadMore]=\"'hidden'\"\n [c8yForNotFound]=\"empty\"\n (c8yForLoadMoreComponent)=\"\n loadMoreComponent = $event; loadMoreComponent.useIntersection = false\n \"\n >\n <c8y-li\n class=\"pointer\"\n [ngClass]=\"{ 'text-primary text-bold': activeMarkers['p' + event?.id] }\"\n (click)=\"toggleMarker(event)\"\n [attr.data-cy]=\"'c8y-tracking--tracking-event-item-' + event?.id\"\n >\n <c8y-li-icon [ngClass]=\"{ 'text-primary': activeMarkers['p' + event?.id] }\">\n <i c8yIcon=\"c8y-location\"></i>\n </c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex\">\n <span>\n {{ event.time | date: 'mediumDate' }}\n </span>\n <span class=\"m-l-auto\">\n {{ event.time | date: 'mediumTime' }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n\n <!-- empty state -->\n <ng-template #empty>\n <c8y-ui-empty-state\n icon=\"c8y-location\"\n [title]=\"'No tracking events found.' | translate\"\n [subtitle]=\"'Select another time range.' | translate\"\n *ngIf=\"!service.hasEvents\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n\n <div *ngIf=\"loadMoreComponent?.hasMore\">\n <button\n class=\"btn btn-link fit-w sticky-bottom separator-top\"\n [title]=\"'Load more' | translate\"\n type=\"button\"\n [disabled]=\"loadMoreComponent?.isLoading\"\n (click)=\"loadMoreComponent.loadMore()\"\n data-cy=\"c8y-tracking--load-more\"\n >\n {{ 'Load more' | translate }}\n </button>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Deselect all markers' | translate\"\n type=\"button\"\n [disabled]=\"(activeMarkers | json) === '{}'\"\n (click)=\"map.clearMarkers('event'); activeMarkers = {}\"\n >\n {{ 'Deselect all markers' | translate }}\n </button>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: MapModule }, { kind: "component", type: i4.MapComponent, selector: "c8y-map", inputs: ["config", "assets", "polyline$", "polylineOptions"], outputs: ["onRealtimeUpdate", "onMove", "onMoveEnd", "onZoomStart", "onZoomEnd", "onMap", "onInit"] }, { kind: "directive", type: i4.MapPopupDirective, selector: "[c8yMapPopup]" }, { kind: "ngmodule", type: ActionBarModule }, { kind: "component", type: i2.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "ngmodule", type: CoreModule }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i5.JsonPipe, name: "json" }, { kind: "pipe", type: i5.DatePipe, name: "date" }, { kind: "directive", type: i2.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i2.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i2.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i2.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i2.ListItemBodyComponent, selector: "c8y-list-item-body, c8y-li-body", inputs: ["body"] }, { kind: "component", type: i2.RealtimeButtonComponent, selector: "c8y-realtime-btn", inputs: ["service", "label", "title", "disabled"], outputs: ["onToggle"] }, { kind: "component", type: i2.TimeIntervalComponent, selector: "c8y-time-interval", inputs: ["minCustomDate", "maxCustomDate", "dateRangePickerConfig", "selectedInterval"], outputs: ["interval"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: TrackingMarkerPopupComponent, selector: "c8y-tracking-marker-popup", inputs: ["context", "showTrackingLink"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TrackingComponent, decorators: [{ type: Component, args: [{ standalone: true, imports: [ MapModule, ActionBarModule, CoreModule, TimeIntervalComponent, FormsModule, TrackingMarkerPopupComponent ], providers: [EventRealtimeService], selector: 'c8y-tracking', template: "<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"100\"\n>\n <c8y-realtime-btn\n [service]=\"realtime\"\n [disabled]=\"realtimeDisabled\"\n (onToggle)=\"togglePositionRealtime($event)\"\n ></c8y-realtime-btn>\n</c8y-action-bar-item>\n<c8y-action-bar-item\n [placement]=\"'right'\"\n [priority]=\"60\"\n>\n <c8y-time-interval\n [maxCustomDate]=\"maxDate\"\n [dateRangePickerConfig]=\"dateRangePickerConfig\"\n (interval)=\"service.setInterval($event); toggleRealtime($event)\"\n ></c8y-time-interval>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid content-fullpage d-grid grid__col--8-4--md\">\n <div class=\"bg-white p-relative\">\n <c8y-map\n [config]=\"config\"\n [assets]=\"device\"\n [polyline$]=\"service.polyline$\"\n [polylineOptions]=\"{ color: 'darkblue' }\"\n >\n <div *c8yMapPopup=\"let context\">\n <c8y-tracking-marker-popup [context]=\"context\"></c8y-tracking-marker-popup>\n </div>\n </c8y-map>\n </div>\n\n <div class=\"d-flex d-col bg-inherit content-fullpage bg-gray-white\">\n <div class=\"card-header large-padding separator sticky-top\">\n <span\n class=\"card-title\"\n translate\n >\n Tracking events\n </span>\n </div>\n <div class=\"inner-scroll\">\n <c8y-list-group class=\"c8y-list__group--strip\">\n <ng-template\n c8yFor\n let-event\n [c8yForOf]=\"service.events$\"\n [c8yForPipe]=\"service.pipe\"\n [c8yForRealtime]=\"realtime\"\n [c8yForRealtimeOptions]=\"{ entityOrId: device }\"\n [c8yForLoadMore]=\"'hidden'\"\n [c8yForNotFound]=\"empty\"\n (c8yForLoadMoreComponent)=\"\n loadMoreComponent = $event; loadMoreComponent.useIntersection = false\n \"\n >\n <c8y-li\n class=\"pointer\"\n [ngClass]=\"{ 'text-primary text-bold': activeMarkers['p' + event?.id] }\"\n (click)=\"toggleMarker(event)\"\n [attr.data-cy]=\"'c8y-tracking--tracking-event-item-' + event?.id\"\n >\n <c8y-li-icon [ngClass]=\"{ 'text-primary': activeMarkers['p' + event?.id] }\">\n <i c8yIcon=\"c8y-location\"></i>\n </c8y-li-icon>\n <c8y-li-body>\n <div class=\"d-flex\">\n <span>\n {{ event.time | date: 'mediumDate' }}\n </span>\n <span class=\"m-l-auto\">\n {{ event.time | date: 'mediumTime' }}\n </span>\n </div>\n </c8y-li-body>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n\n <!-- empty state -->\n <ng-template #empty>\n <c8y-ui-empty-state\n icon=\"c8y-location\"\n [title]=\"'No tracking events found.' | translate\"\n [subtitle]=\"'Select another time range.' | translate\"\n *ngIf=\"!service.hasEvents\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n </ng-template>\n\n <div *ngIf=\"loadMoreComponent?.hasMore\">\n <button\n class=\"btn btn-link fit-w sticky-bottom separator-top\"\n [title]=\"'Load more' | translate\"\n type=\"button\"\n [disabled]=\"loadMoreComponent?.isLoading\"\n (click)=\"loadMoreComponent.loadMore()\"\n data-cy=\"c8y-tracking--load-more\"\n >\n {{ 'Load more' | translate }}\n </button>\n </div>\n\n <div class=\"card-footer separator\">\n <button\n class=\"btn btn-default\"\n [title]=\"'Deselect all markers' | translate\"\n type=\"button\"\n [disabled]=\"(activeMarkers | json) === '{}'\"\n (click)=\"map.clearMarkers('event'); activeMarkers = {}\"\n >\n {{ 'Deselect all markers' | translate }}\n </button>\n </div>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.TrackingService }, { type: i2.EventRealtimeService }, { type: i2.ContextRouteService }, { type: i3.ActivatedRoute }], propDecorators: { map: [{ type: ViewChild, args: [MapComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJhY2tpbmcuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vdHJhY2tpbmcvdHJhY2tpbmcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vdHJhY2tpbmcvdHJhY2tpbmcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFpQixTQUFTLEVBQVUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzVFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3QyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFakQsT0FBTyxFQUNMLGVBQWUsRUFDZixtQkFBbUIsRUFDbkIsVUFBVSxFQUVWLG9CQUFvQixFQUdwQixxQkFBcUIsRUFDdEIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBQUUsWUFBWSxFQUFhLFNBQVMsRUFBeUIsTUFBTSx5QkFBeUIsQ0FBQztBQUNwRyxPQUFPLEVBQUUsNEJBQTRCLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUNqRixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUM7Ozs7Ozs7QUFnQnJELE1BQU0sT0FBTyxpQkFBaUI7SUF5QjVCLFlBQ1MsT0FBd0IsRUFDeEIsUUFBOEIsRUFDN0IsbUJBQXdDLEVBQ3hDLGNBQThCO1FBSC9CLFlBQU8sR0FBUCxPQUFPLENBQWlCO1FBQ3hCLGFBQVEsR0FBUixRQUFRLENBQXNCO1FBQzdCLHdCQUFtQixHQUFuQixtQkFBbUIsQ0FBcUI7UUFDeEMsbUJBQWMsR0FBZCxjQUFjLENBQWdCO1FBekJ4QywwQkFBcUIsR0FBMEI7WUFDN0MsZ0JBQWdCLEVBQUUsSUFBSTtZQUN0QixpQkFBaUIsRUFBRSxJQUFJO1lBQ3ZCLHdCQUF3QixFQUFFLElBQUk7U0FDL0IsQ0FBQztRQUVGLFdBQU0sR0FBYztZQUNsQixRQUFRLEVBQUUsSUFBSTtZQUNkLE1BQU0sRUFB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ZXdJbml0LCBDb21wb25lbnQsIE9uSW5pdCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3Jtc01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEFjdGl2YXRlZFJvdXRlIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IElFdmVudCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7XG4gIEFjdGlvbkJhck1vZHVsZSxcbiAgQ29udGV4dFJvdXRlU2VydmljZSxcbiAgQ29yZU1vZHVsZSxcbiAgRGF0ZVJhbmdlUGlja2VyQ29uZmlnLFxuICBFdmVudFJlYWx0aW1lU2VydmljZSxcbiAgTG9hZE1vcmVDb21wb25lbnQsXG4gIFRpbWVJbnRlcnZhbCxcbiAgVGltZUludGVydmFsQ29tcG9uZW50XG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgTWFwQ29tcG9uZW50LCBNYXBDb25maWcsIE1hcE1vZHVsZSwgUG9zaXRpb25NYW5hZ2VkT2JqZWN0IH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9tYXAnO1xuaW1wb3J0IHsgVHJhY2tpbmdNYXJrZXJQb3B1cENvbXBvbmVudCB9IGZyb20gJy4vdHJhY2tpbmctbWFya2VyLXBvcHVwLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBUcmFja2luZ1NlcnZpY2UgfSBmcm9tICcuL3RyYWNraW5nLnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgdGVtcGxhdGVVcmw6ICcuL3RyYWNraW5nLmNvbXBvbmVudC5odG1sJyxcbiAgaW1wb3J0czogW1xuICAgIE1hcE1vZHVsZSxcbiAgICBBY3Rpb25CYXJNb2R1bGUsXG4gICAgQ29yZU1vZHVsZSxcbiAgICBUaW1lSW50ZXJ2YWxDb21wb25lbnQsXG4gICAgRm9ybXNNb2R1bGUsXG4gICAgVHJhY2tpbmdNYXJrZXJQb3B1cENvbXBvbmVudFxuICBdLFxuICBwcm92aWRlcnM6IFtFdmVudFJlYWx0aW1lU2VydmljZV0sXG4gIHNlbGVjdG9yOiAnYzh5LXRyYWNraW5nJ1xufSlcbmV4cG9ydCBjbGFzcyBUcmFja2luZ0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCB7XG4gIEBWaWV3Q2hpbGQoTWFwQ29tcG9uZW50KVxuICBtYXA6IE1hcENvbXBvbmVudDtcblxuICBkYXRlUmFuZ2VQaWNrZXJDb25maWc6IERhdGVSYW5nZVBpY2tlckNvbmZpZyA9IHtcbiAgICBhZGFwdGl2ZVBvc2l0aW9uOiB0cnVlLFxuICAgIHNob3dQcmV2aW91c01vbnRoOiB0cnVlLFxuICAgIHByZXZlbnRDaGFuZ2VUb05leHRNb250aDogdHJ1ZVxuICB9O1xuXG4gIGNvbmZpZzogTWFwQ29uZmlnID0ge1xuICAgIHJlYWx0aW1lOiB0cnVlLFxuICAgIGZvbGxvdzogZmFsc2UsXG4gICAgem9vbUxldmVsOiAxMixcbiAgICBmaXRCb3VuZHNPcHRpb25zOiB7XG4gICAgICBwYWRkaW5nOiBbNTAsIDUwXVxuICAgIH1cbiAgfTtcblxuICBtYXhEYXRlID0gbmV3IERhdGUoKTtcbiAgYWN0aXZlTWFya2VyczogeyBba2V5OiBzdHJpbmddOiBib29sZWFuIH0gPSB7fTtcbiAgcmVhbHRpbWVEaXNhYmxlZCA9IGZhbHNlO1xuICBkZXZpY2U6IFBvc2l0aW9uTWFuYWdlZE9iamVjdDtcbiAgbG9hZE1vcmVDb21wb25lbnQ6IExvYWRNb3JlQ29tcG9uZW50O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHB1YmxpYyBzZXJ2aWNlOiBUcmFja2luZ1NlcnZpY2UsXG4gICAgcHVibGljIHJlYWx0aW1lOiBFdmVudFJlYWx0aW1lU2VydmljZSxcbiAgICBwcml2YXRlIGNvbnRleHRSb3V0ZVNlcnZpY2U6IENvbnRleHRSb3V0ZVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhY3RpdmF0ZWRSb3V0ZTogQWN0aXZhdGVkUm91dGVcbiAgKSB7fVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIGNvbnN0IHsgY29udGV4dERhdGEgfSA9IHRoaXMuY29udGV4dFJvdXRlU2VydmljZS5nZXRDb250ZXh0RGF0YSh0aGlzLmFjdGl2YXRlZFJvdXRlKTtcbiAgICB0aGlzLmRldmljZSA9IGNvbnRleHREYXRhIGFzIFBvc2l0aW9uTWFuYWdlZE9iamVjdDtcbiAgfVxuXG4gIGFzeW5jIG5nQWZ0ZXJWaWV3SW5pdCgpIHtcbiAgICB0aGlzLnNlcnZpY2Uuc2V0RGV2aWNlSWQodGhpcy5kZXZpY2UuaWQpO1xuICAgIHRoaXMudG9nZ2xlUG9zaXRpb25SZWFsdGltZSh0aGlzLnJlYWx0aW1lLmFjdGl2ZSk7XG4gIH1cblxuICB0b2dnbGVNYXJrZXIoZXZlbnQ6IElFdmVudCkge1xuICAgIGxldCBtYXJrZXIgPSB0aGlzLm1hcC5maW5kTWFya2VyKGV2ZW50KTtcblxuICAgIGlmIChtYXJrZXIpIHtcbiAgICAgIHRoaXMubWFwLnJlbW92ZU1hcmtlcihtYXJrZXIpO1xuICAgICAgZGVsZXRlIHRoaXMuYWN0aXZlTWFya2Vyc1tgcCR7ZXZlbnQuaWR9YF07XG4gICAgfSBlbHNlIHtcbiAgICAgIG1hcmtlciA9IHRoaXMubWFwLmdldFRyYWNraW5nTWFya2VyKGV2ZW50KTtcbiAgICAgIHRoaXMubWFwLmFkZE1hcmtlclRvTWFwKG1hcmtlcik7XG4gICAgICB0aGlzLmFjdGl2ZU1hcmtlcnNbYHAke2V2ZW50LmlkfWBdID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICB0b2dnbGVQb3NpdGlvblJlYWx0aW1lKGFjdGl2ZTogYm9vbGVhbikge1xuICAgIHRoaXMuY29uZmlnID0geyAuLi50aGlzLmNvbmZpZywgcmVhbHRpbWU6IGFjdGl2ZSB9O1xuICB9XG5cbiAgdG9nZ2xlUmVhbHRpbWUoaW50ZXJ2YWw6IFRpbWVJbnRlcnZhbCkge1xuICAgIGNvbnN0IGN1cnJlbnRUaW1lSW5SYW5nZSA9IERhdGUubm93KCkgPD0gaW50ZXJ2YWw/LmRhdGVUbz8uZ2V0VGltZSgpO1xuICAgIHRoaXMudG9nZ2xlUG9zaXRpb25SZWFsdGltZShjdXJyZW50VGltZUluUmFuZ2UpO1xuICAgIHRoaXMucmVhbHRpbWVEaXNhYmxlZCA9ICFjdXJyZW50VGltZUluUmFuZ2U7XG5cbiAgICBpZiAoY3VycmVudFRpbWVJblJhbmdlKSB7XG4gICAgICB0aGlzLnJlYWx0aW1lLnN0YXJ0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucmVhbHRpbWUuc3RvcCgpO1xuICAgIH1cbiAgfVxufVxuIiwiPGM4eS1hY3Rpb24tYmFyLWl0ZW1cbiAgW3BsYWNlbWVudF09XCIncmlnaHQnXCJcbiAgW3ByaW9yaXR5XT1cIjEwMFwiXG4+XG4gIDxjOHktcmVhbHRpbWUtYnRuXG4gICAgW3NlcnZpY2VdPVwicmVhbHRpbWVcIlxuICAgIFtkaXNhYmxlZF09XCJyZWFsdGltZURpc2FibGVkXCJcbiAgICAob25Ub2dnbGUpPVwidG9nZ2xlUG9zaXRpb25SZWFsdGltZSgkZXZlbnQpXCJcbiAgPjwvYzh5LXJlYWx0aW1lLWJ0bj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cbjxjOHktYWN0aW9uLWJhci1pdGVtXG4gIFtwbGFjZW1lbnRdPVwiJ3JpZ2h0J1wiXG4gIFtwcmlvcml0eV09XCI2MFwiXG4+XG4gIDxjOHktdGltZS1pbnRlcnZhbFxuICAgIFttYXhDdXN0b21EYXRlXT1cIm1heERhdGVcIlxuICAgIFtkYXRlUmFuZ2VQaWNrZXJDb25maWddPVwiZGF0ZVJhbmdlUGlja2VyQ29uZmlnXCJcbiAgICAoaW50ZXJ2YWwpPVwic2VydmljZS5zZXRJbnRlcnZhbCgkZXZlbnQpOyB0b2dnbGVSZWFsdGltZSgkZXZlbnQpXCJcbiAgPjwvYzh5LXRpbWUtaW50ZXJ2YWw+XG48L2M4eS1hY3Rpb24tYmFyLWl0ZW0+XG5cbjxkaXYgY2xhc3M9XCJjYXJkIGNhcmQtLWdyaWQgY29udGVudC1mdWxscGFnZSBkLWdyaWQgZ3JpZF9fY29sLS04LTQtLW1kXCI+XG4gIDxkaXYgY2xhc3M9XCJiZy13aGl0ZSBwLXJlbGF0aXZlXCI+XG4gICAgPGM4eS1tYXBcbiAgICAgIFtjb25maWddPVwiY29uZmlnXCJcbiAgICAgIFthc3NldHNdPVwiZGV2aWNlXCJcbiAgICAgIFtwb2x5bGluZSRdPVwic2VydmljZS5wb2x5bGluZSRcIlxuICAgICAgW3BvbHlsaW5lT3B0aW9uc109XCJ7IGNvbG9yOiAnZGFya2JsdWUnIH1cIlxuICAgID5cbiAgICAgIDxkaXYgKmM4eU1hcFBvcHVwPVwibGV0IGNvbnRleHRcIj5cbiAgICAgICAgPGM4eS10cmFja2luZy1tYXJrZXItcG9wdXAgW2NvbnRleHRdPVwiY29udGV4dFwiPjwvYzh5LXRyYWNraW5nLW1hcmtlci1wb3B1cD5cbiAgICAgIDwvZGl2PlxuICAgIDwvYzh5LW1hcD5cbiAgPC9kaXY+XG5cbiAgPGRpdiBjbGFzcz1cImQtZmxleCBkLWNvbCBiZy1pbmhlcml0IGNvbnRlbnQtZnVsbHBhZ2UgYmctZ3JheS13aGl0ZVwiPlxuICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBsYXJnZS1wYWRkaW5nIHNlcGFyYXRvciBzdGlja3ktdG9wXCI+XG4gICAgICA8c3BhblxuICAgICAgICBjbGFzcz1cImNhcmQtdGl0bGVcIlxuICAgICAgICB0cmFuc2xhdGVcbiAgICAgID5cbiAgICAgICAgVHJhY2tpbmcgZXZlbnRzXG4gICAgICA8L3NwYW4+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImlubmVyLXNjcm9sbFwiPlxuICAgICAgPGM4eS1saXN0LWdyb3VwIGNsYXNzPVwiYzh5LWxpc3RfX2dyb3VwLS1zdHJpcFwiPlxuICAgICAgICA8bmctdGVtcGxhdGVcbiAgICAgICAgICBjOHlGb3JcbiAgICAgICAgICBsZXQtZXZlbnRcbiAgICAgICAgICBbYzh5Rm9yT2ZdPVwic2VydmljZS5ldmVudHMkXCJcbiAgICAgICAgICBbYzh5Rm9yUGlwZV09XCJzZXJ2aWNlLnBpcGVcIlxuICAgICAgICAgIFtjOHlGb3JSZWFsdGltZV09XCJyZWFsdGltZVwiXG4gICAgICAgICAgW2M4eUZvclJlYWx0aW1lT3B0aW9uc109XCJ7IGVudGl0eU9ySWQ6IGRldmljZSB9XCJcbiAgICAgICAgICBbYzh5Rm9yTG9hZE1vcmVdPVwiJ2hpZGRlbidcIlxuICAgICAgICAgIFtjOHlGb3JOb3RGb3VuZF09XCJlbXB0eVwiXG4gICAgICAgICAgKGM4eUZvckxvYWRNb3JlQ29tcG9uZW50KT1cIlxuICAgICAgICAgICAgbG9hZE1vcmVDb21wb25lbnQgPSAkZXZlbnQ7IGxvYWRNb3JlQ29tcG9uZW50LnVzZUludGVyc2VjdGlvbiA9IGZhbHNlXG4gICAgICAgICAgXCJcbiAgICAgICAgPlxuICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgIGNsYXNzPVwicG9pbnRlclwiXG4gICAgICAgICAgICBbbmdDbGFzc109XCJ7ICd0ZXh0LXByaW1hcnkgdGV4dC1ib2xkJzogYWN0aXZlTWFya2Vyc1sncCcgKyBldmVudD8uaWRdIH1cIlxuICAgICAgICAgICAgKGNsaWNrKT1cInRvZ2dsZU1hcmtlcihldmVudClcIlxuICAgICAgICAgICAgW2F0dHIuZGF0YS1jeV09XCInYzh5LXRyYWNraW5nLS10cmFja2luZy1ldmVudC1pdGVtLScgKyBldmVudD8uaWRcIlxuICAgICAgICAgID5cbiAgICAgICAgICAgIDxjOHktbGktaWNvbiBbbmdDbGFzc109XCJ7ICd0ZXh0LXByaW1hcnknOiBhY3RpdmVNYXJrZXJzWydwJyArIGV2ZW50Py5pZF0gfVwiPlxuICAgICAgICAgICAgICA8aSBjOHlJY29uPVwiYzh5LWxvY2F0aW9uXCI+PC9pPlxuICAgICAgICAgICAgPC9jOHktbGktaWNvbj5cbiAgICAgICAgICAgIDxjOHktbGktYm9keT5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cImQtZmxleFwiPlxuICAgICAgICAgICAgICAgIDxzcGFuPlxuICAgICAgICAgICAgICAgICAge3sgZXZlbnQudGltZSB8IGRhdGU6ICdtZWRpdW1EYXRlJyB9fVxuICAgICAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgICAgICA8c3BhbiBjbGFzcz1cIm0tbC1hdXRvXCI+XG4gICAgICAgICAgICAgICAgICB7eyBldmVudC50aW1lIHwgZGF0ZTogJ21lZGl1bVRpbWUnIH19XG4gICAgICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvYzh5LWxpLWJvZHk+XG4gICAgICAgICAgPC9jOHktbGk+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICA8L2M4eS1saXN0LWdyb3VwPlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBlbXB0eSBzdGF0ZSAtLT5cbiAgICA8bmctdGVtcGxhdGUgI2VtcHR5PlxuICAgICAgPGM4eS11aS1lbXB0eS1zdGF0ZVxuICAgICAgICBpY29uPVwiYzh5LWxvY2F0aW9uXCJcbiAgICAgICAgW3RpdGxlXT1cIidObyB0cmFja2luZyBldmVudHMgZm91bmQuJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFtzdWJ0aXRsZV09XCInU2VsZWN0IGFub3RoZXIgdGltZSByYW5nZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgKm5nSWY9XCIhc2VydmljZS5oYXNFdmVudHNcIlxuICAgICAgICBbaG9yaXpvbnRhbF09XCJ0cnVlXCJcbiAgICAgID48L2M4eS11aS1lbXB0eS1zdGF0ZT5cbiAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgPGRpdiAqbmdJZj1cImxvYWRNb3JlQ29tcG9uZW50Py5oYXNNb3JlXCI+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1saW5rIGZpdC13IHN0aWNreS1ib3R0b20gc2VwYXJhdG9yLXRvcFwiXG4gICAgICAgIFt0aXRsZV09XCInTG9hZCBtb3JlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICBbZGlzYWJsZWRdPVwibG9hZE1vcmVDb21wb25lbnQ/LmlzTG9hZGluZ1wiXG4gICAgICAgIChjbGljayk9XCJsb2FkTW9yZUNvbXBvbmVudC5sb2FkTW9yZSgpXCJcbiAgICAgICAgZGF0YS1jeT1cImM4eS10cmFja2luZy0tbG9hZC1tb3JlXCJcbiAgICAgID5cbiAgICAgICAge3sgJ0xvYWQgbW9yZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cImNhcmQtZm9vdGVyIHNlcGFyYXRvclwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgICAgIFt0aXRsZV09XCInRGVzZWxlY3QgYWxsIG1hcmtlcnMnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgIFtkaXNhYmxlZF09XCIoYWN0aXZlTWFya2VycyB8IGpzb24pID09PSAne30nXCJcbiAgICAgICAgKGNsaWNrKT1cIm1hcC5jbGVhck1hcmtlcnMoJ2V2ZW50Jyk7IGFjdGl2ZU1hcmtlcnMgPSB7fVwiXG4gICAgICA+XG4gICAgICAgIHt7ICdEZXNlbGVjdCBhbGwgbWFya2VycycgfCB0cmFuc2xhdGUgfX1cbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19