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

264 lines 48.3 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 { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, Output, } from "@angular/core"; import { FormBuilder, } from "@angular/forms"; import get from "lodash/get"; import isUndefined from "lodash/isUndefined"; import values from "lodash/values"; import { Subject } from "rxjs"; import { map } from "rxjs/operators"; import { DialogService, EventBus, immutableSet, uuid, } from "@nova-ui/bits"; import { PizzagnaService } from "../../../../../pizzagna/services/pizzagna.service"; import { SET_PROPERTY_VALUE, } from "../../../../../services/types"; import { PizzagnaLayer, PIZZAGNA_EVENT_BUS, WellKnownDataSourceFeatures, } from "../../../../../types"; import { DATA_SOURCE_CREATED, DATA_SOURCE_OUTPUT } from "../../../../types"; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "@nova-ui/bits"; import * as i3 from "../../../../../pizzagna/services/pizzagna.service"; import * as i4 from "@angular/common"; import * as i5 from "../../../items-dynamic/items-dynamic.component"; export class TableColumnsConfigurationComponent { static { this.lateLoadKey = "TableColumnsConfigurationComponent"; } constructor(formBuilder, changeDetector, dialogService, pizzagnaService, eventBus) { this.formBuilder = formBuilder; this.changeDetector = changeDetector; this.dialogService = dialogService; this.pizzagnaService = pizzagnaService; this.eventBus = eventBus; this.columns = []; this.formatters = []; this.dataFields = []; this.formReady = new EventEmitter(); this.onDestroy$ = new Subject(); // hackfix for NUI-5712 // Depending on the timing of pizzagna changes, the incoming value for dataFields may be undefined. // This property ensures that we are only acting on valid values for the data fields. this.lastValidDataFields = []; this.eventBus.subscribeUntil(DATA_SOURCE_CREATED, this.onDestroy$, (event) => { if (!event.payload) { return; } this.dataSource = event.payload; }); this.eventBus.subscribeUntil(DATA_SOURCE_OUTPUT, this.onDestroy$, (event) => { // Because typing is lenient for the data source output, the event may or may not contain an IDataSourceOutput // with a result property; the payload may actually be the result itself, so both possibilities are accommodated. const { dataFields } = isUndefined(event.payload.result) ? event.payload : event.payload.result || {}; if (dataFields) { let formPizzagna = this.pizzagnaService.pizzagna; formPizzagna = immutableSet(formPizzagna, `${PizzagnaLayer.Data}.columns.properties.dataFields`, dataFields); const columnsTemplate = this.pizzagnaService.pizzagna[PizzagnaLayer.Structure] .columns.properties?.template; const presentationIndex = columnsTemplate.findIndex((val) => val.id === "presentation"); // eslint-disable-next-line max-len const presentationPizzagnaPath = `${PizzagnaLayer.Structure}.columns.properties.template[${presentationIndex}].properties.dataFields`; formPizzagna = immutableSet(formPizzagna, presentationPizzagnaPath, dataFields); const columns = get(this.pizzagnaService.pizzagna, `${PizzagnaLayer.Data}.columns.properties.columns`); const columnIds = columns.map((c) => c.id); formPizzagna = columnIds.reduce((res, id) => immutableSet(res, `${PizzagnaLayer.Data}.${id}/presentation.properties.dataFields`, dataFields), formPizzagna); this.pizzagnaService.updatePizzagna(formPizzagna); this.eventBus.getStream(SET_PROPERTY_VALUE).next({ payload: { path: "", value: formPizzagna, }, }); } }); } ngOnInit() { } ngOnChanges(changes) { if (changes.dataFields && changes.dataFields.currentValue) { // hackfix for NUI-5712 this.lastValidDataFields = changes.dataFields.currentValue; const disableColumnGeneration = this.dataSource?.features?.getFeatureConfig(WellKnownDataSourceFeatures.DisableTableColumnGeneration)?.enabled; const columns = this.mergeColumns(changes.dataFields.currentValue, this.columns); if (columns?.length || disableColumnGeneration) { // if disableColumnGeneration is enabled and there are no columns to be kept, // we have to clear the form by updating the column input via the `onItemsChange` method this.onItemsChange(columns); } else { if (!disableColumnGeneration) { this.resetColumns(false); } } // column components are not updated properly without this one setTimeout(() => this.changeDetector.markForCheck()); } if (changes.columns) { const components = this.columns.map((c) => ({ id: c.id, children: { [`${c.id}/description`]: { ...c, }, [`${c.id}/presentation`]: { ...c, }, }, })); this.pizzagnaService.createComponentsFromTemplateWithProperties("columns", components); // wait for column components to be created from template setTimeout(() => { // triggering the form update to update the preview - without this it was not updating the last added column as form field changes through // pizzagna don't generate valueChange events this.form .get("columns") ?.setValue([...(this.form.get("columns")?.value ?? [])]); }); } } onFormReady(form) { this.form = this.formBuilder.group({ columns: form, // this form field serves as a source of truth for anybody interesting in reading/modifying the columns value // originally the values were mapped from the form directly to the preview without having a place where all the data would be consolidated // together in the form. Converters subscribe to this form field to listen for column changes. The value is transformed in this method down below. columnsOutput: {}, }); this.emptyColumns$ = this.form.valueChanges.pipe(map((result) => result.columns.length === 0)); this.formReady.emit(this.form); // we listen for changes of the `columns` and transform it into ITableWidgetColumnConfig[] this.form.get("columns")?.valueChanges.subscribe((value) => { const newColumns = value.map((c /* form representing one column */) => { let result = { id: c.id, }; for (const key of Object.keys(c.properties)) { result = { ...result, ...c.properties[key] /* merge properties from each child form */, }; } result.sortable = this.lastValidDataFields?.find((df) => df.id === result.formatter?.properties?.dataFieldIds?.value)?.sortable; return result; }); this.form.get("columnsOutput")?.setValue(newColumns); }); } onItemsChange(columns) { const parentPath = "columns"; const componentIds = columns.map((tile) => tile.id); this.pizzagnaService.createComponentsFromTemplate(parentPath, componentIds); const property = { componentId: this.componentId, pizzagnaKey: PizzagnaLayer.Data, propertyPath: ["columns"], }; this.pizzagnaService.setProperty(property, columns); } addColumn() { // @ts-ignore: Types of property 'formatter' are incompatible. this.onItemsChange([ ...this.columns, { id: uuid("column"), label: "", formatter: undefined, }, ]); } onResetColumns() { this.resetColumns(!!this.columns?.length); } resetColumns(confirmation) { const reset = () => { const columns = this.lastValidDataFields.map((df) => ({ id: uuid("column"), formatter: { componentType: "RawFormatterComponent", properties: { dataFieldIds: { value: df.id, }, }, }, isActive: true, label: df.label, width: undefined, sortable: df.sortable, })); this.onItemsChange(columns); }; if (confirmation) { const dialog = this.dialogService.confirm({ title: $localize `Are you sure?`, message: $localize `Resetting the columns will revert them to their default configurations. Do you wish to proceed?`, confirmText: $localize `Reset Columns`, }); dialog.result.then((result) => { if (result) { reset(); } }, () => { // this being here prevents a "unhandled rejection" console error from showing up }); } else { reset(); } } /** * Merges current column definitions with new incoming data fields * * @param currentDatafields * @param columns */ mergeColumns(currentDatafields, columns) { const currentDatafieldIds = currentDatafields.map((datafield) => datafield.id); return columns.filter((column) => { if (!column.formatter?.properties?.dataFieldIds) { return false; } return values(column.formatter?.properties?.dataFieldIds).some((datafield) => currentDatafieldIds.includes(datafield)); }); } ngOnDestroy() { this.onDestroy$.next(); this.onDestroy$.complete(); } /** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableColumnsConfigurationComponent, deps: [{ token: i1.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: i2.DialogService }, { token: i3.PizzagnaService }, { token: PIZZAGNA_EVENT_BUS }], target: i0.ɵɵFactoryTarget.Component }); } /** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TableColumnsConfigurationComponent, selector: "nui-table-columns-configuration", inputs: { columns: "columns", formatters: "formatters", componentId: "componentId", dataFields: "dataFields", nodes: "nodes" }, outputs: { formReady: "formReady" }, usesOnChanges: true, ngImport: i0, template: "<nui-items-dynamic\n [items]=\"columns\"\n [nodes]=\"nodes\"\n headerPrefix=\"Column\"\n i18n-headerPrefix\n (itemsChange)=\"onItemsChange($event)\"\n (formReady)=\"onFormReady($event)\"\n></nui-items-dynamic>\n\n<div class=\"pl-4 pr-4\" *ngIf=\"(emptyColumns$ | async) && form.touched\">\n <nui-message type=\"critical\" [allowDismiss]=\"false\" i18n>\n <b>At least one column must be added.</b>\n </nui-message>\n</div>\n\n<button\n nui-button\n icon=\"add\"\n displayStyle=\"action\"\n id=\"table-widget-add-indicator-btn\"\n type=\"button\"\n class=\"ml-4 mb-4\"\n (click)=\"addColumn()\"\n i18n\n>\n Add new column\n</button>\n\n<button\n nui-button\n icon=\"reset\"\n displayStyle=\"action\"\n id=\"table-widget-reset-indicator-btn\"\n type=\"button\"\n class=\"ml-4 mb-4\"\n (click)=\"onResetColumns()\"\n i18n\n>\n Reset columns\n</button>\n", dependencies: [{ kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.ButtonComponent, selector: "[nui-button]", inputs: ["displayStyle", "icon", "iconColor", "iconRight", "isBusy", "isEmpty", "ariaLabel", "isRepeat", "size"] }, { kind: "component", type: i2.MessageComponent, selector: "nui-message", inputs: ["type", "allowDismiss", "manualControl"], outputs: ["dismiss"] }, { kind: "component", type: i5.ItemsDynamicComponent, selector: "nui-items-dynamic", inputs: ["items", "moveButtons", "nodes", "headerPrefix"], outputs: ["formReady", "itemsChange"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableColumnsConfigurationComponent, decorators: [{ type: Component, args: [{ selector: "nui-table-columns-configuration", changeDetection: ChangeDetectionStrategy.OnPush, template: "<nui-items-dynamic\n [items]=\"columns\"\n [nodes]=\"nodes\"\n headerPrefix=\"Column\"\n i18n-headerPrefix\n (itemsChange)=\"onItemsChange($event)\"\n (formReady)=\"onFormReady($event)\"\n></nui-items-dynamic>\n\n<div class=\"pl-4 pr-4\" *ngIf=\"(emptyColumns$ | async) && form.touched\">\n <nui-message type=\"critical\" [allowDismiss]=\"false\" i18n>\n <b>At least one column must be added.</b>\n </nui-message>\n</div>\n\n<button\n nui-button\n icon=\"add\"\n displayStyle=\"action\"\n id=\"table-widget-add-indicator-btn\"\n type=\"button\"\n class=\"ml-4 mb-4\"\n (click)=\"addColumn()\"\n i18n\n>\n Add new column\n</button>\n\n<button\n nui-button\n icon=\"reset\"\n displayStyle=\"action\"\n id=\"table-widget-reset-indicator-btn\"\n type=\"button\"\n class=\"ml-4 mb-4\"\n (click)=\"onResetColumns()\"\n i18n\n>\n Reset columns\n</button>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i0.ChangeDetectorRef }, { type: i2.DialogService }, { type: i3.PizzagnaService }, { type: i2.EventBus, decorators: [{ type: Inject, args: [PIZZAGNA_EVENT_BUS] }] }], propDecorators: { columns: [{ type: Input }], formatters: [{ type: Input }], componentId: [{ type: Input }], dataFields: [{ type: Input }], nodes: [{ type: Input }], formReady: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtY29sdW1ucy1jb25maWd1cmF0aW9uLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29uZmlndXJhdG9yL2NvbXBvbmVudHMvd2lkZ2V0cy90YWJsZS9jb2x1bW5zLWVkaXRvci90YWJsZS1jb2x1bW5zLWNvbmZpZ3VyYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb25maWd1cmF0b3IvY29tcG9uZW50cy93aWRnZXRzL3RhYmxlL2NvbHVtbnMtZWRpdG9yL3RhYmxlLWNvbHVtbnMtY29uZmlndXJhdGlvbi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUNILHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUlMLE1BQU0sR0FFVCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBR0gsV0FBVyxHQUVkLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEIsT0FBTyxHQUFHLE1BQU0sWUFBWSxDQUFDO0FBQzdCLE9BQU8sV0FBVyxNQUFNLG9CQUFvQixDQUFDO0FBQzdDLE9BQU8sTUFBTSxNQUFNLGVBQWUsQ0FBQztBQUNuQyxPQUFPLEVBQWMsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzND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c0JBQWxCLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUVJLFNBQVM7c0JBQWxCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHtcbiAgICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIEluamVjdCxcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7XG4gICAgQWJzdHJhY3RDb250cm9sLFxuICAgIEZvcm1BcnJheSxcbiAgICBGb3JtQnVpbGRlcixcbiAgICBGb3JtR3JvdXAsXG59IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xuaW1wb3J0IGdldCBmcm9tIFwibG9kYXNoL2dldFwiO1xuaW1wb3J0IGlzVW5kZWZpbmVkIGZyb20gXCJsb2Rhc2gvaXNVbmRlZmluZWRcIjtcbmltcG9ydCB2YWx1ZXMgZnJvbSBcImxvZGFzaC92YWx1ZXNcIjtcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbmltcG9ydCB7XG4gICAgRGlhbG9nU2VydmljZSxcbiAgICBFdmVudEJ1cyxcbiAgICBJRGF0YUZpZWxkLFxuICAgIElEYXRhU291cmNlLFxuICAgIElFdmVudCxcbiAgICBpbW11dGFibGVTZXQsXG4gICAgdXVpZCxcbn0gZnJvbSBcIkBub3ZhLXVpL2JpdHNcIjtcblxuaW1wb3J0IHsgSURhdGFTb3VyY2VPdXRwdXQgfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vY29tcG9uZW50cy9wcm92aWRlcnMvdHlwZXNcIjtcbmltcG9ydCB7IElUYWJsZVdpZGdldENvbHVtbkNvbmZpZyB9IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9jb21wb25lbnRzL3RhYmxlLXdpZGdldC90eXBlc1wiO1xuaW1wb3J0IHsgSUZvcm1hdHRlckRlZmluaXRpb24gfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vY29tcG9uZW50cy90eXBlc1wiO1xuaW1wb3J0IHsgSVBpenphZ25hUHJvcGVydHkgfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vcGl6emFnbmEvZnVuY3Rpb25zL2dldC1waXp6YWduYS1wcm9wZXJ0eS1wYXRoXCI7XG5pbXBvcnQgeyBQaXp6YWduYVNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vcGl6emFnbmEvc2VydmljZXMvcGl6emFnbmEuc2VydmljZVwiO1xuaW1wb3J0IHtcbiAgICBJU2V0UHJvcGVydHlQYXlsb2FkLFxuICAgIFNFVF9QUk9QRVJUWV9WQUxVRSxcbn0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3NlcnZpY2VzL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIElIYXNGb3JtLFxuICAgIElQaXp6YWduYSxcbiAgICBQaXp6YWduYUxheWVyLFxuICAgIFBJWlpBR05BX0VWRU5UX0JVUyxcbiAgICBXZWxsS25vd25EYXRhU291cmNlRmVhdHVyZXMsXG59IGZyb20gXCIuLi8uLi8uLi8uLi8uLi90eXBlc1wiO1xuaW1wb3J0IHsgREFUQV9TT1VSQ0VfQ1JFQVRFRCwgREFUQV9TT1VSQ0VfT1VUUFVUIH0gZnJvbSBcIi4uLy4uLy4uLy4uL3R5cGVzXCI7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS10YWJsZS1jb2x1bW5zLWNvbmZpZ3VyYXRpb25cIixcbiAgICB0ZW1wbGF0ZVVybDogXCIuL3RhYmxlLWNvbHVtbnMtY29uZmlndXJhdGlvbi5jb21wb25lbnQuaHRtbFwiLFxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBUYWJsZUNvbHVtbnNDb25maWd1cmF0aW9uQ29tcG9uZW50XG4gICAgaW1wbGVtZW50cyBPbkluaXQsIElIYXNGb3JtLCBPbkNoYW5nZXMsIE9uRGVzdHJveVxue1xuICAgIHN0YXRpYyBsYXRlTG9hZEtleSA9IFwiVGFibGVDb2x1bW5zQ29uZmlndXJhdGlvbkNvbXBvbmVudFwiO1xuXG4gICAgQElucHV0KCkgY29sdW1uczogSVRhYmxlV2lkZ2V0Q29sdW1uQ29uZmlnW10gPSBbXTtcbiAgICBASW5wdXQoKSBmb3JtYXR0ZXJzOiBBcnJheTxJRm9ybWF0dGVyRGVmaW5pdGlvbj4gPSBbXTtcbiAgICBASW5wdXQoKSBjb21wb25lbnRJZDogc3RyaW5nO1xuICAgIEBJbnB1dCgpIGRhdGFGaWVsZHM6IEFycmF5PElEYXRhRmllbGQ+ID0gW107XG4gICAgQElucHV0KCkgbm9kZXM6IHN0cmluZ1tdO1xuXG4gICAgQE91dHB1dCgpIGZvcm1SZWFkeSA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9ybUdyb3VwPigpO1xuXG4gICAgcHVibGljIGZvcm06IEZvcm1Hcm91cDtcbiAgICBwdWJsaWMgZW1wdHlDb2x1bW5zJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcblxuICAgIC8vIHRoZSBsYXN0IHNlbGVjdGVkIGRhdGEgc291cmNlIHdpbGwgYmUgc3RvcmVkIGhlcmVcbiAgICBwdWJsaWMgZGF0YVNvdXJjZTogSURhdGFTb3VyY2U7XG5cbiAgICBwcml2YXRlIG9uRGVzdHJveSQ6IFN1YmplY3Q8dm9pZD4gPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuXG4gICAgLy8gaGFja2ZpeCBmb3IgTlVJLTU3MTJcbiAgICAvLyBEZXBlbmRpbmcgb24gdGhlIHRpbWluZyBvZiBwaXp6YWduYSBjaGFuZ2VzLCB0aGUgaW5jb21pbmcgdmFsdWUgZm9yIGRhdGFGaWVsZHMgbWF5IGJlIHVuZGVmaW5lZC5cbiAgICAvLyBUaGlzIHByb3BlcnR5IGVuc3VyZXMgdGhhdCB3ZSBhcmUgb25seSBhY3Rpbmcgb24gdmFsaWQgdmFsdWVzIGZvciB0aGUgZGF0YSBmaWVsZHMuXG4gICAgcHJpdmF0ZSBsYXN0VmFsaWREYXRhRmllbGRzOiBJRGF0YUZpZWxkW10gPSBbXTtcblxuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICAgICAgcHJpdmF0ZSBjaGFuZ2VEZXRlY3RvcjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgICAgIHByaXZhdGUgZGlhbG9nU2VydmljZTogRGlhbG9nU2VydmljZSxcbiAgICAgICAgcHJpdmF0ZSBwaXp6YWduYVNlcnZpY2U6IFBpenphZ25hU2VydmljZSxcbiAgICAgICAgQEluamVjdChQSVpaQUdOQV9FVkVOVF9CVVMpIHByaXZhdGUgZXZlbnRCdXM6IEV2ZW50QnVzPElFdmVudD5cbiAgICApIHtcbiAgICAgICAgdGhpcy5ldmVudEJ1cy5zdWJzY3JpYmVVbnRpbChcbiAgICAgICAgICAgIERBVEFfU09VUkNFX0NSRUFURUQsXG4gICAgICAgICAgICB0aGlzLm9uRGVzdHJveSQsXG4gICAgICAgICAgICAoZXZlbnQ6IElFdmVudDxJRGF0YVNvdXJjZT4pID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoIWV2ZW50LnBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuZGF0YVNvdXJjZSA9IGV2ZW50LnBheWxvYWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5ldmVudEJ1cy5zdWJzY3JpYmVVbnRpbChcbiAgICAgICAgICAgIERBVEFfU09VUkNFX09VVFBVVCxcbiAgICAgICAgICAgIHRoaXMub25EZXN0cm95JCxcbiAgICAgICAgICAgIChldmVudDogSUV2ZW50PGFueSB8IElEYXRhU291cmNlT3V0cHV0PGFueT4+KSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gQmVjYXVzZSB0eXBpbmcgaXMgbGVuaWVudCBmb3IgdGhlIGRhdGEgc291cmNlIG91dHB1dCwgdGhlIGV2ZW50IG1heSBvciBtYXkgbm90IGNvbnRhaW4gYW4gSURhdGFTb3VyY2VPdXRwdXRcbiAgICAgICAgICAgICAgICAvLyB3aXRoIGEgcmVzdWx0IHByb3BlcnR5OyB0aGUgcGF5bG9hZCBtYXkgYWN0dWFsbHkgYmUgdGhlIHJlc3VsdCBpdHNlbGYsIHNvIGJvdGggcG9zc2liaWxpdGllcyBhcmUgYWNjb21tb2RhdGVkLlxuICAgICAgICAgICAgICAgIGNvbnN0IHsgZGF0YUZpZWxkcyB9ID0gaXNVbmRlZmluZWQoZXZlbnQucGF5bG9hZC5yZXN1bHQpXG4gICAgICAgICAgICAgICAgICAgID8gZXZlbnQucGF5bG9hZFxuICAgICAgICAgICAgICAgICAgICA6IGV2ZW50LnBheWxvYWQucmVzdWx0IHx8IHt9O1xuXG4gICAgICAgICAgICAgICAgaWYgKGRhdGFGaWVsZHMpIHtcbiAgICAgICAgICAgICAgICAgICAgbGV0IGZvcm1QaXp6YWduYTogSVBpenphZ25hID0gdGhpcy5waXp6YWduYVNlcnZpY2UucGl6emFnbmE7XG4gICAgICAgICAgICAgICAgICAgIGZvcm1QaXp6YWduYSA9IGltbXV0YWJsZVNldChcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1QaXp6YWduYSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGAke1BpenphZ25hTGF5ZXIuRGF0YX0uY29sdW1ucy5wcm9wZXJ0aWVzLmRhdGFGaWVsZHNgLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YUZpZWxkc1xuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNvbHVtbnNUZW1wbGF0ZSA9XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnBpenphZ25hU2VydmljZS5waXp6YWduYVtQaXp6YWduYUxheWVyLlN0cnVjdHVyZV1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuY29sdW1ucy5wcm9wZXJ0aWVzPy50ZW1wbGF0ZTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcHJlc2VudGF0aW9uSW5kZXggPSBjb2x1bW5zVGVtcGxhdGUuZmluZEluZGV4KFxuICAgICAgICAgICAgICAgICAgICAgICAgKHZhbDogeyBpZDogc3RyaW5nIH0pID0+IHZhbC5pZCA9PT0gXCJwcmVzZW50YXRpb25cIlxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBwcmVzZW50YXRpb25QaXp6YWduYVBhdGg6IHN0cmluZyA9IGAke1BpenphZ25hTGF5ZXIuU3RydWN0dXJlfS5jb2x1bW5zLnByb3BlcnRpZXMudGVtcGxhdGVbJHtwcmVzZW50YXRpb25JbmRleH1dLnByb3BlcnRpZXMuZGF0YUZpZWxkc2A7XG4gICAgICAgICAgICAgICAgICAgIGZvcm1QaXp6YWduYSA9IGltbXV0YWJsZVNldChcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1QaXp6YWduYSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXNlbnRhdGlvblBpenphZ25hUGF0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFGaWVsZHNcbiAgICAgICAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBjb2x1bW5zID0gZ2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5waXp6YWduYVNlcnZpY2UucGl6emFnbmEsXG4gICAgICAgICAgICAgICAgICAgICAgICBgJHtQaXp6YWduYUxheWVyLkRhdGF9LmNvbHVtbnMucHJvcGVydGllcy5jb2x1bW5zYFxuICAgICAgICAgICAgICAgICAgICApIGFzIGFueTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY29sdW1uSWRzID0gY29sdW1ucy5tYXAoXG4gICAgICAgICAgICAgICAgICAgICAgICAoYzogSVRhYmxlV2lkZ2V0Q29sdW1uQ29uZmlnKSA9PiBjLmlkXG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIGZvcm1QaXp6YWduYSA9IGNvbHVtbklkcy5yZWR1Y2UoXG4gICAgICAgICAgICAgICAgICAgICAgICAocmVzOiBJUGl6emFnbmEsIGlkOiBzdHJpbmcpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaW1tdXRhYmxlU2V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGAke1BpenphZ25hTGF5ZXIuRGF0YX0uJHtpZH0vcHJlc2VudGF0aW9uLnByb3BlcnRpZXMuZGF0YUZpZWxkc2AsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFGaWVsZHNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybVBpenphZ25hXG4gICAgICAgICAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5waXp6YWduYVNlcnZpY2UudXBkYXRlUGl6emFnbmEoZm9ybVBpenphZ25hKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLmV2ZW50QnVzLmdldFN0cmVhbShTRVRfUFJPUEVSVFlfVkFMVUUpLm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgcGF5bG9hZDoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhdGg6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGZvcm1QaXp6YWduYSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gYXMgSVNldFByb3BlcnR5UGF5bG9hZCxcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uSW5pdCgpOiB2b2lkIHt9XG5cbiAgICBwdWJsaWMgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgICAgICBpZiAoY2hhbmdlcy5kYXRhRmllbGRzICYmIGNoYW5nZXMuZGF0YUZpZWxkcy5jdXJyZW50VmFsdWUpIHtcbiAgICAgICAgICAgIC8vIGhhY2tmaXggZm9yIE5VSS01NzEyXG4gICAgICAgICAgICB0aGlzLmxhc3RWYWxpZERhdGFGaWVsZHMgPSBjaGFuZ2VzLmRhdGFGaWVsZHMuY3VycmVudFZhbHVlO1xuXG4gICAgICAgICAgICBjb25zdCBkaXNhYmxlQ29sdW1uR2VuZXJhdGlvbiA9XG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlPy5mZWF0dXJlcz8uZ2V0RmVhdHVyZUNvbmZpZyhcbiAgICAgICAgICAgICAgICAgICAgV2VsbEtub3duRGF0YVNvdXJjZUZlYXR1cmVzLkRpc2FibGVUYWJsZUNvbHVtbkdlbmVyYXRpb25cbiAgICAgICAgICAgICAgICApPy5lbmFibGVkO1xuXG4gICAgICAgICAgICBjb25zdCBjb2x1bW5zID0gdGhpcy5tZXJnZUNvbHVtbnMoXG4gICAgICAgICAgICAgICAgY2hhbmdlcy5kYXRhRmllbGRzLmN1cnJlbnRWYWx1ZSxcbiAgICAgICAgICAgICAgICB0aGlzLmNvbHVtbnNcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAoY29sdW1ucz8ubGVuZ3RoIHx8IGRpc2FibGVDb2x1bW5HZW5lcmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgLy8gaWYgZGlzYWJsZUNvbHVtbkdlbmVyYXRpb24gaXMgZW5hYmxlZCBhbmQgdGhlcmUgYXJlIG5vIGNvbHVtbnMgdG8gYmUga2VwdCxcbiAgICAgICAgICAgICAgICAvLyB3ZSBoYXZlIHRvIGNsZWFyIHRoZSBmb3JtIGJ5IHVwZGF0aW5nIHRoZSBjb2x1bW4gaW5wdXQgdmlhIHRoZSBgb25JdGVtc0NoYW5nZWAgbWV0aG9kXG4gICAgICAgICAgICAgICAgdGhpcy5vbkl0ZW1zQ2hhbmdlKGNvbHVtbnMpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBpZiAoIWRpc2FibGVDb2x1bW5HZW5lcmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVzZXRDb2x1bW5zKGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBjb2x1bW4gY29tcG9uZW50cyBhcmUgbm90IHVwZGF0ZWQgcHJvcGVybHkgd2l0aG91dCB0aGlzIG9uZVxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLmNoYW5nZURldGVjdG9yLm1hcmtGb3JDaGVjaygpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjaGFuZ2VzLmNvbHVtbnMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbXBvbmVudHMgPSB0aGlzLmNvbHVtbnMubWFwKChjKSA9PiAoe1xuICAgICAgICAgICAgICAgIGlkOiBjLmlkLFxuICAgICAgICAgICAgICAgIGNoaWxkcmVuOiB7XG4gICAgICAgICAgICAgICAgICAgIFtgJHtjLmlkfS9kZXNjcmlwdGlvbmBdOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAuLi5jLFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBbYCR7Yy5pZH0vcHJlc2VudGF0aW9uYF06IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmMsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgdGhpcy5waXp6YWduYVNlcnZpY2UuY3JlYXRlQ29tcG9uZW50c0Zyb21UZW1wbGF0ZVdpdGhQcm9wZXJ0aWVzKFxuICAgICAgICAgICAgICAgIFwiY29sdW1uc1wiLFxuICAgICAgICAgICAgICAgIGNvbXBvbmVudHNcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIC8vIHdhaXQgZm9yIGNvbHVtbiBjb21wb25lbnRzIHRvIGJlIGNyZWF0ZWQgZnJvbSB0ZW1wbGF0ZVxuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgLy8gdHJpZ2dlcmluZyB0aGUgZm9ybSB1cGRhdGUgdG8gdXBkYXRlIHRoZSBwcmV2aWV3IC0gd2l0aG91dCB0aGlzIGl0IHdhcyBub3QgdXBkYXRpbmcgdGhlIGxhc3QgYWRkZWQgY29sdW1uIGFzIGZvcm0gZmllbGQgY2hhbmdlcyB0aHJvdWdoXG4gICAgICAgICAgICAgICAgLy8gcGl6emFnbmEgZG9uJ3QgZ2VuZXJhdGUgdmFsdWVDaGFuZ2UgZXZlbnRzXG4gICAgICAgICAgICAgICAgdGhpcy5mb3JtXG4gICAgICAgICAgICAgICAgICAgIC5nZXQoXCJjb2x1bW5zXCIpXG4gICAgICAgICAgICAgICAgICAgID8uc2V0VmFsdWUoWy4uLih0aGlzLmZvcm0uZ2V0KFwiY29sdW1uc1wiKT8udmFsdWUgPz8gW10pXSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBvbkZvcm1SZWFkeShmb3JtOiBBYnN0cmFjdENvbnRyb2wpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5mb3JtID0gdGhpcy5mb3JtQnVpbGRlci5ncm91cCh7XG4gICAgICAgICAgICBjb2x1bW5zOiBmb3JtIGFzIEZvcm1BcnJheSxcbiAgICAgICAgICAgIC8vIHRoaXMgZm9ybSBmaWVsZCBzZXJ2ZXMgYXMgYSBzb3VyY2Ugb2YgdHJ1dGggZm9yIGFueWJvZHkgaW50ZXJlc3RpbmcgaW4gcmVhZGluZy9tb2RpZnlpbmcgdGhlIGNvbHVtbnMgdmFsdWVcbiAgICAgICAgICAgIC8vIG9yaWdpbmFsbHkgdGhlIHZhbHVlcyB3ZXJlIG1hcHBlZCBmcm9tIHRoZSBmb3JtIGRpcmVjdGx5IHRvIHRoZSBwcmV2aWV3IHdpdGhvdXQgaGF2aW5nIGEgcGxhY2Ugd2hlcmUgYWxsIHRoZSBkYXRhIHdvdWxkIGJlIGNvbnNvbGlkYXRlZFxuICAgICAgICAgICAgLy8gdG9nZXRoZXIgaW4gdGhlIGZvcm0uIENvbnZlcnRlcnMgc3Vic2NyaWJlIHRvIHRoaXMgZm9ybSBmaWVsZCB0byBsaXN0ZW4gZm9yIGNvbHVtbiBjaGFuZ2VzLiBUaGUgdmFsdWUgaXMgdHJhbnNmb3JtZWQgaW4gdGhpcyBtZXRob2QgZG93biBiZWxvdy5cbiAgICAgICAgICAgIGNvbHVtbnNPdXRwdXQ6IHt9LFxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5lbXB0eUNvbHVtbnMkID0gdGhpcy5mb3JtLnZhbHVlQ2hhbmdlcy5waXBlKFxuICAgICAgICAgICAgbWFwKChyZXN1bHQpID0+IHJlc3VsdC5jb2x1bW5zLmxlbmd0aCA9PT0gMClcbiAgICAgICAgKTtcbiAgICAgICAgdGhpcy5mb3JtUmVhZHkuZW1pdCh0aGlzLmZvcm0pO1xuXG4gICAgICAgIC8vIHdlIGxpc3RlbiBmb3IgY2hhbmdlcyBvZiB0aGUgYGNvbHVtbnNgIGFuZCB0cmFuc2Zvcm0gaXQgaW50byBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXVxuICAgICAgICB0aGlzLmZvcm0uZ2V0KFwiY29sdW1uc1wiKT8udmFsdWVDaGFuZ2VzLnN1YnNjcmliZSgodmFsdWUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG5ld0NvbHVtbnMgPSB2YWx1ZS5tYXAoXG4gICAgICAgICAgICAgICAgKGM6IGFueSAvKiBmb3JtIHJlcHJlc2VudGluZyBvbmUgY29sdW1uICovKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGxldCByZXN1bHQ6IElUYWJsZVdpZGdldENvbHVtbkNvbmZpZyA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlkOiBjLmlkLFxuICAgICAgICAgICAgICAgICAgICB9IGFzIGFueTtcbiAgICAgICAgICAgICAgICAgICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXMoYy5wcm9wZXJ0aWVzKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLnJlc3VsdCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi5jLnByb3BlcnRpZXNbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGtleVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIF0gLyogbWVyZ2UgcHJvcGVydGllcyBmcm9tIGVhY2ggY2hpbGQgZm9ybSAqLyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnNvcnRhYmxlID0gdGhpcy5sYXN0VmFsaWREYXRhRmllbGRzPy5maW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgKGRmKSA9PlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmLmlkID09PVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdC5mb3JtYXR0ZXI/LnByb3BlcnRpZXM/LmRhdGFGaWVsZElkcz8udmFsdWVcbiAgICAgICAgICAgICAgICAgICAgKT8uc29ydGFibGU7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgdGhpcy5mb3JtLmdldChcImNvbHVtbnNPdXRwdXRcIik/LnNldFZhbHVlKG5ld0NvbHVtbnMpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb25JdGVtc0NoYW5nZShjb2x1bW5zOiBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXSk6IHZvaWQge1xuICAgICAgICBjb25zdCBwYXJlbnRQYXRoID0gXCJjb2x1bW5zXCI7XG4gICAgICAgIGNvbnN0IGNvbXBvbmVudElkcyA9IGNvbHVtbnMubWFwKCh0aWxlKSA9PiB0aWxlLmlkKTtcbiAgICAgICAgdGhpcy5waXp6YWduYVNlcnZpY2UuY3JlYXRlQ29tcG9uZW50c0Zyb21UZW1wbGF0ZShcbiAgICAgICAgICAgIHBhcmVudFBhdGgsXG4gICAgICAgICAgICBjb21wb25lbnRJZHNcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCBwcm9wZXJ0eTogSVBpenphZ25hUHJvcGVydHkgPSB7XG4gICAgICAgICAgICBjb21wb25lbnRJZDogdGhpcy5jb21wb25lbnRJZCxcbiAgICAgICAgICAgIHBpenphZ25hS2V5OiBQaXp6YWduYUxheWVyLkRhdGEsXG4gICAgICAgICAgICBwcm9wZXJ0eVBhdGg6IFtcImNvbHVtbnNcIl0sXG4gICAgICAgIH07XG4gICAgICAgIHRoaXMucGl6emFnbmFTZXJ2aWNlLnNldFByb3BlcnR5KHByb3BlcnR5LCBjb2x1bW5zKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYWRkQ29sdW1uKCk6IHZvaWQge1xuICAgICAgICAvLyBAdHMtaWdub3JlOiBUeXBlcyBvZiBwcm9wZXJ0eSAnZm9ybWF0dGVyJyBhcmUgaW5jb21wYXRpYmxlLlxuICAgICAgICB0aGlzLm9uSXRlbXNDaGFuZ2UoW1xuICAgICAgICAgICAgLi4udGhpcy5jb2x1bW5zLFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGlkOiB1dWlkKFwiY29sdW1uXCIpLFxuICAgICAgICAgICAgICAgIGxhYmVsOiBcIlwiLFxuICAgICAgICAgICAgICAgIGZvcm1hdHRlcjogdW5kZWZpbmVkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgcHVibGljIG9uUmVzZXRDb2x1bW5zKCk6IHZvaWQge1xuICAgICAgICB0aGlzLnJlc2V0Q29sdW1ucyghIXRoaXMuY29sdW1ucz8ubGVuZ3RoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcmVzZXRDb2x1bW5zKGNvbmZpcm1hdGlvbjogYm9vbGVhbik6IHZvaWQge1xuICAgICAgICBjb25zdCByZXNldCA9ICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNvbHVtbnM6IElUYWJsZVdpZGdldENvbHVtbkNvbmZpZ1tdID1cbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RWYWxpZERhdGFGaWVsZHMubWFwKChkZikgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgaWQ6IHV1aWQoXCJjb2x1bW5cIiksXG4gICAgICAgICAgICAgICAgICAgIGZvcm1hdHRlcjoge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29tcG9uZW50VHlwZTogXCJSYXdGb3JtYXR0ZXJDb21wb25lbnRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhRmllbGRJZHM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGRmLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBpc0FjdGl2ZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgbGFiZWw6IGRmLmxhYmVsLFxuICAgICAgICAgICAgICAgICAgICB3aWR0aDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgICAgICBzb3J0YWJsZTogZGYuc29ydGFibGUsXG4gICAgICAgICAgICAgICAgfSkpO1xuXG4gICAgICAgICAgICB0aGlzLm9uSXRlbXNDaGFuZ2UoY29sdW1ucyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgaWYgKGNvbmZpcm1hdGlvbikge1xuICAgICAgICAgICAgY29uc3QgZGlhbG9nID0gdGhpcy5kaWFsb2dTZXJ2aWNlLmNvbmZpcm0oe1xuICAgICAgICAgICAgICAgIHRpdGxlOiAkbG9jYWxpemVgQXJlIHlvdSBzdXJlP2AsXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogJGxvY2FsaXplYFJlc2V0dGluZyB0aGUgY29sdW1ucyB3aWxsIHJldmVydCB0aGVtIHRvIHRoZWlyIGRlZmF1bHQgY29uZmlndXJhdGlvbnMuIERvIHlvdSB3aXNoIHRvIHByb2NlZWQ/YCxcbiAgICAgICAgICAgICAgICBjb25maXJtVGV4dDogJGxvY2FsaXplYFJlc2V0IENvbHVtbnNgLFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGRpYWxvZy5yZXN1bHQudGhlbihcbiAgICAgICAgICAgICAgICAocmVzdWx0KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc2V0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gdGhpcyBiZWluZyBoZXJlIHByZXZlbnRzIGEgXCJ1bmhhbmRsZWQgcmVqZWN0aW9uXCIgY29uc29sZSBlcnJvciBmcm9tIHNob3dpbmcgdXBcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzZXQoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1lcmdlcyBjdXJyZW50IGNvbHVtbiBkZWZpbml0aW9ucyB3aXRoIG5ldyBpbmNvbWluZyBkYXRhIGZpZWxkc1xuICAgICAqXG4gICAgICogQHBhcmFtIGN1cnJlbnREYXRhZmllbGRzXG4gICAgICogQHBhcmFtIGNvbHVtbnNcbiAgICAgKi9cbiAgICBwcml2YXRlIG1lcmdlQ29sdW1ucyhcbiAgICAgICAgY3VycmVudERhdGFmaWVsZHM6IElEYXRhRmllbGRbXSxcbiAgICAgICAgY29sdW1uczogSVRhYmxlV2lkZ2V0Q29sdW1uQ29uZmlnW11cbiAgICApOiBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXSB7XG4gICAgICAgIGNvbnN0IGN1cnJlbnREYXRhZmllbGRJZHMgPSBjdXJyZW50RGF0YWZpZWxkcy5tYXAoXG4gICAgICAgICAgICAoZGF0YWZpZWxkKSA9PiBkYXRhZmllbGQuaWRcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuIGNvbHVtbnMuZmlsdGVyKChjb2x1bW4pID0+IHtcbiAgICAgICAgICAgIGlmICghY29sdW1uLmZvcm1hdHRlcj8ucHJvcGVydGllcz8uZGF0YUZpZWxkSWRzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHZhbHVlcyhjb2x1bW4uZm9ybWF0dGVyPy5wcm9wZXJ0aWVzPy5kYXRhRmllbGRJZHMpLnNvbWUoXG4gICAgICAgICAgICAgICAgKGRhdGFmaWVsZDogc3RyaW5nKSA9PiBjdXJyZW50RGF0YWZpZWxkSWRzLmluY2x1ZGVzKGRhdGFmaWVsZClcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vbkRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5vbkRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gICAgfVxufVxuIiwiPG51aS1pdGVtcy1keW5hbWljXG4gICAgW2l0ZW1zXT1cImNvbHVtbnNcIlxuICAgIFtub2Rlc109XCJub2Rlc1wiXG4gICAgaGVhZGVyUHJlZml4PVwiQ29sdW1uXCJcbiAgICBpMThuLWhlYWRlclByZWZpeFxuICAgIChpdGVtc0NoYW5nZSk9XCJvbkl0ZW1zQ2hhbmdlKCRldmVudClcIlxuICAgIChmb3JtUmVhZHkpPVwib25Gb3JtUmVhZHkoJGV2ZW50KVwiXG4+PC9udWktaXRlbXMtZHluYW1pYz5cblxuPGRpdiBjbGFzcz1cInBsLTQgcHItNFwiICpuZ0lmPVwiKGVtcHR5Q29sdW1ucyQgfCBhc3luYykgJiYgZm9ybS50b3VjaGVkXCI+XG4gICAgPG51aS1tZXNzYWdlIHR5cGU9XCJjcml0aWNhbFwiIFthbGxvd0Rpc21pc3NdPVwiZmFsc2VcIiBpMThuPlxuICAgICAgICA8Yj5BdCBsZWFzdCBvbmUgY29sdW1uIG11c3QgYmUgYWRkZWQuPC9iPlxuICAgIDwvbnVpLW1lc3NhZ2U+XG48L2Rpdj5cblxuPGJ1dHRvblxuICAgIG51aS1idXR0b25cbiAgICBpY29uPVwiYWRkXCJcbiAgICBkaXNwbGF5U3R5bGU9XCJhY3Rpb25cIlxuICAgIGlkPVwidGFibGUtd2lkZ2V0LWFkZC1pbmRpY2F0b3ItYnRuXCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICBjbGFzcz1cIm1sLTQgbWItNFwiXG4gICAgKGNsaWNrKT1cImFkZENvbHVtbigpXCJcbiAgICBpMThuXG4+XG4gICAgQWRkIG5ldyBjb2x1bW5cbjwvYnV0dG9uPlxuXG48YnV0dG9uXG4gICAgbnVpLWJ1dHRvblxuICAgIGljb249XCJyZXNldFwiXG4gICAgZGlzcGxheVN0eWxlPVwiYWN0aW9uXCJcbiAgICBpZD1cInRhYmxlLXdpZGdldC1yZXNldC1pbmRpY2F0b3ItYnRuXCJcbiAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICBjbGFzcz1cIm1sLTQgbWItNFwiXG4gICAgKGNsaWNrKT1cIm9uUmVzZXRDb2x1bW5zKClcIlxuICAgIGkxOG5cbj5cbiAgICBSZXNldCBjb2x1bW5zXG48L2J1dHRvbj5cbiJdfQ==