UNPKG

cytoscape-angular

Version:
239 lines (236 loc) 46.9 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 "primeng/dropdown"; import * as i2 from "@angular/forms"; import * as i3 from "primeng/button"; import * as i4 from "../fluid-form/fluid-form.component"; const _c0 = ["layoutForm"]; export class CytoscapeLayoutToolComponent { constructor() { this.changed = false; this.layoutOptionsChange = new EventEmitter(); this.layoutOptionsList = [ new BreadthFirstLayoutOptionsImpl(), new CoseLayoutOptionsImpl(), new DagreLayoutOptionsImpl(), new CircleLayoutOptionsImpl(), new ConcentricLayoutOptionsImpl(), new GridLayoutOptionsImpl(), new PresetLayoutOptionsImpl(), new RandomLayoutOptionsImpl(), new NullLayoutOptionsImpl(), ]; } get layoutOptions() { return this._layoutOptions; } set layoutOptions(value) { console.log(`set layoutOptions: ${value === null || value === void 0 ? void 0 : value.name}`); this._layoutOptions = value; } 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); } } CytoscapeLayoutToolComponent.LAYOUT_FORM_INFO = CytoscapeLayoutToolComponent.createLayoutFormInfo(); CytoscapeLayoutToolComponent.ɵfac = function CytoscapeLayoutToolComponent_Factory(t) { return new (t || CytoscapeLayoutToolComponent)(); }; CytoscapeLayoutToolComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CytoscapeLayoutToolComponent, selectors: [["cytoscape-layout-tool"]], viewQuery: function CytoscapeLayoutToolComponent_Query(rf, ctx) { if (rf & 1) { i0.ɵɵviewQuery(_c0, 5); } if (rf & 2) { let _t; i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.layoutForm = _t.first); } }, inputs: { layoutOptions: "layoutOptions" }, outputs: { layoutOptionsChange: "layoutOptionsChange" }, features: [i0.ɵɵNgOnChangesFeature], decls: 8, vars: 5, consts: [[2, "display", "flex"], [1, "layout-header"], ["name", "selectedLayoutInfo", "optionLabel", "name", 1, "layout-dropdown", 3, "options", "ngModel", "ngModelChange"], ["pButton", "", "label", "Apply", 1, "apply-button", 3, "disabled", "click"], [3, "model", "formInfo", "modelChange"]], template: function CytoscapeLayoutToolComponent_Template(rf, ctx) { if (rf & 1) { i0.ɵɵelementStart(0, "div"); i0.ɵɵelementStart(1, "div", 0); i0.ɵɵelementStart(2, "div", 1); i0.ɵɵtext(3, "Edit Layout"); i0.ɵɵelementEnd(); i0.ɵɵelementEnd(); i0.ɵɵelementStart(4, "p-dropdown", 2); i0.ɵɵlistener("ngModelChange", function CytoscapeLayoutToolComponent_Template_p_dropdown_ngModelChange_4_listener($event) { return ctx.layoutOptions = $event; })("ngModelChange", function CytoscapeLayoutToolComponent_Template_p_dropdown_ngModelChange_4_listener() { return ctx.onLayoutModelChange(); }); i0.ɵɵtext(5, " >"); i0.ɵɵelementEnd(); i0.ɵɵelementStart(6, "button", 3); i0.ɵɵlistener("click", function CytoscapeLayoutToolComponent_Template_button_click_6_listener() { return ctx.onApplyLayout(); }); i0.ɵɵelementEnd(); i0.ɵɵelementEnd(); i0.ɵɵelementStart(7, "cyng-fluid-form", 4); i0.ɵɵlistener("modelChange", function CytoscapeLayoutToolComponent_Template_cyng_fluid_form_modelChange_7_listener() { return ctx.onFormModelChange(); }); i0.ɵɵelementEnd(); } if (rf & 2) { i0.ɵɵadvance(4); i0.ɵɵproperty("options", ctx.layoutOptionsList)("ngModel", ctx.layoutOptions); i0.ɵɵadvance(2); i0.ɵɵproperty("disabled", !ctx.changed); i0.ɵɵadvance(1); i0.ɵɵproperty("model", ctx.layoutOptions)("formInfo", ctx.formInfo); } }, directives: [i1.Dropdown, i2.NgControlStatus, i2.NgModel, i3.ButtonDirective, i4.FluidFormComponent], styles: ["[_nghost-%COMP%] {\n width: 400px;\n height: 2em;\n }\n\n .layout-header[_ngcontent-%COMP%] {\n width: 100%;\n height: 20px;\n }\n\n .layout-dropdown[_ngcontent-%COMP%] {\n padding-right: 10px;\n }\n\n input[_ngcontent-%COMP%]:disabled {\n background-color: rgba(204, 204, 204, .33);\n }"] }); (function () { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CytoscapeLayoutToolComponent, [{ type: Component, args: [{ selector: 'cytoscape-layout-tool', styles: [ ` :host { width: 400px; height: 2em; } .layout-header { width: 100%; height: 20px; } .layout-dropdown { padding-right: 10px; } input:disabled { background-color: rgba(204, 204, 204, .33); } ` ], 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> ` }] }], function () { return []; }, { layoutForm: [{ type: ViewChild, args: ['layoutForm'] }], layoutOptions: [{ type: Input }], layoutOptionsChange: [{ type: Output }] }); })(); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3l0b3NjYXBlLWxheW91dC10b29sLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2N5dG9zY2FwZS1hbmd1bGFyL3NyYy9saWIvY3l0b3NjYXBlLWxheW91dC10b29sL2N5dG9zY2FwZS1sYXlvdXQtdG9vbC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUdMLFNBQVMsRUFDVCxZQUFZLEVBRVosS0FBSyxFQUdMLE1BQU0sRUFFTixTQUFTLEVBQ1YsTUFBTSxlQUFlLENBQUE7QUFFdEIsT0FBTyxFQUFFLDZCQUE2QixFQUFFLHVCQUF1QixFQUFFLDJCQUEyQixFQUFFLHFCQUFxQixFQUNqSCxzQkFBc0IsRUFBRSxxQkFBcUIsRUFBRSxxQkFBcUIsRUFBRSx1QkFBdUIsRUFBRSx1QkFBdUIsRUFDdkgsTUFBTSwrQkFBK0IsQ0FBQTtBQUN0QyxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQTs7Ozs7OztBQXlDM0UsTUFBTSxPQUFPLDRCQUE0QjtJQWdDdkM7UUExQkEsWUFBTyxHQUFHLEtBQUssQ0FBQTtRQVVMLHdCQUFtQixHQUFnQyxJQUFJLFlBQVksRUFBaUIsQ0FBQTtRQUV2RixzQkFBaUIsR0FBb0I7WUFDMUMsSUFBSSw2QkFBNkIsRUFBRTtZQUNuQyxJQUFJLHFCQUFxQixFQUFFO1lBQzNCLElBQUksc0JBQXNCLEVBQUU7WUFDNUIsSUFBSSx1QkFBdUIsRUFBRTtZQUM3QixJQUFJLDJCQUEyQixFQUFFO1lBQ2pDLElBQUkscUJBQXFCLEVBQUU7WUFDM0IsSUFBSSx1QkFBdUIsRUFBRTtZQUM3QixJQUFJLHVCQUF1QixFQUFFO1lBQzdCLElBQUkscUJBQXFCLEVBQUU7U0FDNUIsQ0FBQTtJQUtELENBQUM7SUF6QkQsSUFDSSxhQUFhO1FBQ2YsT0FBTyxJQUFJLENBQUMsY0FBYyxDQUFBO0lBQzVCLENBQUM7SUFDRCxJQUFJLGFBQWEsQ0FBQyxLQUFLO1FBQ3JCLE9BQU8sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLEtBQUssYUFBTCxLQUFLLHVCQUFMLEtBQUssQ0FBRSxJQUFJLEVBQUUsQ0FBQyxDQUFBO1FBQ2hELElBQUksQ0FBQyxjQUFjLEdBQUcsS0FBSyxDQUFBO0lBQzdCLENBQUM7SUFvQkQsUUFBUTtRQUNOLElBQUksQ0FBQyxRQUFRLEdBQUcsNEJBQTRCLENBQUMsb0JBQW9CLEVBQUUsQ0FBQTtRQUNuRSxJQUFJLG1CQUFtQixHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUNuRCxPQUFPLENBQUMsR0FBRyxDQUFDLGdEQUFnRCxFQUFFLG1CQUFtQixDQUFDLElBQUksQ0FBQyxDQUFBO1FBQ3ZGLElBQUksSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUN0QixPQUFPLENBQUMsR0FBRyxDQUFDLHFFQUFxRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDLENBQUE7WUFDdEgsSUFBSSxDQUFDLCtCQUErQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQTtTQUN6RDtRQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0VBQWdFLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUE7SUFDcEgsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxPQUFPLENBQUMsR0FBRyxDQUFDLDZCQUE2QixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQTtRQUNuRSxJQUFJLE9BQU8sQ0FBQyxlQUFlLENBQUMsRUFBRTtTQUU3QjtJQUNILENBQUM7SUFFRCxtQkFBbUI7UUFDakIsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFBO1FBQ3hFLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFBO0lBQ3JCLENBQUM7SUFFRCxpQkFBaUI7UUFDZixPQUFPLENBQUMsR0FBRyxDQUFDLG1CQUFtQixDQUFDLENBQUE7UUFDaEMsSUFBSSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUE7SUFDckIsQ0FBQztJQUVELGFBQWE7UUFDWCxJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQTtRQUNwQixJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQTtJQUNuRCxDQUFDO0lBRU8sK0JBQStCLENBQUMsYUFBNEI7UUFDbEUsSUFBSSxlQUFlLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxJQUFJLEtBQUssYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFBO1FBQzNHLElBQUksZUFBZSxFQUFFO1lBQ25CLE9BQU8sQ0FBQyxHQUFHLENBQUMsOEJBQThCLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFBO1lBQzVFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxlQUFlLENBQUMsRUFBRSxDQUFDLEVBQUUsYUFBYSxDQUFDLENBQUE7U0FDakc7YUFBTTtZQUNMLE9BQU8sQ0FBQyxJQUFJLENBQUMsdURBQXVELElBQUksMERBQTBELENBQUMsQ0FBQTtZQUNuSSxJQUFJLENBQUMsaUJBQWlCLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFBO1NBQzlDO0lBQ0gsQ0FBQztJQUVPLE1BQU0sQ0FBQyxvQkFBb0I7UUFDL0IsSUFBSSxHQUFHLEdBQUcsSUFBSSxTQUFTLENBQUMsS0FBSyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsNEJBQTRCLENBQUMsQ0FBQTtRQUM5RSxJQUFJLE9BQU8sR0FBRyxJQUFJLFNBQVMsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBQyxvREFBb0QsQ0FBQyxDQUFBO1FBRWhILElBQUksV0FBVyxHQUFHLElBQUksWUFBWSxDQUFDLEtBQUssRUFBRTtZQUN4QyxHQUFHLEVBQUUsT0FBTztTQUNiLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFBO1FBRVgsTUFBTSxJQUFJLEdBQUcsSUFBSSxTQUFTLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUMsd0RBQXdELENBQUMsQ0FBQTtRQUM3RyxNQUFNLEdBQUcsR0FBRyxJQUFJLFNBQVMsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLFFBQVEsRUFBQyx1REFBdUQsQ0FBQyxDQUFBO1FBQ3pHLE1BQU0sT0FBTyxHQUFHLElBQUksU0FBUyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsU0FBUyxFQUFFLDBDQUEwQyxDQUFDLENBQUE7UUFDMUcsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLFNBQVMsQ0FBQyxvQkFBb0IsRUFBRSxtQkFBbUIsRUFBRSxRQUFRLEVBQUMsd0NBQXdDLENBQUMsQ0FBQTtRQUNySSxNQUFNLGVBQWUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxrQkFBa0IsRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUMsZ0NBQWdDLENBQUMsQ0FBQTtRQUN2SCxJQUFJLGlCQUFpQixHQUFHLElBQUksWUFBWSxDQUFDLFdBQVcsRUFBRTtZQUNwRCxJQUFJLEVBQUUsR0FBRyxFQUFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxlQUFlO1NBQ3ZELEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFBO1FBR2YsSUFBSSxZQUFZLEdBQUcsSUFBSSxTQUFTLENBQUMsZUFBZSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUMscUVBQXFFLENBQUMsQ0FBQTtRQUNsSixJQUFJLGFBQWEsR0FBRyxJQUFJLFNBQVMsQ0FBQyxnQkFBZ0IsRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFDLG9HQUFvRyxDQUFDLENBQUE7UUFDbkwsSUFBSSwyQkFBMkIsR0FBRyxJQUFJLFNBQVMsQ0FBQyxnQ0FBZ0MsRUFBRSw2QkFBNkIsRUFBRSxTQUFTLEVBQUUsa0ZBQWtGLENBQUMsQ0FBQTtRQUMvTSxJQUFJLGNBQWMsR0FBRyxJQUFJLFlBQVksQ0FBQyxRQUFRLEVBQUU7WUFDOUMsWUFBWSxFQUFFLGFBQWEsRUFBRSwyQkFBMkI7U0FDekQsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUE7UUFFcEIsSUFBSSxRQUFRLEdBQUcsSUFBSSxTQUFTLENBQUMsVUFBVSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUUsMkZBQTJGLENBQUMsQ0FBQTtRQUNoSyxJQUFJLE1BQU0sR0FBRyxJQUFJLFNBQVMsQ0FBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBQyx3RUFBd0UsQ0FBQyxDQUFBO1FBQ2xJLElBQUksa0JBQWtCLEdBQUcsSUFBSSxTQUFTLENBQUMscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsUUFBUSxFQUFFLHFGQUFxRixDQUFDLENBQUE7UUFDcEwsSUFBSSxPQUFPLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsa0dBQWtHLENBQUMsQ0FBQTtRQUNoSyxJQUFJLElBQUksR0FBRyxJQUFJLFNBQVMsQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxrR0FBa0csQ0FBQyxDQUFBO1FBQ3ZKLElBQUksS0FBSyxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLHdCQUF3QixDQUFDLENBQUE7UUFDL0UsSUFBSSxvQkFBb0IsR0FBRyxJQUFJLFlBQVksQ0FBQyxlQUFlLEVBQUU7WUFDM0QsUUFBUSxFQUFFLE1BQU0sRUFBRSxrQkFBa0IsRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUs7U0FDM0QsRUFBRSxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUE7UUFFcEIsSUFBSSxPQUFPLEdBQUcsSUFBSSxTQUFTLENBQUMsaUJBQWlCLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSx3REFBd0QsQ0FBQyxDQUFBO1FBQzdILElBQUksT0FBTyxHQUFHLElBQUksU0FBUyxDQUFDLGlCQUFpQixFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQUUsd0RBQXdELENBQUMsQ0FBQTtRQUM3SCxJQUFJLE9BQU8sR0FBRyxJQUFJLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLGdEQUFnRCxDQUFDLENBQUE7UUFDckgsSUFBSSxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUscUVBQXFFLENBQUMsQ0FBQTtRQUNoSSxNQUFNLENBQUMsT0FBTyxHQUFHO1lBQ2YsRUFBQyxJQUFJLEVBQUUsRUFBRSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUM7WUFDckIsRUFBQyxJQUFJLEVBQUUsaUJBQWlCLEVBQUUsS0FBSyxFQUFFLGlCQUFpQixFQUFDO1lBQ25ELEVBQUMsSUFBSSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQUUsWUFBWSxFQUFDO1lBQ3pDLEVBQUMsSUFBSSxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsY0FBYyxFQUFDO1NBQUMsQ0FBQTtRQUVoRCxJQUFJLGFBQWEsR0FBRyxJQUFJLFlBQVksQ0FBQyxPQUFPLEVBQUU7WUFDNUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTTtTQUNsQyxFQUFFLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQTtRQUVmLElBQUksa0JBQWtCLEdBQUcsSUFBSSxTQUFTLENBQUMscUJBQXFCLEVBQUUsb0JBQW9CLEVBQUUsUUFBUSxFQUFFLDZHQUE2RyxDQUFDLENBQUE7UUFDNU0sSUFBSSxPQUFPLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLFNBQVMsRUFBRSxRQUFRLEVBQ3hELGtFQUFrRSxDQUFDLENBQUE7UUFDckUsSUFBSSxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsdUZBQXVGLENBQUMsQ0FBQTtRQUMzSixJQUFJLGdCQUFnQixHQUFHLElBQUksU0FBUyxDQUFDLG1CQUFtQixFQUFFLGtCQUFrQixFQUFFLFFBQVEsRUFBRSx5REFBeUQsQ0FBQyxDQUFBO1FBQ2xKLElBQUksV0FBVyxHQUFHLElBQUksU0FBUyxDQUFDLGNBQWMsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFFLHlDQUF5QyxDQUFDLENBQUE7UUFDbkgsSUFBSSxhQUFhLEdBQUcsSUFBSSxTQUFTLENBQUMsZ0JBQWdCLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSwyRUFBMkUsQ0FBQyxDQUFBO1FBQzNKLElBQUksT0FBTyxHQUFHLElBQUksU0FBUyxDQUFDLFNBQVMsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLDBCQUEwQixDQUFDLENBQUE7UUFDdkYsSUFBSSxPQUFPLEdBQUcsSUFBSSxTQUFTLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSx5Q0FBeUMsQ0FBQyxDQUFBO1FBQzdHLElBQUksV0FBVyxHQUFHLElBQUksU0FBUyxDQUFDLGNBQWMsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFFLGlEQUFpRCxDQUFDLENBQUE7UUFDM0gsSUFBSSxhQUFhLEdBQUcsSUFBSSxTQUFTLENBQUMsZ0JBQWdCLEVBQUUsZUFBZSxFQUFFLFFBQVEsRUFBRSwrRUFBK0UsQ0FBQyxDQUFBO1FBQy9KLElBQUksT0FBTyxHQUFHLElBQUksU0FBUyxDQUFDLFdBQVcsRUFBRSxTQUFTLEVBQUUsUUFBUSxFQUFFLG9FQUFvRSxDQUFDLENBQUE7UUFDbkksSUFBSSxZQUFZLEdBQUcsSUFBSSxZQUFZLENBQUMsTUFBTSxFQUFFO1lBQzFDLGtCQUFrQixFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUUsV0FBVyxFQUFFLGFBQWEsRUFBRSxPQUFPLEVBQUUsT0FBTztZQUN0RyxXQUFXLEVBQUUsYUFBYSxFQUFFLE9BQU87U0FDcEMsRUFBRSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUE7UUFFckIsSUFBSSxtQkFBbUIsR0FBRyxJQUFJLFNBQVMsQ0FBQyxxQkFBcUIsRUFBRSxxQkFBcUIsRUFBRSxRQUFRLEVBQUUsb0RBQW9ELENBQUMsQ0FBQTtRQUNySixJQUFJLFFBQVEsR0FBRyxJQUFJLFNBQVMsQ0FBQyxVQUFVLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSwrREFBK0QsQ0FBQyxDQUFBO1FBQ2hJLElBQUksSUFBSSxHQUFHLElBQUksU0FBUyxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLCtCQUErQixDQUFDLENBQUE7UUFDbkYsSUFBSSxJQUFJLEdBQUcsSUFBSSxTQUFTLENBQUMsU0FBUyxFQUFFLE1BQU0sRUFBRSxRQUFRLEVBQUUsa0NBQWtDLENBQUMsQ0FBQTtRQUV6RixJQUFJLFlBQVksR0FBRyxJQUFJLFlBQVksQ0FBQyxNQUFNLEVBQUU7WUFDMUMsbUJBQW1CLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxJQUFJO1NBQzFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFBO1FBRVosSUFBSSxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsMEJBQTBCLENBQUMsQ0FBQTtRQUNwRixJQUFJLFVBQVUsR0FBRyxJQUFJLFNBQVMsQ0FBQyxhQUFhLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSx3REFBd0QsQ0FBQyxDQUFBO1FBQy9ILElBQUksS0FBSyxHQUFHLElBQUksU0FBUyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLHNGQUFzRixDQUFDLENBQUE7UUFDN0ksSUFBSSxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsV0FBVyxFQUFFLFdBQVcsRUFBRSxRQUFRLEVBQUUseUZBQXlGLENBQUMsQ0FBQTtRQUM1SixJQUFJLGdCQUFnQixHQUFHLElBQUksWUFBWSxDQUFDLFVBQVUsRUFBRTtZQUNsRCxNQUFNLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTO1NBQ3JDLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFBO1FBRWpCLElBQUksV0FBVyxHQUFHLElBQUksU0FBUyxDQUFDLGFBQWEsRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLDJGQUEyRixDQUFDLENBQUE7UUFDckssSUFBSSxjQUFjLEdBQUcsSUFBSSxTQUFTLENBQUMsbUJBQW1CLEVBQUUsZ0JBQWdCLEVBQUUsUUFBUSxFQUFFLG1FQUFtRSxDQUFDLENBQUE7UUFDeEosSUFBSSxNQUFNLEdBQUcsSUFBSSxTQUFTLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDNUQsSUFBSSxLQUFLLEdBQUcsSUFBSSxTQUFTLENBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFDLENBQUE7UUFDekQsSUFBSSxrQkFBa0IsR0FBRyxJQUFJLFlBQVksQ0FBQyxZQUFZLEVBQUU7WUFDdEQsV0FBVyxFQUFFLGNBQWMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLEtBQUs7U0FDdkQsRUFBRSxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUE7UUFFbkIsMkZBQTJGO1FBRTNGLE9BQU8sSUFBSSxRQUFRLENBQUMsUUFBUSxFQUMxQjtZQUNFLG9CQUFvQixFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsWUFBWSxFQUFFLGdCQUFnQixFQUFFLGtCQUFrQjtZQUNyRyxXQUFXLEVBQUUsaUJBQWlCLEVBQUUsY0FBYztTQUFFLEVBQ2xELEtBQUssQ0FBQyxDQUFBO0lBQ1osQ0FBQzs7QUFoTGMsNkNBQWdCLEdBQWEsNEJBQTRCLENBQUMsb0JBQW9CLEVBQUUsQ0FBQTt3R0FEcEYsNEJBQTRCOytFQUE1Qiw0QkFBNEI7Ozs7OztRQWZyQywyQkFBSztRQUNILDhCQUE0QjtRQUMxQiw4QkFBMkI7UUFBQSwyQkFBVztRQUFBLGlCQUFNO1FBQzlDLGlCQUFNO1FBQ04scUNBSzBDO1FBRnhDLGlLQUEyQixnSEFFVix5QkFBcUIsSUFGWDtRQUc3QixrQkFBQztRQUFBLGlCQUFhO1FBQ2QsaUNBQW1HO1FBQTFCLHlHQUFTLG1CQUFlLElBQUM7UUFBQyxpQkFBUztRQUM5RyxpQkFBTTtRQUNOLDBDQUFtRztRQUFwQyw4SEFBZSx1QkFBbUIsSUFBQztRQUFDLGlCQUFrQjs7UUFQakgsZUFBNkI7UUFBN0IsK0NBQTZCLDhCQUFBO1FBS29CLGVBQXFCO1FBQXJCLHVDQUFxQjtRQUV6RCxlQUF1QjtRQUF2Qix5Q0FBdUIsMEJBQUE7O3VGQUUvQiw0QkFBNEI7Y0F2Q3hDLFNBQVM7ZUFBQztnQkFDVCxRQUFRLEVBQUUsdUJBQXVCO2dCQUNqQyxNQUFNLEVBQUU7b0JBQ047Ozs7Ozs7Ozs7Ozs7Ozs7OztLQWtCQztpQkFDRjtnQkFDRCxRQUFRLEVBQUU7Ozs7Ozs7Ozs7Ozs7OztHQWVUO2FBQUM7c0NBSXVCLFVBQVU7a0JBQWxDLFNBQVM7bUJBQUMsWUFBWTtZQU1uQixhQUFhO2tCQURoQixLQUFLO1lBUUksbUJBQW1CO2tCQUE1QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQWZ0ZXJWaWV3Q2hlY2tlZCxcbiAgQWZ0ZXJWaWV3SW5pdCxcbiAgQ29tcG9uZW50LFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3RMaXN0ZW5lcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25Jbml0LFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJ1xuaW1wb3J0IHsgTGF5b3V0T3B0aW9ucyB9IGZyb20gJ2N5dG9zY2FwZSdcbmltcG9ydCB7IEJyZWFkdGhGaXJzdExheW91dE9wdGlvbnNJbXBsLCBDaXJjbGVMYXlvdXRPcHRpb25zSW1wbCwgQ29uY2VudHJpY0xheW91dE9wdGlvbnNJbXBsLCBDb3NlTGF5b3V0T3B0aW9uc0ltcGwsXG4gIERhZ3JlTGF5b3V0T3B0aW9uc0ltcGwsIEdyaWRMYXlvdXRPcHRpb25zSW1wbCwgTnVsbExheW91dE9wdGlvbnNJbXBsLCBQcmVzZXRMYXlvdXRPcHRpb25zSW1wbCwgUmFuZG9tTGF5b3V0T3B0aW9uc0ltcGxcbn0gZnJvbSAnLi4vbGF5b3V0L2xheW91dC1vcHRpb25zLWltcGwnXG5pbXBvcnQgeyBGaWVsZEluZm8sIEZpZWxkc2V0SW5mbywgRm9ybUluZm8gfSBmcm9tICcuLi9mbHVpZC1mb3JtL2Zvcm0taW5mbydcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnY3l0b3NjYXBlLWxheW91dC10b29sJyxcbiAgc3R5bGVzOiBbXG4gICAgYFxuICAgICAgOmhvc3Qge1xuICAgICAgICB3aWR0aDogNDAwcHg7XG4gICAgICAgIGhlaWdodDogMmVtO1xuICAgICAgfVxuXG4gICAgICAubGF5b3V0LWhlYWRlciB7XG4gICAgICAgIHdpZHRoOiAxMDAlO1xuICAgICAgICBoZWlnaHQ6IDIwcHg7XG4gICAgICB9XG5cbiAgICAgIC5sYXlvdXQtZHJvcGRvd24ge1xuICAgICAgICBwYWRkaW5nLXJpZ2h0OiAxMHB4O1xuICAgICAgfVxuXG4gICAgICBpbnB1dDpkaXNhYmxlZCB7XG4gICAgICAgIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMjA0LCAyMDQsIDIwNCwgLjMzKTtcbiAgICAgIH1cbiAgICBgXG4gIF0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPGRpdj5cbiAgICAgIDxkaXYgc3R5bGU9XCJkaXNwbGF5OiBmbGV4O1wiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibGF5b3V0LWhlYWRlclwiPkVkaXQgTGF5b3V0PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxwLWRyb3Bkb3duIGNsYXNzPVwibGF5b3V0LWRyb3Bkb3duXCJcbiAgICAgICAgbmFtZT1cInNlbGVjdGVkTGF5b3V0SW5mb1wiXG4gICAgICAgIFtvcHRpb25zXT1cImxheW91dE9wdGlvbnNMaXN0XCJcbiAgICAgICAgWyhuZ01vZGVsKV09XCJsYXlvdXRPcHRpb25zXCJcbiAgICAgICAgb3B0aW9uTGFiZWw9XCJuYW1lXCJcbiAgICAgICAgKG5nTW9kZWxDaGFuZ2UpPVwib25MYXlvdXRNb2RlbENoYW5nZSgpXCI+XG4gICAgICA+PC9wLWRyb3Bkb3duPlxuICAgICAgPGJ1dHRvbiBjbGFzcz1cImFwcGx5LWJ1dHRvblwiIHBCdXR0b24gbGFiZWw9XCJBcHBseVwiIFtkaXNhYmxlZF09XCIhY2hhbmdlZFwiIChjbGljayk9XCJvbkFwcGx5TGF5b3V0KClcIj48L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgICA8Y3luZy1mbHVpZC1mb3JtIFttb2RlbF09XCJsYXlvdXRPcHRpb25zXCIgW2Zvcm1JbmZvXT1cImZvcm1JbmZvXCIgKG1vZGVsQ2hhbmdlKT1cIm9uRm9ybU1vZGVsQ2hhbmdlKClcIj48L2N5bmctZmx1aWQtZm9ybT5cbiAgYH0pXG5leHBvcnQgY2xhc3MgQ3l0b3NjYXBlTGF5b3V0VG9vbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcbiAgcHJpdmF0ZSBzdGF0aWMgTEFZT1VUX0ZPUk1fSU5GTzogRm9ybUluZm8gPSBDeXRvc2NhcGVMYXlvdXRUb29sQ29tcG9uZW50LmNyZWF0ZUxheW91dEZvcm1JbmZvKClcblxuICBAVmlld0NoaWxkKCdsYXlvdXRGb3JtJykgbGF5b3V0Rm9ybTtcblxuICBfbGF5b3V0T3B0aW9uczogYW55XG4gIGNoYW5nZWQgPSBmYWxzZVxuXG4gIEBJbnB1dCgpXG4gIGdldCBsYXlvdXRPcHRpb25zKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX2xheW91dE9wdGlvbnNcbiAgfVxuICBzZXQgbGF5b3V0T3B0aW9ucyh2YWx1ZSkge1xuICAgIGNvbnNvbGUubG9nKGBzZXQgbGF5b3V0T3B0aW9uczogJHt2YWx1ZT8ubmFtZX1gKVxuICAgIHRoaXMuX2xheW91dE9wdGlvbnMgPSB2YWx1ZVxuICB9XG4gIEBPdXRwdXQoKSBsYXlvdXRPcHRpb25zQ2hhbmdlOiBFdmVudEVtaXR0ZXI8TGF5b3V0T3B0aW9ucz4gPSBuZXcgRXZlbnRFbWl0dGVyPExheW91dE9wdGlvbnM+KClcblxuICBwdWJsaWMgbGF5b3V0T3B0aW9uc0xpc3Q6IExheW91dE9wdGlvbnNbXSA9IFtcbiAgICBuZXcgQnJlYWR0aEZpcnN0TGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgQ29zZUxheW91dE9wdGlvbnNJbXBsKCksXG4gICAgbmV3IERhZ3JlTGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgQ2lyY2xlTGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgICBuZXcgQ29uY2VudHJpY0xheW91dE9wdGlvbnNJbXBsKCksXG4gICAgbmV3IEdyaWRMYXlvdXRPcHRpb25zSW1wbCgpLFxuICAgIG5ldyBQcmVzZXRMYXlvdXRPcHRpb25zSW1wbCgpLFxuICAgIG5ldyBSYW5kb21MYXlvdXRPcHRpb25zSW1wbCgpLFxuICAgIG5ldyBOdWxsTGF5b3V0T3B0aW9uc0ltcGwoKSxcbiAgXVxuXG4gIGZvcm1JbmZvOiBGb3JtSW5mb1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtSW5mbyA9IEN5dG9zY2FwZUxheW91dFRvb2xDb21wb25lbnQuY3JlYXRlTGF5b3V0Rm9ybUluZm8oKVxuICAgIGxldCBsYXlvdXRPcHRpb25zU2VsZWN0ID0gdGhpcy5sYXlvdXRPcHRpb25zTGlzdFs1XVxuICAgIGNvbnNvbGUubG9nKCdzZXR0aW5nIHRoZSBpbml0aWFsIHNlbGVjdGVkIGxheW91dCwgZGVmYXVsdDogJywgbGF5b3V0T3B0aW9uc1NlbGVjdC5uYW1lKVxuICAgIGlmICh0aGlzLmxheW91dE9wdGlvbnMpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBzZXR0aW5nICB0aGUgaW5pdGlhbCBzZWxlY3RlZCBsYXlvdXQgYmFzZWQgb24gaW5wdXQvb3V0cHV0IGxheW91dCAke0pTT04uc3RyaW5naWZ5KHRoaXMubGF5b3V0T3B0aW9ucyl9YClcbiAgICAgIHRoaXMuYWRkT3JSZXBsYWNlSW5MYXlvdXRPcHRpb25zTGlzdCh0aGlzLmxheW91dE9wdGlvbnMpXG4gICAgfVxuICAgIGNvbnNvbGUubG9nKCdJbml0aWFsaXppbmcgdGhpcy5zZWxlY3RlZExheW91dEluZm8gd2l0aCBsYXlvdXRPcHRpb25zU2VsZWN0ICcsIEpTT04uc3RyaW5naWZ5KGxheW91dE9wdGlvbnNTZWxlY3QpKVxuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlczogU2ltcGxlQ2hhbmdlcyk6IHZvaWQge1xuICAgIGNvbnNvbGUubG9nKCduZ09uQ2hhbmdlcyBsYXlvdXQgY2hhbmdlczonLCBKU09OLnN0cmluZ2lmeShjaGFuZ2VzKSlcbiAgICBpZiAoY2hhbmdlc1snbGF5b3V0T3B0aW9ucyddKSB7XG5cbiAgICB9XG4gIH1cblxuICBvbkxheW91dE1vZGVsQ2hhbmdlKCkge1xuICAgIGNvbnNvbGUubG9nKCdMYXlvdXQgbW9kZWwgY2hhbmdlOiAnLCBKU09OLnN0cmluZ2lmeSh0aGlzLmxheW91dE9wdGlvbnMpKVxuICAgIHRoaXMuY2hhbmdlZCA9IHRydWVcbiAgfVxuXG4gIG9uRm9ybU1vZGVsQ2hhbmdlKCkge1xuICAgIGNvbnNvbGUubG9nKCdvbkZvcm1Nb2RlbENoYW5nZScpXG4gICAgdGhpcy5jaGFuZ2VkID0gdHJ1ZVxuICB9XG5cbiAgb25BcHBseUxheW91dCgpIHtcbiAgICB0aGlzLmNoYW5nZWQgPSBmYWxzZVxuICAgIHRoaXMubGF5b3V0T3B0aW9uc0NoYW5nZS5lbWl0KHRoaXMubGF5b3V0T3B0aW9ucylcbiAgfVxuXG4gIHByaXZhdGUgYWRkT3JSZXBsYWNlSW5MYXlvdXRPcHRpb25zTGlzdChsYXlvdXRPcHRpb25zOiBMYXlvdXRPcHRpb25zKTogdm9pZCB7XG4gICAgbGV0IG1hdGNoaW5nT3B0aW9ucyA9IHRoaXMubGF5b3V0T3B0aW9uc0xpc3QuZmluZChzZWxlY3RPcHRpb24gPT4gc2VsZWN0T3B0aW9uLm5hbWUgPT09IGxheW91dE9wdGlvbnMubmFtZSlcbiAgICBpZiAobWF0Y2hpbmdPcHRpb25zKSB7XG4gICAgICBjb25zb2xlLmxvZygnZ290IG1hdGNoaW5nIGxheW91dE9wdGlvbnM6ICcsIEpTT04uc3RyaW5naWZ5KG1hdGNoaW5nT3B0aW9ucykpXG4gICAgICB0aGlzLmxheW91dE9wdGlvbnNMaXN0LnNwbGljZSh0aGlzLmxheW91dE9wdGlvbnNMaXN0LmluZGV4T2YobWF0Y2hpbmdPcHRpb25zKSwgMSwgbGF5b3V0T3B0aW9ucylcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5pbmZvKGBEaWQgeW91IHBhc3MgYSBuZXcga2luZCBvZiBsYXlvdXQ/ICBUaGUgbGF5b3V0IG5hbWUgJHtuYW1lfSB3YXMgbm90IGZvdW5kLCBhZGRpbmcgYSBuZXcgb25lIHRvIHRoZSB0b3Agb2YgdGhlIGxpc3QuYClcbiAgICAgIHRoaXMubGF5b3V0T3B0aW9uc0xpc3QudW5zaGlmdChsYXlvdXRPcHRpb25zKVxuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGNyZWF0ZUxheW91dEZvcm1JbmZvKCk6IEZvcm1JbmZvIHtcbiAgICAgIGxldCBmaXQgPSBuZXcgRmllbGRJbmZvKCdGaXQnLCAnZml0JywgJ2Jvb2xlYW4nLCAnV2hldGhlciB0byBmaXQgdG8gdmlld3BvcnQnKVxuICAgICAgbGV0IHBhZGRpbmcgPSBuZXcgRmllbGRJbmZvKCdQYWRkaW5nJywgJ3BhZGRpbmcnLCAnbnVtYmVyJywnV2hlbiBmaXQgdG8gdmlld3BvcnQsIHBhZGRpbmcgaW5zaWRlIHRoZSB2aWV3cG9ydC4nKVxuXG4gICAgICBsZXQgZml0RmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKCdGaXQnLCBbXG4gICAgICAgIGZpdCwgcGFkZGluZ1xuICAgICAgXSwgWydmaXQnXSlcblxuICAgICAgY29uc3Qgem9vbSA9IG5ldyBGaWVsZEluZm8oJ1pvb20nLCAnem9vbScsICdudW1iZXInLCd0aGUgem9vbSBsZXZlbCB0byBzZXQgKGxpa2VseSB3YW50IGZpdCA9IGZhbHNlIGlmIHNldCknKVxuICAgICAgY29uc3QgcGFuID0gbmV3IEZpZWxkSW5mbygnUGFuJywgJ3BhbicsICdudW1iZXInLCd0aGUgcGFuIGxldmVsIHRvIHNldCAobGlrZWx5IHdhbnQgZml0ID0gZmFsc2UgaWYgc2V0KScpXG4gICAgICBjb25zdCBhbmltYXRlID0gbmV3IEZpZWxkSW5mbygnQW5pbWF0ZScsIFwiYW5pbWF0ZVwiLCAnYm9vbGVhbicsIFwid2hldGhlciB0byB0cmFuc2l0aW9uIHRoZSBub2RlIHBvc2l0aW9uc1wiKVxuICAgICAgY29uc3QgYW5pbWF0aW9uRHVyYXRpb24gPSBuZXcgRmllbGRJbmZvKFwiQW5pbWF0aW9uIER1cmF0aW9uXCIsICdhbmltYXRpb25EdXJhdGlvbicsICdudW1iZXInLFwiZHVyYXRpb24gb2YgYW5pbWF0aW9uIGluIG1zIGlmIGVuYWJsZWRcIilcbiAgICAgIGNvbnN0IGFuaW1hdGlvbkVhc2luZyA9IG5ldyBGaWVsZEluZm8oXCJBbmltYXRpb24gRWFzaW5nXCIsICdhbmltYXRpb25FYXNpbmcnLCAnbnVtYmVyJyxcImVhc2luZyBvZiBhbmltYXRpb24gaWYgZW5hYmxlZFwiKVxuICAgICAgbGV0IGFuaW1hdGlvbkZpZWxkc2V0ID0gbmV3IEZpZWxkc2V0SW5mbygnQW5pbWF0aW9uJywgW1xuICAgICAgICB6b29tLCBwYW4sIGFuaW1hdGUsIGFuaW1hdGlvbkR1cmF0aW9uLCBhbmltYXRpb25FYXNpbmdcbiAgICAgIF0sIFsnYW5pbWF0ZSddKVxuXG5cbiAgICAgIGxldCBhdm9pZE92ZXJsYXAgPSBuZXcgRmllbGRJbmZvKCdBdm9pZCBPdmVybGFwJywgJ2F2b2lkT3ZlcmxhcCcsICdib29sZWFuJywncHJldmVudHMgbm9kZSBvdmVybGFwLCBtYXkgb3ZlcmZsb3cgYm91bmRpbmdCb3ggaWYgbm90IGVub3VnaCBzcGFjZScpXG4gICAgICBsZXQgc3BhY2luZ0ZhY3RvciA9IG5ldyBGaWVsZEluZm8oJ1NwYWNpbmcgRmFjdG9yJywgJ3NwYWNpbmdGYWN0b3InLCAnbnVtYmVyJywnQXBwbGllcyBhIG11bHRpcGxpY2F0aXZlIGZhY3RvciAoPjApIHRvIGV4cGFuZCBvciBjb21wcmVzcyB0aGUgb3ZlcmFsbCBhcmVhIHRoYXQgdGhlIG5vZGVzIHRha2UgdXAnKVxuICAgICAgbGV0IG5vZGVEaW1lbnNpb25zSW5jbHVkZUxhYmVscyA9IG5ldyBGaWVsZEluZm8oJ05vZGUgRGltZW5zaW9ucyBJbmNsdWRlIExhYmVscycsICdub2RlRGltZW5zaW9uc0luY2x1ZGVMYWJlbHMnLCAnYm9vbGVhbicsICdFeGNsdWRlcyB0aGUgbGFiZWwgd2hlbiBjYWxjdWxhdGluZyBub2RlIGJvdW5kaW5nIGJveGVzIGZvciB0aGUgbGF5b3V0IGFsZ29yaXRobScpXG4gICAgICBsZXQgc2hhcGVkRmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKCdTaGFwZWQnLCBbXG4gICAgICAgIGF2b2lkT3ZlcmxhcCwgc3BhY2luZ0ZhY3Rvciwgbm9kZURpbWVuc2lvbnNJbmNsdWRlTGFiZWxzXG4gICAgICBdLCBbJ2F2b2lkT3ZlcmxhcCddKVxuXG4gICAgICBsZXQgZGlyZWN0ZWQgPSBuZXcgRmllbGRJbmZvKCdEaXJlY3RlZCcsICdicmVhZHRoRmlyc3QnLCAnYm9vbGVhbicsICd3aGV0aGVyIHRoZSB0cmVlIGlzIGJyZWFkdGhGaXJzdCBkb3dud2FyZHMgKG9yIGVkZ2VzIGNhbiBwb2ludCBpbiBhbnkgZGlyZWN0aW9uIGlmIGZhbHNlKScpXG4gICAgICBsZXQgY2lyY2xlID0gbmV3IEZpZWxkSW5mbygnQ2lyY2xlJywgJ2NpcmNsZScsICdib29sZWFuJywncHV0IGRlcHRocyBpbiBjb25jZW50cmljIGNpcmNsZXMgaWYgdHJ1ZSwgcHV0IGRlcHRocyB0b3AgZG93biBpZiBmYWxzZScpXG4gICAgICBsZXQgbWF4aW1hbEFkanVzdG1lbnRzID0gbmV3IEZpZWxkSW5mbygnTWF4aW1hbCBBZGp1c3RtZW50cycsICdtYXhpbWFsQWRqdXN0bWVudHMnLCAnbnVtYmVyJywgJ2hvdyBtYW55IHRpbWVzIHRvIHRyeSB0byBwb3NpdGlvbiB0aGUgbm9kZXMgaW4gYSBtYXhpbWFsIHdheSAoaS5lLiBubyBiYWNrdHJhY2tpbmcpJylcbiAgICAgIGxldCBtYXhpbWFsID0gbmV3IEZpZWxkSW5mbygnTWF4aW1hbCcsICdtYXhpbWFsJywgJ2Jvb2xlYW4nLCAnd2hldGhlciB0byBzaGlmdCBub2RlcyBkb3duIHRoZWlyIG5hdHVyYWwgQkZTIGRlcHRocyBpbiBvcmRlciB0byBhdm9pZCB1cHdhcmRzIGVkZ2VzIChEQUdTIG9ubHkpJylcbiAgICAgIGxldCBncmlkID0gbmV3IEZpZWxkSW5mbygnR3JpZCcsICdncmlkJywgJ2Jvb2xlYW4nLCAnd2hldGhlciB0byBzaGlmdCBub2RlcyBkb3duIHRoZWlyIG5hdHVyYWwgQkZTIGRlcHRocyBpbiBvcmRlciB0byBhdm9pZCB1cHdhcmRzIGVkZ2VzIChEQUdTIG9ubHkpJylcbiAgICAgIGxldCByb290cyA9IG5ldyBGaWVsZEluZm8oJ1Jvb3RzJywgJ3Jvb3RzJywgJ3N0cmluZycsICd0aGUgcm9vdHMgb2YgdGhlIHRyZWVzJylcbiAgICAgIGxldCBicmVhZHRoRmlyc3RGaWVsZHNldCA9IG5ldyBGaWVsZHNldEluZm8oJ0JyZWFkdGggRmlyc3QnLCBbXG4gICAgICAgIGRpcmVjdGVkLCBjaXJjbGUsIG1heGltYWxBZGp1c3RtZW50cywgbWF4aW1hbCwgZ3JpZCwgcm9vdHNcbiAgICAgIF0sIFsnYnJlYWR0aEZpcnN0J10pXG5cbiAgICAgIGxldCBub2RlU2VwID0gbmV3IEZpZWxkSW5mbygnTm9kZSBTZXBhcmF0aW9uJywgJ25vZGVTZXAnLCAnbnVtYmVyJywgJ3RoZSBzZXBhcmF0aW9uIGJldHdlZW4gYWRqYWNlbnQgbm9kZXMgaW4gdGhlIHNhbWUgcmFuaycpXG4gICAgICBsZXQgZWRnZVNlcCA9IG5ldyBGaWVsZEluZm8oJ0VkZ2UgU2VwYXJhdGlvbicsICdlZGdlU2VwJywgJ251bWJlcicsICd0aGUgc2VwYXJhdGlvbiBiZXR3ZWVuIGFkamFjZW50IGVkZ2VzIGluIHRoZSBzYW1lIHJhbmsnKVxuICAgICAgbGV0IHJhbmtTZXAgPSBuZXcgRmllbGRJbmZvKCdSYW5rIFNlcGFyYXRpb24nLCAncmFua1NlcCcsICdudW1iZXInLCAndGhlIHNlcGFyYXRpb24gYmV0d2VlbiBlYWNoIHJhbmsgaW4gdGhlIGxheW91dCcpXG4gICAgICBsZXQgcmFua2VyID0gbmV3IEZpZWxkSW5mbygnUmFua2VyJywgJ3JhbmtlcicsICdvcHRpb25zJywgJ1R5cGUgb2YgYWxnb3JpdGhtIHRvIGFzc2lnbiBhIHJhbmsgdG8gZWFjaCBub2RlIGluIHRoZSBpbnB1dCBncmFwaC4nKVxuICAgICAgcmFua2VyLm9wdGlvbnMgPSBbXG4gICAgICAgIHtuYW1lOiAnJywgbGFiZWw6ICcnfSxcbiAgICAgICAge25hbWU6ICduZXR3b3JrLXNpbXBsZXgnLCBsYWJlbDogJ25ldHdvcmstc2ltcGxleCd9LFxuICAgICAgICB7bmFtZTogJ3RpZ2h0LXRyZWUnLCBsYWJlbDogJ3RpZ2h0LXRyZWUnfSxcbiAgICAgICAge25hbWU6ICdsb25nZXN0LXBhdGgnLCBsYWJlbDogJ2xvbmdlc3QtcGF0aCd9XVxuXG4gICAgICBsZXQgZGFncmVGaWVsZHNldCA9IG5ldyBGaWVsZHNldEluZm8oJ0RhZ3JlJywgW1xuICAgICAgICBub2RlU2VwLCBlZGdlU2VwLCByYW5rU2VwLCByYW5rZXJcbiAgICAgIF0sIFsnbm9kZVNlcCddKVxuXG4gICAgICBsZXQgYW5pbWF0aW9uVGhyZXNob2xkID0gbmV3IEZpZWxkSW5mbygnQW5pbWF0aW9uIFRocmVzaG9sZCcsICdhbmltYXRpb25UaHJlc2hvbGQnLCAnbnVtYmVyJywgJ1RoZSBsYXlvdXQgYW5pbWF0ZXMgb25seSBhZnRlciB0aGlzIG1hbnkgbWlsbGlzZWNvbmRzIHdoZW4gYW5pbWF0ZSBpcyB0cnVlIChwcmV2ZW50cyBmbGFzaGluZyBvbiBmYXN0IHJ1bnMpJylcbiAgICAgIGxldCByZWZyZXNoID0gbmV3IEZpZWxkSW5mbygnUmVmcmVzaCcsICdyZWZyZXNoJywgJ251bWJlcicsXG4gICAgICAgICdOdW1iZXIgb2YgaXRlcmF0aW9ucyBiZXR3ZWVuIGNvbnNlY3V0aXZlIHNjcmVlbiBwb3NpdGlvbnMgdXBkYXRlJylcbiAgICAgIGxldCByYW5kb21pemUgPSBuZXcgRmllbGRJbmZvKCdSYW5kb21pemUnLCAncmFuZG9taXplJywgJ2Jvb2xlYW4nLCAnUmFuZG9taXplIHRoZSBpbml0aWFsIHBvc2l0aW9ucyBvZiB0aGUgbm9kZXMgKHRydWUpIG9yIHVzZSBleGlzdGluZyBwb3NpdGlvbnMgKGZhbHNlKScpXG4gICAgICBsZXQgY29tcG9uZW50U3BhY2luZyA9IG5ldyBGaWVsZEluZm8oJ0NvbXBvbmVudCBTcGFjaW5nJywgJ2NvbXBvbmVudFNwYWNpbmcnLCAnbnVtYmVyJywgJ0V4dHJhIHNwYWNpbmcgYmV0d2VlbiBjb21wb25lbnRzIGluIG5vbi1jb21wb3VuZCBncmFwaHMnKVxuICAgICAgbGV0IG5vZGVPdmVybGFwID0gbmV3IEZpZWxkSW5mbygnTm9kZSBPdmVybGFwJywgJ25vZGVPdmVybGFwJywgJ251bWJlcicsICdOb2RlIHJlcHVsc2lvbiAob3ZlcmxhcHBpbmcpIG11bHRpcGxpZXInKVxuICAgICAgbGV0IG5lc3RpbmdGYWN0b3IgPSBuZXcgRmllbGRJbmZvKCdOZXN0aW5nIEZhY3RvcicsICduZXN0aW5nRmFjdG9yJywgJ251bWJlcicsICdOZXN0aW5nIGZhY3RvciAobXVsdGlwbGllcikgdG8gY29tcHV0ZSBpZGVhbCBlZGdlIGxlbmd0aCBmb3IgbmVzdGVkIGVkZ2VzJylcbiAgICAgIGxldCBncmF2aXR5ID0gbmV3IEZpZWxkSW5mbygnR3Jhdml0eScsICdncmF2aXR5JywgJ251bWJlcicsICdHcmF2aXR5IGZvcmNlIChjb25zdGFudCknKVxuICAgICAgbGV0IG51bUl0ZXIgPSBuZXcgRmllbGRJbmZvKCdNYXggSXRlcmF0aW9ucycsICdudW1JdGVyJywgJ251bWJlcicsICdNYXhpbXVtIG51bWJlciBvZiBpdGVyYXRpb25zIHRvIHBlcmZvcm0nKVxuICAgICAgbGV0IGluaXRpYWxUZW1wID0gbmV3IEZpZWxkSW5mbygnSW5pdGlhbCBUZW1wJywgJ2luaXRpYWxUZW1wJywgJ251bWJlcicsICdJbml0aWFsIHRlbXBlcmF0dXJlIChtYXhpbXVtIG5vZGUgZGlzcGxhY2VtZW50KScpXG4gICAgICBsZXQgY29vbGluZ0ZhY3RvciA9IG5ldyBGaWVsZEluZm8oJ0Nvb2xpbmcgRmFjdG9yJywgJ2Nvb2xpbmdGYWN0b3InLCAnbnVtYmVyJywgJ0Nvb2xpbmcgZmFjdG9yIChob3cgdGhlIHRlbXBlcmF0dXJlIGlzIHJlZHVjZWQgYmV0d2VlbiBjb25zZWN1dGl2ZSBpdGVyYXRpb25zJylcbiAgICAgIGxldCBtaW5UZW1wID0gbmV3IEZpZWxkSW5mbygnTWluLiBUZW1wJywgJ21pblRlbXAnLCAnbnVtYmVyJywgJ0xvd2VyIHRlbXBlcmF0dXJlIHRocmVzaG9sZCAoYmVsb3cgdGhpcyBwb2ludCB0aGUgbGF5b3V0IHdpbGwgZW5kKScpXG4gICAgICBsZXQgY29zZUZpZWxkc2V0ID0gbmV3IEZpZWxkc2V0SW5mbygnQ09TRScsIFtcbiAgICAgICAgYW5pbWF0aW9uVGhyZXNob2xkLCByZWZyZXNoLCByYW5kb21pemUsIGNvbXBvbmVudFNwYWNpbmcsIG5vZGVPdmVybGFwLCBuZXN0aW5nRmFjdG9yLCBncmF2aXR5LCBudW1JdGVyLFxuICAgICAgICBpbml0aWFsVGVtcCwgY29vbGluZ0ZhY3RvciwgbWluVGVtcFxuICAgICAgXSwgWydjb29saW5nRmFjdG9yJ10pXG5cbiAgICAgIGxldCBhdm9pZE92ZXJsYXBQYWRkaW5nID0gbmV3IEZpZWxkSW5mbygnYXZvaWRPdmVybGFwUGFkZGluZycsICdhdm9pZE92ZXJsYXBQYWRkaW5nJywgJ251bWJlcicsICdleHRyYSBzcGFjaW5nIGFyb3VuZCBub2RlcyB3aGVuIGF2b2lkT3ZlcmxhcDogdHJ1ZScpXG4gICAgICBsZXQgY29uZGVuc2UgPSBuZXcgRmllbGRJbmZvKCdjb25kZW5zZScsICdjb25kZW5zZScsICdib29sZWFuJywgJ3VzZXMgYWxsIGF2YWlsYWJsZSBzcGFjZSBvbiBmYWxzZSwgdXNlcyBtaW5pbWFsIHNwYWNlIG9uIHRydWUnKVxuICAgICAgbGV0IHJvd3MgPSBuZXcgRmllbGRJbmZvKCdSb3dzJywgJ3Jvd3MnLCAnbnVtYmVyJywgJ2ZvcmNlIG51bSBvZiByb3dzIGluIHRoZSBncmlkJylcbiAgICAgIGxldCBjb2xzID0gbmV3IEZpZWxkSW5mbygnQ29sdW1ucycsICdjb2xzJywgJ251bWJlcicsICdmb3JjZSBudW0gb2YgY29sdW1ucyBpbiB0aGUgZ3JpZCcpXG5cbiAgICAgIGxldCBncmlkRmllbGRzZXQgPSBuZXcgRmllbGRzZXRJbmZvKCdHcmlkJywgW1xuICAgICAgICBhdm9pZE92ZXJsYXBQYWRkaW5nLCBjb25kZW5zZSwgcm93cywgY29sc1xuICAgICAgXSwgWydjb2xzJ10pXG5cbiAgICAgIGxldCByYWRpdXMgPSBuZXcgRmllbGRJbmZvKCdSYWRpdXMnLCAncmFkaXVzJywgJ251bWJlcicsICd0aGUgcmFkaXVzIG9mIHRoZSBjaXJjbGUnKVxuICAgICAgbGV0IHN0YXJ0QW5nbGUgPSBuZXcgRmllbGRJbmZvKCdTdGFydCBBbmdsZScsICdzdGFydEFuZ2xlJywgJ251bWJlcicsICd3aGVyZSBub2RlcyBzdGFydCBpbiByYWRpYW5zIChkZWZhdWx0OjMgLyAyICogTWF0aC5QSSknKVxuICAgICAgbGV0IHN3ZWVwID0gbmV3IEZpZWxkSW5mbygnU3dlZXAnLCAnc3dlZXAnLCAnbnVtYmVyJywgJ2hvdyBtYW55IHJhZGlhbnMgc2hvdWxkIGJlIGJldHdlZW4gdGhlIGZpcnN0IGFuZCBsYXN0IG5vZGUgKGRlZmF1bHRzIHRvIGZ1bGwgY2lyY2xlKScpXG4gICAgICBsZXQgY2xvY2t3aXNlID0gbmV3IEZpZWxkSW5mbygnQ2xvY2t3aXNlJywgJ2Nsb2Nrd2lzZScsICdudW1iZXInLCAnd2hldGhlciB0aGUgbGF5b3V0IHNob3VsZCBnbyBjbG9ja3dpc2UgKHRydWUpIG9yIGNvdW50ZXJjbG9ja3dpc2UvYW50aWNsb2Nrd2lzZSAoZmFsc2UpJylcbiAgICAgIGxldCBjaXJjdWxhckZpZWxkU2V0ID0gbmV3IEZpZWxkc2V0SW5mbygnQ2lyY3VsYXInLCBbXG4gICAgICAgIHJhZGl1cywgc3RhcnRBbmdsZSwgc3dlZXAsIGNsb2Nrd2lzZVxuICAgICAgXSwgWydjbG9ja3dpc2UnXSlcblxuICAgICAgbGV0IGVxdWlkaXN0YW50ID0gbmV3IEZpZWxkSW5mbygnRXF1aWRpc3RhbnQnLCAnZXF1aWRpc3RhbnQnLCAnYm9vbGVhbicsICd3aGV0aGVyIGxldmVscyBoYXZlIGFuIGVxdWFsIHJhZGlhbCBkaXN0YW5jZSBiZXR3ZW4gdGhlbSwgbWF5IGNhdXNlIGJvdW5kaW5nIGJveCBvdmVyZmxvdycpXG4gICAgICBsZXQgbWluTm9kZVNwYWNpbmcgPSBuZXcgRmllbGRJbmZvKCdNaW4uIE5vZGUgU3BhY2luZycsICdtaW5Ob2RlU3BhY2luZycsICdudW1iZXInLCAnbWluIHNwYWNpbmcgYmV0d2VlbiBvdXRzaWRlIG9mIG5vZGVzICh1c2VkIGZvciByYWRpdXMgYWRqdXN0bWVudCknKVxuICAgICAgbGV0IGhlaWdodCA9IG5ldyBGaWVsZEluZm8oJ0hlaWdodCcsICdoZWlnaHQnLCAnbnVtYmVyJywgJycpXG4gICAgICBsZXQgd2lkdGggPSBuZXcgRmllbGRJbmZvKCdXaWR0aCcsICd3aWR0aCcsICdudW1iZXInLCAnJylcbiAgICAgIGxldCBjb25jZW50cmljRmllbGRTZXQgPSBuZXcgRmllbGRzZXRJbmZvKCdDb25jZW50cmljJywgW1xuICAgICAgICBlcXVpZGlzdGFudCwgbWluTm9kZVNwYWNpbmcsIHN0YXJ0QW5nbGUsIGhlaWdodCwgd2lkdGhcbiAgICAgIF0sIFsnZXF1aWRpc3RhbnQnXSlcblxuICAgICAgLy9ib3VuZGluZ0JveDogdW5kZWZpbmVkIC8vIGNvbnN0cmFpbiBsYXlvdXQgYm91bmRzOyB7IHgxLCB5MSwgeDIsIHkyIH0gb3IgeyB4MSwgeTEsIHcsIGggfVxuXG4gICAgICByZXR1cm4gbmV3IEZvcm1JbmZvKCdMYXlvdXQnLFxuICAgICAgICBbXG4gICAgICAgICAgYnJlYWR0aEZpcnN0RmllbGRzZXQsIGNvc2VGaWVsZHNldCwgZGFncmVGaWVsZHNldCwgZ3JpZEZpZWxkc2V0LCBjaXJjdWxhckZpZWxkU2V0LCBjb25jZW50cmljRmllbGRTZXQsXG4gICAgICAgICAgZml0RmllbGRzZXQsIGFuaW1hdGlvbkZpZWxkc2V0LCBzaGFwZWRGaWVsZHNldCBdLFxuICAgICAgICBmYWxzZSlcbiAgfVxufVxuLypcbiAgICA8IS0tXG5cbiAgICAgIERhZ3JlXG4gICAgICAgIC8vIFR5cGUgb2YgYWxnb3JpdGhtIHRvIGFzc2lnbiBhIHJhbmsgdG8gZWFjaCBub2RlIGluIHRoZSBpbnB1dCBncmFwaC5cbiAgICAgICAgLy8gUG9zc2libGUgdmFsdWVzOlxuICAgICAgICBjID0gdW5kZWZpbmVkXG4gICAgICAgIC8vIG51bWJlciBvZiByYW5rcyB0byBrZWVwIGJldHdlZW4gdGhlIHNvdXJjZSBhbmQgdGFyZ2V0IG9mIHRoZSBlZGdlXG4gICAgICAgIG1pbkxlbiA9ICggZWRnZSApID0+IHsgcmV0dXJuIDEgfVxuICAgICAgICBlZGdlV2VpZ2h0ID0gKCBlZGdlICkgPT4geyByZXR1cm4gMSB9IC8vIGhpZ2hlciB3ZWlnaHQgZWRnZXMgYXJlIGdlbmVyYWxseSBtYWRlIHNob3J0ZXIgYW5kIHN0cmFpZ2h0ZXIgdGhhbiBsb3dlciB3ZWlnaHQgZWRnZXNcblxuICAgIEFuaW1hdGVMYXlvdXRPcHRpb25zSW1wbFxuICAgICAgLy8gYSBmdW5jdGlvbiB0aGF0IGRldGVybWluZXMgd2hldGhlciB0aGUgbm9kZSBzaG91bGQgYmUgYW5pbWF0ZWQuXG4gICAgICAvLyBBbGwgbm9kZXMgYW5pbWF0ZWQgYnkgZGVmYXVsdCBvbiBhbmltYXRlIGVuYWJsZWQuICBOb24tYW5pbWF0ZWQgbm9kZXMgYXJlXG4gICAgICAvLyBwb3NpdGlvbmVkIGltbWVkaWF0ZWx5IHdoZW4gdGhlIGxheW91dCBzdGFydHNcbiAgICAgIGFuaW1hdGVGaWx0ZXIgPSAoIG5vZGUsIGkgKSA9PiB0cnVlXG5cbiAgICAgIFByZXNldFxuICAgICAgLy8gbWFwIG9mIChub2RlIGlkKSA9PiAocG9zaXRpb24gb2JqKTsgb3IgZnVuY3Rpb24obm9kZSl7IHJldHVybiBzb21Qb3M7IH1cbiAgICAgIHBvc2l0aW9uczogdW5kZWZpbmVkXG5cbiAgICAgIFNoYXBlZFxuICAgICAgICAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kc1xuICAgICAgICBib3VuZGluZ0JveD86IEJvdW5kaW5nQm94MTIgfCBCb3VuZGluZ0JveFdIIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXG5cbiAgICAgICAgLy8gYSBzb3J0aW5nIGZ1bmN0aW9uIHRvIG9yZGVyIHRoZSBub2RlczsgZS5nLiBmdW5jdGlvbihhLCBiKXsgcmV0dXJuIGEuZGF0YSgnd2VpZ2h0JykgLSBiLmRhdGEoJ3dlaWdodCcpIH1cbiAgICAgICAgc29ydD86IFNvcnRpbmdGdW5jdGlvbiA9IHVuZGVmaW5lZFxuICAgICAgICAvLyB0cmFuc2Zvcm0gYSBnaXZlbiBub2RlIHBvc2l0aW9uLiBVc2VmdWwgZm9yIGNoYW5naW5nIGZsb3cgZGlyZWN0aW9uIGluIGRpc2NyZXRlIGxheW91dHNcbiAgICAgICAgdHJhbnNmb3JtID0gKG5vZGUsIHBvc2l0aW9uICkgPT4gcG9zaXRpb25cblxuICAgICAgLy9HcmlkXG4gICAgICAgIC8vIHJldHVybnMgeyByb3csIGNvbCB9IGZvciBlbGVtZW50XG4gICAgICAgIC8vIChub2RlOiBOb2RlU2luZ3VsYXIpID0+IHJldHVybiB7IHJvdzogbnVtYmVyOyBjb2w6IG51bWJlcjsgfVxuICAgICAgICBwb3NpdGlvbiA9IHVuZGVmaW5lZFxuXG4gICAgICAvL1JhbmRvbVxuICAgICAgICAvLyBjb25zdHJhaW4gbGF5b3V0IGJvdW5kczsgeyB4MSwgeTEsIHgyLCB5MiB9IG9yIHsgeDEsIHkxLCB3LCBoIH1cbiAgICAgICAgYm91bmRpbmdCb3g6IGN5dG9zY2FwZS5Cb3VuZGluZ0JveDEyIHwgY3l0b3NjYXBlLkJvdW5kaW5nQm94V0ggfCB1bmRlZmluZWQgPSB1bmRlZmluZWRcbiAgICAgICAgLy8gdHJhbnNmb3JtIGEgZ2l2ZW4gbm9kZSBwb3NpdGlvbi4gVXNlZnVsIGZvciBjaGFuZ2luZyBmbG93IGRpcmVjdGlvbiBpbiBkaXNjcmV0ZSBsYXlvdXRzXG4gICAgICAgIHRyYW5zZm9ybSA9IChub2RlLCBwb3NpdGlvbiApID0+IHBvc2l0aW9uXG5cbiAgICAgIC8vQ2lyY3VsYXJcbiAgICAgIC8vQ29uZWNudHJpY1xuICAgICAgICBjb25jZW50cmljKG5vZGU6IHsgZGVncmVlKCk6IG51bWJlciB9KTogbnVtYmVyIHtcbiAgICAgICAgICBldHVybiAwXG4gICAgICAgIH1cblxuICAgICAgICBsZXZlbFdpZHRoKG5vZGU6IHsgbWF4RGVncmVlKCk6IG51bWJlciB9KTogbnVtYmVyIHtcbiAgICAgICAgICByZXR1cm4gMFxuICAgICAgICB9XG5cbiAgICAgICAgQnJlYWR0aCBGaXJzdFxuXG4gICAgICAgICBDb3NlTGF5b3V0T3B0aW9uc0ltcGxcblxuICAgICAgICAgIC8vIE5vZGUgcmVwdWxzaW9uIChub24gb3ZlcmxhcHBpbmcpIG11bHRpcGxpZXJcbiAgICAgICAgICBub2RlUmVwdWxzaW9uID0gIGZ1bmN0aW9uKCBub2RlICl7IHJldHVybiAyMDQ4IH1cblxuICAgICAgICAgIC8vIElkZWFsIGVkZ2UgKG5vbiBuZXN0ZWQpIGxlbmd0aFxuICAgICAgICAgIGlkZWFsRWRnZUxlbmd0aCA9ICggZWRnZSApID0+IHsgcmV0dXJuIDMyIH1cblxuICAgICAgICAgIC8vIERpdmlzb3IgdG8gY29tcHV0ZSBlZGdlIGZvcmNlc1xuICAgICAgICAgIGVkZ2VFbGFzdGljaXR5ID0gKCBlZGdlICkgPT4gMzJcblxuICAgIC0tPlxuICovXG4iXX0=