@ngx-dynamic-components/tools
Version:
@ngx-dynamic-components/tools is Angular 7+ library what contains a core interfaces to build a configuration driven web pages.
188 lines • 35.3 kB
JavaScript
import { Component, Input, HostBinding, ViewChild, } from '@angular/core';
import { formatObjToJsonStr, getComponentById, CoreService, } from '@ngx-dynamic-components/core';
import { debounceTime, map } from 'rxjs/operators';
import { fromEvent } from 'rxjs';
import { edit } from 'ace-builds';
import { jsPython } from 'jspython-interpreter';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@ngx-dynamic-components/core";
import * as i3 from "@angular/material/button";
import * as i4 from "@angular/material/tabs";
import * as i5 from "@angular/material/card";
import * as i6 from "@angular/material/icon";
import * as i7 from "@angular/material/tooltip";
import * as i8 from "angular-split";
// eslint-disable-next-line no-shadow
var Layout;
(function (Layout) {
Layout["horizontal"] = "horizontal";
Layout["vertical"] = "vertical";
})(Layout || (Layout = {}));
export class PreviewEditorComponent {
scripts;
initUiModel;
initDataModel;
title;
uiModelEl;
uiModelJSONEl;
scriptsEl;
dataModelEl;
dynamicComponent;
flex = 'initial';
dataModel;
dataModelCopy;
uiModel;
uiModelEditor;
uiModelJSONEditor;
dataModelEditor;
scriptsEditor;
interpreter;
editorOptions = {
language: 'json',
automaticLayout: true,
};
direction = Layout.horizontal;
codeSize = 50;
async eventHandlers({ eventName, rootUIModel, parameters = null, sender, eventHandler }) {
if (!this.interpreter) {
return;
}
if (this.interpreter.hasFunction(this.scripts, eventHandler)) {
try {
if (parameters) {
parameters[parameters.argsKey] = parameters.argsValue;
}
const res = await this.interpreter.evaluate(this.scripts, {
rootUIModel,
dataModel: this.dataModel,
...parameters,
}, eventHandler);
sender?.setEventHandlerResult(eventName, res);
}
catch (e) {
alert(`${e.message}`);
}
}
}
ngOnInit() {
this.interpreter = jsPython();
this.interpreter.addFunction('getComponentById', (uiModel, id) => getComponentById(uiModel, id));
this.interpreter.addFunction('alert', (msg) => alert(msg));
this.interpreter.assignGlobalContext({});
this.uiModel = this.initUiModel;
this.dataModel = this.initDataModel;
}
ngAfterViewInit() {
this.onDataModelChange(this.dynamicComponent.dataModel);
this.initUIPreview();
}
toggleSourceCode() {
this.codeSize = !this.codeSize ? 50 : 0;
}
toggleLayout() {
this.direction =
this.direction === Layout.horizontal
? Layout.vertical
: Layout.horizontal;
}
get isHorizontal() {
return this.direction === Layout.horizontal;
}
onRendered(data) {
console.log('rendered', data);
}
onDataModelChange(data) {
if (data && this.dataModelEditor) {
this.dataModelEditor.setValue(formatObjToJsonStr(data));
}
else if (this.uiModelEditor) {
this.uiModelEditor.setValue(formatObjToJsonStr(this.uiModel));
}
}
resize() {
this.scriptsEditor.resize();
this.uiModelEditor.resize();
this.uiModelJSONEditor.resize();
this.dataModelEditor.resize();
}
initUIPreview() {
if (this.uiModelEl) {
this.uiModelJSONEditor = edit(this.uiModelJSONEl.nativeElement, {
mode: 'ace/mode/json',
autoScrollEditorIntoView: true,
tabSize: 2,
useSoftTabs: true,
readOnly: true,
});
this.setJSONEditor(this.initUiModel);
this.initEditor('uiModel', this.uiModelEl, this.initUiModel, 'ace/mode/xml').pipe(debounceTime(500)).subscribe((uiModel) => {
this.dynamicComponent.containerRef.clear();
this.setJSONEditor(uiModel);
this.refreshPreview(uiModel, this.dataModel);
});
this.initEditor('dataModel', this.dataModelEl, this.initDataModel).subscribe((dataModel) => this.refreshPreview(this.uiModel, dataModel ? JSON.parse(dataModel) : dataModel));
this.initEditor('scripts', this.scriptsEl, this.scripts, 'ace/mode/python').subscribe((sc) => (this.scripts = sc));
}
}
setJSONEditor(uiModel) {
const res = CoreService.parseXMLModel(uiModel);
this.uiModelJSONEditor.setValue(formatObjToJsonStr(res), -1);
this.uiModelJSONEditor.resize();
}
refreshPreview(uiModel, dataModel) {
this.uiModel = uiModel;
this.dataModelCopy = JSON.parse(JSON.stringify(dataModel));
}
// eslint-disable-next-line max-len
initEditor(name, element, value, mode = 'ace/mode/json') {
const editor = edit(element.nativeElement, {
mode,
autoScrollEditorIntoView: true,
value: formatObjToJsonStr(value),
tabSize: 2,
useSoftTabs: true,
indentedSoftWrap: true,
});
editor.setOptions({
enableBasicAutocompletion: true,
enableSnippets: false,
enableLiveAutocompletion: true,
});
this[`${name}Editor`] = editor;
return fromEvent(editor, 'change').pipe(map(() => editor.getValue()));
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PreviewEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.1.6", type: PreviewEditorComponent, selector: "dc-preview-editor", inputs: { scripts: "scripts", initUiModel: "initUiModel", initDataModel: "initDataModel", title: "title" }, host: { properties: { "style.flex": "this.flex" } }, viewQueries: [{ propertyName: "uiModelEl", first: true, predicate: ["uiModelEl"], descendants: true }, { propertyName: "uiModelJSONEl", first: true, predicate: ["uiModelJSONEl"], descendants: true }, { propertyName: "scriptsEl", first: true, predicate: ["scriptsEl"], descendants: true }, { propertyName: "dataModelEl", first: true, predicate: ["dataModelEl"], descendants: true }, { propertyName: "dynamicComponent", first: true, predicate: ["dynamicComponent"], descendants: true }], ngImport: i0, template: "<mat-card *ngIf=\"initUiModel\" class=\"h-100 preview-card d-flex flex-column\">\r\n <mat-card-header>\r\n <span class=\"flex-fill align-self-center\">{{title}}</span>\r\n <button mat-icon-button *ngIf=\"codeSize\" (click)=\"toggleLayout()\"\r\n [matTooltip]=\"(isHorizontal ? 'Vertical' : 'Horizontal') + ' layout'\">\r\n <mat-icon>{{isHorizontal ? 'vertical_split' : 'horizontal_split'}}</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Source code\" (click)=\"toggleSourceCode()\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </mat-card-header>\r\n <mat-card-content class=\"h-100\">\r\n <as-split [useTransition]=\"true\" [direction]=\"direction\" unit=\"percent\" [gutterSize]=\"codeSize ? 11 : 0\">\r\n <as-split-area #area0=\"asSplitArea\" class=\"d-flex\" [size]=\"codeSize\">\r\n <mat-tab-group class=\"w-100 ui-model-tab\">\r\n <mat-tab label=\"UI Model\">\r\n <mat-tab-group class=\"w-100 h-100\" headerPosition=\"below\">\r\n <mat-tab label=\"XML\">\r\n <div #uiModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"JSON\">\r\n <div #uiModelJSONEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </mat-tab>\r\n <mat-tab label=\"Scripts\">\r\n <div #scriptsEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"Data Model\">\r\n <div #dataModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </as-split-area>\r\n <as-split-area [size]=\"100 - codeSize\" #area1=\"asSplitArea\">\r\n <div class=\"preview\">\r\n <ngx-dynamic-component class=\"d-block\" *ngIf=\"uiModel\" #dynamicComponent\r\n [xmlUIModel]='uiModel'\r\n [dataModel]='dataModel'\r\n (render)='onRendered($event)'\r\n (changedDataModel)=\"onDataModelChange($event)\"\r\n (eventHandlers)=\"eventHandlers($event)\"></ngx-dynamic-component>\r\n </div>\r\n </as-split-area>\r\n </as-split>\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:flex}::ng-deep mat-card .mat-card-header-text{margin:0}::ng-deep mat-card .mat-mdc-tab-body-wrapper,::ng-deep mat-card .mat-tab-body-wrapper{display:block;overflow:visible;height:100%;min-height:200px}::ng-deep mat-card .mat-mdc-tab-body-wrapper mat-tab-body,::ng-deep mat-card .mat-tab-body-wrapper mat-tab-body{height:100%}.preview-card mat-card-content ::ng-deep .as-init .as-split-gutter,.preview-card mat-card-content .as-split-area{height:auto}.ui-model-tab ::ng-deep .mat-tab-label{height:24px;font-size:.85rem}mat-card{width:100%;padding:0}mat-card mat-card-header,mat-card mat-card-content{padding:1em}mat-card mat-divider{margin:1em 0;position:static}mat-card mat-card-header{color:#00000080;background:#eeeeee;padding:8px 20px}mat-card mat-card-header mat-icon{cursor:pointer}mat-card mat-card-header h3{margin:0}mat-card .preview{background:#eeeeee;padding:1em}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.NGXDynamicComponent, selector: "ngx-dynamic-component", inputs: ["dataModel", "xmlUIModel"], outputs: ["render", "changedDataModel", "eventHandlers"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatTab, selector: "mat-tab", inputs: ["disabled"], exportAs: ["matTab"] }, { kind: "component", type: i4.MatTabGroup, selector: "mat-tab-group", inputs: ["color", "disableRipple", "fitInkBarToContent", "mat-stretch-tabs"], exportAs: ["matTabGroup"] }, { kind: "component", type: i5.MatCard, selector: "mat-card", inputs: ["appearance"], exportAs: ["matCard"] }, { kind: "directive", type: i5.MatCardContent, selector: "mat-card-content" }, { kind: "component", type: i5.MatCardHeader, selector: "mat-card-header" }, { kind: "component", type: i6.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "component", type: i8.SplitComponent, selector: "as-split", inputs: ["direction", "unit", "gutterSize", "gutterStep", "restrictMove", "useTransition", "disabled", "dir", "gutterDblClickDuration", "gutterClickDeltaPx", "gutterAriaLabel"], outputs: ["transitionEnd", "dragStart", "dragEnd", "gutterClick", "gutterDblClick"], exportAs: ["asSplit"] }, { kind: "directive", type: i8.SplitAreaDirective, selector: "as-split-area, [as-split-area]", inputs: ["order", "size", "minSize", "maxSize", "lockSize", "visible"], exportAs: ["asSplitArea"] }] });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.6", ngImport: i0, type: PreviewEditorComponent, decorators: [{
type: Component,
args: [{ selector: 'dc-preview-editor', template: "<mat-card *ngIf=\"initUiModel\" class=\"h-100 preview-card d-flex flex-column\">\r\n <mat-card-header>\r\n <span class=\"flex-fill align-self-center\">{{title}}</span>\r\n <button mat-icon-button *ngIf=\"codeSize\" (click)=\"toggleLayout()\"\r\n [matTooltip]=\"(isHorizontal ? 'Vertical' : 'Horizontal') + ' layout'\">\r\n <mat-icon>{{isHorizontal ? 'vertical_split' : 'horizontal_split'}}</mat-icon>\r\n </button>\r\n <button mat-icon-button matTooltip=\"Source code\" (click)=\"toggleSourceCode()\">\r\n <mat-icon>code</mat-icon>\r\n </button>\r\n </mat-card-header>\r\n <mat-card-content class=\"h-100\">\r\n <as-split [useTransition]=\"true\" [direction]=\"direction\" unit=\"percent\" [gutterSize]=\"codeSize ? 11 : 0\">\r\n <as-split-area #area0=\"asSplitArea\" class=\"d-flex\" [size]=\"codeSize\">\r\n <mat-tab-group class=\"w-100 ui-model-tab\">\r\n <mat-tab label=\"UI Model\">\r\n <mat-tab-group class=\"w-100 h-100\" headerPosition=\"below\">\r\n <mat-tab label=\"XML\">\r\n <div #uiModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"JSON\">\r\n <div #uiModelJSONEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </mat-tab>\r\n <mat-tab label=\"Scripts\">\r\n <div #scriptsEl class=\"h-100\"></div>\r\n </mat-tab>\r\n <mat-tab label=\"Data Model\">\r\n <div #dataModelEl class=\"h-100\"></div>\r\n </mat-tab>\r\n </mat-tab-group>\r\n </as-split-area>\r\n <as-split-area [size]=\"100 - codeSize\" #area1=\"asSplitArea\">\r\n <div class=\"preview\">\r\n <ngx-dynamic-component class=\"d-block\" *ngIf=\"uiModel\" #dynamicComponent\r\n [xmlUIModel]='uiModel'\r\n [dataModel]='dataModel'\r\n (render)='onRendered($event)'\r\n (changedDataModel)=\"onDataModelChange($event)\"\r\n (eventHandlers)=\"eventHandlers($event)\"></ngx-dynamic-component>\r\n </div>\r\n </as-split-area>\r\n </as-split>\r\n </mat-card-content>\r\n</mat-card>\r\n", styles: [":host{display:flex}::ng-deep mat-card .mat-card-header-text{margin:0}::ng-deep mat-card .mat-mdc-tab-body-wrapper,::ng-deep mat-card .mat-tab-body-wrapper{display:block;overflow:visible;height:100%;min-height:200px}::ng-deep mat-card .mat-mdc-tab-body-wrapper mat-tab-body,::ng-deep mat-card .mat-tab-body-wrapper mat-tab-body{height:100%}.preview-card mat-card-content ::ng-deep .as-init .as-split-gutter,.preview-card mat-card-content .as-split-area{height:auto}.ui-model-tab ::ng-deep .mat-tab-label{height:24px;font-size:.85rem}mat-card{width:100%;padding:0}mat-card mat-card-header,mat-card mat-card-content{padding:1em}mat-card mat-divider{margin:1em 0;position:static}mat-card mat-card-header{color:#00000080;background:#eeeeee;padding:8px 20px}mat-card mat-card-header mat-icon{cursor:pointer}mat-card mat-card-header h3{margin:0}mat-card .preview{background:#eeeeee;padding:1em}\n"] }]
}], propDecorators: { scripts: [{
type: Input
}], initUiModel: [{
type: Input
}], initDataModel: [{
type: Input
}], title: [{
type: Input
}], uiModelEl: [{
type: ViewChild,
args: ['uiModelEl']
}], uiModelJSONEl: [{
type: ViewChild,
args: ['uiModelJSONEl']
}], scriptsEl: [{
type: ViewChild,
args: ['scriptsEl']
}], dataModelEl: [{
type: ViewChild,
args: ['dataModelEl']
}], dynamicComponent: [{
type: ViewChild,
args: ['dynamicComponent']
}], flex: [{
type: HostBinding,
args: ['style.flex']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJldmlldy1lZGl0b3IuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvdG9vbHMvc3JjL2xpYi9jb21wb25lbnRzL3ByZXZpZXctZWRpdG9yL3ByZXZpZXctZWRpdG9yLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL3Rvb2xzL3NyYy9saWIvY29tcG9uZW50cy9wcmV2aWV3LWVkaXRvci9wcmV2aWV3LWVkaXRvci5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQ0wsU0FBUyxFQUVULEtBQUssRUFDTCxXQUFXLEVBQ1gsU0FBUyxHQUVWLE1BQU0sZUFBZSxDQUFDO0FBRXZCLE9BQU8sRUFDTCxrQkFBa0IsRUFFbEIsZ0JBQWdCLEVBRWhCLFdBQVcsR0FDWixNQUFNLDhCQUE4QixDQUFDO0FBS3RDLE9BQU8sRUFBRSxZQUFZLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDbkQsT0FBTyxFQUFjLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUM3QyxPQUFPLEVBQU8sSUFBSSxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxRQUFRLEVBQWUsTUFBTSxzQkFBc0IsQ0FBQzs7Ozs7Ozs7OztBQUU3RCxxQ0FBcUM7QUFDckMsSUFBSyxNQUdKO0FBSEQsV0FBSyxNQUFNO0lBQ1QsbUNBQXlCLENBQUE7SUFDekIsK0JBQXFCLENBQUE7QUFDdkIsQ0FBQyxFQUhJLE1BQU0sS0FBTixNQUFNLFFBR1Y7QUFPRCxNQUFNLE9BQU8sc0JBQXNCO0lBQ3hCLE9BQU8sQ0FBUztJQUNoQixXQUFXLENBQW1CO0lBQzlCLGFBQWEsQ0FBTTtJQUNuQixLQUFLLENBQVM7SUFDQyxTQUFTLENBQTBCO0lBQy9CLGFBQWEsQ0FBMEI7SUFDM0MsU0FBUyxDQUEwQjtJQUNqQyxXQUFXLENBQTBCO0lBQ2hDLGdCQUFnQixDQUFzQjtJQUMxQyxJQUFJLEdBQUcsU0FBUyxDQUFDO0lBRTVDLFNBQVMsQ0FBTTtJQUNmLGFBQWEsQ0FBTTtJQUNuQixPQUFPLENBQVM7SUFFaEIsYUFBYSxDQUFhO0lBQzFCLGlCQUFpQixDQUFhO0lBQzlCLGVBQWUsQ0FBYTtJQUM1QixhQUFhLENBQWE7SUFDMUIsV0FBVyxDQUFjO0lBQ3pCLGFBQWEsR0FBRztRQUNkLFFBQVEsRUFBRSxNQUFNO1FBQ2hCLGVBQWUsRUFBRSxJQUFJO0tBQ3RCLENBQUM7SUFDRixTQUFTLEdBQVcsTUFBTSxDQUFDLFVBQVUsQ0FBQztJQUN0QyxRQUFRLEdBQUcsRUFBRSxDQUFDO0lBRWQsS0FBSyxDQUFDLGFBQWEsQ0FBQyxFQUNsQixTQUFTLEVBQ1QsV0FBVyxFQUNYLFVBQVUsR0FBRyxJQUFJLEVBQ2pCLE1BQU0sRUFDTixZQUFZLEVBQ0c7UUFDZixJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRTtZQUNyQixPQUFPO1NBQ1I7UUFFRCxJQUFJLElBQUksQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLEVBQUU7WUFDNUQsSUFBSTtnQkFDRixJQUFJLFVBQVUsRUFBRTtvQkFDZCxVQUFVLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUM7aUJBQ3ZEO2dCQUNELE1BQU0sR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQ3pDLElBQUksQ0FBQyxPQUFPLEVBQ1o7b0JBQ0UsV0FBVztvQkFDWCxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7b0JBQ3pCLEdBQUcsVUFBVTtpQkFDZCxFQUNELFlBQVksQ0FDYixDQUFDO2dCQUNGLE1BQU0sRUFBRSxxQkFBcUIsQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDLENBQUM7YUFDL0M7WUFBQyxPQUFPLENBQUMsRUFBRTtnQkFDVixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQzthQUN2QjtTQUNGO0lBQ0gsQ0FBQztJQUVELFFBQVE7UUFDTixJQUFJLENBQUMsV0FBVyxHQUFHLFFBQVEsRUFBRSxDQUFDO1FBQzlCLElBQUksQ0FBQyxXQUFXLENBQUMsV0FBVyxDQUMxQixrQkFBa0IsRUFDbEIsQ0FBQyxPQUFnQixFQUFFLEVBQVUsRUFBd0IsRUFBRSxDQUNyRCxnQkFBZ0IsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQ2hDLENBQUM7UUFFRixJQUFJLENBQUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxHQUFXLEVBQVEsRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRXpFLElBQUksQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDekMsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsV0FBcUIsQ0FBQztRQUMxQyxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDdEMsQ0FBQztJQUVELGVBQWU7UUFDYixJQUFJLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3hELElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDO0lBRUQsZ0JBQWdCO1FBQ2QsSUFBSSxDQUFDLFFBQVEsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFFRCxZQUFZO1FBQ1YsSUFBSSxDQUFDLFNBQVM7WUFDWixJQUFJLENBQUMsU0FBUyxLQUFLLE1BQU0sQ0FBQyxVQUFVO2dCQUNsQyxDQUFDLENBQUMsTUFBTSxDQUFDLFFBQVE7Z0JBQ2pCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDO0lBQzFCLENBQUM7SUFFRCxJQUFJLFlBQVk7UUFDZCxPQUFPLElBQUksQ0FBQyxTQUFTLEtBQUssTUFBTSxDQUFDLFVBQVUsQ0FBQztJQUM5QyxDQUFDO0lBRUQsVUFBVSxDQUFDLElBQVM7UUFDbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVELGlCQUFpQixDQUFDLElBQVM7UUFDekIsSUFBSSxJQUFJLElBQUksSUFBSSxDQUFDLGVBQWUsRUFBRTtZQUNoQyxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1NBQ3pEO2FBQU0sSUFBSSxJQUFJLENBQUMsYUFBYSxFQUFFO1lBQzdCLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1NBQy9EO0lBQ0gsQ0FBQztJQUVELE1BQU07UUFDSixJQUFJLENBQUMsYUFBYSxDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDNUIsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxDQUFDO1FBQ2hDLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxFQUFFLENBQUM7SUFDaEMsQ0FBQztJQUVPLGFBQWE7UUFDbkIsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFO1lBQ2xCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxhQUFhLEVBQUU7Z0JBQzlELElBQUksRUFBRSxlQUFlO2dCQUNyQix3QkFBd0IsRUFBRSxJQUFJO2dCQUM5QixPQUFPLEVBQUUsQ0FBQztnQkFDVixXQUFXLEVBQUUsSUFBSTtnQkFDakIsUUFBUSxFQUFFLElBQUk7YUFDZixDQUFDLENBQUM7WUFFSCxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxXQUFxQixDQUFDLENBQUM7WUFFL0MsSUFBSSxDQUFDLFVBQVUsQ0FDYixTQUFTLEVBQ1QsSUFBSSxDQUFDLFNBQVMsRUFDZCxJQUFJLENBQUMsV0FBVyxFQUNoQixjQUFjLENBQ2YsQ0FBQyxJQUFJLENBQ0osWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUNsQixDQUFDLFNBQVMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO2dCQUN0QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLEtBQUssRUFBRSxDQUFDO2dCQUMzQyxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUM1QixJQUFJLENBQUMsY0FBYyxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDL0MsQ0FBQyxDQUFDLENBQUM7WUFFSCxJQUFJLENBQUMsVUFBVSxDQUNiLFdBQVcsRUFDWCxJQUFJLENBQUMsV0FBVyxFQUNoQixJQUFJLENBQUMsYUFBYSxDQUNuQixDQUFDLFNBQVMsQ0FBQyxDQUFDLFNBQVMsRUFBRSxFQUFFLENBQ3hCLElBQUksQ0FBQyxjQUFjLENBQ2pCLElBQUksQ0FBQyxPQUFPLEVBQ1osU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQzlDLENBQ0YsQ0FBQztZQUVGLElBQUksQ0FBQyxVQUFVLENBQ2IsU0FBUyxFQUNULElBQUksQ0FBQyxTQUFTLEVBQ2QsSUFBSSxDQUFDLE9BQU8sRUFDWixpQkFBaUIsQ0FDbEIsQ0FBQyxTQUFTLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDO1NBQzFDO0lBQ0gsQ0FBQztJQUVPLGFBQWEsQ0FBQyxPQUFlO1FBQ25DLE1BQU0sR0FBRyxHQUFHLFdBQVcsQ0FBQyxhQUFhLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFL0MsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdELElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQUUsQ0FBQztJQUNsQyxDQUFDO0lBRU8sY0FBYyxDQUFDLE9BQWUsRUFBRSxTQUFjO1FBQ2hELElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUM7SUFDakUsQ0FBQztJQUNELG1DQUFtQztJQUMzQixVQUFVLENBQ2hCLElBQVksRUFDWixPQUFtQixFQUNuQixLQUFnRCxFQUNoRCxJQUFJLEdBQUcsZUFBZTtRQUV0QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLGFBQWEsRUFBRTtZQUN6QyxJQUFJO1lBQ0osd0JBQXdCLEVBQUUsSUFBSTtZQUM5QixLQUFLLEVBQUUsa0JBQWtCLENBQUMsS0FBSyxDQUFDO1lBQ2hDLE9BQU8sRUFBRSxDQUFDO1lBQ1YsV0FBVyxFQUFFLElBQUk7WUFDakIsZ0JBQWdCLEVBQUUsSUFBSTtTQUN2QixDQUFDLENBQUM7UUFFSCxNQUFNLENBQUMsVUFBVSxDQUFDO1lBQ2hCLHlCQUF5QixFQUFFLElBQUk7WUFDL0IsY0FBYyxFQUFFLEtBQUs7WUFDckIsd0JBQXdCLEVBQUUsSUFBSTtTQUMvQixDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsR0FBRyxJQUFJLFFBQVEsQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUUvQixPQUFPLFNBQVMsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7dUdBbk1VLHNCQUFzQjsyRkFBdEIsc0JBQXNCLGdzQkNwQ25DLGtxRUE4Q0E7OzJGRFZhLHNCQUFzQjtrQkFMbEMsU0FBUzsrQkFDRSxtQkFBbUI7OEJBS3BCLE9BQU87c0JBQWYsS0FBSztnQkFDRyxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csS0FBSztzQkFBYixLQUFLO2dCQUNrQixTQUFTO3NCQUFoQyxTQUFTO3VCQUFDLFdBQVc7Z0JBQ00sYUFBYTtzQkFBeEMsU0FBUzt1QkFBQyxlQUFlO2dCQUNGLFNBQVM7c0JBQWhDLFNBQVM7dUJBQUMsV0FBVztnQkFDSSxXQUFXO3NCQUFwQyxTQUFTO3VCQUFDLGFBQWE7Z0JBQ08sZ0JBQWdCO3NCQUE5QyxTQUFTO3VCQUFDLGtCQUFrQjtnQkFDRixJQUFJO3NCQUE5QixXQUFXO3VCQUFDLFlBQVkiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBPbkluaXQsXHJcbiAgSW5wdXQsXHJcbiAgSG9zdEJpbmRpbmcsXHJcbiAgVmlld0NoaWxkLFxyXG4gIEFmdGVyVmlld0luaXQsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB0eXBlIHsgRWxlbWVudFJlZiB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQge1xyXG4gIGZvcm1hdE9ialRvSnNvblN0cixcclxuICBDb21wb25lbnRFdmVudCxcclxuICBnZXRDb21wb25lbnRCeUlkLFxyXG4gIEJhc2VEeW5hbWljQ29tcG9uZW50LFxyXG4gIENvcmVTZXJ2aWNlLFxyXG59IGZyb20gJ0BuZ3gtZHluYW1pYy1jb21wb25lbnRzL2NvcmUnO1xyXG5pbXBvcnQgdHlwZSB7XHJcbiAgTkdYRHluYW1pY0NvbXBvbmVudCxcclxuICBVSU1vZGVsLFxyXG59IGZyb20gJ0BuZ3gtZHluYW1pYy1jb21wb25lbnRzL2NvcmUnO1xyXG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIG1hcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgZnJvbUV2ZW50IH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IEFjZSwgZWRpdCB9IGZyb20gJ2FjZS1idWlsZHMnO1xyXG5pbXBvcnQgeyBqc1B5dGhvbiwgSW50ZXJwcmV0ZXIgfSBmcm9tICdqc3B5dGhvbi1pbnRlcnByZXRlcic7XHJcblxyXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tc2hhZG93XHJcbmVudW0gTGF5b3V0IHtcclxuICBob3Jpem9udGFsID0gJ2hvcml6b250YWwnLFxyXG4gIHZlcnRpY2FsID0gJ3ZlcnRpY2FsJyxcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdkYy1wcmV2aWV3LWVkaXRvcicsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL3ByZXZpZXctZWRpdG9yLmNvbXBvbmVudC5odG1sJyxcclxuICBzdHlsZVVybHM6IFsnLi9wcmV2aWV3LWVkaXRvci5jb21wb25lbnQuc2NzcyddLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgUHJldmlld0VkaXRvckNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCB7XHJcbiAgQElucHV0KCkgc2NyaXB0czogc3RyaW5nO1xyXG4gIEBJbnB1dCgpIGluaXRVaU1vZGVsOiBVSU1vZGVsIHwgc3RyaW5nO1xyXG4gIEBJbnB1dCgpIGluaXREYXRhTW9kZWw6IGFueTtcclxuICBASW5wdXQoKSB0aXRsZTogc3RyaW5nO1xyXG4gIEBWaWV3Q2hpbGQoJ3VpTW9kZWxFbCcpIHVpTW9kZWxFbDogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XHJcbiAgQFZpZXdDaGlsZCgndWlNb2RlbEpTT05FbCcpIHVpTW9kZWxKU09ORWw6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+O1xyXG4gIEBWaWV3Q2hpbGQoJ3NjcmlwdHNFbCcpIHNjcmlwdHNFbDogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XHJcbiAgQFZpZXdDaGlsZCgnZGF0YU1vZGVsRWwnKSBkYXRhTW9kZWxFbDogRWxlbWVudFJlZjxIVE1MRWxlbWVudD47XHJcbiAgQFZpZXdDaGlsZCgnZHluYW1pY0NvbXBvbmVudCcpIGR5bmFtaWNDb21wb25lbnQ6IE5HWER5bmFtaWNDb21wb25lbnQ7XHJcbiAgQEhvc3RCaW5kaW5nKCdzdHlsZS5mbGV4JykgZmxleCA9ICdpbml0aWFsJztcclxuXHJcbiAgZGF0YU1vZGVsOiBhbnk7XHJcbiAgZGF0YU1vZGVsQ29weTogYW55O1xyXG4gIHVpTW9kZWw6IHN0cmluZztcclxuXHJcbiAgdWlNb2RlbEVkaXRvcjogQWNlLkVkaXRvcjtcclxuICB1aU1vZGVsSlNPTkVkaXRvcjogQWNlLkVkaXRvcjtcclxuICBkYXRhTW9kZWxFZGl0b3I6IEFjZS5FZGl0b3I7XHJcbiAgc2NyaXB0c0VkaXRvcjogQWNlLkVkaXRvcjtcclxuICBpbnRlcnByZXRlcjogSW50ZXJwcmV0ZXI7XHJcbiAgZWRpdG9yT3B0aW9ucyA9IHtcclxuICAgIGxhbmd1YWdlOiAnanNvbicsXHJcbiAgICBhdXRvbWF0aWNMYXlvdXQ6IHRydWUsXHJcbiAgfTtcclxuICBkaXJlY3Rpb246IExheW91dCA9IExheW91dC5ob3Jpem9udGFsO1xyXG4gIGNvZGVTaXplID0gNTA7XHJcblxyXG4gIGFzeW5jIGV2ZW50SGFuZGxlcnMoe1xyXG4gICAgZXZlbnROYW1lLFxyXG4gICAgcm9vdFVJTW9kZWwsXHJcbiAgICBwYXJhbWV0ZXJzID0gbnVsbCxcclxuICAgIHNlbmRlcixcclxuICAgIGV2ZW50SGFuZGxlclxyXG4gIH06IENvbXBvbmVudEV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XHJcbiAgICBpZiAoIXRoaXMuaW50ZXJwcmV0ZXIpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLmludGVycHJldGVyLmhhc0Z1bmN0aW9uKHRoaXMuc2NyaXB0cywgZXZlbnRIYW5kbGVyKSkge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmIChwYXJhbWV0ZXJzKSB7XHJcbiAgICAgICAgICBwYXJhbWV0ZXJzW3BhcmFtZXRlcnMuYXJnc0tleV0gPSBwYXJhbWV0ZXJzLmFyZ3NWYWx1ZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5pbnRlcnByZXRlci5ldmFsdWF0ZShcclxuICAgICAgICAgIHRoaXMuc2NyaXB0cyxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgcm9vdFVJTW9kZWwsXHJcbiAgICAgICAgICAgIGRhdGFNb2RlbDogdGhpcy5kYXRhTW9kZWwsXHJcbiAgICAgICAgICAgIC4uLnBhcmFtZXRlcnMsXHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZXZlbnRIYW5kbGVyXHJcbiAgICAgICAgKTtcclxuICAgICAgICBzZW5kZXI/LnNldEV2ZW50SGFuZGxlclJlc3VsdChldmVudE5hbWUsIHJlcyk7XHJcbiAgICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgICBhbGVydChgJHtlLm1lc3NhZ2V9YCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5pbnRlcnByZXRlciA9IGpzUHl0aG9uKCk7XHJcbiAgICB0aGlzLmludGVycHJldGVyLmFkZEZ1bmN0aW9uKFxyXG4gICAgICAnZ2V0Q29tcG9uZW50QnlJZCcsXHJcbiAgICAgICh1aU1vZGVsOiBVSU1vZGVsLCBpZDogc3RyaW5nKTogQmFzZUR5bmFtaWNDb21wb25lbnQgPT5cclxuICAgICAgICBnZXRDb21wb25lbnRCeUlkKHVpTW9kZWwsIGlkKVxyXG4gICAgKTtcclxuXHJcbiAgICB0aGlzLmludGVycHJldGVyLmFkZEZ1bmN0aW9uKCdhbGVydCcsIChtc2c6IHN0cmluZyk6IHZvaWQgPT4gYWxlcnQobXNnKSk7XHJcblxyXG4gICAgdGhpcy5pbnRlcnByZXRlci5hc3NpZ25HbG9iYWxDb250ZXh0KHt9KTtcclxuICAgIHRoaXMudWlNb2RlbCA9IHRoaXMuaW5pdFVpTW9kZWwgYXMgc3RyaW5nO1xyXG4gICAgdGhpcy5kYXRhTW9kZWwgPSB0aGlzLmluaXREYXRhTW9kZWw7XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLm9uRGF0YU1vZGVsQ2hhbmdlKHRoaXMuZHluYW1pY0NvbXBvbmVudC5kYXRhTW9kZWwpO1xyXG4gICAgdGhpcy5pbml0VUlQcmV2aWV3KCk7XHJcbiAgfVxyXG5cclxuICB0b2dnbGVTb3VyY2VDb2RlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jb2RlU2l6ZSA9ICF0aGlzLmNvZGVTaXplID8gNTAgOiAwO1xyXG4gIH1cclxuXHJcbiAgdG9nZ2xlTGF5b3V0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5kaXJlY3Rpb24gPVxyXG4gICAgICB0aGlzLmRpcmVjdGlvbiA9PT0gTGF5b3V0Lmhvcml6b250YWxcclxuICAgICAgICA/IExheW91dC52ZXJ0aWNhbFxyXG4gICAgICAgIDogTGF5b3V0Lmhvcml6b250YWw7XHJcbiAgfVxyXG5cclxuICBnZXQgaXNIb3Jpem9udGFsKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuIHRoaXMuZGlyZWN0aW9uID09PSBMYXlvdXQuaG9yaXpvbnRhbDtcclxuICB9XHJcblxyXG4gIG9uUmVuZGVyZWQoZGF0YTogYW55KTogdm9pZCB7XHJcbiAgICBjb25zb2xlLmxvZygncmVuZGVyZWQnLCBkYXRhKTtcclxuICB9XHJcblxyXG4gIG9uRGF0YU1vZGVsQ2hhbmdlKGRhdGE6IGFueSk6IHZvaWQge1xyXG4gICAgaWYgKGRhdGEgJiYgdGhpcy5kYXRhTW9kZWxFZGl0b3IpIHtcclxuICAgICAgdGhpcy5kYXRhTW9kZWxFZGl0b3Iuc2V0VmFsdWUoZm9ybWF0T2JqVG9Kc29uU3RyKGRhdGEpKTtcclxuICAgIH0gZWxzZSBpZiAodGhpcy51aU1vZGVsRWRpdG9yKSB7XHJcbiAgICAgIHRoaXMudWlNb2RlbEVkaXRvci5zZXRWYWx1ZShmb3JtYXRPYmpUb0pzb25TdHIodGhpcy51aU1vZGVsKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXNpemUoKTogdm9pZCB7XHJcbiAgICB0aGlzLnNjcmlwdHNFZGl0b3IucmVzaXplKCk7XHJcbiAgICB0aGlzLnVpTW9kZWxFZGl0b3IucmVzaXplKCk7XHJcbiAgICB0aGlzLnVpTW9kZWxKU09ORWRpdG9yLnJlc2l6ZSgpO1xyXG4gICAgdGhpcy5kYXRhTW9kZWxFZGl0b3IucmVzaXplKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGluaXRVSVByZXZpZXcoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy51aU1vZGVsRWwpIHtcclxuICAgICAgdGhpcy51aU1vZGVsSlNPTkVkaXRvciA9IGVkaXQodGhpcy51aU1vZGVsSlNPTkVsLm5hdGl2ZUVsZW1lbnQsIHtcclxuICAgICAgICBtb2RlOiAnYWNlL21vZGUvanNvbicsXHJcbiAgICAgICAgYXV0b1Njcm9sbEVkaXRvckludG9WaWV3OiB0cnVlLFxyXG4gICAgICAgIHRhYlNpemU6IDIsXHJcbiAgICAgICAgdXNlU29mdFRhYnM6IHRydWUsXHJcbiAgICAgICAgcmVhZE9ubHk6IHRydWUsXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy5zZXRKU09ORWRpdG9yKHRoaXMuaW5pdFVpTW9kZWwgYXMgc3RyaW5nKTtcclxuXHJcbiAgICAgIHRoaXMuaW5pdEVkaXRvcihcclxuICAgICAgICAndWlNb2RlbCcsXHJcbiAgICAgICAgdGhpcy51aU1vZGVsRWwsXHJcbiAgICAgICAgdGhpcy5pbml0VWlNb2RlbCxcclxuICAgICAgICAnYWNlL21vZGUveG1sJ1xyXG4gICAgICApLnBpcGUoXHJcbiAgICAgICAgZGVib3VuY2VUaW1lKDUwMClcclxuICAgICAgKS5zdWJzY3JpYmUoKHVpTW9kZWwpID0+IHtcclxuICAgICAgICB0aGlzLmR5bmFtaWNDb21wb25lbnQuY29udGFpbmVyUmVmLmNsZWFyKCk7XHJcbiAgICAgICAgdGhpcy5zZXRKU09ORWRpdG9yKHVpTW9kZWwpO1xyXG4gICAgICAgIHRoaXMucmVmcmVzaFByZXZpZXcodWlNb2RlbCwgdGhpcy5kYXRhTW9kZWwpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIHRoaXMuaW5pdEVkaXRvcihcclxuICAgICAgICAnZGF0YU1vZGVsJyxcclxuICAgICAgICB0aGlzLmRhdGFNb2RlbEVsLFxyXG4gICAgICAgIHRoaXMuaW5pdERhdGFNb2RlbFxyXG4gICAgICApLnN1YnNjcmliZSgoZGF0YU1vZGVsKSA9PlxyXG4gICAgICAgIHRoaXMucmVmcmVzaFByZXZpZXcoXHJcbiAgICAgICAgICB0aGlzLnVpTW9kZWwsXHJcbiAgICAgICAgICBkYXRhTW9kZWwgPyBKU09OLnBhcnNlKGRhdGFNb2RlbCkgOiBkYXRhTW9kZWxcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aGlzLmluaXRFZGl0b3IoXHJcbiAgICAgICAgJ3NjcmlwdHMnLFxyXG4gICAgICAgIHRoaXMuc2NyaXB0c0VsLFxyXG4gICAgICAgIHRoaXMuc2NyaXB0cyxcclxuICAgICAgICAnYWNlL21vZGUvcHl0aG9uJ1xyXG4gICAgICApLnN1YnNjcmliZSgoc2MpID0+ICh0aGlzLnNjcmlwdHMgPSBzYykpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXRKU09ORWRpdG9yKHVpTW9kZWw6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgcmVzID0gQ29yZVNlcnZpY2UucGFyc2VYTUxNb2RlbCh1aU1vZGVsKTtcclxuXHJcbiAgICB0aGlzLnVpTW9kZWxKU09ORWRpdG9yLnNldFZhbHVlKGZvcm1hdE9ialRvSnNvblN0cihyZXMpLCAtMSk7XHJcbiAgICB0aGlzLnVpTW9kZWxKU09ORWRpdG9yLnJlc2l6ZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZWZyZXNoUHJldmlldyh1aU1vZGVsOiBzdHJpbmcsIGRhdGFNb2RlbDogYW55KTogdm9pZCB7XHJcbiAgICAgICAgdGhpcy51aU1vZGVsID0gdWlNb2RlbDtcclxuICAgICAgICB0aGlzLmRhdGFNb2RlbENvcHkgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KGRhdGFNb2RlbCkpO1xyXG4gIH1cclxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxyXG4gIHByaXZhdGUgaW5pdEVkaXRvcihcclxuICAgIG5hbWU6IHN0cmluZyxcclxuICAgIGVsZW1lbnQ6IEVsZW1lbnRSZWYsXHJcbiAgICB2YWx1ZTogVUlNb2RlbDxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPj4gfCBzdHJpbmcsXHJcbiAgICBtb2RlID0gJ2FjZS9tb2RlL2pzb24nXHJcbiAgKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIGNvbnN0IGVkaXRvciA9IGVkaXQoZWxlbWVudC5uYXRpdmVFbGVtZW50LCB7XHJcbiAgICAgIG1vZGUsXHJcbiAgICAgIGF1dG9TY3JvbGxFZGl0b3JJbnRvVmlldzogdHJ1ZSxcclxuICAgICAgdmFsdWU6IGZvcm1hdE9ialRvSnNvblN0cih2YWx1ZSksXHJcbiAgICAgIHRhYlNpemU6IDIsXHJcbiAgICAgIHVzZVNvZnRUYWJzOiB0cnVlLFxyXG4gICAgICBpbmRlbnRlZFNvZnRXcmFwOiB0cnVlLFxyXG4gICAgfSk7XHJcblxyXG4gICAgZWRpdG9yLnNldE9wdGlvbnMoe1xyXG4gICAgICBlbmFibGVCYXNpY0F1dG9jb21wbGV0aW9uOiB0cnVlLFxyXG4gICAgICBlbmFibGVTbmlwcGV0czogZmFsc2UsXHJcbiAgICAgIGVuYWJsZUxpdmVBdXRvY29tcGxldGlvbjogdHJ1ZSxcclxuICAgIH0pO1xyXG5cclxuICAgIHRoaXNbYCR7bmFtZX1FZGl0b3JgXSA9IGVkaXRvcjtcclxuXHJcbiAgICByZXR1cm4gZnJvbUV2ZW50KGVkaXRvciwgJ2NoYW5nZScpLnBpcGUobWFwKCgpID0+IGVkaXRvci5nZXRWYWx1ZSgpKSk7XHJcbiAgfVxyXG59XHJcbiIsIjxtYXQtY2FyZCAqbmdJZj1cImluaXRVaU1vZGVsXCIgY2xhc3M9XCJoLTEwMCBwcmV2aWV3LWNhcmQgZC1mbGV4IGZsZXgtY29sdW1uXCI+XHJcbiAgPG1hdC1jYXJkLWhlYWRlcj5cclxuICAgIDxzcGFuIGNsYXNzPVwiZmxleC1maWxsIGFsaWduLXNlbGYtY2VudGVyXCI+e3t0aXRsZX19PC9zcGFuPlxyXG4gICAgPGJ1dHRvbiBtYXQtaWNvbi1idXR0b24gKm5nSWY9XCJjb2RlU2l6ZVwiIChjbGljayk9XCJ0b2dnbGVMYXlvdXQoKVwiXHJcbiAgICAgIFttYXRUb29sdGlwXT1cIihpc0hvcml6b250YWwgPyAnVmVydGljYWwnIDogJ0hvcml6b250YWwnKSArICcgbGF5b3V0J1wiPlxyXG4gICAgICA8bWF0LWljb24+e3tpc0hvcml6b250YWwgPyAndmVydGljYWxfc3BsaXQnIDogJ2hvcml6b250YWxfc3BsaXQnfX08L21hdC1pY29uPlxyXG4gICAgPC9idXR0b24+XHJcbiAgICA8YnV0dG9uIG1hdC1pY29uLWJ1dHRvbiBtYXRUb29sdGlwPVwiU291cmNlIGNvZGVcIiAoY2xpY2spPVwidG9nZ2xlU291cmNlQ29kZSgpXCI+XHJcbiAgICAgIDxtYXQtaWNvbj5jb2RlPC9tYXQtaWNvbj5cclxuICAgIDwvYnV0dG9uPlxyXG4gIDwvbWF0LWNhcmQtaGVhZGVyPlxyXG4gIDxtYXQtY2FyZC1jb250ZW50IGNsYXNzPVwiaC0xMDBcIj5cclxuICAgIDxhcy1zcGxpdCBbdXNlVHJhbnNpdGlvbl09XCJ0cnVlXCIgW2RpcmVjdGlvbl09XCJkaXJlY3Rpb25cIiB1bml0PVwicGVyY2VudFwiIFtndXR0ZXJTaXplXT1cImNvZGVTaXplID8gMTEgOiAwXCI+XHJcbiAgICAgIDxhcy1zcGxpdC1hcmVhICNhcmVhMD1cImFzU3BsaXRBcmVhXCIgY2xhc3M9XCJkLWZsZXhcIiBbc2l6ZV09XCJjb2RlU2l6ZVwiPlxyXG4gICAgICAgIDxtYXQtdGFiLWdyb3VwIGNsYXNzPVwidy0xMDAgdWktbW9kZWwtdGFiXCI+XHJcbiAgICAgICAgICA8bWF0LXRhYiBsYWJlbD1cIlVJIE1vZGVsXCI+XHJcbiAgICAgICAgICAgIDxtYXQtdGFiLWdyb3VwIGNsYXNzPVwidy0xMDAgaC0xMDBcIiBoZWFkZXJQb3NpdGlvbj1cImJlbG93XCI+XHJcbiAgICAgICAgICAgICAgPG1hdC10YWIgbGFiZWw9XCJYTUxcIj5cclxuICAgICAgICAgICAgICAgIDxkaXYgI3VpTW9kZWxFbCBjbGFzcz1cImgtMTAwXCI+PC9kaXY+XHJcbiAgICAgICAgICAgICAgPC9tYXQtdGFiPlxyXG4gICAgICAgICAgICAgIDxtYXQtdGFiIGxhYmVsPVwiSlNPTlwiPlxyXG4gICAgICAgICAgICAgICAgPGRpdiAjdWlNb2RlbEpTT05FbCBjbGFzcz1cImgtMTAwXCI+PC9kaXY+XHJcbiAgICAgICAgICAgICAgPC9tYXQtdGFiPlxyXG4gICAgICAgICAgICA8L21hdC10YWItZ3JvdXA+XHJcbiAgICAgICAgICA8L21hdC10YWI+XHJcbiAgICAgICAgICA8bWF0LXRhYiBsYWJlbD1cIlNjcmlwdHNcIj5cclxuICAgICAgICAgICAgPGRpdiAjc2NyaXB0c0VsIGNsYXNzPVwiaC0xMDBcIj48L2Rpdj5cclxuICAgICAgICAgIDwvbWF0LXRhYj5cclxuICAgICAgICAgIDxtYXQtdGFiIGxhYmVsPVwiRGF0YSBNb2RlbFwiPlxyXG4gICAgICAgICAgICA8ZGl2ICNkYXRhTW9kZWxFbCBjbGFzcz1cImgtMTAwXCI+PC9kaXY+XHJcbiAgICAgICAgICA8L21hdC10YWI+XHJcbiAgICAgICAgPC9tYXQtdGFiLWdyb3VwPlxyXG4gICAgICA8L2FzLXNwbGl0LWFyZWE+XHJcbiAgICAgIDxhcy1zcGxpdC1hcmVhIFtzaXplXT1cIjEwMCAtIGNvZGVTaXplXCIgI2FyZWExPVwiYXNTcGxpdEFyZWFcIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwicHJldmlld1wiPlxyXG4gICAgICAgICAgPG5neC1keW5hbWljLWNvbXBvbmVudCBjbGFzcz1cImQtYmxvY2tcIiAqbmdJZj1cInVpTW9kZWxcIiAjZHluYW1pY0NvbXBvbmVudFxyXG4gICAgICAgICAgICBbeG1sVUlNb2RlbF09J3VpTW9kZWwnXHJcbiAgICAgICAgICAgIFtkYXRhTW9kZWxdPSdkYXRhTW9kZWwnXHJcbiAgICAgICAgICAgIChyZW5kZXIpPSdvblJlbmRlcmVkKCRldmVudCknXHJcbiAgICAgICAgICAgIChjaGFuZ2VkRGF0YU1vZGVsKT1cIm9uRGF0YU1vZGVsQ2hhbmdlKCRldmVudClcIlxyXG4gICAgICAgICAgICAoZXZlbnRIYW5kbGVycyk9XCJldmVudEhhbmRsZXJzKCRldmVudClcIj48L25neC1keW5hbWljLWNvbXBvbmVudD5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9hcy1zcGxpdC1hcmVhPlxyXG4gICAgPC9hcy1zcGxpdD5cclxuICA8L21hdC1jYXJkLWNvbnRlbnQ+XHJcbjwvbWF0LWNhcmQ+XHJcbiJdfQ==