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

222 lines 43 kB
import { Component, EventEmitter, HostBinding, Inject, Input, Output, QueryList, ViewChild, ViewChildren, ViewEncapsulation, } from "@angular/core"; import { GridsterComponent, GridsterItemComponent, } from "angular-gridster2"; import _defaultsDeep from "lodash/defaultsDeep"; import { EventBus, immutableSet } from "@nova-ui/bits"; import { DEFAULT_GRIDSTER_CONFIG } from "./default-gridster-config"; import { DASHBOARD_EDIT_MODE, WIDGET_POSITION_CHANGE, WIDGET_RESIZE, } from "../../services/types"; import { DASHBOARD_EVENT_BUS } from "../../types"; import * as i0 from "@angular/core"; import * as i1 from "@angular/common"; import * as i2 from "angular-gridster2"; import * as i3 from "../../directives/gridster-item-widget-id/gridster-item-widget-id.directive"; import * as i4 from "../loading/loading.component"; import * as i5 from "../widget/widget.component"; import * as i6 from "@nova-ui/bits"; export class DashboardComponent { get dashboard() { return this.dashboardBuffer || this._dashboard; } set dashboard(value) { this._dashboard = value; this.dashboardBuffer = null; } get hostClass() { return true; } constructor(eventBus) { this.eventBus = eventBus; this.editMode = false; this.gridsterConfigChange = new EventEmitter(); this.dashboardChange = new EventEmitter(); this.gridsterItemsVisibilityMap = {}; this.orderWidgets = (a, b) => { const nextWidget = this.dashboard.positions[a.key]; const currentWidget = this.dashboard.positions[b.key]; return nextWidget.y - currentWidget.y || nextWidget.x - currentWidget.x; }; this.trackByFn = (index, item) => item.key; this.updateWidgetPosition = (item, itemComponent) => { const widgetId = String(itemComponent.widgetId); const dashboard = immutableSet(this.dashboard, "positions." + widgetId, item); this.dashboardChange.emit(dashboard); this.eventBus.getStream(WIDGET_POSITION_CHANGE).next({ widgetId, payload: item, }); }; this.emitWidgetResize = (item, itemComponent) => { const widgetId = itemComponent.widgetId; this.eventBus.getStream(WIDGET_RESIZE).next({ widgetId, payload: { widgetId, height: itemComponent.height, width: itemComponent.width, }, }); }; } ngAfterViewInit() { // need to wait till DOM is rendered because of "getBoundingClientRect" under the hood setTimeout(() => this.calculateWidgetsVisibility()); } onGridsterScroll() { this.calculateWidgetsVisibility(); } ngOnChanges(changes) { if (changes.gridsterConfig) { if (changes.gridsterConfig.isFirstChange()) { const gridsterConfig = _defaultsDeep(this.gridsterConfig || {}, DEFAULT_GRIDSTER_CONFIG); this.hookEvent(gridsterConfig, "itemChangeCallback", this.updateWidgetPosition); this.hookEvent(gridsterConfig, "itemResizeCallback", this.emitWidgetResize); this.gridsterConfigChange.emit(gridsterConfig); } if (this.gridsterConfig?.api) { this.gridsterConfig.api.optionsChanged?.(); } } if (changes.editMode) { if (!this.gridsterConfig.resizable) { throw new Error(`Gridster's resizable prop is undefined`); } this.gridsterConfig.resizable.enabled = this.editMode; if (!this.gridsterConfig.draggable) { throw new Error(`Gridster's draggable prop is undefined`); } this.gridsterConfig.draggable.enabled = this.editMode; this.gridsterConfigChange.emit(Object.assign({}, this.gridsterConfig)); this.eventBus .getStream(DASHBOARD_EDIT_MODE) .next({ payload: this.editMode }); } // TODO: position doesn't update on external change of position // if (!changes.dashboard.isFirstChange() && // changes.dashboard.currentValue.positions !== changes.dashboard.previousValue.positions) { // if (this.gridsterConfig.api) { // this.gridsterConfig.api.optionsChanged(); // } // } } onWidgetChange(widget) { // this could happen when changes are being made on a widget that is being removed if (!this.dashboard.widgets[widget.id]) { return; } this.updateWidget(widget); } updateWidget(widget) { let dashboard = this.dashboard; if (!this.dashboard.positions[widget.id] && this.gridsterConfig?.api) { const gridsterItem = this.gridsterConfig.api.getFirstPossiblePosition?.({ x: 0, y: 0, rows: this.gridsterConfig?.defaultItemRows, cols: this.gridsterConfig?.defaultItemCols, }); dashboard = immutableSet(dashboard, `positions.${widget.id}`, gridsterItem); } dashboard = immutableSet(dashboard, `widgets.${widget.id}`, widget); this.dashboardBuffer = dashboard; this.dashboardChange.emit(dashboard); } removeWidget(widgetId, removePosition = true) { let dashboard = this.dashboard; if (!dashboard.widgets[widgetId]) { return; } const widgetsClone = Object.assign({}, dashboard.widgets); delete widgetsClone[widgetId]; dashboard = immutableSet(dashboard, "widgets", widgetsClone); if (removePosition) { const positionsClone = Object.assign({}, dashboard.positions); delete positionsClone[widgetId]; dashboard = immutableSet(dashboard, "positions", positionsClone); } this.dashboardChange.emit(dashboard); } shouldWidgetRender(key) { return this.belowFoldLazyLoadingConfig?.enabled ? this.gridsterItemsVisibilityMap[key] : true; } hookEvent(options, eventName, invoke) { const prevEvent = options[eventName]; options[eventName] = (item, itemComponent) => { invoke(item, itemComponent); if (prevEvent) { prevEvent(item, itemComponent); } }; } calculateWidgetsVisibility() { if (!this.belowFoldLazyLoadingConfig?.enabled) { return; } const gridsterRect = this.gridster.el.getBoundingClientRect(); this.gridsterItemsVisibilityMap = this.gridsterItems.reduce((acc, next) => { const { el } = next; const idx = next.widgetId; // if widget is already loaded don't hide it if (!this.belowFoldLazyLoadingConfig.configuration ?.reloadWidgetsOnScroll) { const prevVisibility = acc[idx]; if (prevVisibility) { return acc; } } const rect = el.getBoundingClientRect(); const getHeightVisibility = () => (rect.top > gridsterRect.top && rect.top < gridsterRect.bottom) || (rect.bottom > gridsterRect.top && rect.bottom < gridsterRect.bottom); const getWidthVisibility = () => (rect.left > gridsterRect.left && rect.left < gridsterRect.right) || (rect.right > gridsterRect.left && rect.right < gridsterRect.right); const isVisible = getHeightVisibility() && getWidthVisibility(); acc[idx] = isVisible; return acc; }, this.gridsterItemsVisibilityMap); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DashboardComponent, deps: [{ token: DASHBOARD_EVENT_BUS }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DashboardComponent, selector: "nui-dashboard", inputs: { gridsterConfig: "gridsterConfig", dashboard: "dashboard", editMode: "editMode", belowFoldLazyLoadingConfig: "belowFoldLazyLoadingConfig" }, outputs: { gridsterConfigChange: "gridsterConfigChange", dashboardChange: "dashboardChange" }, host: { properties: { "class.nui-dashboard": "this.hostClass" } }, providers: [ { provide: DASHBOARD_EVENT_BUS, useClass: EventBus, }, ], viewQueries: [{ propertyName: "gridster", first: true, predicate: GridsterComponent, descendants: true }, { propertyName: "gridsterItems", predicate: GridsterItemComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<gridster\n class=\"nui-dashboard__gridster\"\n [options]=\"gridsterConfig\"\n (scroll)=\"onGridsterScroll()\"\n>\n <gridster-item\n *ngFor=\"\n let widget of dashboard.widgets | keyvalue : orderWidgets;\n trackBy: trackByFn\n \"\n [item]=\"dashboard.positions[widget.key]\"\n class=\"nui-dashboard__gridster-item\"\n [nuiGridsterItemWidgetId]=\"widget.key\"\n >\n <nui-widget\n *ngIf=\"shouldWidgetRender(widget.key); else emptyWidgetTpl\"\n [widget]=\"widget.value\"\n (widgetChange)=\"onWidgetChange($event)\"\n [attr.widget-id]=\"widget.key\"\n [attr.widget-type]=\"widget.value.type\"\n [attr.widget-guid]=\"widget.value.uniqueKey\"\n class=\"w-100 h-100 d-block\"\n >\n </nui-widget>\n </gridster-item>\n</gridster>\n\n<ng-template #emptyWidgetTpl>\n <div class=\"w-100 h-100 d-block\">\n <nui-loading [active]=\"true\"></nui-loading>\n </div>\n</ng-template>\n", styles: [".nui-dashboard__gridster{background-color:var(--nui-color-bg-workspace,#f0f0f0)}.nui-dashboard__gridster .gridster-preview{border-width:4px;border-style:solid;border-color:var(--nui-color-selected-contrast,#00c4d2);background-color:var(--nui-color-selected,rgba(0, 196, 210, .1))}.nui-dashboard__gridster .gridster-preview:before{background-color:var(--nui-color-selected-contrast,#00c4d2);border-radius:50%;content:\"\";display:block;height:40px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:40px;z-index:1}.nui-dashboard__gridster .gridster-preview:after{color:var(--nui-color-icon-light,#fff);content:\"+\";display:block;font-size:19px;font-weight:700;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:2}.nui-dashboard__gridster-item{box-shadow:0 0 5px #999;box-shadow:0 0 var(--nui-space-xs, 5px) var(--nui-color-line-dark, #999999);background-color:var(--nui-color-bg-light,#fff)}.nui-dashboard__gridster-item:hover .gridster-item-resizable-handler{border-bottom-color:#00c4d2;border-bottom-color:var(--nui-color-selected-contrast,#00c4d2);margin:0;z-index:2000}.nui-dashboard__gridster-item:hover .gridster-item-resizable-handler.handle-se{border-bottom-color:var(--nui-color-selected-contrast,#00c4d2);right:2px;bottom:2px}.mobile .nui-dashboard__gridster-item.nui-dashboard__gridster-item{height:auto!important}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.GridsterComponent, selector: "gridster", inputs: ["options"] }, { kind: "component", type: i2.GridsterItemComponent, selector: "gridster-item", inputs: ["item"], outputs: ["itemInit", "itemChange", "itemResize"] }, { kind: "directive", type: i3.GridsterItemWidgetIdDirective, selector: "[nuiGridsterItemWidgetId]", inputs: ["nuiGridsterItemWidgetId"] }, { kind: "component", type: i4.LoadingComponent, selector: "nui-loading", inputs: ["active"] }, { kind: "component", type: i5.WidgetComponent, selector: "nui-widget", inputs: ["widget"], outputs: ["widgetChange"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }], encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DashboardComponent, decorators: [{ type: Component, args: [{ selector: "nui-dashboard", encapsulation: ViewEncapsulation.None, providers: [ { provide: DASHBOARD_EVENT_BUS, useClass: EventBus, }, ], template: "<gridster\n class=\"nui-dashboard__gridster\"\n [options]=\"gridsterConfig\"\n (scroll)=\"onGridsterScroll()\"\n>\n <gridster-item\n *ngFor=\"\n let widget of dashboard.widgets | keyvalue : orderWidgets;\n trackBy: trackByFn\n \"\n [item]=\"dashboard.positions[widget.key]\"\n class=\"nui-dashboard__gridster-item\"\n [nuiGridsterItemWidgetId]=\"widget.key\"\n >\n <nui-widget\n *ngIf=\"shouldWidgetRender(widget.key); else emptyWidgetTpl\"\n [widget]=\"widget.value\"\n (widgetChange)=\"onWidgetChange($event)\"\n [attr.widget-id]=\"widget.key\"\n [attr.widget-type]=\"widget.value.type\"\n [attr.widget-guid]=\"widget.value.uniqueKey\"\n class=\"w-100 h-100 d-block\"\n >\n </nui-widget>\n </gridster-item>\n</gridster>\n\n<ng-template #emptyWidgetTpl>\n <div class=\"w-100 h-100 d-block\">\n <nui-loading [active]=\"true\"></nui-loading>\n </div>\n</ng-template>\n", styles: [".nui-dashboard__gridster{background-color:var(--nui-color-bg-workspace,#f0f0f0)}.nui-dashboard__gridster .gridster-preview{border-width:4px;border-style:solid;border-color:var(--nui-color-selected-contrast,#00c4d2);background-color:var(--nui-color-selected,rgba(0, 196, 210, .1))}.nui-dashboard__gridster .gridster-preview:before{background-color:var(--nui-color-selected-contrast,#00c4d2);border-radius:50%;content:\"\";display:block;height:40px;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);width:40px;z-index:1}.nui-dashboard__gridster .gridster-preview:after{color:var(--nui-color-icon-light,#fff);content:\"+\";display:block;font-size:19px;font-weight:700;left:50%;position:absolute;top:50%;transform:translate(-50%,-50%);z-index:2}.nui-dashboard__gridster-item{box-shadow:0 0 5px #999;box-shadow:0 0 var(--nui-space-xs, 5px) var(--nui-color-line-dark, #999999);background-color:var(--nui-color-bg-light,#fff)}.nui-dashboard__gridster-item:hover .gridster-item-resizable-handler{border-bottom-color:#00c4d2;border-bottom-color:var(--nui-color-selected-contrast,#00c4d2);margin:0;z-index:2000}.nui-dashboard__gridster-item:hover .gridster-item-resizable-handler.handle-se{border-bottom-color:var(--nui-color-selected-contrast,#00c4d2);right:2px;bottom:2px}.mobile .nui-dashboard__gridster-item.nui-dashboard__gridster-item{height:auto!important}\n"] }] }], ctorParameters: () => [{ type: i6.EventBus, decorators: [{ type: Inject, args: [DASHBOARD_EVENT_BUS] }] }], propDecorators: { gridsterConfig: [{ type: Input }], dashboard: [{ type: Input }], editMode: [{ type: Input }], belowFoldLazyLoadingConfig: [{ type: Input }], gridsterConfigChange: [{ type: Output }], dashboardChange: [{ type: Output }], hostClass: [{ type: HostBinding, args: ["class.nui-dashboard"] }], gridster: [{ type: ViewChild, args: [GridsterComponent] }], gridsterItems: [{ type: ViewChildren, args: [GridsterItemComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGFzaGJvYXJkLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9kYXNoYm9hcmQvZGFzaGJvYXJkLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29tcG9uZW50cy9kYXNoYm9hcmQvZGFzaGJvYXJkLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQXFCQSxPQUFPLEVBRUgsU0FBUyxFQUNULFlBQVksRUFDWixXQUFXLEVBQ1gsTUFBTSxFQUNOLEtBQUssRUFFTCxNQUFNLEVBQ04sU0FBUyxFQUVULFNBQVMsRUFDVCxZQUFZLEVBQ1osaUJBQWlCLEdBQ3BCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFDSCxpQkFBaUIsRUFHakIscUJBQXFCLEdBRXhCLE1BQU0sbUJBQW1CLENBQUM7QUFDM0IsT0FBTyxhQUFhLE1BQU0scUJBQXFCLENBQUM7QUFFaEQsT0FBTyxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFdkQsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFFcEUsT0FBTyxFQUNILG1CQUFtQixFQUNuQixzQkFBc0IsRUFDdEIsYUFBYSxHQUNoQixNQUFNLHNCQUFzQixDQUFDO0FBRTlCLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLGFBQWEsQ0FBQzs7Ozs7Ozs7QUFlbEQsTUFBTSxPQUFPLGtCQUFrQjtJQUczQixJQUNJLFNBQVM7UUFDVCxPQUFPLElBQUksQ0FBQyxlQUFlLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQztJQUNuRCxDQUFDO0lBRUQsSUFBSSxTQUFTLENBQUMsS0FBaUI7UUFDM0IsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUM7UUFDeEIsSUFBSSxDQUFDLGVBQWUsR0FBRyxJQUFJLENBQUM7SUFDaEMsQ0FBQztJQWFELElBQ0ksU0FB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QyxDQUFDO1lBRXpDLE1BQU0sU0FBUyxHQUFHLG1CQUFtQixFQUFFLElBQUksa0JBQWtCLEVBQUUsQ0FBQztZQUVoRSxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsU0FBUyxDQUFDO1lBRXJCLE9BQU8sR0FBRyxDQUFDO1FBQ2YsQ0FBQyxFQUNELElBQUksQ0FBQywwQkFBMEIsQ0FDbEMsQ0FBQztJQUNOLENBQUM7a0lBdlJRLGtCQUFrQixrQkFzQ2YsbUJBQW1CO3NIQXRDdEIsa0JBQWtCLGdXQVBoQjtZQUNQO2dCQUNJLE9BQU8sRUFBRSxtQkFBbUI7Z0JBQzVCLFFBQVEsRUFBRSxRQUFRO2FBQ3JCO1NBQ0osb0VBK0JVLGlCQUFpQixtRUFHZCxxQkFBcUIscUVDdEd2QywraENBZ0NBOzs0RkRzQ2Esa0JBQWtCO2tCQVo5QixTQUFTOytCQUNJLGVBQWUsaUJBR1YsaUJBQWlCLENBQUMsSUFBSSxhQUMxQjt3QkFDUDs0QkFDSSxPQUFPLEVBQUUsbUJBQW1COzRCQUM1QixRQUFRLEVBQUUsUUFBUTt5QkFDckI7cUJBQ0o7OzBCQXdDSSxNQUFNOzJCQUFDLG1CQUFtQjt5Q0FyQ3RCLGNBQWM7c0JBQXRCLEtBQUs7Z0JBR0YsU0FBUztzQkFEWixLQUFLO2dCQWNHLFFBQVE7c0JBQWhCLEtBQUs7Z0JBRUMsMEJBQTBCO3NCQURoQyxLQUFLO2dCQUdJLG9CQUFvQjtzQkFBN0IsTUFBTTtnQkFDRyxlQUFlO3NCQUF4QixNQUFNO2dCQUdILFNBQVM7c0JBRFosV0FBVzt1QkFBQyxxQkFBcUI7Z0JBTTNCLFFBQVE7c0JBRGQsU0FBUzt1QkFBQyxpQkFBaUI7Z0JBSXJCLGFBQWE7c0JBRG5CLFlBQVk7dUJBQUMscUJBQXFCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IEtleVZhbHVlIH0gZnJvbSBcIkBhbmd1bGFyL2NvbW1vblwiO1xuaW1wb3J0IHtcbiAgICBBZnRlclZpZXdJbml0LFxuICAgIENvbXBvbmVudCxcbiAgICBFdmVudEVtaXR0ZXIsXG4gICAgSG9zdEJpbmRpbmcsXG4gICAgSW5qZWN0LFxuICAgIElucHV0LFxuICAgIE9uQ2hhbmdlcyxcbiAgICBPdXRwdXQsXG4gICAgUXVlcnlMaXN0LFxuICAgIFNpbXBsZUNoYW5nZXMsXG4gICAgVmlld0NoaWxkLFxuICAgIFZpZXdDaGlsZHJlbixcbiAgICBWaWV3RW5jYXBzdWxhdGlvbixcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7XG4gICAgR3JpZHN0ZXJDb21wb25lbnQsXG4gICAgR3JpZHN0ZXJDb25maWcsXG4gICAgR3JpZHN0ZXJJdGVtLFxuICAgIEdyaWRzdGVySXRlbUNvbXBvbmVudCxcbiAgICBHcmlkc3Rlckl0ZW1Db21wb25lbnRJbnRlcmZhY2UsXG59IGZyb20gXCJhbmd1bGFyLWdyaWRzdGVyMlwiO1xuaW1wb3J0IF9kZWZhdWx0c0RlZXAgZnJvbSBcImxvZGFzaC9kZWZhdWx0c0RlZXBcIjtcblxuaW1wb3J0IHsgRXZlbnRCdXMsIGltbXV0YWJsZVNldCB9IGZyb20gXCJAbm92YS11aS9iaXRzXCI7XG5cbmltcG9ydCB7IERFRkFVTFRfR1JJRFNURVJfQ09ORklHIH0gZnJvbSBcIi4vZGVmYXVsdC1ncmlkc3Rlci1jb25maWdcIjtcbmltcG9ydCB7IElEYXNoYm9hcmQsIElEYXNoYm9hcmRCZWxvd0ZvbGRMYXp5TG9hZGluZ0NvbmZpZyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIERBU0hCT0FSRF9FRElUX01PREUsXG4gICAgV0lER0VUX1BPU0lUSU9OX0NIQU5HRSxcbiAgICBXSURHRVRfUkVTSVpFLFxufSBmcm9tIFwiLi4vLi4vc2VydmljZXMvdHlwZXNcIjtcbmltcG9ydCB7IElXaWRnZXRFdmVudCB9IGZyb20gXCIuLi8uLi9zZXJ2aWNlcy93aWRnZXQtdG8tZGFzaGJvYXJkLWV2ZW50LXByb3h5LnNlcnZpY2VcIjtcbmltcG9ydCB7IERBU0hCT0FSRF9FVkVOVF9CVVMgfSBmcm9tIFwiLi4vLi4vdHlwZXNcIjtcbmltcG9ydCB7IElXaWRnZXQgfSBmcm9tIFwiLi4vd2lkZ2V0L3R5cGVzXCI7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS1kYXNoYm9hcmRcIixcbiAgICB0ZW1wbGF0ZVVybDogXCIuL2Rhc2hib2FyZC5jb21wb25lbnQuaHRtbFwiLFxuICAgIHN0eWxlVXJsczogW1wiLi9kYXNoYm9hcmQuY29tcG9uZW50Lmxlc3NcIl0sXG4gICAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgICBwcm92aWRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogREFTSEJPQVJEX0VWRU5UX0JVUyxcbiAgICAgICAgICAgIHVzZUNsYXNzOiBFdmVudEJ1cyxcbiAgICAgICAgfSxcbiAgICBdLFxufSlcbmV4cG9ydCBjbGFzcyBEYXNoYm9hcmRDb21wb25lbnQgaW1wbGVtZW50cyBPbkNoYW5nZXMsIEFmdGVyVmlld0luaXQge1xuICAgIEBJbnB1dCgpIGdyaWRzdGVyQ29uZmlnOiBHcmlkc3RlckNvbmZpZztcblxuICAgIEBJbnB1dCgpXG4gICAgZ2V0IGRhc2hib2FyZCgpOiBJRGFzaGJvYXJkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGFzaGJvYXJkQnVmZmVyIHx8IHRoaXMuX2Rhc2hib2FyZDtcbiAgICB9XG5cbiAgICBzZXQgZGFzaGJvYXJkKHZhbHVlOiBJRGFzaGJvYXJkKSB7XG4gICAgICAgIHRoaXMuX2Rhc2hib2FyZCA9IHZhbHVlO1xuICAgICAgICB0aGlzLmRhc2hib2FyZEJ1ZmZlciA9IG51bGw7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZGFzaGJvYXJkOiBJRGFzaGJvYXJkO1xuICAgIC8vIHdlIHVzZSB0aGlzIGJ1ZmZlciB0byBzdG9yZSB0ZW1wb3JhcnkgdmFsdWVzIHdoZW4gY3VtdWxhdGl2ZSBjaGFuZ2VzIGFyZSBuZWNlc3NhcnkgYmVmb3JlIHR3by13YXkgYmluZGluZyBraWNrcyBpblxuICAgIHB1YmxpYyBkYXNoYm9hcmRCdWZmZXI6IElEYXNoYm9hcmQgfCBudWxsO1xuXG4gICAgQElucHV0KCkgZWRpdE1vZGUgPSBmYWxzZTtcbiAgICBASW5wdXQoKVxuICAgIHB1YmxpYyBiZWxvd0ZvbGRMYXp5TG9hZGluZ0NvbmZpZzogSURhc2hib2FyZEJlbG93Rm9sZExhenlMb2FkaW5nQ29uZmlnO1xuXG4gICAgQE91dHB1dCgpIGdyaWRzdGVyQ29uZmlnQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxHcmlkc3RlckNvbmZpZz4oKTtcbiAgICBAT3V0cHV0KCkgZGFzaGJvYXJkQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxJRGFzaGJvYXJkPigpO1xuXG4gICAgQEhvc3RCaW5kaW5nKFwiY2xhc3MubnVpLWRhc2hib2FyZFwiKVxuICAgIGdldCBob3N0Q2xhc3MoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIEBWaWV3Q2hpbGQoR3JpZHN0ZXJDb21wb25lbnQpXG4gICAgcHVibGljIGdyaWRzdGVyOiBHcmlkc3RlckNvbXBvbmVudDtcblxuICAgIEBWaWV3Q2hpbGRyZW4oR3JpZHN0ZXJJdGVtQ29tcG9uZW50KVxuICAgIHB1YmxpYyBncmlkc3Rlckl0ZW1zOiBRdWVyeUxpc3Q8R3JpZHN0ZXJJdGVtQ29tcG9uZW50PjtcblxuICAgIHB1YmxpYyBncmlkc3Rlckl0ZW1zVmlzaWJpbGl0eU1hcDogUmVjb3JkPHN0cmluZywgYm9vbGVhbj4gPSB7fTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBASW5qZWN0KERBU0hCT0FSRF9FVkVOVF9CVVMpXG4gICAgICAgIHB1YmxpYyByZWFkb25seSBldmVudEJ1czogRXZlbnRCdXM8SVdpZGdldEV2ZW50PlxuICAgICkge31cblxuICAgIHB1YmxpYyBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XG4gICAgICAgIC8vIG5lZWQgdG8gd2FpdCB0aWxsIERPTSBpcyByZW5kZXJlZCBiZWNhdXNlIG9mIFwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0XCIgdW5kZXIgdGhlIGhvb2RcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLmNhbGN1bGF0ZVdpZGdldHNWaXNpYmlsaXR5KCkpO1xuICAgIH1cblxuICAgIHB1YmxpYyBvbkdyaWRzdGVyU2Nyb2xsKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmNhbGN1bGF0ZVdpZGdldHNWaXNpYmlsaXR5KCk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICAgICAgaWYgKGNoYW5nZXMuZ3JpZHN0ZXJDb25maWcpIHtcbiAgICAgICAgICAgIGlmIChjaGFuZ2VzLmdyaWRzdGVyQ29uZmlnLmlzRmlyc3RDaGFuZ2UoKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGdyaWRzdGVyQ29uZmlnID0gX2RlZmF1bHRzRGVlcChcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5ncmlkc3RlckNvbmZpZyB8fCB7fSxcbiAgICAgICAgICAgICAgICAgICAgREVGQVVMVF9HUklEU1RFUl9DT05GSUdcbiAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5ob29rRXZlbnQoXG4gICAgICAgICAgICAgICAgICAgIGdyaWRzdGVyQ29uZmlnLFxuICAgICAgICAgICAgICAgICAgICBcIml0ZW1DaGFuZ2VDYWxsYmFja1wiLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVdpZGdldFBvc2l0aW9uXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB0aGlzLmhvb2tFdmVudChcbiAgICAgICAgICAgICAgICAgICAgZ3JpZHN0ZXJDb25maWcsXG4gICAgICAgICAgICAgICAgICAgIFwiaXRlbVJlc2l6ZUNhbGxiYWNrXCIsXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZW1pdFdpZGdldFJlc2l6ZVxuICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmdyaWRzdGVyQ29uZmlnQ2hhbmdlLmVtaXQoZ3JpZHN0ZXJDb25maWcpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5ncmlkc3RlckNvbmZpZz8uYXBpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ncmlkc3RlckNvbmZpZy5hcGkub3B0aW9uc0NoYW5nZWQ/LigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNoYW5nZXMuZWRpdE1vZGUpIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5ncmlkc3RlckNvbmZpZy5yZXNpemFibGUpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEdyaWRzdGVyJ3MgcmVzaXphYmxlIHByb3AgaXMgdW5kZWZpbmVkYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmdyaWRzdGVyQ29uZmlnLnJlc2l6YWJsZS5lbmFibGVkID0gdGhpcy5lZGl0TW9kZTtcblxuICAgICAgICAgICAgaWYgKCF0aGlzLmdyaWRzdGVyQ29uZmlnLmRyYWdnYWJsZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgR3JpZHN0ZXIncyBkcmFnZ2FibGUgcHJvcCBpcyB1bmRlZmluZWRgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuZ3JpZHN0ZXJDb25maWcuZHJhZ2dhYmxlLmVuYWJsZWQgPSB0aGlzLmVkaXRNb2RlO1xuXG4gICAgICAgICAgICB0aGlzLmdyaWRzdGVyQ29uZmlnQ2hhbmdlLmVtaXQoXG4gICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgdGhpcy5ncmlkc3RlckNvbmZpZylcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIHRoaXMuZXZlbnRCdXNcbiAgICAgICAgICAgICAgICAuZ2V0U3RyZWFtKERBU0hCT0FSRF9FRElUX01PREUpXG4gICAgICAgICAgICAgICAgLm5leHQoeyBwYXlsb2FkOiB0aGlzLmVkaXRNb2RlIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVE9ETzogcG9zaXRpb24gZG9lc24ndCB1cGRhdGUgb24gZXh0ZXJuYWwgY2hhbmdlIG9mIHBvc2l0aW9uXG4gICAgICAgIC8vIGlmICghY2hhbmdlcy5kYXNoYm9hcmQuaXNGaXJzdENoYW5nZSgpICYmXG4gICAgICAgIC8vICAgICBjaGFuZ2VzLmRhc2hib2FyZC5jdXJyZW50VmFsdWUucG9zaXRpb25zICE9PSBjaGFuZ2VzLmRhc2hib2FyZC5wcmV2aW91c1ZhbHVlLnBvc2l0aW9ucykge1xuICAgICAgICAvLyAgICAgaWYgKHRoaXMuZ3JpZHN0ZXJDb25maWcuYXBpKSB7XG4gICAgICAgIC8vICAgICAgICAgdGhpcy5ncmlkc3RlckNvbmZpZy5hcGkub3B0aW9uc0NoYW5nZWQoKTtcbiAgICAgICAgLy8gICAgIH1cbiAgICAgICAgLy8gfVxuICAgIH1cblxuICAgIHB1YmxpYyBvcmRlcldpZGdldHMgPSAoXG4gICAgICAgIGE6IEtleVZhbHVlPHN0cmluZywgSVdpZGdldD4sXG4gICAgICAgIGI6IEtleVZhbHVlPHN0cmluZywgSVdpZGdldD5cbiAgICApOiBudW1iZXIgPT4ge1xuICAgICAgICBjb25zdCBuZXh0V2lkZ2V0ID0gdGhpcy5kYXNoYm9hcmQucG9zaXRpb25zW2Eua2V5XTtcbiAgICAgICAgY29uc3QgY3VycmVudFdpZGdldCA9IHRoaXMuZGFzaGJvYXJkLnBvc2l0aW9uc1tiLmtleV07XG5cbiAgICAgICAgcmV0dXJuIG5leHRXaWRnZXQueSAtIGN1cnJlbnRXaWRnZXQueSB8fCBuZXh0V2lkZ2V0LnggLSBjdXJyZW50V2lkZ2V0Lng7XG4gICAgfTtcblxuICAgIHB1YmxpYyB0cmFja0J5Rm4gPSAoXG4gICAgICAgIGluZGV4OiBudW1iZXIsXG4gICAgICAgIGl0ZW06IEtleVZhbHVlPHN0cmluZywgSVdpZGdldD5cbiAgICApOiBzdHJpbmcgPT4gaXRlbS5rZXk7XG5cbiAgICBwdWJsaWMgb25XaWRnZXRDaGFuZ2Uod2lkZ2V0OiBJV2lkZ2V0KTogdm9pZCB7XG4gICAgICAgIC8vIHRoaXMgY291bGQgaGFwcGVuIHdoZW4gY2hhbmdlcyBhcmUgYmVpbmcgbWFkZSBvbiBhIHdpZGdldCB0aGF0IGlzIGJlaW5nIHJlbW92ZWRcbiAgICAgICAgaWYgKCF0aGlzLmRhc2hib2FyZC53aWRnZXRzW3dpZGdldC5pZF0pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVwZGF0ZVdpZGdldCh3aWRnZXQpO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVXaWRnZXQod2lkZ2V0OiBJV2lkZ2V0KTogdm9pZCB7XG4gICAgICAgIGxldCBkYXNoYm9hcmQ6IElEYXNoYm9hcmQgPSB0aGlzLmRhc2hib2FyZDtcbiAgICAgICAgaWYgKCF0aGlzLmRhc2hib2FyZC5wb3NpdGlvbnNbd2lkZ2V0LmlkXSAmJiB0aGlzLmdyaWRzdGVyQ29uZmlnPy5hcGkpIHtcbiAgICAgICAgICAgIGNvbnN0IGdyaWRzdGVySXRlbSA9XG4gICAgICAgICAgICAgICAgdGhpcy5ncmlkc3RlckNvbmZpZy5hcGkuZ2V0Rmlyc3RQb3NzaWJsZVBvc2l0aW9uPy4oe1xuICAgICAgICAgICAgICAgICAgICB4OiAwLFxuICAgICAgICAgICAgICAgICAgICB5OiAwLFxuICAgICAgICAgICAgICAgICAgICByb3dzOiB0aGlzLmdyaWRzdGVyQ29uZmlnPy5kZWZhdWx0SXRlbVJvd3MgYXMgbnVtYmVyLFxuICAgICAgICAgICAgICAgICAgICBjb2xzOiB0aGlzLmdyaWRzdGVyQ29uZmlnPy5kZWZhdWx0SXRlbUNvbHMgYXMgbnVtYmVyLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZGFzaGJvYXJkID0gaW1tdXRhYmxlU2V0KFxuICAgICAgICAgICAgICAgIGRhc2hib2FyZCxcbiAgICAgICAgICAgICAgICBgcG9zaXRpb25zLiR7d2lkZ2V0LmlkfWAsXG4gICAgICAgICAgICAgICAgZ3JpZHN0ZXJJdGVtXG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgZGFzaGJvYXJkID0gaW1tdXRhYmxlU2V0KGRhc2hib2FyZCwgYHdpZGdldHMuJHt3aWRnZXQuaWR9YCwgd2lkZ2V0KTtcbiAgICAgICAgdGhpcy5kYXNoYm9hcmRCdWZmZXIgPSBkYXNoYm9hcmQ7XG4gICAgICAgIHRoaXMuZGFzaGJvYXJkQ2hhbmdlLmVtaXQoZGFzaGJvYXJkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVtb3ZlV2lkZ2V0KHdpZGdldElkOiBzdHJpbmcsIHJlbW92ZVBvc2l0aW9uID0gdHJ1ZSk6IHZvaWQge1xuICAgICAgICBsZXQgZGFzaGJvYXJkOiBJRGFzaGJvYXJkID0gdGhpcy5kYXNoYm9hcmQ7XG4gICAgICAgIGlmICghZGFzaGJvYXJkLndpZGdldHNbd2lkZ2V0SWRdKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB3aWRnZXRzQ2xvbmUgPSBPYmplY3QuYXNzaWduKHt9LCBkYXNoYm9hcmQud2lkZ2V0cyk7XG4gICAgICAgIGRlbGV0ZSB3aWRnZXRzQ2xvbmVbd2lkZ2V0SWRdO1xuICAgICAgICBkYXNoYm9hcmQgPSBpbW11dGFibGVTZXQoZGFzaGJvYXJkLCBcIndpZGdldHNcIiwgd2lkZ2V0c0Nsb25lKTtcblxuICAgICAgICBpZiAocmVtb3ZlUG9zaXRpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IHBvc2l0aW9uc0Nsb25lID0gT2JqZWN0LmFzc2lnbih7fSwgZGFzaGJvYXJkLnBvc2l0aW9ucyk7XG4gICAgICAgICAgICBkZWxldGUgcG9zaXRpb25zQ2xvbmVbd2lkZ2V0SWRdO1xuICAgICAgICAgICAgZGFzaGJvYXJkID0gaW1tdXRhYmxlU2V0KGRhc2hib2FyZCwgXCJwb3NpdGlvbnNcIiwgcG9zaXRpb25zQ2xvbmUpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5kYXNoYm9hcmRDaGFuZ2UuZW1pdChkYXNoYm9hcmQpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzaG91bGRXaWRnZXRSZW5kZXIoa2V5OiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYmVsb3dGb2xkTGF6eUxvYWRpbmdDb25maWc/LmVuYWJsZWRcbiAgICAgICAgICAgID8gdGhpcy5ncmlkc3Rlckl0ZW1zVmlzaWJpbGl0eU1hcFtrZXldXG4gICAgICAgICAgICA6IHRydWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSB1cGRhdGVXaWRnZXRQb3NpdGlvbiA9IChcbiAgICAgICAgaXRlbTogR3JpZHN0ZXJJdGVtLFxuICAgICAgICBpdGVtQ29tcG9uZW50OiBHcmlkc3Rlckl0ZW1Db21wb25lbnRJbnRlcmZhY2VcbiAgICApOiB2b2lkID0+IHtcbiAgICAgICAgY29uc3Qgd2lkZ2V0SWQgPSBTdHJpbmcoKGl0ZW1Db21wb25lbnQgYXMgYW55KS53aWRnZXRJZCk7XG4gICAgICAgIGNvbnN0IGRhc2hib2FyZCA9IGltbXV0YWJsZVNldChcbiAgICAgICAgICAgIHRoaXMuZGFzaGJvYXJkLFxuICAgICAgICAgICAgXCJwb3NpdGlvbnMuXCIgKyB3aWRnZXRJZCxcbiAgICAgICAgICAgIGl0ZW1cbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmRhc2hib2FyZENoYW5nZS5lbWl0KGRhc2hib2FyZCk7XG5cbiAgICAgICAgdGhpcy5ldmVudEJ1cy5nZXRTdHJlYW0oV0lER0VUX1BPU0lUSU9OX0NIQU5HRSkubmV4dCh7XG4gICAgICAgICAgICB3aWRnZXRJZCxcbiAgICAgICAgICAgIHBheWxvYWQ6IGl0ZW0sXG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICBwcml2YXRlIGVtaXRXaWRnZXRSZXNpemUgPSAoXG4gICAgICAgIGl0ZW06IEdyaWRzdGVySXRlbSxcbiAgICAgICAgaXRlbUNvbXBvbmVudDogR3JpZHN0ZXJJdGVtQ29tcG9uZW50SW50ZXJmYWNlXG4gICAgKTogdm9pZCA9PiB7XG4gICAgICAgIGNvbnN0IHdpZGdldElkID0gKGl0ZW1Db21wb25lbnQgYXMgYW55KS53aWRnZXRJZDtcblxuICAgICAgICB0aGlzLmV2ZW50QnVzLmdldFN0cmVhbShXSURHRVRfUkVTSVpFKS5uZXh0KHtcbiAgICAgICAgICAgIHdpZGdldElkLFxuICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgIHdpZGdldElkLFxuICAgICAgICAgICAgICAgIGhlaWdodDogaXRlbUNvbXBvbmVudC5oZWlnaHQsXG4gICAgICAgICAgICAgICAgd2lkdGg6IGl0ZW1Db21wb25lbnQud2lkdGgsXG4gICAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSBob29rRXZlbnQoXG4gICAgICAgIG9wdGlvbnM6IEdyaWRzdGVyQ29uZmlnLFxuICAgICAgICBldmVudE5hbWU6IHN0cmluZyxcbiAgICAgICAgaW52b2tlOiAoXG4gICAgICAgICAgICBpdGVtOiBHcmlkc3Rlckl0ZW0sXG4gICAgICAgICAgICBpdGVtQ29tcG9uZW50OiBHcmlkc3Rlckl0ZW1Db21wb25lbnRJbnRlcmZhY2VcbiAgICAgICAgKSA9PiB2b2lkXG4gICAgKSB7XG4gICAgICAgIGNvbnN0IHByZXZFdmVudCA9IG9wdGlvbnNbZXZlbnROYW1lXTtcbiAgICAgICAgb3B0aW9uc1tldmVudE5hbWVdID0gKFxuICAgICAgICAgICAgaXRlbTogR3JpZHN0ZXJJdGVtLFxuICAgICAgICAgICAgaXRlbUNvbXBvbmVudDogR3JpZHN0ZXJJdGVtQ29tcG9uZW50SW50ZXJmYWNlXG4gICAgICAgICkgPT4ge1xuICAgICAgICAgICAgaW52b2tlKGl0ZW0sIGl0ZW1Db21wb25lbnQpO1xuXG4gICAgICAgICAgICBpZiAocHJldkV2ZW50KSB7XG4gICAgICAgICAgICAgICAgcHJldkV2ZW50KGl0ZW0sIGl0ZW1Db21wb25lbnQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgY2FsY3VsYXRlV2lkZ2V0c1Zpc2liaWxpdHkoKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5iZWxvd0ZvbGRMYXp5TG9hZGluZ0NvbmZpZz8uZW5hYmxlZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZ3JpZHN0ZXJSZWN0OiBDbGllbnRSZWN0ID1cbiAgICAgICAgICAgIHRoaXMuZ3JpZHN0ZXIuZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICAgICAgdGhpcy5ncmlkc3Rlckl0ZW1zVmlzaWJpbGl0eU1hcCA9IHRoaXMuZ3JpZHN0ZXJJdGVtcy5yZWR1Y2UoXG4gICAgICAgICAgICAoYWNjOiBSZWNvcmQ8c3RyaW5nLCBib29sZWFuPiwgbmV4dCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgZWwgfSA9IG5leHQ7XG4gICAgICAgICAgICAgICAgY29uc3QgaWR4OiBzdHJpbmcgPSAobmV4dCBhcyBhbnkpLndpZGdldElkO1xuXG4gICAgICAgICAgICAgICAgLy8gaWYgd2lkZ2V0IGlzIGFscmVhZHkgbG9hZGVkIGRvbid0IGhpZGUgaXRcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICF0aGlzLmJlbG93Rm9sZExhenlMb2FkaW5nQ29uZmlnLmNvbmZpZ3VyYXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgID8ucmVsb2FkV2lkZ2V0c09uU2Nyb2xsXG4gICAgICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZWaXNpYmlsaXR5ID0gYWNjW2lkeF07XG4gICAgICAgICAgICAgICAgICAgIGlmIChwcmV2VmlzaWJpbGl0eSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFjYztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNvbnN0IHJlY3Q6IENsaWVudFJlY3QgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGdldEhlaWdodFZpc2liaWxpdHkgPSAoKSA9PlxuICAgICAgICAgICAgICAgICAgICAocmVjdC50b3AgPiBncmlkc3RlclJlY3QudG9wICYmXG4gICAgICAgICAgICAgICAgICAgICAgICByZWN0LnRvcCA8IGdyaWRzdGVyUmVjdC5ib3R0b20pIHx8XG4gICAgICAgICAgICAgICAgICAgIChyZWN0LmJvdHRvbSA+IGdyaWRzdGVyUmVjdC50b3AgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3QuYm90dG9tIDwgZ3JpZHN0ZXJSZWN0LmJvdHRvbSk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBnZXRXaWR0aFZpc2liaWxpdHkgPSAoKSA9PlxuICAgICAgICAgICAgICAgICAgICAocmVjdC5sZWZ0ID4gZ3JpZHN0ZXJSZWN0LmxlZnQgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3QubGVmdCA8IGdyaWRzdGVyUmVjdC5yaWdodCkgfHxcbiAgICAgICAgICAgICAgICAgICAgKHJlY3QucmlnaHQgPiBncmlkc3RlclJlY3QubGVmdCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVjdC5yaWdodCA8IGdyaWRzdGVyUmVjdC5yaWdodCk7XG5cbiAgICAgICAgICAgICAgICBjb25zdCBpc1Zpc2libGUgPSBnZXRIZWlnaHRWaXNpYmlsaXR5KCkgJiYgZ2V0V2lkdGhWaXNpYmlsaXR5KCk7XG5cbiAgICAgICAgICAgICAgICBhY2NbaWR4XSA9IGlzVmlzaWJsZTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBhY2M7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdGhpcy5ncmlkc3Rlckl0ZW1zVmlzaWJpbGl0eU1hcFxuICAgICAgICApO1xuICAgIH1cbn1cbiIsIjxncmlkc3RlclxuICAgIGNsYXNzPVwibnVpLWRhc2hib2FyZF9fZ3JpZHN0ZXJcIlxuICAgIFtvcHRpb25zXT1cImdyaWRzdGVyQ29uZmlnXCJcbiAgICAoc2Nyb2xsKT1cIm9uR3JpZHN0ZXJTY3JvbGwoKVwiXG4+XG4gICAgPGdyaWRzdGVyLWl0ZW1cbiAgICAgICAgKm5nRm9yPVwiXG4gICAgICAgICAgICBsZXQgd2lkZ2V0IG9mIGRhc2hib2FyZC53aWRnZXRzIHwga2V5dmFsdWUgOiBvcmRlcldpZGdldHM7XG4gICAgICAgICAgICB0cmFja0J5OiB0cmFja0J5Rm5cbiAgICAgICAgXCJcbiAgICAgICAgW2l0ZW1dPVwiZGFzaGJvYXJkLnBvc2l0aW9uc1t3aWRnZXQua2V5XVwiXG4gICAgICAgIGNsYXNzPVwibnVpLWRhc2hib2FyZF9fZ3JpZHN0ZXItaXRlbVwiXG4gICAgICAgIFtudWlHcmlkc3Rlckl0ZW1XaWRnZXRJZF09XCJ3aWRnZXQua2V5XCJcbiAgICA+XG4gICAgICAgIDxudWktd2lkZ2V0XG4gICAgICAgICAgICAqbmdJZj1cInNob3VsZFdpZGdldFJlbmRlcih3aWRnZXQua2V5KTsgZWxzZSBlbXB0eVdpZGdldFRwbFwiXG4gICAgICAgICAgICBbd2lkZ2V0XT1cIndpZGdldC52YWx1ZVwiXG4gICAgICAgICAgICAod2lkZ2V0Q2hhbmdlKT1cIm9uV2lkZ2V0Q2hhbmdlKCRldmVudClcIlxuICAgICAgICAgICAgW2F0dHIud2lkZ2V0LWlkXT1cIndpZGdldC5rZXlcIlxuICAgICAgICAgICAgW2F0dHIud2lkZ2V0LXR5cGVdPVwid2lkZ2V0LnZhbHVlLnR5cGVcIlxuICAgICAgICAgICAgW2F0dHIud2lkZ2V0LWd1aWRdPVwid2lkZ2V0LnZhbHVlLnVuaXF1ZUtleVwiXG4gICAgICAgICAgICBjbGFzcz1cInctMTAwIGgtMTAwIGQtYmxvY2tcIlxuICAgICAgICA+XG4gICAgICAgIDwvbnVpLXdpZGdldD5cbiAgICA8L2dyaWRzdGVyLWl0ZW0+XG48L2dyaWRzdGVyPlxuXG48bmctdGVtcGxhdGUgI2VtcHR5V2lkZ2V0VHBsPlxuICAgIDxkaXYgY2xhc3M9XCJ3LTEwMCBoLTEwMCBkLWJsb2NrXCI+XG4gICAgICAgIDxudWktbG9hZGluZyBbYWN0aXZlXT1cInRydWVcIj48L251aS1sb2FkaW5nPlxuICAgIDwvZGl2PlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==