UNPKG

@nova-ui/dashboards

Version:

Nova Dashboards is a framework designed to provide feature developers with a common solution for presenting data coming from various sources within a single view, as well as a set of predefined widget visualizations that are 100% configuration-driven and

150 lines 27.4 kB
// © 2022 SolarWinds Worldwide, LLC. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import { Component, ElementRef, Inject, Input, } from "@angular/core"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { EventBus } from "@nova-ui/bits"; import { TimeseriesZoomPlugin, TimeseriesZoomPluginsSyncService, } from "@nova-ui/charts"; import { PIZZAGNA_EVENT_BUS } from "../../../types"; import * as i0 from "@angular/core"; import * as i1 from "@nova-ui/charts"; import * as i2 from "@angular/common"; import * as i3 from "@nova-ui/bits"; export const TIMESERIES_INSPECTION_MENU_ZOOM_IN = { id: "TIMESERIES_INSPECTION_MENU_ZOOM_IN", }; export const TIMESERIES_INSPECTION_MENU_ZOOM_OUT = { id: "TIMESERIES_INSPECTION_MENU_ZOOM_OUT", }; export const TIMESERIES_INSPECTION_MENU_EXPLORE = { id: "TIMESERIES_INSPECTION_MENU_EXPLORE", }; export const TIMESERIES_INSPECTION_MENU_CLOSE = { id: "TIMESERIES_INSPECTION_MENU_CLOSE", }; export const TIMESERIES_INSPECTION_MENU_SYNCHRONIZE = { id: "TIMESERIES_INSPECTION_MENU_SYNCHRONIZE", }; export const TIMESERIES_INSPECTION_MENU_CLEAR = { id: "TIMESERIES_INSPECTION_MENU_CLEAR", }; export class TimeseriesInspectionMenuComponent { constructor(element, eventBus, syncService) { this.element = element; this.eventBus = eventBus; this.syncService = syncService; this.exploringEnabled = false; this.allowed = false; this.offset = 38; this.destroy$ = new Subject(); } ngOnInit() { this.plugin.zoomCreated$.subscribe(() => this.explore(false)); this.eventBus .getStream(TIMESERIES_INSPECTION_MENU_SYNCHRONIZE) .subscribe(() => { const { startDate, endDate } = this.plugin.getInspectionFrame(); if (startDate && endDate) { this.syncService.syncPositionInsideCollection(this.collectionId ?? "", startDate, endDate); } }); this.eventBus .getStream(TIMESERIES_INSPECTION_MENU_CLEAR) .subscribe(() => this.clearZoom()); this.plugin?.openPopover$ .pipe(takeUntil(this.destroy$)) .subscribe((x) => { // moves element to the correct position this.element.nativeElement.style.left = this.offset + x + "px"; }); } ngOnChanges(changes) { if (changes.allowed?.currentValue) { this.plugin.showPopover(); } else { this.plugin.closePopover(); } } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } clearZoom() { this.syncService.clearZoomInsideCollection(this.collectionId ?? ""); this.eventBus.next(TIMESERIES_INSPECTION_MENU_CLOSE, {}); } isZoomInAllowed() { const { startDate, endDate } = this.plugin.getInspectionFrame(); if (!startDate || !endDate) { return true; } // doesn't allow zoom for timeframe smaller than 10 minutes return endDate.diff(startDate, "minutes") > 10; } zoomIn() { const inspectionTimeframe = this.plugin.getInspectionFrame(); this.eventBus.next(TIMESERIES_INSPECTION_MENU_ZOOM_IN, { payload: inspectionTimeframe, }); this.syncService.clearZoomInsideCollection(this.collectionId ?? ""); } zoomOut() { const inspectionTimeframe = this.plugin.getInspectionFrame(); this.eventBus.next(TIMESERIES_INSPECTION_MENU_ZOOM_OUT, { payload: inspectionTimeframe, }); setTimeout(() => { this.plugin.closePopover(); }); } explore(openSidePanel = false) { const inspectionTimeframe = this.plugin.getInspectionFrame(); this.eventBus.next(TIMESERIES_INSPECTION_MENU_EXPLORE, { payload: { ids: this.metricIds, startDate: inspectionTimeframe.startDate, endDate: inspectionTimeframe.endDate, openSidePanel, exploringEnabled: this.exploringEnabled, }, }); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesInspectionMenuComponent, deps: [{ token: i0.ElementRef }, { token: PIZZAGNA_EVENT_BUS }, { token: i1.TimeseriesZoomPluginsSyncService }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TimeseriesInspectionMenuComponent, selector: "nui-timeseries-inspection-menu", inputs: { plugin: "plugin", exploringEnabled: "exploringEnabled", metricIds: "metricIds", collectionId: "collectionId", allowed: "allowed" }, usesOnChanges: true, ngImport: i0, template: "<nui-popover\n class=\"popover\"\n trigger=\"openPopoverSubject\"\n placement=\"right\"\n [unlimited]=\"true\"\n [template]=\"popoverTemplate\"\n [container]=\"element.nativeElement\"\n [openPopover]=\"plugin.openPopover$\"\n [closePopover]=\"plugin.closePopover$\"\n [hasPadding]=\"false\"\n [withGrowAfterOpen]=\"true\"\n>\n</nui-popover>\n\n<ng-template #popoverTemplate>\n <div class=\"inspection-menu\">\n <button\n *ngIf=\"exploringEnabled\"\n nui-button\n type=\"button\"\n icon=\"details\"\n title=\"Inspect selection in the data explorer\"\n i18n-title\n (click)=\"explore(true)\"\n ></button>\n <button\n *ngIf=\"isZoomInAllowed()\"\n nui-button\n type=\"button\"\n icon=\"zoom-in\"\n title=\"Zoom In\"\n i18n-title\n (click)=\"zoomIn()\"\n ></button>\n <button\n nui-button\n type=\"button\"\n icon=\"zoom-out\"\n title=\"Zoom Out\"\n i18n-title\n (click)=\"zoomOut()\"\n ></button>\n <button\n nui-button\n type=\"button\"\n icon=\"remove\"\n title=\"Clear selection\"\n i18n-title\n (click)=\"clearZoom()\"\n ></button>\n </div>\n</ng-template>\n", styles: [":host{position:absolute;top:5px}.popover{position:absolute;pointer-events:none}:host ::ng-deep nui-overlay-arrow{display:none!important}.inspection-menu{display:flex;flex-direction:column;align-items:center;justify-content:center}.inspection-menu ::ng-deep button{border:0}.inspection-menu ::ng-deep .nui-button.is-empty{min-width:25px!important;min-height:25px!important}\n"], dependencies: [{ kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.ButtonComponent, selector: "[nui-button]", inputs: ["displayStyle", "icon", "iconColor", "iconRight", "isBusy", "isEmpty", "ariaLabel", "isRepeat", "size"] }, { kind: "component", type: i3.PopoverComponent, selector: "nui-popover", inputs: ["closePopover", "openPopover", "disabled", "trigger", "template", "placement", "popoverTitle", "icon", "modal", "container", "hasPadding", "preventClosing", "unlimited", "delay", "withGrowAfterOpen", "popoverOverlayPosition"], outputs: ["shown", "hidden"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TimeseriesInspectionMenuComponent, decorators: [{ type: Component, args: [{ selector: "nui-timeseries-inspection-menu", template: "<nui-popover\n class=\"popover\"\n trigger=\"openPopoverSubject\"\n placement=\"right\"\n [unlimited]=\"true\"\n [template]=\"popoverTemplate\"\n [container]=\"element.nativeElement\"\n [openPopover]=\"plugin.openPopover$\"\n [closePopover]=\"plugin.closePopover$\"\n [hasPadding]=\"false\"\n [withGrowAfterOpen]=\"true\"\n>\n</nui-popover>\n\n<ng-template #popoverTemplate>\n <div class=\"inspection-menu\">\n <button\n *ngIf=\"exploringEnabled\"\n nui-button\n type=\"button\"\n icon=\"details\"\n title=\"Inspect selection in the data explorer\"\n i18n-title\n (click)=\"explore(true)\"\n ></button>\n <button\n *ngIf=\"isZoomInAllowed()\"\n nui-button\n type=\"button\"\n icon=\"zoom-in\"\n title=\"Zoom In\"\n i18n-title\n (click)=\"zoomIn()\"\n ></button>\n <button\n nui-button\n type=\"button\"\n icon=\"zoom-out\"\n title=\"Zoom Out\"\n i18n-title\n (click)=\"zoomOut()\"\n ></button>\n <button\n nui-button\n type=\"button\"\n icon=\"remove\"\n title=\"Clear selection\"\n i18n-title\n (click)=\"clearZoom()\"\n ></button>\n </div>\n</ng-template>\n", styles: [":host{position:absolute;top:5px}.popover{position:absolute;pointer-events:none}:host ::ng-deep nui-overlay-arrow{display:none!important}.inspection-menu{display:flex;flex-direction:column;align-items:center;justify-content:center}.inspection-menu ::ng-deep button{border:0}.inspection-menu ::ng-deep .nui-button.is-empty{min-width:25px!important;min-height:25px!important}\n"] }] }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i3.EventBus, decorators: [{ type: Inject, args: [PIZZAGNA_EVENT_BUS] }] }, { type: i1.TimeseriesZoomPluginsSyncService }], propDecorators: { plugin: [{ type: Input }], exploringEnabled: [{ type: Input }], metricIds: [{ type: Input }], collectionId: [{ type: Input }], allowed: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGltZXNlcmllcy1pbnNwZWN0aW9uLW1lbnUuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb21wb25lbnRzL3RpbWVzZXJpZXMtd2lkZ2V0L3RpbWVzZXJpZXMtaW5zcGVjdGlvbi1tZW51L3RpbWVzZXJpZXMtaW5zcGVjdGlvbi1tZW51LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy90aW1lc2VyaWVzLXdpZGdldC90aW1lc2VyaWVzLWluc3BlY3Rpb24tbWVudS90aW1lc2VyaWVzLWluc3BlY3Rpb24tbWVudS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUNILFNBQVMsRUFDVCxVQUFVLEVBQ1YsTUFBTSxFQUNOLEtBQUssR0FLUixNQUFNLGVBQWUsQ0FBQztBQUV2QixPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUUzQyxPQUFPLEVBQUUsUUFBUSxFQUE0QixNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQ0gsb0JBQW9CLEVBQ3BCLGdDQUFnQyxHQUVuQyxNQUFNLGlCQUFpQixDQUFDO0FBRXpCLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdCQUFnQixDQUFD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QztRQUM3RCxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsRUFBRTtZQUNuRCxPQUFPLEVBQUU7Z0JBQ0wsR0FBRyxFQUFFLElBQUksQ0FBQyxTQUFTO2dCQUNuQixTQUFTLEVBQUUsbUJBQW1CLENBQUMsU0FBUztnQkFDeEMsT0FBTyxFQUFFLG1CQUFtQixDQUFDLE9BQU87Z0JBQ3BDLGFBQWE7Z0JBQ2IsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLGdCQUFnQjthQUMxQztTQUNKLENBQUMsQ0FBQztJQUNQLENBQUM7a0lBdkdRLGlDQUFpQyw0Q0FjOUIsa0JBQWtCO3NIQWRyQixpQ0FBaUMseU9DMUY5QywrNUNBb0RBOzs0RkRzQ2EsaUNBQWlDO2tCQUw3QyxTQUFTOytCQUNJLGdDQUFnQzs7MEJBa0JyQyxNQUFNOzJCQUFDLGtCQUFrQjt3RkFYckIsTUFBTTtzQkFBZCxLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7XG4gICAgQ29tcG9uZW50LFxuICAgIEVsZW1lbnRSZWYsXG4gICAgSW5qZWN0LFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPbkRlc3Ryb3ksXG4gICAgT25Jbml0LFxuICAgIFNpbXBsZUNoYW5nZXMsXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQgbW9tZW50IGZyb20gXCJtb21lbnQvbW9tZW50XCI7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IHRha2VVbnRpbCB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuXG5pbXBvcnQgeyBFdmVudEJ1cywgSUV2ZW50LCBJRXZlbnREZWZpbml0aW9uIH0gZnJvbSBcIkBub3ZhLXVpL2JpdHNcIjtcbmltcG9ydCB7XG4gICAgVGltZXNlcmllc1pvb21QbHVnaW4sXG4gICAgVGltZXNlcmllc1pvb21QbHVnaW5zU3luY1NlcnZpY2UsXG4gICAgSVRpbWVzZXJpZXNab29tUGx1Z2luSW5zcGVjdGlvbkZyYW1lLFxufSBmcm9tIFwiQG5vdmEtdWkvY2hhcnRzXCI7XG5cbmltcG9ydCB7IFBJWlpBR05BX0VWRU5UX0JVUyB9IGZyb20gXCIuLi8uLi8uLi90eXBlc1wiO1xuXG5leHBvcnQgY29uc3QgVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfWk9PTV9JTjogSUV2ZW50RGVmaW5pdGlvbjxcbiAgICBJRXZlbnQ8SVRpbWVzZXJpZXNab29tUGx1Z2luSW5zcGVjdGlvbkZyYW1lPlxuPiA9IHtcbiAgICBpZDogXCJUSU1FU0VSSUVTX0lOU1BFQ1RJT05fTUVOVV9aT09NX0lOXCIsXG59O1xuXG5leHBvcnQgY29uc3QgVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfWk9PTV9PVVQ6IElFdmVudERlZmluaXRpb248XG4gICAgSUV2ZW50PElUaW1lc2VyaWVzWm9vbVBsdWdpbkluc3BlY3Rpb25GcmFtZT5cbj4gPSB7XG4gICAgaWQ6IFwiVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfWk9PTV9PVVRcIixcbn07XG5cbmV4cG9ydCBjb25zdCBUSU1FU0VSSUVTX0lOU1BFQ1RJT05fTUVOVV9FWFBMT1JFOiBJRXZlbnREZWZpbml0aW9uPFxuICAgIElFdmVudDxJVGltZXNlcmllc1pvb21QbHVnaW5FeHBsb3JlRGF0YT5cbj4gPSB7XG4gICAgaWQ6IFwiVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfRVhQTE9SRVwiLFxufTtcblxuZXhwb3J0IGNvbnN0IFRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX0NMT1NFOiBJRXZlbnREZWZpbml0aW9uPElFdmVudDx2b2lkPj4gPVxuICAgIHtcbiAgICAgICAgaWQ6IFwiVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfQ0xPU0VcIixcbiAgICB9O1xuXG5leHBvcnQgY29uc3QgVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfU1lOQ0hST05JWkU6IElFdmVudERlZmluaXRpb248XG4gICAgSUV2ZW50PHZvaWQ+XG4+ID0ge1xuICAgIGlkOiBcIlRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX1NZTkNIUk9OSVpFXCIsXG59O1xuXG5leHBvcnQgY29uc3QgVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfQ0xFQVI6IElFdmVudERlZmluaXRpb248SUV2ZW50PHZvaWQ+PiA9XG4gICAge1xuICAgICAgICBpZDogXCJUSU1FU0VSSUVTX0lOU1BFQ1RJT05fTUVOVV9DTEVBUlwiLFxuICAgIH07XG5cbmV4cG9ydCBpbnRlcmZhY2UgSVRpbWVzZXJpZXNab29tUGx1Z2luRXhwbG9yZURhdGEge1xuICAgIGlkczogc3RyaW5nO1xuICAgIHN0YXJ0RGF0ZTogbW9tZW50Lk1vbWVudDtcbiAgICBlbmREYXRlOiBtb21lbnQuTW9tZW50O1xuICAgIG9wZW5TaWRlUGFuZWw6IGJvb2xlYW47XG4gICAgZXhwbG9yaW5nRW5hYmxlZDogYm9vbGVhbjtcbn1cblxuQENvbXBvbmVudCh7XG4gICAgc2VsZWN0b3I6IFwibnVpLXRpbWVzZXJpZXMtaW5zcGVjdGlvbi1tZW51XCIsXG4gICAgdGVtcGxhdGVVcmw6IFwiLi90aW1lc2VyaWVzLWluc3BlY3Rpb24tbWVudS5jb21wb25lbnQuaHRtbFwiLFxuICAgIHN0eWxlVXJsczogW1wiLi90aW1lc2VyaWVzLWluc3BlY3Rpb24tbWVudS5jb21wb25lbnQubGVzc1wiXSxcbn0pXG5leHBvcnQgY2xhc3MgVGltZXNlcmllc0luc3BlY3Rpb25NZW51Q29tcG9uZW50XG4gICAgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95XG57XG4gICAgQElucHV0KCkgcGx1Z2luOiBUaW1lc2VyaWVzWm9vbVBsdWdpbjtcbiAgICBASW5wdXQoKSBleHBsb3JpbmdFbmFibGVkID0gZmFsc2U7XG4gICAgQElucHV0KCkgbWV0cmljSWRzPzogc3RyaW5nO1xuICAgIEBJbnB1dCgpIGNvbGxlY3Rpb25JZD86IHN0cmluZztcbiAgICBASW5wdXQoKSBhbGxvd2VkPzogYm9vbGVhbiA9IGZhbHNlO1xuXG4gICAgcHJpdmF0ZSBvZmZzZXQgPSAzODtcbiAgICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwdWJsaWMgZWxlbWVudDogRWxlbWVudFJlZixcbiAgICAgICAgQEluamVjdChQSVpaQUdOQV9FVkVOVF9CVVMpIHByaXZhdGUgZXZlbnRCdXM6IEV2ZW50QnVzPElFdmVudD4sXG4gICAgICAgIHByaXZhdGUgc3luY1NlcnZpY2U6IFRpbWVzZXJpZXNab29tUGx1Z2luc1N5bmNTZXJ2aWNlXG4gICAgKSB7fVxuICAgIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5wbHVnaW4uem9vbUNyZWF0ZWQkLnN1YnNjcmliZSgoKSA9PiB0aGlzLmV4cGxvcmUoZmFsc2UpKTtcblxuICAgICAgICB0aGlzLmV2ZW50QnVzXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKFRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX1NZTkNIUk9OSVpFKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBzdGFydERhdGUsIGVuZERhdGUgfSA9IHRoaXMucGx1Z2luLmdldEluc3BlY3Rpb25GcmFtZSgpO1xuICAgICAgICAgICAgICAgIGlmIChzdGFydERhdGUgJiYgZW5kRGF0ZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnN5bmNTZXJ2aWNlLnN5bmNQb3NpdGlvbkluc2lkZUNvbGxlY3Rpb24oXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbGxlY3Rpb25JZCA/PyBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhcnREYXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZW5kRGF0ZVxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuZXZlbnRCdXNcbiAgICAgICAgICAgIC5nZXRTdHJlYW0oVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfQ0xFQVIpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHRoaXMuY2xlYXJab29tKCkpO1xuXG4gICAgICAgIHRoaXMucGx1Z2luPy5vcGVuUG9wb3ZlciRcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKHg6IG51bWJlcikgPT4ge1xuICAgICAgICAgICAgICAgIC8vIG1vdmVzIGVsZW1lbnQgdG8gdGhlIGNvcnJlY3QgcG9zaXRpb25cbiAgICAgICAgICAgICAgICB0aGlzLmVsZW1lbnQubmF0aXZlRWxlbWVudC5zdHlsZS5sZWZ0ID0gdGhpcy5vZmZzZXQgKyB4ICsgXCJweFwiO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMuYWxsb3dlZD8uY3VycmVudFZhbHVlKSB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5zaG93UG9wb3ZlcigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5wbHVnaW4uY2xvc2VQb3BvdmVyKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgICAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGNsZWFyWm9vbSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5zeW5jU2VydmljZS5jbGVhclpvb21JbnNpZGVDb2xsZWN0aW9uKHRoaXMuY29sbGVjdGlvbklkID8/IFwiXCIpO1xuICAgICAgICB0aGlzLmV2ZW50QnVzLm5leHQoVElNRVNFUklFU19JTlNQRUNUSU9OX01FTlVfQ0xPU0UsIHt9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgaXNab29tSW5BbGxvd2VkKCk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCB7IHN0YXJ0RGF0ZSwgZW5kRGF0ZSB9ID0gdGhpcy5wbHVnaW4uZ2V0SW5zcGVjdGlvbkZyYW1lKCk7XG5cbiAgICAgICAgaWYgKCFzdGFydERhdGUgfHwgIWVuZERhdGUpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gZG9lc24ndCBhbGxvdyB6b29tIGZvciB0aW1lZnJhbWUgc21hbGxlciB0aGFuIDEwIG1pbnV0ZXNcbiAgICAgICAgcmV0dXJuIGVuZERhdGUuZGlmZihzdGFydERhdGUsIFwibWludXRlc1wiKSA+IDEwO1xuICAgIH1cblxuICAgIHB1YmxpYyB6b29tSW4oKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGluc3BlY3Rpb25UaW1lZnJhbWUgPSB0aGlzLnBsdWdpbi5nZXRJbnNwZWN0aW9uRnJhbWUoKTtcbiAgICAgICAgdGhpcy5ldmVudEJ1cy5uZXh0KFRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX1pPT01fSU4sIHtcbiAgICAgICAgICAgIHBheWxvYWQ6IGluc3BlY3Rpb25UaW1lZnJhbWUsXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnN5bmNTZXJ2aWNlLmNsZWFyWm9vbUluc2lkZUNvbGxlY3Rpb24odGhpcy5jb2xsZWN0aW9uSWQgPz8gXCJcIik7XG4gICAgfVxuXG4gICAgcHVibGljIHpvb21PdXQoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGluc3BlY3Rpb25UaW1lZnJhbWUgPSB0aGlzLnBsdWdpbi5nZXRJbnNwZWN0aW9uRnJhbWUoKTtcbiAgICAgICAgdGhpcy5ldmVudEJ1cy5uZXh0KFRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX1pPT01fT1VULCB7XG4gICAgICAgICAgICBwYXlsb2FkOiBpbnNwZWN0aW9uVGltZWZyYW1lLFxuICAgICAgICB9KTtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnBsdWdpbi5jbG9zZVBvcG92ZXIoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGV4cGxvcmUob3BlblNpZGVQYW5lbCA9IGZhbHNlKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IGluc3BlY3Rpb25UaW1lZnJhbWUgPSB0aGlzLnBsdWdpbi5nZXRJbnNwZWN0aW9uRnJhbWUoKTtcbiAgICAgICAgdGhpcy5ldmVudEJ1cy5uZXh0KFRJTUVTRVJJRVNfSU5TUEVDVElPTl9NRU5VX0VYUExPUkUsIHtcbiAgICAgICAgICAgIHBheWxvYWQ6IHtcbiAgICAgICAgICAgICAgICBpZHM6IHRoaXMubWV0cmljSWRzLFxuICAgICAgICAgICAgICAgIHN0YXJ0RGF0ZTogaW5zcGVjdGlvblRpbWVmcmFtZS5zdGFydERhdGUsXG4gICAgICAgICAgICAgICAgZW5kRGF0ZTogaW5zcGVjdGlvblRpbWVmcmFtZS5lbmREYXRlLFxuICAgICAgICAgICAgICAgIG9wZW5TaWRlUGFuZWwsXG4gICAgICAgICAgICAgICAgZXhwbG9yaW5nRW5hYmxlZDogdGhpcy5leHBsb3JpbmdFbmFibGVkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgfVxufVxuIiwiPG51aS1wb3BvdmVyXG4gICAgY2xhc3M9XCJwb3BvdmVyXCJcbiAgICB0cmlnZ2VyPVwib3BlblBvcG92ZXJTdWJqZWN0XCJcbiAgICBwbGFjZW1lbnQ9XCJyaWdodFwiXG4gICAgW3VubGltaXRlZF09XCJ0cnVlXCJcbiAgICBbdGVtcGxhdGVdPVwicG9wb3ZlclRlbXBsYXRlXCJcbiAgICBbY29udGFpbmVyXT1cImVsZW1lbnQubmF0aXZlRWxlbWVudFwiXG4gICAgW29wZW5Qb3BvdmVyXT1cInBsdWdpbi5vcGVuUG9wb3ZlciRcIlxuICAgIFtjbG9zZVBvcG92ZXJdPVwicGx1Z2luLmNsb3NlUG9wb3ZlciRcIlxuICAgIFtoYXNQYWRkaW5nXT1cImZhbHNlXCJcbiAgICBbd2l0aEdyb3dBZnRlck9wZW5dPVwidHJ1ZVwiXG4+XG48L251aS1wb3BvdmVyPlxuXG48bmctdGVtcGxhdGUgI3BvcG92ZXJUZW1wbGF0ZT5cbiAgICA8ZGl2IGNsYXNzPVwiaW5zcGVjdGlvbi1tZW51XCI+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwiZXhwbG9yaW5nRW5hYmxlZFwiXG4gICAgICAgICAgICBudWktYnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGljb249XCJkZXRhaWxzXCJcbiAgICAgICAgICAgIHRpdGxlPVwiSW5zcGVjdCBzZWxlY3Rpb24gaW4gdGhlIGRhdGEgZXhwbG9yZXJcIlxuICAgICAgICAgICAgaTE4bi10aXRsZVxuICAgICAgICAgICAgKGNsaWNrKT1cImV4cGxvcmUodHJ1ZSlcIlxuICAgICAgICA+PC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICpuZ0lmPVwiaXNab29tSW5BbGxvd2VkKClcIlxuICAgICAgICAgICAgbnVpLWJ1dHRvblxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgICBpY29uPVwiem9vbS1pblwiXG4gICAgICAgICAgICB0aXRsZT1cIlpvb20gSW5cIlxuICAgICAgICAgICAgaTE4bi10aXRsZVxuICAgICAgICAgICAgKGNsaWNrKT1cInpvb21JbigpXCJcbiAgICAgICAgPjwvYnV0dG9uPlxuICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICBudWktYnV0dG9uXG4gICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgIGljb249XCJ6b29tLW91dFwiXG4gICAgICAgICAgICB0aXRsZT1cIlpvb20gT3V0XCJcbiAgICAgICAgICAgIGkxOG4tdGl0bGVcbiAgICAgICAgICAgIChjbGljayk9XCJ6b29tT3V0KClcIlxuICAgICAgICA+PC9idXR0b24+XG4gICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIG51aS1idXR0b25cbiAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgaWNvbj1cInJlbW92ZVwiXG4gICAgICAgICAgICB0aXRsZT1cIkNsZWFyIHNlbGVjdGlvblwiXG4gICAgICAgICAgICBpMThuLXRpdGxlXG4gICAgICAgICAgICAoY2xpY2spPVwiY2xlYXJab29tKClcIlxuICAgICAgICA+PC9idXR0b24+XG4gICAgPC9kaXY+XG48L25nLXRlbXBsYXRlPlxuIl19