UNPKG

cytoscape-angular-ng17

Version:
227 lines 49.2 kB
import { Component, EventEmitter, Input, Output, ViewChild, } from '@angular/core'; import { BreadthFirstLayoutOptionsImpl, CircleLayoutOptionsImpl, ConcentricLayoutOptionsImpl, CoseLayoutOptionsImpl, DagreLayoutOptionsImpl, GridLayoutOptionsImpl, NullLayoutOptionsImpl, PresetLayoutOptionsImpl, RandomLayoutOptionsImpl, } from '../layout/layout-options-impl'; import { FieldInfo, FieldsetInfo, FormInfo } from '../fluid-form/form-info'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "primeng/button"; import * as i3 from "primeng/dropdown"; import * as i4 from "../fluid-form/fluid-form.component"; export class CytoscapeLayoutToolComponent { static LAYOUT_FORM_INFO = CytoscapeLayoutToolComponent.createLayoutFormInfo(); layoutForm; _layoutOptions; changed = false; get layoutOptions() { return this._layoutOptions; } set layoutOptions(value) { console.log(`set layoutOptions: ${value?.name}`); this._layoutOptions = value; } layoutOptionsChange = new EventEmitter(); layoutOptionsList = [ new BreadthFirstLayoutOptionsImpl(), new CoseLayoutOptionsImpl(), new DagreLayoutOptionsImpl(), new CircleLayoutOptionsImpl(), new ConcentricLayoutOptionsImpl(), new GridLayoutOptionsImpl(), new PresetLayoutOptionsImpl(), new RandomLayoutOptionsImpl(), new NullLayoutOptionsImpl(), ]; formInfo; constructor() { } ngOnInit() { this.formInfo = CytoscapeLayoutToolComponent.createLayoutFormInfo(); let layoutOptionsSelect = this.layoutOptionsList[5]; console.log('setting the initial selected layout, default: ', layoutOptionsSelect.name); if (this.layoutOptions) { console.log(`setting the initial selected layout based on input/output layout ${JSON.stringify(this.layoutOptions)}`); this.addOrReplaceInLayoutOptionsList(this.layoutOptions); } console.log('Initializing this.selectedLayoutInfo with layoutOptionsSelect ', JSON.stringify(layoutOptionsSelect)); } ngOnChanges(changes) { console.log('ngOnChanges layout changes:', JSON.stringify(changes)); if (changes['layoutOptions']) { } } onLayoutModelChange() { console.log('Layout model change: ', JSON.stringify(this.layoutOptions)); this.changed = true; } onFormModelChange() { console.log('onFormModelChange'); this.changed = true; } onApplyLayout() { this.changed = false; this.layoutOptionsChange.emit(this.layoutOptions); } addOrReplaceInLayoutOptionsList(layoutOptions) { let matchingOptions = this.layoutOptionsList.find((selectOption) => selectOption.name === layoutOptions.name); if (matchingOptions) { console.log('got matching layoutOptions: ', JSON.stringify(matchingOptions)); this.layoutOptionsList.splice(this.layoutOptionsList.indexOf(matchingOptions), 1, layoutOptions); } else { console.info(`Did you pass a new kind of layout? The layout name ${name} was not found, adding a new one to the top of the list.`); this.layoutOptionsList.unshift(layoutOptions); } } static createLayoutFormInfo() { let fit = new FieldInfo('Fit', 'fit', 'boolean', 'Whether to fit to viewport'); let padding = new FieldInfo('Padding', 'padding', 'number', 'When fit to viewport, padding inside the viewport.'); let fitFieldset = new FieldsetInfo('Fit', [fit, padding], ['fit']); const zoom = new FieldInfo('Zoom', 'zoom', 'number', 'the zoom level to set (likely want fit = false if set)'); const pan = new FieldInfo('Pan', 'pan', 'number', 'the pan level to set (likely want fit = false if set)'); const animate = new FieldInfo('Animate', 'animate', 'boolean', 'whether to transition the node positions'); const animationDuration = new FieldInfo('Animation Duration', 'animationDuration', 'number', 'duration of animation in ms if enabled'); const animationEasing = new FieldInfo('Animation Easing', 'animationEasing', 'number', 'easing of animation if enabled'); let animationFieldset = new FieldsetInfo('Animation', [zoom, pan, animate, animationDuration, animationEasing], ['animate']); let avoidOverlap = new FieldInfo('Avoid Overlap', 'avoidOverlap', 'boolean', 'prevents node overlap, may overflow boundingBox if not enough space'); let spacingFactor = new FieldInfo('Spacing Factor', 'spacingFactor', 'number', 'Applies a multiplicative factor (>0) to expand or compress the overall area that the nodes take up'); let nodeDimensionsIncludeLabels = new FieldInfo('Node Dimensions Include Labels', 'nodeDimensionsIncludeLabels', 'boolean', 'Excludes the label when calculating node bounding boxes for the layout algorithm'); let shapedFieldset = new FieldsetInfo('Shaped', [avoidOverlap, spacingFactor, nodeDimensionsIncludeLabels], ['avoidOverlap']); let directed = new FieldInfo('Directed', 'breadthFirst', 'boolean', 'whether the tree is breadthFirst downwards (or edges can point in any direction if false)'); let circle = new FieldInfo('Circle', 'circle', 'boolean', 'put depths in concentric circles if true, put depths top down if false'); let maximalAdjustments = new FieldInfo('Maximal Adjustments', 'maximalAdjustments', 'number', 'how many times to try to position the nodes in a maximal way (i.e. no backtracking)'); let maximal = new FieldInfo('Maximal', 'maximal', 'boolean', 'whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)'); let grid = new FieldInfo('Grid', 'grid', 'boolean', 'whether to shift nodes down their natural BFS depths in order to avoid upwards edges (DAGS only)'); let roots = new FieldInfo('Roots', 'roots', 'string', 'the roots of the trees'); let breadthFirstFieldset = new FieldsetInfo('Breadth First', [directed, circle, maximalAdjustments, maximal, grid, roots], ['breadthFirst']); let nodeSep = new FieldInfo('Node Separation', 'nodeSep', 'number', 'the separation between adjacent nodes in the same rank'); let edgeSep = new FieldInfo('Edge Separation', 'edgeSep', 'number', 'the separation between adjacent edges in the same rank'); let rankSep = new FieldInfo('Rank Separation', 'rankSep', 'number', 'the separation between each rank in the layout'); let ranker = new FieldInfo('Ranker', 'ranker', 'options', 'Type of algorithm to assign a rank to each node in the input graph.'); ranker.options = [ { name: '', label: '' }, { name: 'network-simplex', label: 'network-simplex' }, { name: 'tight-tree', label: 'tight-tree' }, { name: 'longest-path', label: 'longest-path' }, ]; let dagreFieldset = new FieldsetInfo('Dagre', [nodeSep, edgeSep, rankSep, ranker], ['nodeSep']); let animationThreshold = new FieldInfo('Animation Threshold', 'animationThreshold', 'number', 'The layout animates only after this many milliseconds when animate is true (prevents flashing on fast runs)'); let refresh = new FieldInfo('Refresh', 'refresh', 'number', 'Number of iterations between consecutive screen positions update'); let randomize = new FieldInfo('Randomize', 'randomize', 'boolean', 'Randomize the initial positions of the nodes (true) or use existing positions (false)'); let componentSpacing = new FieldInfo('Component Spacing', 'componentSpacing', 'number', 'Extra spacing between components in non-compound graphs'); let nodeOverlap = new FieldInfo('Node Overlap', 'nodeOverlap', 'number', 'Node repulsion (overlapping) multiplier'); let nestingFactor = new FieldInfo('Nesting Factor', 'nestingFactor', 'number', 'Nesting factor (multiplier) to compute ideal edge length for nested edges'); let gravity = new FieldInfo('Gravity', 'gravity', 'number', 'Gravity force (constant)'); let numIter = new FieldInfo('Max Iterations', 'numIter', 'number', 'Maximum number of iterations to perform'); let initialTemp = new FieldInfo('Initial Temp', 'initialTemp', 'number', 'Initial temperature (maximum node displacement)'); let coolingFactor = new FieldInfo('Cooling Factor', 'coolingFactor', 'number', 'Cooling factor (how the temperature is reduced between consecutive iterations'); let minTemp = new FieldInfo('Min. Temp', 'minTemp', 'number', 'Lower temperature threshold (below this point the layout will end)'); let coseFieldset = new FieldsetInfo('COSE', [ animationThreshold, refresh, randomize, componentSpacing, nodeOverlap, nestingFactor, gravity, numIter, initialTemp, coolingFactor, minTemp, ], ['coolingFactor']); let avoidOverlapPadding = new FieldInfo('avoidOverlapPadding', 'avoidOverlapPadding', 'number', 'extra spacing around nodes when avoidOverlap: true'); let condense = new FieldInfo('condense', 'condense', 'boolean', 'uses all available space on false, uses minimal space on true'); let rows = new FieldInfo('Rows', 'rows', 'number', 'force num of rows in the grid'); let cols = new FieldInfo('Columns', 'cols', 'number', 'force num of columns in the grid'); let gridFieldset = new FieldsetInfo('Grid', [avoidOverlapPadding, condense, rows, cols], ['cols']); let radius = new FieldInfo('Radius', 'radius', 'number', 'the radius of the circle'); let startAngle = new FieldInfo('Start Angle', 'startAngle', 'number', 'where nodes start in radians (default:3 / 2 * Math.PI)'); let sweep = new FieldInfo('Sweep', 'sweep', 'number', 'how many radians should be between the first and last node (defaults to full circle)'); let clockwise = new FieldInfo('Clockwise', 'clockwise', 'number', 'whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)'); let circularFieldSet = new FieldsetInfo('Circular', [radius, startAngle, sweep, clockwise], ['clockwise']); let equidistant = new FieldInfo('Equidistant', 'equidistant', 'boolean', 'whether levels have an equal radial distance betwen them, may cause bounding box overflow'); let minNodeSpacing = new FieldInfo('Min. Node Spacing', 'minNodeSpacing', 'number', 'min spacing between outside of nodes (used for radius adjustment)'); let height = new FieldInfo('Height', 'height', 'number', ''); let width = new FieldInfo('Width', 'width', 'number', ''); let concentricFieldSet = new FieldsetInfo('Concentric', [equidistant, minNodeSpacing, startAngle, height, width], ['equidistant']); //boundingBox: undefined // constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } return new FormInfo('Layout', [ breadthFirstFieldset, coseFieldset, dagreFieldset, gridFieldset, circularFieldSet, concentricFieldSet, fitFieldset, animationFieldset, shapedFieldset, ], false); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.3", ngImport: i0, type: CytoscapeLayoutToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.3", type: CytoscapeLayoutToolComponent, selector: "cytoscape-layout-tool", inputs: { layoutOptions: "layoutOptions" }, outputs: { layoutOptionsChange: "layoutOptionsChange" }, viewQueries: [{ propertyName: "layoutForm", first: true, predicate: ["layoutForm"], descendants: true }], usesOnChanges: true, ngImport: i0, template: ` <div> <div style="display: flex;"> <div class="layout-header">Edit Layout</div> </div> <p-dropdown class="layout-dropdown" name="selectedLayoutInfo" [options]="layoutOptionsList" [(ngModel)]="layoutOptions" optionLabel="name" (ngModelChange)="onLayoutModelChange()" > ></p-dropdown > <button class="apply-button" pButton label="Apply" [disabled]="!changed" (click)="onApplyLayout()" ></button> </div> <cyng-fluid-form [model]="layoutOptions" [formInfo]="formInfo" (modelChange)="onFormModelChange()" ></cyng-fluid-form> `, isInline: true, styles: [":host{width:400px;height:2em}.layout-header{width:100%;height:20px}.layout-dropdown{padding-right:10px}input:disabled{background-color:#cccccc54}\n"], dependencies: [{ kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "label", "icon", "loading"] }, { kind: "component", type: i3.Dropdown, selector: "p-dropdown", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "dropdownIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4.FluidFormComponent, selector: "cyng-fluid-form", inputs: ["model", "modelProperty", "formInfo"], outputs: ["modelChange"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.3", ngImport: i0, type: CytoscapeLayoutToolComponent, decorators: [{ type: Component, args: [{ selector: 'cytoscape-layout-tool', template: ` <div> <div style="display: flex;"> <div class="layout-header">Edit Layout</div> </div> <p-dropdown class="layout-dropdown" name="selectedLayoutInfo" [options]="layoutOptionsList" [(ngModel)]="layoutOptions" optionLabel="name" (ngModelChange)="onLayoutModelChange()" > ></p-dropdown > <button class="apply-button" pButton label="Apply" [disabled]="!changed" (click)="onApplyLayout()" ></button> </div> <cyng-fluid-form [model]="layoutOptions" [formInfo]="formInfo" (modelChange)="onFormModelChange()" ></cyng-fluid-form> `, styles: [":host{width:400px;height:2em}.layout-header{width:100%;height:20px}.layout-dropdown{padding-right:10px}input:disabled{background-color:#cccccc54}\n"] }] }], ctorParameters: () => [], propDecorators: { layoutForm: [{ type: ViewChild, args: ['layoutForm'] }], layoutOptions: [{ type: Input }], layoutOptionsChange: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3l0b3NjYXBlLWxheW91dC10b29sLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2N5dG9zY2FwZS1hbmd1bGFyL3NyYy9saWIvY3l0b3NjYXBlLWxheW91dC10b29sL2N5dG9zY2FwZS1sYXlvdXQtdG9vbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUdMLFNBQVMsRUFDVCxZQUFZLEVBRVosS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEdBQ1YsTUFBTSxlQUFlLENBQUM7QUFFdkIsT0FBTyxFQUNMLDZCQUE2QixFQUM3Qix1QkFBdUIsRUFDdkIsMkJBQTJCLEVBQzNCLHFCQUFxQixFQUNyQixzQkFBc0IsRUFDdEIscUJBQXFCLEVBQ3JCLHFCQUFxQixFQUNyQix1QkFBdUIsRUFDdkIsdUJBQXVCLEdBQ3hCLE1BQU0sK0JBQStCLENBQUM7QUFDdkMsT0FBTyxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLE1BQU0seUJBQXlCLENBQUM7Ozs7OztBQXVENUUsTUFBTSxPQUFPLDRCQUE0QjtJQUMvQixNQUFNLENBQUMsZ0JBQWdCLEdBQzdCLDRCQUE0QixDQUFDLG9CQUFvQixFQUFFLENBQUM7SUFFN0IsVUFBVSxDQUFDO0lBRXBDLGNBQWMsQ0FBTTtJQUNwQixPQUFPLEdBQUcsS0FBSyxDQUFDO0lBRWhCLElBQ0ksYUFBYTtRQUNmLE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0lBQ0QsSUFBSSxhQUFhLENBQUMsS0FBSztRQUNyQixPQUFPLENBQUMsR0FBRyxDQUFDLHNCQUFzQixLQUFLLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsY0FBYyxHQUFHLEtBQUssQ0FBQztJQUM5QixDQUFDO0lBQ1MsbUJBQW1CLEdBQzNCLElBQUksWUFBWSxFQUFpQixDQUFDO0lBRTdCLGlCQUFpQixH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QVM7K0JBQ0UsdUJBQXVCLFlBc0J2Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQTRCVDt3REFNd0IsVUFBVTtzQkFBbEMsU0FBUzt1QkFBQyxZQUFZO2dCQU1uQixhQUFhO3NCQURoQixLQUFLO2dCQVFJLG1CQUFtQjtzQkFBNUIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEFmdGVyVmlld0NoZWNrZWQsXG4gIEFmdGVyVmlld0luaXQsXG4gIENvbXBvbmVudCxcbiAgRXZlbnRFbWl0dGVyLFxuICBIb3N0TGlzdGVuZXIsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uSW5pdCxcbiAgT3V0cHV0LFxuICBTaW1wbGVDaGFuZ2VzLFxuICBWaWV3Q2hpbGQsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTGF5b3V0T3B0aW9ucyB9IGZyb20gJ2N5dG9zY2FwZSc7XG5pbXBvcnQge1xuICBCcmVhZHRoRmlyc3RMYXlvdXRPcHRpb25zSW1wbCxcbiAgQ2lyY2xlTGF5b3V0T3B0aW9uc0ltcGwsXG4gIENvbmNlbnRyaWNMYXlvdXRPcHRpb25zSW1wbCxcbiAgQ29zZUxheW91dE9wdGlvbnNJbXBsLFxuICBEYWdyZUxheW91dE9wdGlvbnNJbXBsLFxuICBHcmlkTGF5b3V0T3B0aW9uc0ltcGwsXG4gIE51bGxMYXlvdXRPcHRpb25zSW1wbCxcbiAgUHJlc2V0TGF5b3V0T3B0aW9uc0ltcGwsXG4gIFJhbmRvbUxheW91dE9wdGlvbnNJbXBsLFxufSBmcm9tICcuLi9sYXlvdXQvbGF5b3V0LW9wdGlvbnMtaW1wbCc7XG5pbXBvcnQgeyBGaWVsZEluZm8sIEZpZWxkc2V0SW5mbywgRm9ybUluZm8gfSBmcm9tICcuLi9mbHVpZC1mb3JtL2Zvcm0taW5mbyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2N5dG9zY2FwZS1sYXlvdXQtdG9vbCcsXG4gIHN0eWxlczogW1xuICAgIGBcbiAgICAgIDpob3N0IHtcbiAgICAgICAgd2lkdGg6IDQwMHB4O1xuICAgICAgICBoZWlnaHQ6IDJlbTtcbiAgICAgIH1cblxuICAgICAgLmxheW91dC1oZWFkZXIge1xuICAgICAgICB3aWR0aDogMTAwJTtcbiAgICAgICAgaGVpZ2h0OiAyMHB4O1xuICAgICAgfVxuXG4gICAgICAubGF5b3V0LWRyb3Bkb3duIHtcbiAgICAgICAgcGFkZGluZy1yaWdodDogMTBweDtcbiAgICAgIH1cblxuICAgICAgaW5wdXQ6ZGlzYWJsZWQge1xuICAgICAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDIwNCwgMjA0LCAyMDQsIDAuMzMpO1xuICAgICAgfVxuICAgIGAsXG4gIF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdj5cbiAgICAgIDxkaXYgc3R5bGU9XCJkaXNwbGF5OiBmbGV4O1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWhlYWRlclwiPkVkaXQgTGF5b3V0PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxwLWRyb3Bkb3duXG4gICAgICAgIGNsYXNzPVwibGF5b3V0LWRyb3Bkb3duXCJcbiAgICAgICAgbmFtZT1cInNlbGVjdGVkTGF5b3V0SW5mb1wiXG4gICAgICAgIFtvcHRpb25zXT1cImxheW91dE9wdGlvbnNMaXN0XCJcbiAgICAgICAgWyhuZ01vZGVsKV09XCJsYXlvdXRPcHRpb25zXCJcbiAgICAgICAgb3B0aW9uTGFiZWw9XCJuYW1lXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25MYXlvdXRNb2RlbENoYW5nZSgpXCJcbiAgICAgID5cbiAgICAgICAgPjwvcC1kcm9wZG93blxuICAgICAgPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBjbGFzcz1cImFwcGx5LWJ1dHRvblwiXG4gICAgICAgIHBCdXR0b25cbiAgICAgICAgbGFiZWw9XCJBcHBseVwiXG4gICAgICAgIFtkaXNhYmxlZF09XCIhY2hhbmdlZFwiXG4gICAgICAgIChjbGljayk9XCJvbkFwcGx5TGF5b3V0KClcIlxuICAgICAgPjwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICAgIDxjeW5nLWZsdWlkLWZvcm1cbiAgICAgIFttb2RlbF09XCJsYXlvdXRPcHRpb25zXCJcbiAgICAgIFtmb3JtSW5mb109XCJmb3JtSW5mb1wiXG4gICAgICAobW9kZWxDaGFuZ2UpPVwib25Gb3JtTW9kZWxDaGFuZ2UoKVwiXG4gICAgPjwvY3luZy1mbHVpZC1mb3JtPlxuICBgLFxufSlcbmV4cG9ydCBjbGFzcyBDeXRvc2NhcGVMYXlvdXRUb29sQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMge1xuICBwcml2YXRlIHN0YXRpYyBMQVlPVVRfRk9STV9JTkZPOiBGb3JtSW5mbyA9XG4gICAgQ3l0b3NjYXBlTGF5b3V0VG9vbENvbXBvbmVudC5jcmVhdGVMYXlvdXRGb3JtSW5mbygpO1xuXG4gIEBWaWV3Q2hpbGQoJ2xheW91dEZvcm0nKSBsYXlvdXRGb3JtO1xuXG4gIF9sYXlvdXRPcHRpb25zOiBhbnk7XG4gIGNoYW5nZWQgPSBmYWxzZTtcblxuICBASW5wdXQoKVxuICBnZXQgbGF5b3V0T3B0aW9ucygpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLl9sYXlvdXRPcHRpb25zO1xuICB9XG4gIHNldCBsYXlvdXRPcHRpb25zKHZhbHVlKSB7XG4gICAgY29uc29sZS5sb2coYHNldCBsYXlvdXRPcHRpb25zOiAke3ZhbHVlPy5uYW1lfWApO1xuICAgIHRoaXMuX2xheW91dE9wdGlvbnMgPSB2YWx1ZTtcbiAgfVxuICBAT3V0cHV0KCkgbGF5b3V0T3B0aW9uc0NoYW5nZTogRXZlbnRFbWl0dGVyPExheW91dE9wdGlvbnM+ID1cbiAgICBuZXcgRXZlbnRFbWl0dGVyPExheW91dE9wdGlvbnM+KCk7XG5cbiAgcHVibGljIGxheW91dE9wdGlvbnNMaXN0OiBMYXlvdXRPcHRpb25zW10gPSBbXG4gICAgbmV3IEJyZWFkdGhGaXJzdExheW91dE9wdGlvbnNJbXBsKCksXG4gICAgbmV3IENvc2VMYXlvdXRPcHRpb25zSW1wbCgpLFxuICAgIG5ldyBEYWdyZUxheW91dE9wdGlvbnNJbXBsKCksXG4gICAgbmV3IENpcmNsZUxheW91dE9wdGlvbnNJbXBsKCksXG4gICAgbmV3IENvbmNlbnRyaWNMYXlvdXRPcHRpb25zSW1wbCgpLFxuICAgIG5ldyBHcmlkTGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgUHJlc2V0TGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgUmFuZG9tTGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgTnVsbExheW91dE9wdGlvbnNJbXBsKCksXG4gIF07XG5cbiAgZm9ybUluZm8hOiBGb3JtSW5mbztcblxuICBjb25zdHJ1Y3RvcigpIHt9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtSW5mbyA9IEN5dG9zY2FwZUxheW91dFRvb2xDb21wb25lbnQuY3JlYXRlTGF5b3V0Rm9ybUluZm8oKTtcbiAgICBsZXQgbGF5b3V0T3B0aW9uc1NlbGVjdCA9IHRoaXMubGF5b3V0T3B0aW9uc0xpc3RbNV07XG4gICAgY29uc29sZS5sb2coXG4gICAgICAnc2V0dGluZyB0aGUgaW5pdGlhbCBzZWxlY3RlZCBsYXlvdXQsIGRlZmF1bHQ6ICcsXG4gICAgICBsYXlvdXRPcHRpb25zU2VsZWN0Lm5hbWVcbiAgICApO1xuICAgIGlmICh0aGlzLmxheW91dE9wdGlvbnMpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBgc2V0dGluZyAgdGhlIGluaXRpYWwgc2VsZWN0ZWQgbGF5b3V0IGJhc2VkIG9uIGlucHV0L291dHB1dCBsYXlvdXQgJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICB0aGlzLmxheW91dE9wdGlvbnNcbiAgICAgICAgKX1gXG4gICAgICApO1xuICAgICAgdGhpcy5hZGRPclJlcGxhY2VJbkxheW91dE9wdGlvbnNMaXN0KHRoaXMubGF5b3V0T3B0aW9ucyk7XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKFxuICAgICAgJ0luaXRpYWxpemluZyB0aGlzLnNlbGVjdGVkTGF5b3V0SW5mbyB3aXRoIGxheW91dE9wdGlvbnNTZWxlY3QgJyxcbiAgICAgIEpTT04uc3RyaW5naWZ5KGxheW91dE9wdGlvbnNTZWxlY3QpXG4gICAgKTtcbiAgfVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICBjb25zb2xlLmxvZygnbmdPbkNoYW5nZXMgbGF5b3V0IGNoYW5nZXM6JywgSlNPTi5zdHJpbmdpZnkoY2hhbmdlcykpO1xuICAgIGlmIChjaGFuZ2VzWydsYXlvdXRPcHRpb25zJ10pIHtcbiAgICB9XG4gIH1cblxuICBvbkxheW91dE1vZGVsQ2hhbmdlKCkge1xuICAgIGNvbnNvbGUubG9nKCdMYXlvdXQgbW9kZWwgY2hhbmdlOiAnLCBKU09OLnN0cmluZ2lmeSh0aGlzLmxheW91dE9wdGlvbnMpKTtcbiAgICB0aGlzLmNoYW5nZWQgPSB0cnVlO1xuICB9XG5cbiAgb25Gb3JtTW9kZWxDaGFuZ2UoKSB7XG4gICAgY29uc29sZS5sb2coJ29uRm9ybU1vZGVsQ2hhbmdlJyk7XG4gICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZTtcbiAgfVxuXG4gIG9uQXBwbHlMYXlvdXQoKSB7XG4gICAgdGhpcy5jaGFuZ2VkID0gZmFsc2U7XG4gICAgdGhpcy5sYXlvdXRPcHRpb25zQ2hhbmdlLmVtaXQodGhpcy5sYXlvdXRPcHRpb25zKTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkT3JSZXBsYWNlSW5MYXlvdXRPcHRpb25zTGlzdChsYXlvdXRPcHRpb25zOiBMYXlvdXRPcHRpb25zKTogdm9pZCB7XG4gICAgbGV0IG1hdGNoaW5nT3B0aW9ucyA9IHRoaXMubGF5b3V0T3B0aW9uc0xpc3QuZmluZChcbiAgICAgIChzZWxlY3RPcHRpb24pID0+IHNlbGVjdE9wdGlvbi5uYW1lID09PSBsYXlvdXRPcHRpb25zLm5hbWVcbiAgICApO1xuICAgIGlmIChtYXRjaGluZ09wdGlvbnMpIHtcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAnZ290IG1hdGNoaW5nIGxheW91dE9wdGlvbnM6ICcsXG4gICAgICAgIEpTT04uc3RyaW5naWZ5KG1hdGNoaW5nT3B0aW9ucylcbiAgICAgICk7XG4gICAgICB0aGlzLmxheW91dE9wdGlvbnNMaXN0LnNwbGljZShcbiAgICAgICAgdGhpcy5sYXlvdXRPcHRpb25zTGlzdC5pbmRleE9mKG1hdGNoaW5nT3B0aW9ucyksXG4gICAgICAgIDEsXG4gICAgICAgIGxheW91dE9wdGlvbnNcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgYERpZCB5b3UgcGFzcyBhIG5ldyBraW5kIG9mIGxheW91dD8gIFRoZSBsYXlvdXQgbmFtZSAke25hbWV9IHdhcyBub3QgZm91bmQsIGFkZGluZyBhIG5ldyBvbmUgdG8gdGhlIHRvcCBvZiB0aGUgbGlzdC5gXG4gICAgICApO1xuICAgICAgdGhpcy5sYXlvdXRPcHRpb25zTGlzdC51bnNoaWZ0KGxheW91dE9wdGlvbnMpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUxheW91dEZvcm1JbmZvKCk6IEZvcm1JbmZvIHtcbiAgICBsZXQgZml0ID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdGaXQnLFxuICAgICAgJ2ZpdCcsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAnV2hldGhlciB0byBmaXQgdG8gdmlld3BvcnQnXG4gICAgKTtcbiAgICBsZXQgcGFkZGluZyA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnUGFkZGluZycsXG4gICAgICAncGFkZGluZycsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdXaGVuIGZpdCB0byB2aWV3cG9ydCwgcGFkZGluZyBpbnNpZGUgdGhlIHZpZXdwb3J0LidcbiAgICApO1xuXG4gICAgbGV0IGZpdEZpZWxkc2V0ID0gbmV3IEZpZWxkc2V0SW5mbygnRml0JywgW2ZpdCwgcGFkZGluZ10sIFsnZml0J10pO1xuXG4gICAgY29uc3Qgem9vbSA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnWm9vbScsXG4gICAgICAnem9vbScsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICd0aGUgem9vbSBsZXZlbCB0byBzZXQgKGxpa2VseSB3YW50IGZpdCA9IGZhbHNlIGlmIHNldCknXG4gICAgKTtcbiAgICBjb25zdCBwYW4gPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ1BhbicsXG4gICAgICAncGFuJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ3RoZSBwYW4gbGV2ZWwgdG8gc2V0IChsaWtlbHkgd2FudCBmaXQgPSBmYWxzZSBpZiBzZXQpJ1xuICAgICk7XG4gICAgY29uc3QgYW5pbWF0ZSA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnQW5pbWF0ZScsXG4gICAgICAnYW5pbWF0ZScsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAnd2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9ucydcbiAgICApO1xuICAgIGNvbnN0IGFuaW1hdGlvbkR1cmF0aW9uID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdBbmltYXRpb24gRHVyYXRpb24nLFxuICAgICAgJ2FuaW1hdGlvbkR1cmF0aW9uJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ2R1cmF0aW9uIG9mIGFuaW1hdGlvbiBpbiBtcyBpZiBlbmFibGVkJ1xuICAgICk7XG4gICAgY29uc3QgYW5pbWF0aW9uRWFzaW5nID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdBbmltYXRpb24gRWFzaW5nJyxcbiAgICAgICdhbmltYXRpb25FYXNpbmcnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnZWFzaW5nIG9mIGFuaW1hdGlvbiBpZiBlbmFibGVkJ1xuICAgICk7XG4gICAgbGV0IGFuaW1hdGlvbkZpZWxkc2V0ID0gbmV3IEZpZWxkc2V0SW5mbyhcbiAgICAgICdBbmltYXRpb24nLFxuICAgICAgW3pvb20sIHBhbiwgYW5pbWF0ZSwgYW5pbWF0aW9uRHVyYXRpb24sIGFuaW1hdGlvbkVhc2luZ10sXG4gICAgICBbJ2FuaW1hdGUnXVxuICAgICk7XG5cbiAgICBsZXQgYXZvaWRPdmVybGFwID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdBdm9pZCBPdmVybGFwJyxcbiAgICAgICdhdm9pZE92ZXJsYXAnLFxuICAgICAgJ2Jvb2xlYW4nLFxuICAgICAgJ3ByZXZlbnRzIG5vZGUgb3ZlcmxhcCwgbWF5IG92ZXJmbG93IGJvdW5kaW5nQm94IGlmIG5vdCBlbm91Z2ggc3BhY2UnXG4gICAgKTtcbiAgICBsZXQgc3BhY2luZ0ZhY3RvciA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnU3BhY2luZyBGYWN0b3InLFxuICAgICAgJ3NwYWNpbmdGYWN0b3InLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnQXBwbGllcyBhIG11bHRpcGxpY2F0aXZlIGZhY3RvciAoPjApIHRvIGV4cGFuZCBvciBjb21wcmVzcyB0aGUgb3ZlcmFsbCBhcmVhIHRoYXQgdGhlIG5vZGVzIHRha2UgdXAnXG4gICAgKTtcbiAgICBsZXQgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdOb2RlIERpbWVuc2lvbnMgSW5jbHVkZSBMYWJlbHMnLFxuICAgICAgJ25vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVscycsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAnRXhjbHVkZXMgdGhlIGxhYmVsIHdoZW4gY2FsY3VsYXRpbmcgbm9kZSBib3VuZGluZyBib3hlcyBmb3IgdGhlIGxheW91dCBhbGdvcml0aG0nXG4gICAgKTtcbiAgICBsZXQgc2hhcGVkRmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKFxuICAgICAgJ1NoYXBlZCcsXG4gICAgICBbYXZvaWRPdmVybGFwLCBzcGFjaW5nRmFjdG9yLCBub2RlRGltZW5zaW9uc0luY2x1ZGVMYWJlbHNdLFxuICAgICAgWydhdm9pZE92ZXJsYXAnXVxuICAgICk7XG5cbiAgICBsZXQgZGlyZWN0ZWQgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ0RpcmVjdGVkJyxcbiAgICAgICdicmVhZHRoRmlyc3QnLFxuICAgICAgJ2Jvb2xlYW4nLFxuICAgICAgJ3doZXRoZXIgdGhlIHRyZWUgaXMgYnJlYWR0aEZpcnN0IGRvd253YXJkcyAob3IgZWRnZXMgY2FuIHBvaW50IGluIGFueSBkaXJlY3Rpb24gaWYgZmFsc2UpJ1xuICAgICk7XG4gICAgbGV0IGNpcmNsZSA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnQ2lyY2xlJyxcbiAgICAgICdjaXJjbGUnLFxuICAgICAgJ2Jvb2xlYW4nLFxuICAgICAgJ3B1dCBkZXB0aHMgaW4gY29uY2VudHJpYyBjaXJjbGVzIGlmIHRydWUsIHB1dCBkZXB0aHMgdG9wIGRvd24gaWYgZmFsc2UnXG4gICAgKTtcbiAgICBsZXQgbWF4aW1hbEFkanVzdG1lbnRzID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdNYXhpbWFsIEFkanVzdG1lbnRzJyxcbiAgICAgICdtYXhpbWFsQWRqdXN0bWVudHMnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnaG93IG1hbnkgdGltZXMgdG8gdHJ5IHRvIHBvc2l0aW9uIHRoZSBub2RlcyBpbiBhIG1heGltYWwgd2F5IChpLmUuIG5vIGJhY2t0cmFja2luZyknXG4gICAgKTtcbiAgICBsZXQgbWF4aW1hbCA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnTWF4aW1hbCcsXG4gICAgICAnbWF4aW1hbCcsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAnd2hldGhlciB0byBzaGlmdCBub2RlcyBkb3duIHRoZWlyIG5hdHVyYWwgQkZTIGRlcHRocyBpbiBvcmRlciB0byBhdm9pZCB1cHdhcmRzIGVkZ2VzIChEQUdTIG9ubHkpJ1xuICAgICk7XG4gICAgbGV0IGdyaWQgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ0dyaWQnLFxuICAgICAgJ2dyaWQnLFxuICAgICAgJ2Jvb2xlYW4nLFxuICAgICAgJ3doZXRoZXIgdG8gc2hpZnQgbm9kZXMgZG93biB0aGVpciBuYXR1cmFsIEJGUyBkZXB0aHMgaW4gb3JkZXIgdG8gYXZvaWQgdXB3YXJkcyBlZGdlcyAoREFHUyBvbmx5KSdcbiAgICApO1xuICAgIGxldCByb290cyA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnUm9vdHMnLFxuICAgICAgJ3Jvb3RzJyxcbiAgICAgICdzdHJpbmcnLFxuICAgICAgJ3RoZSByb290cyBvZiB0aGUgdHJlZXMnXG4gICAgKTtcbiAgICBsZXQgYnJlYWR0aEZpcnN0RmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKFxuICAgICAgJ0JyZWFkdGggRmlyc3QnLFxuICAgICAgW2RpcmVjdGVkLCBjaXJjbGUsIG1heGltYWxBZGp1c3RtZW50cywgbWF4aW1hbCwgZ3JpZCwgcm9vdHNdLFxuICAgICAgWydicmVhZHRoRmlyc3QnXVxuICAgICk7XG5cbiAgICBsZXQgbm9kZVNlcCA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnTm9kZSBTZXBhcmF0aW9uJyxcbiAgICAgICdub2RlU2VwJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ3RoZSBzZXBhcmF0aW9uIGJldHdlZW4gYWRqYWNlbnQgbm9kZXMgaW4gdGhlIHNhbWUgcmFuaydcbiAgICApO1xuICAgIGxldCBlZGdlU2VwID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdFZGdlIFNlcGFyYXRpb24nLFxuICAgICAgJ2VkZ2VTZXAnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAndGhlIHNlcGFyYXRpb24gYmV0d2VlbiBhZGphY2VudCBlZGdlcyBpbiB0aGUgc2FtZSByYW5rJ1xuICAgICk7XG4gICAgbGV0IHJhbmtTZXAgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ1JhbmsgU2VwYXJhdGlvbicsXG4gICAgICAncmFua1NlcCcsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICd0aGUgc2VwYXJhdGlvbiBiZXR3ZWVuIGVhY2ggcmFuayBpbiB0aGUgbGF5b3V0J1xuICAgICk7XG4gICAgbGV0IHJhbmtlciA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnUmFua2VyJyxcbiAgICAgICdyYW5rZXInLFxuICAgICAgJ29wdGlvbnMnLFxuICAgICAgJ1R5cGUgb2YgYWxnb3JpdGhtIHRvIGFzc2lnbiBhIHJhbmsgdG8gZWFjaCBub2RlIGluIHRoZSBpbnB1dCBncmFwaC4nXG4gICAgKTtcbiAgICByYW5rZXIub3B0aW9ucyA9IFtcbiAgICAgIHsgbmFtZTogJycsIGxhYmVsOiAnJyB9LFxuICAgICAgeyBuYW1lOiAnbmV0d29yay1zaW1wbGV4JywgbGFiZWw6ICduZXR3b3JrLXNpbXBsZXgnIH0sXG4gICAgICB7IG5hbWU6ICd0aWdodC10cmVlJywgbGFiZWw6ICd0aWdodC10cmVlJyB9LFxuICAgICAgeyBuYW1lOiAnbG9uZ2VzdC1wYXRoJywgbGFiZWw6ICdsb25nZXN0LXBhdGgnIH0sXG4gICAgXTtcblxuICAgIGxldCBkYWdyZUZpZWxkc2V0ID0gbmV3IEZpZWxkc2V0SW5mbyhcbiAgICAgICdEYWdyZScsXG4gICAgICBbbm9kZVNlcCwgZWRnZVNlcCwgcmFua1NlcCwgcmFua2VyXSxcbiAgICAgIFsnbm9kZVNlcCddXG4gICAgKTtcblxuICAgIGxldCBhbmltYXRpb25UaHJlc2hvbGQgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ0FuaW1hdGlvbiBUaHJlc2hvbGQnLFxuICAgICAgJ2FuaW1hdGlvblRocmVzaG9sZCcsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdUaGUgbGF5b3V0IGFuaW1hdGVzIG9ubHkgYWZ0ZXIgdGhpcyBtYW55IG1pbGxpc2Vjb25kcyB3aGVuIGFuaW1hdGUgaXMgdHJ1ZSAocHJldmVudHMgZmxhc2hpbmcgb24gZmFzdCBydW5zKSdcbiAgICApO1xuICAgIGxldCByZWZyZXNoID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdSZWZyZXNoJyxcbiAgICAgICdyZWZyZXNoJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ051bWJlciBvZiBpdGVyYXRpb25zIGJldHdlZW4gY29uc2VjdXRpdmUgc2NyZWVuIHBvc2l0aW9ucyB1cGRhdGUnXG4gICAgKTtcbiAgICBsZXQgcmFuZG9taXplID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdSYW5kb21pemUnLFxuICAgICAgJ3JhbmRvbWl6ZScsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAnUmFuZG9taXplIHRoZSBpbml0aWFsIHBvc2l0aW9ucyBvZiB0aGUgbm9kZXMgKHRydWUpIG9yIHVzZSBleGlzdGluZyBwb3NpdGlvbnMgKGZhbHNlKSdcbiAgICApO1xuICAgIGxldCBjb21wb25lbnRTcGFjaW5nID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdDb21wb25lbnQgU3BhY2luZycsXG4gICAgICAnY29tcG9uZW50U3BhY2luZycsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdFeHRyYSBzcGFjaW5nIGJldHdlZW4gY29tcG9uZW50cyBpbiBub24tY29tcG91bmQgZ3JhcGhzJ1xuICAgICk7XG4gICAgbGV0IG5vZGVPdmVybGFwID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdOb2RlIE92ZXJsYXAnLFxuICAgICAgJ25vZGVPdmVybGFwJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ05vZGUgcmVwdWxzaW9uIChvdmVybGFwcGluZykgbXVsdGlwbGllcidcbiAgICApO1xuICAgIGxldCBuZXN0aW5nRmFjdG9yID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdOZXN0aW5nIEZhY3RvcicsXG4gICAgICAnbmVzdGluZ0ZhY3RvcicsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdOZXN0aW5nIGZhY3RvciAobXVsdGlwbGllcikgdG8gY29tcHV0ZSBpZGVhbCBlZGdlIGxlbmd0aCBmb3IgbmVzdGVkIGVkZ2VzJ1xuICAgICk7XG4gICAgbGV0IGdyYXZpdHkgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ0dyYXZpdHknLFxuICAgICAgJ2dyYXZpdHknLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnR3Jhdml0eSBmb3JjZSAoY29uc3RhbnQpJ1xuICAgICk7XG4gICAgbGV0IG51bUl0ZXIgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ01heCBJdGVyYXRpb25zJyxcbiAgICAgICdudW1JdGVyJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ01heGltdW0gbnVtYmVyIG9mIGl0ZXJhdGlvbnMgdG8gcGVyZm9ybSdcbiAgICApO1xuICAgIGxldCBpbml0aWFsVGVtcCA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnSW5pdGlhbCBUZW1wJyxcbiAgICAgICdpbml0aWFsVGVtcCcsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdJbml0aWFsIHRlbXBlcmF0dXJlIChtYXhpbXVtIG5vZGUgZGlzcGxhY2VtZW50KSdcbiAgICApO1xuICAgIGxldCBjb29saW5nRmFjdG9yID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdDb29saW5nIEZhY3RvcicsXG4gICAgICAnY29vbGluZ0ZhY3RvcicsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdDb29saW5nIGZhY3RvciAoaG93IHRoZSB0ZW1wZXJhdHVyZSBpcyByZWR1Y2VkIGJldHdlZW4gY29uc2VjdXRpdmUgaXRlcmF0aW9ucydcbiAgICApO1xuICAgIGxldCBtaW5UZW1wID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdNaW4uIFRlbXAnLFxuICAgICAgJ21pblRlbXAnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnTG93ZXIgdGVtcGVyYXR1cmUgdGhyZXNob2xkIChiZWxvdyB0aGlzIHBvaW50IHRoZSBsYXlvdXQgd2lsbCBlbmQpJ1xuICAgICk7XG4gICAgbGV0IGNvc2VGaWVsZHNldCA9IG5ldyBGaWVsZHNldEluZm8oXG4gICAgICAnQ09TRScsXG4gICAgICBbXG4gICAgICAgIGFuaW1hdGlvblRocmVzaG9sZCxcbiAgICAgICAgcmVmcmVzaCxcbiAgICAgICAgcmFuZG9taXplLFxuICAgICAgICBjb21wb25lbnRTcGFjaW5nLFxuICAgICAgICBub2RlT3ZlcmxhcCxcbiAgICAgICAgbmVzdGluZ0ZhY3RvcixcbiAgICAgICAgZ3Jhdml0eSxcbiAgICAgICAgbnVtSXRlcixcbiAgICAgICAgaW5pdGlhbFRlbXAsXG4gICAgICAgIGNvb2xpbmdGYWN0b3IsXG4gICAgICAgIG1pblRlbXAsXG4gICAgICBdLFxuICAgICAgWydjb29saW5nRmFjdG9yJ11cbiAgICApO1xuXG4gICAgbGV0IGF2b2lkT3ZlcmxhcFBhZGRpbmcgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ2F2b2lkT3ZlcmxhcFBhZGRpbmcnLFxuICAgICAgJ2F2b2lkT3ZlcmxhcFBhZGRpbmcnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnZXh0cmEgc3BhY2luZyBhcm91bmQgbm9kZXMgd2hlbiBhdm9pZE92ZXJsYXA6IHRydWUnXG4gICAgKTtcbiAgICBsZXQgY29uZGVuc2UgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ2NvbmRlbnNlJyxcbiAgICAgICdjb25kZW5zZScsXG4gICAgICAnYm9vbGVhbicsXG4gICAgICAndXNlcyBhbGwgYXZhaWxhYmxlIHNwYWNlIG9uIGZhbHNlLCB1c2VzIG1pbmltYWwgc3BhY2Ugb24gdHJ1ZSdcbiAgICApO1xuICAgIGxldCByb3dzID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdSb3dzJyxcbiAgICAgICdyb3dzJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ2ZvcmNlIG51bSBvZiByb3dzIGluIHRoZSBncmlkJ1xuICAgICk7XG4gICAgbGV0IGNvbHMgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ0NvbHVtbnMnLFxuICAgICAgJ2NvbHMnLFxuICAgICAgJ251bWJlcicsXG4gICAgICAnZm9yY2UgbnVtIG9mIGNvbHVtbnMgaW4gdGhlIGdyaWQnXG4gICAgKTtcblxuICAgIGxldCBncmlkRmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKFxuICAgICAgJ0dyaWQnLFxuICAgICAgW2F2b2lkT3ZlcmxhcFBhZGRpbmcsIGNvbmRlbnNlLCByb3dzLCBjb2xzXSxcbiAgICAgIFsnY29scyddXG4gICAgKTtcblxuICAgIGxldCByYWRpdXMgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ1JhZGl1cycsXG4gICAgICAncmFkaXVzJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ3RoZSByYWRpdXMgb2YgdGhlIGNpcmNsZSdcbiAgICApO1xuICAgIGxldCBzdGFydEFuZ2xlID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdTdGFydCBBbmdsZScsXG4gICAgICAnc3RhcnRBbmdsZScsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICd3aGVyZSBub2RlcyBzdGFydCBpbiByYWRpYW5zIChkZWZhdWx0OjMgLyAyICogTWF0aC5QSSknXG4gICAgKTtcbiAgICBsZXQgc3dlZXAgPSBuZXcgRmllbGRJbmZvKFxuICAgICAgJ1N3ZWVwJyxcbiAgICAgICdzd2VlcCcsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICdob3cgbWFueSByYWRpYW5zIHNob3VsZCBiZSBiZXR3ZWVuIHRoZSBmaXJzdCBhbmQgbGFzdCBub2RlIChkZWZhdWx0cyB0byBmdWxsIGNpcmNsZSknXG4gICAgKTtcbiAgICBsZXQgY2xvY2t3aXNlID0gbmV3IEZpZWxkSW5mbyhcbiAgICAgICdDbG9ja3dpc2UnLFxuICAgICAgJ2Nsb2Nrd2lzZScsXG4gICAgICAnbnVtYmVyJyxcbiAgICAgICd3aGV0aGVyIHRoZSBsYXlvdXQgc2hvdWxkIGdvIGNsb2Nrd2lzZSAodHJ1ZSkgb3IgY291bnRlcmNsb2Nrd2lzZS9hbnRpY2xvY2t3aXNlIChmYWxzZSknXG4gICAgKTtcbiAgICBsZXQgY2lyY3VsYXJGaWVsZFNldCA9IG5ldyBGaWVsZHNldEluZm8oXG4gICAgICAnQ2lyY3VsYXInLFxuICAgICAgW3JhZGl1cywgc3RhcnRBbmdsZSwgc3dlZXAsIGNsb2Nrd2lzZV0sXG4gICAgICBbJ2Nsb2Nrd2lzZSddXG4gICAgKTtcblxuICAgIGxldCBlcXVpZGlzdGFudCA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnRXF1aWRpc3RhbnQnLFxuICAgICAgJ2VxdWlkaXN0YW50JyxcbiAgICAgICdib29sZWFuJyxcbiAgICAgICd3aGV0aGVyIGxldmVscyBoYXZlIGFuIGVxdWFsIHJhZGlhbCBkaXN0YW5jZSBiZXR3ZW4gdGhlbSwgbWF5IGNhdXNlIGJvdW5kaW5nIGJveCBvdmVyZmxvdydcbiAgICApO1xuICAgIGxldCBtaW5Ob2RlU3BhY2luZyA9IG5ldyBGaWVsZEluZm8oXG4gICAgICAnTWluLiBOb2RlIFNwYWNpbmcnLFxuICAgICAgJ21pbk5vZGVTcGFjaW5nJyxcbiAgICAgICdudW1iZXInLFxuICAgICAgJ21pbiBzcGFjaW5nIGJldHdlZW4gb3V0c2lkZSBvZiBub2RlcyAodXNlZCBmb3IgcmFkaXVzIGFkanVzdG1lbnQpJ1xuICAgICk7XG4gICAgbGV0IGhlaWdodCA9IG5ldyBGaWVsZEluZm8oJ0hlaWdodCcsICdoZWlnaHQnLCAnbnVtYmVyJywgJycpO1xuICAgIGxldCB3aWR0aCA9IG5ldyBGaWVsZEluZm8oJ1dpZHRoJywgJ3dpZHRoJywgJ251bWJlcicsICcnKTtcbiAgICBsZXQgY29uY2VudHJpY0ZpZWxkU2V0ID0gbmV3IEZpZWxkc2V0SW5mbyhcbiAgICAgICdDb25jZW50cmljJyxcbiAgICAgIFtlcXVpZGlzdGFudCwgbWluTm9kZVNwYWNpbmcsIHN0YXJ0QW5nbGUsIGhlaWdodCwgd2lkdGhdLFxuICAgICAgWydlcXVpZGlzdGFudCddXG4gICAgKTtcblxuICAgIC8vYm91bmRpbmdCb3g6IHVuZGVmaW5lZCAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cblxuICAgIHJldHVybiBuZXcgRm9ybUluZm8oXG4gICAgICAnTGF5b3V0JyxcbiAgICAgIFtcbiAgICAgICAgYnJlYWR0aEZpcnN0RmllbGRzZXQsXG4gICAgICAgIGNvc2VGaWVsZHNldCxcbiAgICAgICAgZGFncmVGaWVsZHNldCxcbiAgICAgICAgZ3JpZEZpZWxkc2V0LFxuICAgICAgICBjaXJjdWxhckZpZWxkU2V0LFxuICAgICAgICBjb25jZW50cmljRmllbGRTZXQsXG4gICAgICAgIGZpdEZpZWxkc2V0LFxuICAgICAgICBhbmltYXRpb25GaWVsZHNldCxcbiAgICAgICAgc2hhcGVkRmllbGRzZXQsXG4gICAgICBdLFxuICAgICAgZmFsc2VcbiAgICApO1xuICB9XG59XG4vKlxuICAgIDwhLS1cblxuICAgICAgRGFncmVcbiAgICAgICAgLy8gVHlwZSBvZiBhbGdvcml0aG0gdG8gYXNzaWduIGEgcmFuayB0byBlYWNoIG5vZGUgaW4gdGhlIGlucHV0IGdyYXBoLlxuICAgICAgICAvLyBQb3NzaWJsZSB2YWx1ZXM6XG4gICAgICAgIGMgPSB1bmRlZmluZWRcbiAgICAgICAgLy8gbnVtYmVyIG9mIHJhbmtzIHRvIGtlZXAgYmV0d2VlbiB0aGUgc291cmNlIGFuZCB0YXJnZXQgb2YgdGhlIGVkZ2VcbiAgICAgICAgbWluTGVuID0gKCBlZGdlICkgPT4geyByZXR1cm4gMSB9XG4gICAgICAgIGVkZ2VXZWlnaHQgPSAoIGVkZ2UgKSA9PiB7IHJldHVybiAxIH0gLy8gaGlnaGVyIHdlaWdodCBlZGdlcyBhcmUgZ2VuZXJhbGx5IG1hZGUgc2hvcnRlciBhbmQgc3RyYWlnaHRlciB0aGFuIGxvd2VyIHdlaWdodCBlZGdlc1xuXG4gICAgQW5pbWF0ZUxheW91dE9wdGlvbnNJbXBsXG4gICAgICAvLyBhIGZ1bmN0aW9uIHRoYXQgZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBub2RlIHNob3VsZCBiZSBhbmltYXRlZC5cbiAgICAgIC8vIEFsbCBub2RlcyBhbmltYXRlZCBieSBkZWZhdWx0IG9uIGFuaW1hdGUgZW5hYmxlZC4gIE5vbi1hbmltYXRlZCBub2RlcyBhcmVcbiAgICAgIC8vIHBvc2l0aW9uZWQgaW1tZWRpYXRlbHkgd2hlbiB0aGUgbGF5b3V0IHN0YXJ0c1xuICAgICAgYW5pbWF0ZUZpbHRlciA9ICggbm9kZSwgaSApID0+IHRydWVcblxuICAgICAgUHJlc2V0XG4gICAgICAvLyBtYXAgb2YgKG5vZGUgaWQpID0+IChwb3NpdGlvbiBvYmopOyBvciBmdW5jdGlvbihub2RlKXsgcmV0dXJuIHNvbVBvczsgfVxuICAgICAgcG9zaXRpb25zOiB1bmRlZmluZWRcblxuICAgICAgU2hhcGVkXG4gICAgICAgIC8vIGNvbnN0cmFpbiBsYXlvdXQgYm91bmRzXG4gICAgICAgIGJvdW5kaW5nQm94PzogQm91bmRpbmdCb3gxMiB8IEJvdW5kaW5nQm94V0ggfCB1bmRlZmluZWQgPSB1bmRlZmluZWRcblxuICAgICAgICAvLyBhIHNvcnRpbmcgZnVuY3Rpb24gdG8gb3JkZXIgdGhlIG5vZGVzOyBlLmcuIGZ1bmN0aW9uKGEsIGIpeyByZXR1cm4gYS5kYXRhKCd3ZWlnaHQnKSAtIGIuZGF0YSgnd2VpZ2h0JykgfVxuICAgICAgICBzb3J0PzogU29ydGluZ0Z1bmN0aW9uID0gdW5kZWZpbmVkXG4gICAgICAgIC8vIHRyYW5zZm9ybSBhIGdpdmVuIG5vZGUgcG9zaXRpb24uIFVzZWZ1bCBmb3IgY2hhbmdpbmcgZmxvdyBkaXJlY3Rpb24gaW4gZGlzY3JldGUgbGF5b3V0c1xuICAgICAgICB0cmFuc2Zvcm0gPSAobm9kZSwgcG9zaXRpb24gKSA9PiBwb3NpdGlvblxuXG4gICAgICAvL0dyaWRcbiAgICAgICAgLy8gcmV0dXJucyB7IHJvdywgY29sIH0gZm9yIGVsZW1lbnRcbiAgICAgICAgLy8gKG5vZGU6IE5vZGVTaW5ndWxhcikgPT4gcmV0dXJuIHsgcm93OiBudW1iZXI7IGNvbDogbnVtYmVyOyB9XG4gICAgICAgIHBvc2l0aW9uID0gdW5kZWZpbmVkXG5cbiAgICAgIC8vUmFuZG9tXG4gICAgICAgIC8vIGNvbnN0cmFpbiBsYXlvdXQgYm91bmRzOyB7IHgxLCB5MSwgeDIsIHkyIH0gb3IgeyB4MSwgeTEsIHcsIGggfVxuICAgICAgICBib3VuZGluZ0JveDogY3l0b3NjYXBlLkJvdW5kaW5nQm94MTIgfCBjeXRvc2NhcGUuQm91bmRpbmdCb3hXSCB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZFxuICAgICAgICAvLyB0cmFuc2Zvcm0gYSBnaXZlbiBub2RlIHBvc2l0aW9uLiBVc2VmdWwgZm9yIGNoYW5naW5nIGZsb3cgZGlyZWN0aW9uIGluIGRpc2NyZXRlIGxheW91dHNcbiAgICAgICAgdHJhbnNmb3JtID0gKG5vZGUsIHBvc2l0aW9uICkgPT4gcG9zaXRpb25cblxuICAgICAgLy9DaXJjdWxhclxuICAgICAgLy9Db25lY250cmljXG4gICAgICAgIGNvbmNlbnRyaWMobm9kZTogeyBkZWdyZWUoKTogbnVtYmVyIH0pOiBudW1iZXIge1xuICAgICAgICAgIGV0dXJuIDBcbiAgICAgICAgfVxuXG4gICAgICAgIGxldmVsV2lkdGgobm9kZTogeyBtYXhEZWdyZWUoKTogbnVtYmVyIH0pOiBudW1iZXIge1xuICAgICAgICAgIHJldHVybiAwXG4gICAgICAgIH1cblxuICAgICAgICBCcmVhZHRoIEZpcnN0XG5cbiAgICAgICAgIENvc2VMYXlvdXRPcHRpb25zSW1wbFxuXG4gICAgICAgICAgLy8gTm9kZSByZXB1bHNpb24gKG5vbiBvdmVybGFwcGluZykgbXVsdGlwbGllclxuICAgICAgICAgIG5vZGVSZXB1bHNpb24gPSAgZnVuY3Rpb24oIG5vZGUgKXsgcmV0dXJuIDIwNDggfVxuXG4gICAgICAgICAgLy8gSWRlYWwgZWRnZSAobm9uIG5lc3RlZCkgbGVuZ3RoXG4gICAgICAgICAgaWRlYWxFZGdlTGVuZ3RoID0gKCBlZGdlICkgPT4geyByZXR1cm4gMzIgfVxuXG4gICAgICAgICAgLy8gRGl2aXNvciB0byBjb21wdXRlIGVkZ2UgZm9yY2VzXG4gICAgICAgICAgZWRnZUVsYXN0aWNpdHkgPSAoIGVkZ2UgKSA9PiAzMlxuXG4gICAgLS0+XG4gKi9cbiJdfQ==