@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
250 lines • 58.1 kB
JavaScript
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, EventEmitter, Inject, Input, Output, ViewEncapsulation, } from "@angular/core";
import { FormBuilder, FormControl, } from "@angular/forms";
import isUndefined from "lodash/isUndefined";
import values from "lodash/values";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { DialogService, EventBus, uuid, } from "@nova-ui/bits";
import { PizzagnaService } from "../../../../../pizzagna/services/pizzagna.service";
import { TableFormatterRegistryService } from "../../../../../services/table-formatter-registry.service";
import { PIZZAGNA_EVENT_BUS, WellKnownDataSourceFeatures, } from "../../../../../types";
import { ConfiguratorDataSourceManagerService } from "../../../../services/configurator-data-source-manager.service";
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 "../../../../services/configurator-data-source-manager.service";
import * as i5 from "../../../../../services/table-formatter-registry.service";
import * as i6 from "@angular/common";
import * as i7 from "@angular/cdk/drag-drop";
import * as i8 from "./column-configuration/table-column-configuration/table-column-configuration.component";
import * as i9 from "../../../widget-configurator-section/widget-configurator-section.component";
import * as i10 from "../../../drop-area/drop-area.component";
import * as i11 from "../../../../pipe/widget-configurator-section-header.pipe";
export class TableColumnsConfigurationV2Component {
static { this.lateLoadKey = "TableColumnsConfigurationV2Component"; }
get columnForms() {
return this.form.controls["columns"]
.controls;
}
constructor(formBuilder, changeDetector, dialogService, pizzagnaService, dataSourceManager, tableFormatterRegistry, eventBus) {
this.formBuilder = formBuilder;
this.changeDetector = changeDetector;
this.dialogService = dialogService;
this.pizzagnaService = pizzagnaService;
this.dataSourceManager = dataSourceManager;
this.tableFormatterRegistry = tableFormatterRegistry;
this.eventBus = eventBus;
this.columns = [];
this.formReady = new EventEmitter();
// this can't be "dataFields" because that's an already used name for a property in pizzagna
this.dataSourceFields = [];
this.isWidthMessageDisplayed = false;
this.columnLabel = $localize `Column`;
this.onDestroy$ = new Subject();
this.form = this.formBuilder.group({
columns: this.formBuilder.array([]),
});
this.form.controls["columns"].valueChanges
.pipe(takeUntil(this.onDestroy$))
.subscribe((columns) => {
this.isWidthMessageDisplayed =
this.getWidthMessageDisplayed(columns);
this.changeDetector.markForCheck();
});
this.eventBus.subscribeUntil(DATA_SOURCE_CREATED, this.onDestroy$, (event) => {
if (!event.payload) {
return;
}
this.dataSource = event.payload;
this.changeDetector.markForCheck();
});
this.eventBus.subscribeUntil(DATA_SOURCE_OUTPUT, this.onDestroy$, (event) => {
if (event.payload?.error) {
return;
}
const { dataFields } = isUndefined(event.payload.result)
? event.payload
: event.payload.result || {};
this.dataSourceFields = dataFields ?? [];
const disableColumnGeneration = this.dataSource?.features?.getFeatureConfig(WellKnownDataSourceFeatures.DisableTableColumnGeneration)?.enabled;
const columns = this.mergeColumns(this.dataSourceFields, this.getColumns());
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.updateColumns(columns);
}
else {
if (!disableColumnGeneration) {
this.resetColumns(false);
}
}
this.changeDetector.markForCheck();
});
dataSourceManager.error$
.pipe(takeUntil(this.onDestroy$))
.subscribe((err) => {
this.dataSourceError = err;
this.changeDetector.markForCheck();
});
}
ngOnInit() {
this.formReady.emit(this.form);
if (this.template && !this.tableFormatterRegistry.getItems()?.length) {
const formatters = this.template?.[1].properties?.formatters;
this.tableFormatterRegistry.addItems(formatters);
}
}
ngOnChanges(changes) {
// columns from input property are set directly to the form
if (changes.columns) {
this.updateColumns(this.columns, false);
}
}
ngOnDestroy() {
this.onDestroy$.next();
this.onDestroy$.complete();
}
getColumns() {
return this.form.controls["columns"].value;
}
updateColumns(columns, emitEvent = true) {
const cols = this.form.controls["columns"];
cols.controls = columns.map((c) => {
const fc = new FormControl(c);
fc.setParent(cols);
// Nova's markAsTouched function gets attached to formControl during init of TableColumnConfigurationComponent,
// must be pass to newly created formControl here otherwise gets lost and column validation doesn't get triggered.
const colControl = cols.controls.find((cControl) => cControl.value.id === c.id);
if (colControl) {
fc.markAsTouched = colControl.markAsTouched;
}
return fc;
});
cols.updateValueAndValidity({ emitEvent });
this.changeDetector.markForCheck();
}
trackBy(index, item) {
return item?.value?.id;
}
addColumn() {
this.form.controls["columns"].push(new FormControl({
id: uuid("column"),
label: "",
isActive: true,
formatter: {},
}));
}
onResetColumns() {
this.resetColumns(!!this.getColumns()?.length);
}
resetColumns(confirmation) {
const reset = () => {
const columns = this.dataSourceFields?.map((df) => ({
id: uuid("column"),
formatter: {
componentType: "RawFormatterComponent",
properties: {
dataFieldIds: {
value: df.id,
},
},
},
isActive: true,
label: df.label,
width: undefined,
sortable: df.sortable,
}));
this.updateColumns(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));
});
}
/**
* This method calculates whether the width message should be displayed
*
* @param columns
* @private
*/
getWidthMessageDisplayed(columns) {
let count = 0;
for (const c of columns) {
if (typeof c.width !== "number") {
count++;
}
if (count > 1) {
return false;
}
}
return true;
}
// ------------------------------------------------- items dynamic stuff ------------------------------------------------
moveItem(index, toIndex) {
const columns = this.form.controls["columns"];
const column = columns.at(index);
columns.removeAt(index);
columns.insert(toIndex, column);
this.changeDetector.detectChanges();
}
removeItem(index) {
const columns = this.form.controls["columns"];
columns.removeAt(index);
this.changeDetector.detectChanges();
}
drop(event) {
this.moveItem(event.previousIndex, event.currentIndex);
}
cdkDragStarted(event) {
this.draggedItemHeight =
event.source.element.nativeElement.offsetHeight;
}
/** @nocollapse */ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableColumnsConfigurationV2Component, deps: [{ token: i1.FormBuilder }, { token: i0.ChangeDetectorRef }, { token: i2.DialogService }, { token: i3.PizzagnaService }, { token: i4.ConfiguratorDataSourceManagerService }, { token: i5.TableFormatterRegistryService }, { token: PIZZAGNA_EVENT_BUS }], target: i0.ɵɵFactoryTarget.Component }); }
/** @nocollapse */ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: TableColumnsConfigurationV2Component, selector: "nui-table-columns-configuration", inputs: { columns: "columns", componentId: "componentId", template: "template" }, outputs: { formReady: "formReady" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"nui-table-columns-configuration\">\n <div\n *ngIf=\"!dataSourceError && dataSourceFields.length\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [formGroup]=\"form\"\n >\n <div formArrayName=\"columns\">\n <div\n cdkDrag\n (cdkDragStarted)=\"cdkDragStarted($event)\"\n class=\"nui-table-columns-configuration__node-item\"\n *ngFor=\"\n let columnForm of columnForms;\n index as i;\n trackBy: trackBy\n \"\n >\n <nui-drop-area\n class=\"nui-table-columns-configuration__drop-area\"\n *cdkDragPlaceholder\n [style.height.px]=\"draggedItemHeight\"\n ></nui-drop-area>\n\n <ng-template #headerText>\n <ng-container>\n <div\n class=\"nui-table-columns-configuration__drag-handler\"\n cdkDragHandle\n >\n <nui-icon icon=\"drag\"></nui-icon>\n </div>\n </ng-container>\n <span\n class=\"nui-table-columns-configuration__header-text\"\n [title]=\"\n columnForm?.value.label\n | nuiWidgetConfiguratorSectionHeader\n : i\n : columnLabel\n \"\n >\n {{\n columnForm?.value.label\n | nuiWidgetConfiguratorSectionHeader\n : i\n : columnLabel\n }}\n </span>\n </ng-template>\n\n <ng-template #headerButtons>\n <div class=\"d-flex\">\n <button\n id=\"table-widget-remove-column-btn-{{ i }}\"\n nui-button\n type=\"button\"\n icon=\"delete\"\n displayStyle=\"action\"\n (click)=\"removeItem(i)\"\n ></button>\n </div>\n </ng-template>\n\n <nui-widget-configurator-section\n class=\"no-margin\"\n [headerTextTemplate]=\"headerText\"\n [headerButtonsTemplate]=\"headerButtons\"\n >\n <nui-table-column-configuration\n [formControl]=\"columnForm\"\n [isWidthMessageDisplayed]=\"isWidthMessageDisplayed\"\n ></nui-table-column-configuration>\n </nui-widget-configurator-section>\n </div>\n\n <div\n class=\"pl-4 pr-4\"\n *ngIf=\"(emptyColumns$ | async) && form.touched\"\n >\n <nui-message type=\"critical\" [allowDismiss]=\"false\">\n <b i18n>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 </div>\n </div>\n</div>\n", styles: [".nui-table-columns-configuration__header-text{white-space:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis}.nui-table-columns-configuration__drag-handler{cursor:move;display:flex}.nui-table-columns-configuration__node-item{background-color:var(--nui-color-bg-light,#fff);margin:15px}.nui-table-columns-configuration__node-item .widget-configurator-section{margin:0}.nui-table-columns-configuration__drop-area{margin:15px}.cdk-drag-preview{z-index:2000!important;opacity:.9;box-shadow:0 0 5px 0 var(--nui-shadow-color, rgba(17, 17, 17, .3))}\n"], dependencies: [{ kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: i7.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { kind: "directive", type: i7.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: i7.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "directive", type: i7.CdkDragPlaceholder, selector: "ng-template[cdkDragPlaceholder]", inputs: ["data"] }, { kind: "component", type: i2.IconComponent, selector: "nui-icon", inputs: ["iconColor", "brushType", "iconHoverColor", "iconSize", "cssClass", "fillContainer", "status", "childStatus", "icon", "counter"] }, { 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: i8.TableColumnConfigurationComponent, selector: "nui-table-column-configuration", inputs: ["formControl", "isWidthMessageDisplayed"] }, { kind: "component", type: i9.WidgetConfiguratorSectionComponent, selector: "nui-widget-configurator-section", inputs: ["headerTextTemplate", "headerButtonsTemplate", "nodes", "headerText"], outputs: ["formReady", "formDestroy"] }, { kind: "component", type: i10.DropAreaComponent, selector: "nui-drop-area" }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i11.WidgetConfiguratorSectionHeaderPipe, name: "nuiWidgetConfiguratorSectionHeader" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TableColumnsConfigurationV2Component, decorators: [{
type: Component,
args: [{ selector: "nui-table-columns-configuration", changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<div class=\"nui-table-columns-configuration\">\n <div\n *ngIf=\"!dataSourceError && dataSourceFields.length\"\n cdkDropList\n (cdkDropListDropped)=\"drop($event)\"\n [formGroup]=\"form\"\n >\n <div formArrayName=\"columns\">\n <div\n cdkDrag\n (cdkDragStarted)=\"cdkDragStarted($event)\"\n class=\"nui-table-columns-configuration__node-item\"\n *ngFor=\"\n let columnForm of columnForms;\n index as i;\n trackBy: trackBy\n \"\n >\n <nui-drop-area\n class=\"nui-table-columns-configuration__drop-area\"\n *cdkDragPlaceholder\n [style.height.px]=\"draggedItemHeight\"\n ></nui-drop-area>\n\n <ng-template #headerText>\n <ng-container>\n <div\n class=\"nui-table-columns-configuration__drag-handler\"\n cdkDragHandle\n >\n <nui-icon icon=\"drag\"></nui-icon>\n </div>\n </ng-container>\n <span\n class=\"nui-table-columns-configuration__header-text\"\n [title]=\"\n columnForm?.value.label\n | nuiWidgetConfiguratorSectionHeader\n : i\n : columnLabel\n \"\n >\n {{\n columnForm?.value.label\n | nuiWidgetConfiguratorSectionHeader\n : i\n : columnLabel\n }}\n </span>\n </ng-template>\n\n <ng-template #headerButtons>\n <div class=\"d-flex\">\n <button\n id=\"table-widget-remove-column-btn-{{ i }}\"\n nui-button\n type=\"button\"\n icon=\"delete\"\n displayStyle=\"action\"\n (click)=\"removeItem(i)\"\n ></button>\n </div>\n </ng-template>\n\n <nui-widget-configurator-section\n class=\"no-margin\"\n [headerTextTemplate]=\"headerText\"\n [headerButtonsTemplate]=\"headerButtons\"\n >\n <nui-table-column-configuration\n [formControl]=\"columnForm\"\n [isWidthMessageDisplayed]=\"isWidthMessageDisplayed\"\n ></nui-table-column-configuration>\n </nui-widget-configurator-section>\n </div>\n\n <div\n class=\"pl-4 pr-4\"\n *ngIf=\"(emptyColumns$ | async) && form.touched\"\n >\n <nui-message type=\"critical\" [allowDismiss]=\"false\">\n <b i18n>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 </div>\n </div>\n</div>\n", styles: [".nui-table-columns-configuration__header-text{white-space:nowrap;overflow:hidden;-ms-text-overflow:ellipsis;-o-text-overflow:ellipsis;text-overflow:ellipsis}.nui-table-columns-configuration__drag-handler{cursor:move;display:flex}.nui-table-columns-configuration__node-item{background-color:var(--nui-color-bg-light,#fff);margin:15px}.nui-table-columns-configuration__node-item .widget-configurator-section{margin:0}.nui-table-columns-configuration__drop-area{margin:15px}.cdk-drag-preview{z-index:2000!important;opacity:.9;box-shadow:0 0 5px 0 var(--nui-shadow-color, rgba(17, 17, 17, .3))}\n"] }]
}], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i0.ChangeDetectorRef }, { type: i2.DialogService }, { type: i3.PizzagnaService }, { type: i4.ConfiguratorDataSourceManagerService }, { type: i5.TableFormatterRegistryService }, { type: i2.EventBus, decorators: [{
type: Inject,
args: [PIZZAGNA_EVENT_BUS]
}] }], propDecorators: { columns: [{
type: Input
}], componentId: [{
type: Input
}], template: [{
type: Input
}], formReady: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtY29sdW1ucy1jb25maWd1cmF0aW9uLXYyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uLy4uL3NyYy9saWIvY29uZmlndXJhdG9yL2NvbXBvbmVudHMvd2lkZ2V0cy90YWJsZS9jb2x1bW5zLWVkaXRvci12Mi90YWJsZS1jb2x1bW5zLWNvbmZpZ3VyYXRpb24tdjIuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9jb25maWd1cmF0b3IvY29tcG9uZW50cy93aWRnZXRzL3RhYmxlL2NvbHVtbnMtZWRpdG9yLXYyL3RhYmxlLWNvbHVtbnMtY29uZmlndXJhdGlvbi12Mi5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFxQkEsT0FBTyxFQUNILHVCQUF1QixFQUN2QixpQkFBaUIsRUFDakIsU0FBUyxFQUNULFlBQVksRUFDWixNQUFNLEVBQ04sS0FBSyxFQUlMLE1BQU0sRUFFTixpQkFBaUIsR0FDcEIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUdILFdBQVcsRUFDWCxXQUFXLEdBRWQsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLFdBQVcsTUFBTSxvQkFBb0IsQ0FBQztBQUM3QyxPQUFPLE1BQU0sTUFBTSxlQUFlLENBQUM7QUFDbkMsT0FBTyxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMzQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUNILGFBQWEsRUFDYixRQUFRLEVBSVIsSUFBSSxHQUNQLE1BQU0sZUFBZSxDQUFDO0FBT3ZCLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUNwRixPQUFPLEVBQUUsNkJBQTZCLEVBQUUsTUFBTSwwREFBMEQsQ0FBQztBQUN6RyxPQUFPLEVBRUgsa0JBQWtCLEVBQ2xCLDJCQUEyQixHQUM5QixN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Q0FBQyxDQUFDO0lBQzNELENBQUM7SUFFTSxjQUFjLENBQUMsS0FBbUI7UUFDckMsSUFBSSxDQUFDLGlCQUFpQjtZQUNsQixLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDO0lBQ3hELENBQUM7a0lBblNRLG9DQUFvQywyT0EyQ2pDLGtCQUFrQjtzSEEzQ3JCLG9DQUFvQyxtTkM5RWpELHNvSUFpSEE7OzRGRG5DYSxvQ0FBb0M7a0JBUGhELFNBQVM7K0JBQ0ksaUNBQWlDLG1CQUcxQix1QkFBdUIsQ0FBQyxNQUFNLGlCQUNoQyxpQkFBaUIsQ0FBQyxJQUFJOzswQkE2Q2hDLE1BQU07MkJBQUMsa0JBQWtCO3lDQXRDckIsT0FBTztzQkFBZixLQUFLO2dCQUNHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBT0csUUFBUTtzQkFBaEIsS0FBSztnQkFFSSxTQUFTO3NCQUFsQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IENka0RyYWdEcm9wLCBDZGtEcmFnU3RhcnQgfSBmcm9tIFwiQGFuZ3VsYXIvY2RrL2RyYWctZHJvcFwiO1xuaW1wb3J0IHtcbiAgICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBDb21wb25lbnQsXG4gICAgRXZlbnRFbWl0dGVyLFxuICAgIEluamVjdCxcbiAgICBJbnB1dCxcbiAgICBPbkNoYW5nZXMsXG4gICAgT25EZXN0cm95LFxuICAgIE9uSW5pdCxcbiAgICBPdXRwdXQsXG4gICAgU2ltcGxlQ2hhbmdlcyxcbiAgICBWaWV3RW5jYXBzdWxhdGlvbixcbn0gZnJvbSBcIkBhbmd1bGFyL2NvcmVcIjtcbmltcG9ydCB7XG4gICAgQWJzdHJhY3RDb250cm9sLFxuICAgIEZvcm1BcnJheSxcbiAgICBGb3JtQnVpbGRlcixcbiAgICBGb3JtQ29udHJvbCxcbiAgICBGb3JtR3JvdXAsXG59IGZyb20gXCJAYW5ndWxhci9mb3Jtc1wiO1xuaW1wb3J0IGlzVW5kZWZpbmVkIGZyb20gXCJsb2Rhc2gvaXNVbmRlZmluZWRcIjtcbmltcG9ydCB2YWx1ZXMgZnJvbSBcImxvZGFzaC92YWx1ZXNcIjtcbmltcG9ydCB7IE9ic2VydmFibGUsIFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbmltcG9ydCB7XG4gICAgRGlhbG9nU2VydmljZSxcbiAgICBFdmVudEJ1cyxcbiAgICBJRGF0YUZpZWxkLFxuICAgIElEYXRhU291cmNlLFxuICAgIElFdmVudCxcbiAgICB1dWlkLFxufSBmcm9tIFwiQG5vdmEtdWkvYml0c1wiO1xuXG5pbXBvcnQge1xuICAgIElEYXRhU291cmNlRXJyb3IsXG4gICAgSURhdGFTb3VyY2VPdXRwdXQsXG59IGZyb20gXCIuLi8uLi8uLi8uLi8uLi9jb21wb25lbnRzL3Byb3ZpZGVycy90eXBlc1wiO1xuaW1wb3J0IHsgSVRhYmxlV2lkZ2V0Q29sdW1uQ29uZmlnIH0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL2NvbXBvbmVudHMvdGFibGUtd2lkZ2V0L3R5cGVzXCI7XG5pbXBvcnQgeyBQaXp6YWduYVNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vcGl6emFnbmEvc2VydmljZXMvcGl6emFnbmEuc2VydmljZVwiO1xuaW1wb3J0IHsgVGFibGVGb3JtYXR0ZXJSZWdpc3RyeVNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vLi4vc2VydmljZXMvdGFibGUtZm9ybWF0dGVyLXJlZ2lzdHJ5LnNlcnZpY2VcIjtcbmltcG9ydCB7XG4gICAgSUhhc0Zvcm0sXG4gICAgUElaWkFHTkFfRVZFTlRfQlVTLFxuICAgIFdlbGxLbm93bkRhdGFTb3VyY2VGZWF0dXJlcyxcbn0gZnJvbSBcIi4uLy4uLy4uLy4uLy4uL3R5cGVzXCI7XG5pbXBvcnQgeyBDb25maWd1cmF0b3JEYXRhU291cmNlTWFuYWdlclNlcnZpY2UgfSBmcm9tIFwiLi4vLi4vLi4vLi4vc2VydmljZXMvY29uZmlndXJhdG9yLWRhdGEtc291cmNlLW1hbmFnZXIuc2VydmljZVwiO1xuaW1wb3J0IHsgREFUQV9TT1VSQ0VfQ1JFQVRFRCwgREFUQV9TT1VSQ0VfT1VUUFVUIH0gZnJvbSBcIi4uLy4uLy4uLy4uL3R5cGVzXCI7XG5cbkBDb21wb25lbnQoe1xuICAgIHNlbGVjdG9yOiBcIm51aS10YWJsZS1jb2x1bW5zLWNvbmZpZ3VyYXRpb25cIixcbiAgICB0ZW1wbGF0ZVVybDogXCIuL3RhYmxlLWNvbHVtbnMtY29uZmlndXJhdGlvbi12Mi5jb21wb25lbnQuaHRtbFwiLFxuICAgIHN0eWxlVXJsczogW1wiLi90YWJsZS1jb2x1bW5zLWNvbmZpZ3VyYXRpb24tdjIuY29tcG9uZW50Lmxlc3NcIl0sXG4gICAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG4gICAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbn0pXG5leHBvcnQgY2xhc3MgVGFibGVDb2x1bW5zQ29uZmlndXJhdGlvblYyQ29tcG9uZW50XG4gICAgaW1wbGVtZW50cyBPbkluaXQsIElIYXNGb3JtLCBPbkNoYW5nZXMsIE9uRGVzdHJveVxue1xuICAgIHN0YXRpYyBsYXRlTG9hZEtleSA9IFwiVGFibGVDb2x1bW5zQ29uZmlndXJhdGlvblYyQ29tcG9uZW50XCI7XG5cbiAgICBASW5wdXQoKSBjb2x1bW5zOiBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXSA9IFtdO1xuICAgIEBJbnB1dCgpIGNvbXBvbmVudElkOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBAZGVwcmVjYXRlZCBiYWNrd2FyZCBjb21wYXRpYmlsaXR5IG1lYXN1cmUgLSBkZXByZWNhdGVkIGluIHYxMS4gUmVtb3ZhbDogTlVJLTU4OThcbiAgICAgKlxuICAgICAqIFRoaXMgcHJvcGVydHkgaXMgaGVyZSBiZWNhdXNlIGl0IHdhcyBwcmVzZW50IGluIFYxIGNvbXBvbmVudCBhbmQgd2FzIHVzZWQgdG8gY29uZmlndXJlIGZvcm1hdHRlcnNcbiAgICAgKi9cbiAgICBASW5wdXQoKSB0ZW1wbGF0ZTogYW55O1xuXG4gICAgQE91dHB1dCgpIGZvcm1SZWFkeSA9IG5ldyBFdmVudEVtaXR0ZXI8Rm9ybUdyb3VwPigpO1xuXG4gICAgcHVibGljIGZvcm06IEZvcm1Hcm91cDtcbiAgICBwdWJsaWMgZW1wdHlDb2x1bW5zJDogT2JzZXJ2YWJsZTxib29sZWFuPjtcbiAgICAvLyB0aGlzIGNhbid0IGJlIFwiZGF0YUZpZWxkc1wiIGJlY2F1c2UgdGhhdCdzIGFuIGFscmVhZHkgdXNlZCBuYW1lIGZvciBhIHByb3BlcnR5IGluIHBpenphZ25hXG4gICAgcHVibGljIGRhdGFTb3VyY2VGaWVsZHM6IEFycmF5PElEYXRhRmllbGQ+ID0gW107XG4gICAgcHVibGljIGRyYWdnZWRJdGVtSGVpZ2h0OiBudW1iZXI7XG4gICAgcHVibGljIGlzV2lkdGhNZXNzYWdlRGlzcGxheWVkID0gZmFsc2U7XG4gICAgcHVibGljIGRhdGFTb3VyY2VFcnJvcjogSURhdGFTb3VyY2VFcnJvciB8IG51bGw7XG5cbiAgICBwdWJsaWMgZ2V0IGNvbHVtbkZvcm1zKCk6IEZvcm1Db250cm9sW10ge1xuICAgICAgICByZXR1cm4gKHRoaXMuZm9ybS5jb250cm9sc1tcImNvbHVtbnNcIl0gYXMgRm9ybUFycmF5KVxuICAgICAgICAgICAgLmNvbnRyb2xzIGFzIEZvcm1Db250cm9sW107XG4gICAgfVxuXG4gICAgLy8gdGhlIGxhc3Qgc2VsZWN0ZWQgZGF0YSBzb3VyY2Ugd2lsbCBiZSBzdG9yZWQgaGVyZVxuICAgIHB1YmxpYyBkYXRhU291cmNlOiBJRGF0YVNvdXJjZTtcbiAgICBwdWJsaWMgY29sdW1uTGFiZWwgPSAkbG9jYWxpemVgQ29sdW1uYDtcblxuICAgIHByaXZhdGUgb25EZXN0cm95JDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIsXG4gICAgICAgIHByaXZhdGUgY2hhbmdlRGV0ZWN0b3I6IENoYW5nZURldGVjdG9yUmVmLFxuICAgICAgICBwcml2YXRlIGRpYWxvZ1NlcnZpY2U6IERpYWxvZ1NlcnZpY2UsXG4gICAgICAgIHByaXZhdGUgcGl6emFnbmFTZXJ2aWNlOiBQaXp6YWduYVNlcnZpY2UsXG4gICAgICAgIHB1YmxpYyBkYXRhU291cmNlTWFuYWdlcjogQ29uZmlndXJhdG9yRGF0YVNvdXJjZU1hbmFnZXJTZXJ2aWNlLFxuICAgICAgICBwdWJsaWMgdGFibGVGb3JtYXR0ZXJSZWdpc3RyeTogVGFibGVGb3JtYXR0ZXJSZWdpc3RyeVNlcnZpY2UsXG4gICAgICAgIEBJbmplY3QoUElaWkFHTkFfRVZFTlRfQlVTKSBwcml2YXRlIGV2ZW50QnVzOiBFdmVudEJ1czxJRXZlbnQ+XG4gICAgKSB7XG4gICAgICAgIHRoaXMuZm9ybSA9IHRoaXMuZm9ybUJ1aWxkZXIuZ3JvdXAoe1xuICAgICAgICAgICAgY29sdW1uczogdGhpcy5mb3JtQnVpbGRlci5hcnJheShbXSksXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuZm9ybS5jb250cm9sc1tcImNvbHVtbnNcIl0udmFsdWVDaGFuZ2VzXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5vbkRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGNvbHVtbnM6IElUYWJsZVdpZGdldENvbHVtbkNvbmZpZ1tdKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc1dpZHRoTWVzc2FnZURpc3BsYXllZCA9XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0V2lkdGhNZXNzYWdlRGlzcGxheWVkKGNvbHVtbnMpO1xuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3IubWFya0ZvckNoZWNrKCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmV2ZW50QnVzLnN1YnNjcmliZVVudGlsKFxuICAgICAgICAgICAgREFUQV9TT1VSQ0VfQ1JFQVRFRCxcbiAgICAgICAgICAgIHRoaXMub25EZXN0cm95JCxcbiAgICAgICAgICAgIChldmVudDogSUV2ZW50PElEYXRhU291cmNlPikgPT4ge1xuICAgICAgICAgICAgICAgIGlmICghZXZlbnQucGF5bG9hZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlID0gZXZlbnQucGF5bG9hZDtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yLm1hcmtGb3JDaGVjaygpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMuZXZlbnRCdXMuc3Vic2NyaWJlVW50aWwoXG4gICAgICAgICAgICBEQVRBX1NPVVJDRV9PVVRQVVQsXG4gICAgICAgICAgICB0aGlzLm9uRGVzdHJveSQsXG4gICAgICAgICAgICAoZXZlbnQ6IElFdmVudDxhbnkgfCBJRGF0YVNvdXJjZU91dHB1dDxhbnk+PikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChldmVudC5wYXlsb2FkPy5lcnJvcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHsgZGF0YUZpZWxkcyB9ID0gaXNVbmRlZmluZWQoZXZlbnQucGF5bG9hZC5yZXN1bHQpXG4gICAgICAgICAgICAgICAgICAgID8gZXZlbnQucGF5bG9hZFxuICAgICAgICAgICAgICAgICAgICA6IGV2ZW50LnBheWxvYWQucmVzdWx0IHx8IHt9O1xuICAgICAgICAgICAgICAgIHRoaXMuZGF0YVNvdXJjZUZpZWxkcyA9IGRhdGFGaWVsZHMgPz8gW107XG4gICAgICAgICAgICAgICAgY29uc3QgZGlzYWJsZUNvbHVtbkdlbmVyYXRpb24gPVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmRhdGFTb3VyY2U/LmZlYXR1cmVzPy5nZXRGZWF0dXJlQ29uZmlnKFxuICAgICAgICAgICAgICAgICAgICAgICAgV2VsbEtub3duRGF0YVNvdXJjZUZlYXR1cmVzLkRpc2FibGVUYWJsZUNvbHVtbkdlbmVyYXRpb25cbiAgICAgICAgICAgICAgICAgICAgKT8uZW5hYmxlZDtcblxuICAgICAgICAgICAgICAgIGNvbnN0IGNvbHVtbnMgPSB0aGlzLm1lcmdlQ29sdW1ucyhcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlRmllbGRzLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmdldENvbHVtbnMoKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgaWYgKGNvbHVtbnM/Lmxlbmd0aCB8fCBkaXNhYmxlQ29sdW1uR2VuZXJhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAvLyBpZiBkaXNhYmxlQ29sdW1uR2VuZXJhdGlvbiBpcyBlbmFibGVkIGFuZCB0aGVyZSBhcmUgbm8gY29sdW1ucyB0byBiZSBrZXB0LFxuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBoYXZlIHRvIGNsZWFyIHRoZSBmb3JtIGJ5IHVwZGF0aW5nIHRoZSBjb2x1bW4gaW5wdXQgdmlhIHRoZSBgb25JdGVtc0NoYW5nZWAgbWV0aG9kXG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQ29sdW1ucyhjb2x1bW5zKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWRpc2FibGVDb2x1bW5HZW5lcmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlc2V0Q29sdW1ucyhmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3Rvci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgZGF0YVNvdXJjZU1hbmFnZXIuZXJyb3IkXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5vbkRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGVycjogSURhdGFTb3VyY2VFcnJvciB8IG51bGwpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGFTb3VyY2VFcnJvciA9IGVycjtcbiAgICAgICAgICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yLm1hcmtGb3JDaGVjaygpO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIG5nT25Jbml0KCk6IHZvaWQge1xuICAgICAgICB0aGlzLmZvcm1SZWFkeS5lbWl0KHRoaXMuZm9ybSk7XG5cbiAgICAgICAgaWYgKHRoaXMudGVtcGxhdGUgJiYgIXRoaXMudGFibGVGb3JtYXR0ZXJSZWdpc3RyeS5nZXRJdGVtcygpPy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IGZvcm1hdHRlcnMgPSB0aGlzLnRlbXBsYXRlPy5bMV0ucHJvcGVydGllcz8uZm9ybWF0dGVycztcbiAgICAgICAgICAgIHRoaXMudGFibGVGb3JtYXR0ZXJSZWdpc3RyeS5hZGRJdGVtcyhmb3JtYXR0ZXJzKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgICAgIC8vIGNvbHVtbnMgZnJvbSBpbnB1dCBwcm9wZXJ0eSBhcmUgc2V0IGRpcmVjdGx5IHRvIHRoZSBmb3JtXG4gICAgICAgIGlmIChjaGFuZ2VzLmNvbHVtbnMpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlQ29sdW1ucyh0aGlzLmNvbHVtbnMsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5vbkRlc3Ryb3kkLm5leHQoKTtcbiAgICAgICAgdGhpcy5vbkRlc3Ryb3kkLmNvbXBsZXRlKCk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldENvbHVtbnMoKTogYW55W10ge1xuICAgICAgICByZXR1cm4gdGhpcy5mb3JtLmNvbnRyb2xzW1wiY29sdW1uc1wiXS52YWx1ZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlQ29sdW1ucyhcbiAgICAgICAgY29sdW1uczogSVRhYmxlV2lkZ2V0Q29sdW1uQ29uZmlnW10sXG4gICAgICAgIGVtaXRFdmVudDogYm9vbGVhbiA9IHRydWVcbiAgICApOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY29scyA9IHRoaXMuZm9ybS5jb250cm9sc1tcImNvbHVtbnNcIl0gYXMgRm9ybUFycmF5O1xuICAgICAgICBjb2xzLmNvbnRyb2xzID0gY29sdW1ucy5tYXAoKGMpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZjID0gbmV3IEZvcm1Db250cm9sKGMpO1xuICAgICAgICAgICAgZmMuc2V0UGFyZW50KGNvbHMpO1xuXG4gICAgICAgICAgICAvLyBOb3ZhJ3MgbWFya0FzVG91Y2hlZCBmdW5jdGlvbiBnZXRzIGF0dGFjaGVkIHRvIGZvcm1Db250cm9sIGR1cmluZyBpbml0IG9mIFRhYmxlQ29sdW1uQ29uZmlndXJhdGlvbkNvbXBvbmVudCxcbiAgICAgICAgICAgIC8vIG11c3QgYmUgcGFzcyB0byBuZXdseSBjcmVhdGVkIGZvcm1Db250cm9sIGhlcmUgb3RoZXJ3aXNlIGdldHMgbG9zdCBhbmQgY29sdW1uIHZhbGlkYXRpb24gZG9lc24ndCBnZXQgdHJpZ2dlcmVkLlxuICAgICAgICAgICAgY29uc3QgY29sQ29udHJvbCA9IGNvbHMuY29udHJvbHMuZmluZChcbiAgICAgICAgICAgICAgICAoY0NvbnRyb2w6IEFic3RyYWN0Q29udHJvbCkgPT4gY0NvbnRyb2wudmFsdWUuaWQgPT09IGMuaWRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAoY29sQ29udHJvbCkge1xuICAgICAgICAgICAgICAgIGZjLm1hcmtBc1RvdWNoZWQgPSBjb2xDb250cm9sLm1hcmtBc1RvdWNoZWQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBmYztcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbHMudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSh7IGVtaXRFdmVudCB9KTtcblxuICAgICAgICB0aGlzLmNoYW5nZURldGVjdG9yLm1hcmtGb3JDaGVjaygpO1xuICAgIH1cblxuICAgIHB1YmxpYyB0cmFja0J5KGluZGV4OiBudW1iZXIsIGl0ZW06IEZvcm1Db250cm9sKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIGl0ZW0/LnZhbHVlPy5pZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYWRkQ29sdW1uKCk6IHZvaWQge1xuICAgICAgICAodGhpcy5mb3JtLmNvbnRyb2xzW1wiY29sdW1uc1wiXSBhcyBGb3JtQXJyYXkpLnB1c2goXG4gICAgICAgICAgICBuZXcgRm9ybUNvbnRyb2woe1xuICAgICAgICAgICAgICAgIGlkOiB1dWlkKFwiY29sdW1uXCIpLFxuICAgICAgICAgICAgICAgIGxhYmVsOiBcIlwiLFxuICAgICAgICAgICAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgIGZvcm1hdHRlcjoge30sXG4gICAgICAgICAgICB9IGFzIElUYWJsZVdpZGdldENvbHVtbkNvbmZpZylcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgb25SZXNldENvbHVtbnMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMucmVzZXRDb2x1bW5zKCEhdGhpcy5nZXRDb2x1bW5zKCk/Lmxlbmd0aCk7XG4gICAgfVxuXG4gICAgcHVibGljIHJlc2V0Q29sdW1ucyhjb25maXJtYXRpb246IGJvb2xlYW4pOiB2b2lkIHtcbiAgICAgICAgY29uc3QgcmVzZXQgPSAoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjb2x1bW5zOiBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXSA9XG4gICAgICAgICAgICAgICAgdGhpcy5kYXRhU291cmNlRmllbGRzPy5tYXAoKGRmKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICBpZDogdXVpZChcImNvbHVtblwiKSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybWF0dGVyOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb21wb25lbnRUeXBlOiBcIlJhd0Zvcm1hdHRlckNvbXBvbmVudFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFGaWVsZElkczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogZGYuaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBsYWJlbDogZGYubGFiZWwsXG4gICAgICAgICAgICAgICAgICAgIHdpZHRoOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgICAgIHNvcnRhYmxlOiBkZi5zb3J0YWJsZSxcbiAgICAgICAgICAgICAgICB9KSk7XG5cbiAgICAgICAgICAgIHRoaXMudXBkYXRlQ29sdW1ucyhjb2x1bW5zKTtcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoY29uZmlybWF0aW9uKSB7XG4gICAgICAgICAgICBjb25zdCBkaWFsb2cgPSB0aGlzLmRpYWxvZ1NlcnZpY2UuY29uZmlybSh7XG4gICAgICAgICAgICAgICAgdGl0bGU6ICRsb2NhbGl6ZWBBcmUgeW91IHN1cmU/YCxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiAkbG9jYWxpemVgUmVzZXR0aW5nIHRoZSBjb2x1bW5zIHdpbGwgcmV2ZXJ0IHRoZW0gdG8gdGhlaXIgZGVmYXVsdCBjb25maWd1cmF0aW9ucy4gRG8geW91IHdpc2ggdG8gcHJvY2VlZD9gLFxuICAgICAgICAgICAgICAgIGNvbmZpcm1UZXh0OiAkbG9jYWxpemVgUmVzZXQgQ29sdW1uc2AsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgZGlhbG9nLnJlc3VsdC50aGVuKFxuICAgICAgICAgICAgICAgIChyZXN1bHQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzZXQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIGJlaW5nIGhlcmUgcHJldmVudHMgYSBcInVuaGFuZGxlZCByZWplY3Rpb25cIiBjb25zb2xlIGVycm9yIGZyb20gc2hvd2luZyB1cFxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNldCgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogTWVyZ2VzIGN1cnJlbnQgY29sdW1uIGRlZmluaXRpb25zIHdpdGggbmV3IGluY29taW5nIGRhdGEgZmllbGRzXG4gICAgICpcbiAgICAgKiBAcGFyYW0gY3VycmVudERhdGFmaWVsZHNcbiAgICAgKiBAcGFyYW0gY29sdW1uc1xuICAgICAqL1xuICAgIHByaXZhdGUgbWVyZ2VDb2x1bW5zKFxuICAgICAgICBjdXJyZW50RGF0YWZpZWxkczogSURhdGFGaWVsZFtdLFxuICAgICAgICBjb2x1bW5zOiBJVGFibGVXaWRnZXRDb2x1bW5Db25maWdbXVxuICAgICk6IElUYWJsZVdpZGdldENvbHVtbkNvbmZpZ1tdIHtcbiAgICAgICAgY29uc3QgY3VycmVudERhdGFmaWVsZElkcyA9IGN1cnJlbnREYXRhZmllbGRzLm1hcChcbiAgICAgICAgICAgIChkYXRhZmllbGQ