UNPKG

ng-zorro-antd

Version:

An enterprise-class UI components based on Ant Design and Angular

483 lines (475 loc) 60.2 kB
import { __decorate } from "tslib"; /** * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ import { NgTemplateOutlet } from '@angular/common'; import { ChangeDetectionStrategy, Component, ContentChild, ElementRef, EventEmitter, Host, Input, Optional, Output, TemplateRef, ViewChildren, ViewEncapsulation } from '@angular/core'; import { forkJoin, ReplaySubject, Subject } from 'rxjs'; import { finalize, take, takeUntil } from 'rxjs/operators'; import { buildGraph } from 'dagre-compound'; import { cancelRequestAnimationFrame } from 'ng-zorro-antd/core/polyfill'; import { InputBoolean } from 'ng-zorro-antd/core/util'; import { calculateTransform } from './core/utils'; import { NzGraph } from './graph'; import { NzGraphDefsComponent } from './graph-defs.component'; import { NzGraphEdgeComponent } from './graph-edge.component'; import { NzGraphEdgeDirective } from './graph-edge.directive'; import { NzGraphGroupNodeDirective } from './graph-group-node.directive'; import { NzGraphNodeComponent } from './graph-node.component'; import { NzGraphNodeDirective } from './graph-node.directive'; import { NZ_GRAPH_LAYOUT_SETTING, nzTypeDefinition } from './interface'; import * as i0 from "@angular/core"; import * as i1 from "ng-zorro-antd/core/no-animation"; import * as i2 from "./graph-zoom.directive"; /** Checks whether an object is a data source. */ export function isDataSource(value) { // Check if the value is a DataSource by observing if it has a connect function. Cannot // be checked as an `instanceof DataSource` since people could create their own sources // that match the interface, but don't extend DataSource. return value && typeof value.connect === 'function'; } export class NzGraphComponent { constructor(cdr, elementRef, noAnimation, nzGraphZoom) { this.cdr = cdr; this.elementRef = elementRef; this.noAnimation = noAnimation; this.nzGraphZoom = nzGraphZoom; this.nzRankDirection = 'LR'; this.nzAutoSize = false; this.nzGraphInitialized = new EventEmitter(); this.nzGraphRendered = new EventEmitter(); this.nzNodeClick = new EventEmitter(); this.requestId = -1; this.transformStyle = ''; this.graphRenderedSubject$ = new ReplaySubject(1); this.renderInfo = { labelHeight: 0 }; this.mapOfNodeAttr = {}; this.mapOfEdgeAttr = {}; this.zoom = 1; this.typedNodes = nzTypeDefinition(); this.layoutSetting = NZ_GRAPH_LAYOUT_SETTING; this.destroy$ = new Subject(); this.edgeTrackByFun = (_, edge) => `${edge.v}-${edge.w}`; this.subGraphTransform = (node) => { const x = node.x - node.coreBox.width / 2.0; const y = node.y - node.height / 2.0 + node.paddingTop; return `translate(${x}, ${y})`; }; this.$asNzGraphEdges = (data) => data; this.coreTransform = (node) => `translate(0, ${node.parentNodeName ? node.labelHeight : 0})`; } ngOnInit() { this.graphRenderedSubject$.pipe(take(1), takeUntil(this.destroy$)).subscribe(() => { // Only zooming is not set, move graph to center if (!this.nzGraphZoom) { this.fitCenter(); } this.nzGraphInitialized.emit(this); }); } ngOnChanges(changes) { const { nzAutoFit, nzRankDirection, nzGraphData, nzGraphLayoutConfig } = changes; if (nzGraphLayoutConfig) { this.layoutSetting = this.mergeConfig(nzGraphLayoutConfig.currentValue); } if (nzGraphData) { if (this.dataSource !== this.nzGraphData) { this._switchDataSource(this.nzGraphData); } } if ((nzAutoFit && !nzAutoFit.firstChange) || (nzRankDirection && !nzRankDirection.firstChange)) { // Render graph if (this.dataSource.dataSource) { this.drawGraph(this.dataSource.dataSource, { rankDirection: this.nzRankDirection, expanded: this.dataSource.expansionModel.selected || [] }).then(() => { this.cdr.markForCheck(); }); } } this.cdr.markForCheck(); } ngAfterContentChecked() { if (this.dataSource && !this._dataSubscription) { this.observeRenderChanges(); } } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); if (this.dataSource && typeof this.dataSource.disconnect === 'function') { this.dataSource.disconnect(); } if (this._dataSubscription) { this._dataSubscription.unsubscribe(); this._dataSubscription = null; } cancelRequestAnimationFrame(this.requestId); } /** * Move graph to center and scale automatically */ fitCenter() { const { x, y, k } = calculateTransform(this.elementRef.nativeElement.querySelector('svg'), this.elementRef.nativeElement.querySelector('svg > g')); if (k) { this.zoom = k; this.transformStyle = `translate(${x}, ${y})scale(${k})`; } this.cdr.markForCheck(); } /** * re-Draw graph * * @param data * @param options * @param needResize */ drawGraph(data, options, needResize = false) { return new Promise(resolve => { this.requestId = requestAnimationFrame(() => { const renderInfo = this.buildGraphInfo(data, options); // TODO // Need better performance this.renderInfo = renderInfo; this.cdr.markForCheck(); this.requestId = requestAnimationFrame(() => { this.drawNodes(!this.noAnimation?.nzNoAnimation).then(() => { // Update element this.cdr.markForCheck(); if (needResize) { this.resizeNodeSize().then(() => { const dataSource = this.dataSource.dataSource; this.drawGraph(dataSource, options, false).then(() => resolve()); }); } else { this.graphRenderedSubject$.next(); this.nzGraphRendered.emit(this); resolve(); } }); }); }); this.cdr.markForCheck(); }); } /** * Redraw all nodes * * @param animate */ drawNodes(animate = true) { return new Promise(resolve => { if (animate) { this.makeNodesAnimation().subscribe(() => { resolve(); }); } else { this.listOfNodeComponent.map(node => { node.makeNoAnimation(); }); resolve(); } }); } resizeNodeSize() { return new Promise(resolve => { const dataSource = this.dataSource.dataSource; let scale = this.nzGraphZoom?.nzZoom || this.zoom || 1; this.listOfNodeElement.forEach(nodeEle => { const contentEle = nodeEle.nativeElement; if (contentEle) { let width; let height; // Check if foreignObject is set const clientRect = contentEle.querySelector('foreignObject > :first-child')?.getBoundingClientRect(); if (clientRect) { width = clientRect.width; height = clientRect.height; } else { const bBoxRect = contentEle.getBBox(); width = bBoxRect.width; height = bBoxRect.height; // getBBox will return actual value scale = 1; } // Element id type is string const node = dataSource.nodes.find(n => `${n.id}` === nodeEle.nativeElement.id); if (node && width && height) { node.height = height / scale; node.width = width / scale; } } }); resolve(); }); } /** * Switch to the provided data source by resetting the data and unsubscribing from the current * render change subscription if one exists. If the data source is null, interpret this by * clearing the node outlet. Otherwise start listening for new data. */ _switchDataSource(dataSource) { if (this.dataSource && typeof this.dataSource.disconnect === 'function') { this.nzGraphData.disconnect(); } if (this._dataSubscription) { this._dataSubscription.unsubscribe(); this._dataSubscription = null; } this.dataSource = dataSource; this.observeRenderChanges(); } /** Set up a subscription for the data provided by the data source. */ observeRenderChanges() { let dataStream; let graphOptions = { rankDirection: this.nzRankDirection }; if (isDataSource(this.dataSource)) { dataStream = this.dataSource.connect(); } if (dataStream) { this._dataSubscription = dataStream.pipe(takeUntil(this.destroy$)).subscribe(data => { graphOptions = { rankDirection: this.nzRankDirection, expanded: this.nzGraphData.expansionModel.selected }; this.drawGraph(data, graphOptions, this.nzAutoSize).then(() => { this.cdr.detectChanges(); }); }); } else { throw Error(`A valid data source must be provided.`); } } /** * Get renderInfo and prepare some data * * @param data * @param options * @private */ buildGraphInfo(data, options) { this.parseInfo(data); const renderInfo = buildGraph(data, options, this.layoutSetting); const dig = (nodes) => { nodes.forEach(node => { const { x, y } = node; node.xOffset = x; node.yOffset = y; if (node.type === 1 && this.mapOfNodeAttr.hasOwnProperty(node.name)) { Object.assign(node, this.mapOfNodeAttr[node.name]); } else if (node.type === 0) { node.edges.forEach(edge => { if (this.mapOfEdgeAttr.hasOwnProperty(`${edge.v}-${edge.w}`)) { Object.assign(edge, this.mapOfEdgeAttr[`${edge.v}-${edge.w}`]); } }); dig(node.nodes); } }); }; dig(renderInfo.nodes); // Assign data to edges of root graph renderInfo.edges.forEach(edge => { if (this.mapOfEdgeAttr.hasOwnProperty(`${edge.v}-${edge.w}`)) { Object.assign(edge, this.mapOfEdgeAttr[`${edge.v}-${edge.w}`]); } }); return renderInfo; } /** * Play with animation * * @private */ makeNodesAnimation() { return forkJoin(this.listOfNodeComponent.map(node => node.makeAnimation())).pipe(finalize(() => { this.cdr.detectChanges(); })); } parseInfo(data) { data.nodes.forEach(n => { this.mapOfNodeAttr[n.id] = n; }); data.edges.forEach(e => { this.mapOfEdgeAttr[`${e.v}-${e.w}`] = e; }); } /** * Merge config with user inputs * * @param config * @private */ mergeConfig(config) { const graphMeta = config?.layout || {}; const subSceneMeta = config?.subScene || {}; const defaultNodeMeta = config?.defaultNode || {}; const defaultCompoundNodeMeta = config?.defaultCompoundNode || {}; const bridge = NZ_GRAPH_LAYOUT_SETTING.nodeSize.bridge; const graph = { meta: { ...NZ_GRAPH_LAYOUT_SETTING.graph.meta, ...graphMeta } }; const subScene = { meta: { ...NZ_GRAPH_LAYOUT_SETTING.subScene.meta, ...subSceneMeta } }; const nodeSize = { meta: { ...NZ_GRAPH_LAYOUT_SETTING.nodeSize.meta, ...defaultCompoundNodeMeta }, node: { ...NZ_GRAPH_LAYOUT_SETTING.nodeSize.node, ...defaultNodeMeta }, bridge }; return { graph, subScene, nodeSize }; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: NzGraphComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i1.NzNoAnimationDirective, host: true, optional: true }, { token: i2.NzGraphZoomDirective, optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.4", type: NzGraphComponent, isStandalone: true, selector: "nz-graph", inputs: { nzGraphData: "nzGraphData", nzRankDirection: "nzRankDirection", nzGraphLayoutConfig: "nzGraphLayoutConfig", nzAutoSize: "nzAutoSize" }, outputs: { nzGraphInitialized: "nzGraphInitialized", nzGraphRendered: "nzGraphRendered", nzNodeClick: "nzNodeClick" }, host: { properties: { "class.nz-graph": "true", "class.nz-graph-auto-size": "nzAutoSize" } }, providers: [{ provide: NzGraph, useExisting: NzGraphComponent }], queries: [{ propertyName: "nodeTemplate", first: true, predicate: NzGraphNodeDirective, descendants: true, read: TemplateRef, static: true }, { propertyName: "groupNodeTemplate", first: true, predicate: NzGraphGroupNodeDirective, descendants: true, read: TemplateRef, static: true }, { propertyName: "customGraphEdgeTemplate", first: true, predicate: NzGraphEdgeDirective, descendants: true, read: TemplateRef, static: true }], viewQueries: [{ propertyName: "listOfNodeElement", predicate: NzGraphNodeComponent, descendants: true, read: ElementRef }, { propertyName: "listOfNodeComponent", predicate: NzGraphNodeComponent, descendants: true }], exportAs: ["nzGraph"], usesOnChanges: true, ngImport: i0, template: ` <ng-content></ng-content> <svg width="100%" height="100%"> <svg:defs nz-graph-defs></svg:defs> <svg:g [attr.transform]="transformStyle"> <ng-container [ngTemplateOutlet]="groupTemplate" [ngTemplateOutletContext]="{ renderNode: renderInfo, type: 'root' }" ></ng-container> </svg:g> </svg> <ng-template #groupTemplate let-renderNode="renderNode" let-type="type"> <svg:g [attr.transform]="type === 'sub' ? subGraphTransform(renderNode) : null"> <svg:g class="core" [attr.transform]="coreTransform(renderNode)"> <svg:g class="nz-graph-edges"> @for (edge of $asNzGraphEdges(renderNode.edges); track edgeTrackByFun) { <g class="nz-graph-edge" nz-graph-edge [edge]="edge" [edgeType]="nzGraphLayoutConfig?.defaultEdge?.type" [customTemplate]="customGraphEdgeTemplate" ></g> } </svg:g> <svg:g class="nz-graph-nodes"> @for (node of typedNodes(renderNode.nodes); track node.name) { @if (node.type === 1) { <g class="nz-graph-node" nz-graph-node [node]="node" [customTemplate]="nodeTemplate"></g> } @if (node.type === 0) { <g class="nz-graph-node" nz-graph-node [node]="node" [customTemplate]="groupNodeTemplate"></g> } @if (node.expanded) { <ng-container [ngTemplateOutlet]="groupTemplate" [ngTemplateOutletContext]="{ renderNode: node, type: 'sub' }" /> } } </svg:g> </svg:g> </svg:g> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NzGraphEdgeComponent, selector: "[nz-graph-edge]", inputs: ["edge", "edgeType", "customTemplate"] }, { kind: "component", type: NzGraphNodeComponent, selector: "[nz-graph-node]", inputs: ["node", "noAnimation", "customTemplate"] }, { kind: "component", type: NzGraphDefsComponent, selector: "svg:defs[nz-graph-defs]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } __decorate([ InputBoolean() ], NzGraphComponent.prototype, "nzAutoSize", void 0); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: NzGraphComponent, decorators: [{ type: Component, args: [{ changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, selector: 'nz-graph', exportAs: 'nzGraph', providers: [{ provide: NzGraph, useExisting: NzGraphComponent }], template: ` <ng-content></ng-content> <svg width="100%" height="100%"> <svg:defs nz-graph-defs></svg:defs> <svg:g [attr.transform]="transformStyle"> <ng-container [ngTemplateOutlet]="groupTemplate" [ngTemplateOutletContext]="{ renderNode: renderInfo, type: 'root' }" ></ng-container> </svg:g> </svg> <ng-template #groupTemplate let-renderNode="renderNode" let-type="type"> <svg:g [attr.transform]="type === 'sub' ? subGraphTransform(renderNode) : null"> <svg:g class="core" [attr.transform]="coreTransform(renderNode)"> <svg:g class="nz-graph-edges"> @for (edge of $asNzGraphEdges(renderNode.edges); track edgeTrackByFun) { <g class="nz-graph-edge" nz-graph-edge [edge]="edge" [edgeType]="nzGraphLayoutConfig?.defaultEdge?.type" [customTemplate]="customGraphEdgeTemplate" ></g> } </svg:g> <svg:g class="nz-graph-nodes"> @for (node of typedNodes(renderNode.nodes); track node.name) { @if (node.type === 1) { <g class="nz-graph-node" nz-graph-node [node]="node" [customTemplate]="nodeTemplate"></g> } @if (node.type === 0) { <g class="nz-graph-node" nz-graph-node [node]="node" [customTemplate]="groupNodeTemplate"></g> } @if (node.expanded) { <ng-container [ngTemplateOutlet]="groupTemplate" [ngTemplateOutletContext]="{ renderNode: node, type: 'sub' }" /> } } </svg:g> </svg:g> </svg:g> </ng-template> `, host: { '[class.nz-graph]': 'true', '[class.nz-graph-auto-size]': 'nzAutoSize' }, imports: [NgTemplateOutlet, NzGraphEdgeComponent, NzGraphNodeComponent, NzGraphDefsComponent], standalone: true }] }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i1.NzNoAnimationDirective, decorators: [{ type: Host }, { type: Optional }] }, { type: i2.NzGraphZoomDirective, decorators: [{ type: Optional }] }], propDecorators: { listOfNodeElement: [{ type: ViewChildren, args: [NzGraphNodeComponent, { read: ElementRef }] }], listOfNodeComponent: [{ type: ViewChildren, args: [NzGraphNodeComponent] }], nodeTemplate: [{ type: ContentChild, args: [NzGraphNodeDirective, { static: true, read: TemplateRef }] }], groupNodeTemplate: [{ type: ContentChild, args: [NzGraphGroupNodeDirective, { static: true, read: TemplateRef }] }], customGraphEdgeTemplate: [{ type: ContentChild, args: [NzGraphEdgeDirective, { static: true, read: TemplateRef }] }], nzGraphData: [{ type: Input }], nzRankDirection: [{ type: Input }], nzGraphLayoutConfig: [{ type: Input }], nzAutoSize: [{ type: Input }], nzGraphInitialized: [{ type: Output }], nzGraphRendered: [{ type: Output }], nzNodeClick: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhcGguY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vY29tcG9uZW50cy9ncmFwaC9ncmFwaC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7R0FHRztBQUVILE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ25ELE9BQU8sRUFFTCx1QkFBdUIsRUFFdkIsU0FBUyxFQUNULFlBQVksRUFDWixVQUFVLEVBQ1YsWUFBWSxFQUNaLElBQUksRUFDSixLQUFLLEVBSUwsUUFBUSxFQUNSLE1BQU0sRUFHTixXQUFXLEVBQ1gsWUFBWSxFQUNaLGlCQUFpQixFQUNsQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsUUFBUSxFQUFjLGFBQWEsRUFBRSxPQUFPLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUc1QyxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUUxRSxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFdkQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRWxELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDbEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDOUQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDekUsT0FBTyxFQUFFLG9CQUFvQixFQUFF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MEJBMkRJLElBQUk7OzBCQUFJLFFBQVE7OzBCQUNoQixRQUFRO3lDQXhEK0MsaUJBQWlCO3NCQUExRSxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRTtnQkFDcEIsbUJBQW1CO3NCQUF0RCxZQUFZO3VCQUFDLG9CQUFvQjtnQkFFdUMsWUFBWTtzQkFBcEYsWUFBWTt1QkFBQyxvQkFBb0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRTtnQkFHTyxpQkFBaUI7c0JBQTlGLFlBQVk7dUJBQUMseUJBQXlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBR0gsdUJBQXVCO3NCQUEvRixZQUFZO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO2dCQU85RCxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUNtQixVQUFVO3NCQUFsQyxLQUFLO2dCQUVhLGtCQUFrQjtzQkFBcEMsTUFBTTtnQkFDWSxlQUFlO3NCQUFqQyxNQUFNO2dCQUNZLFdBQVc7c0JBQTdCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9ORy1aT1JSTy9uZy16b3Jyby1hbnRkL2Jsb2IvbWFzdGVyL0xJQ0VOU0VcbiAqL1xuXG5pbXBvcnQgeyBOZ1RlbXBsYXRlT3V0bGV0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gIEFmdGVyQ29udGVudENoZWNrZWQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBDb250ZW50Q2hpbGQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSG9zdCxcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE9wdGlvbmFsLFxuICBPdXRwdXQsXG4gIFF1ZXJ5TGlzdCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVGVtcGxhdGVSZWYsXG4gIFZpZXdDaGlsZHJlbixcbiAgVmlld0VuY2Fwc3VsYXRpb25cbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBmb3JrSm9pbiwgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCwgU3ViamVjdCwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBmaW5hbGl6ZSwgdGFrZSwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuXG5pbXBvcnQgeyBidWlsZEdyYXBoIH0gZnJvbSAnZGFncmUtY29tcG91bmQnO1xuXG5pbXBvcnQgeyBOek5vQW5pbWF0aW9uRGlyZWN0aXZlIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL25vLWFuaW1hdGlvbic7XG5pbXBvcnQgeyBjYW5jZWxSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfSBmcm9tICduZy16b3Jyby1hbnRkL2NvcmUvcG9seWZpbGwnO1xuaW1wb3J0IHsgQm9vbGVhbklucHV0LCBOelNhZmVBbnkgfSBmcm9tICduZy16b3Jyby1hbnRkL2NvcmUvdHlwZXMnO1xuaW1wb3J0IHsgSW5wdXRCb29sZWFuIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL3V0aWwnO1xuXG5pbXBvcnQgeyBjYWxjdWxhdGVUcmFuc2Zvcm0gfSBmcm9tICcuL2NvcmUvdXRpbHMnO1xuaW1wb3J0IHsgTnpHcmFwaERhdGEgfSBmcm9tICcuL2RhdGEtc291cmNlL2dyYXBoLWRhdGEtc291cmNlJztcbmltcG9ydCB7IE56R3JhcGggfSBmcm9tICcuL2dyYXBoJztcbmltcG9ydCB7IE56R3JhcGhEZWZzQ29tcG9uZW50IH0gZnJvbSAnLi9ncmFwaC1kZWZzLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOekdyYXBoRWRnZUNvbXBvbmVudCB9IGZyb20gJy4vZ3JhcGgtZWRnZS5jb21wb25lbnQnO1xuaW1wb3J0IHsgTnpHcmFwaEVkZ2VEaXJlY3RpdmUgfSBmcm9tICcuL2dyYXBoLWVkZ2UuZGlyZWN0aXZlJztcbmltcG9ydCB7IE56R3JhcGhHcm91cE5vZGVEaXJlY3RpdmUgfSBmcm9tICcuL2dyYXBoLWdyb3VwLW5vZGUuZGlyZWN0aXZlJztcbmltcG9ydCB7IE56R3JhcGhOb2RlQ29tcG9uZW50IH0gZnJvbSAnLi9ncmFwaC1ub2RlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOekdyYXBoTm9kZURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtbm9kZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnpHcmFwaFpvb21EaXJlY3RpdmUgfSBmcm9tICcuL2dyYXBoLXpvb20uZGlyZWN0aXZlJztcbmltcG9ydCB7XG4gIE5aX0dSQVBIX0xBWU9VVF9TRVRUSU5HLFxuICBOekdyYXBoRGF0YURlZixcbiAgTnpHcmFwaEVkZ2UsXG4gIE56R3JhcGhFZGdlRGVmLFxuICBOekdyYXBoR3JvdXBOb2RlLFxuICBOekdyYXBoTGF5b3V0Q29uZmlnLFxuICBOekdyYXBoTm9kZSxcbiAgTnpHcmFwaE5vZGVEZWYsXG4gIE56R3JhcGhPcHRpb24sXG4gIE56TGF5b3V0U2V0dGluZyxcbiAgTnpSYW5rRGlyZWN0aW9uLFxuICBuelR5cGVEZWZpbml0aW9uXG59IGZyb20gJy4vaW50ZXJmYWNlJztcblxuLyoqIENoZWNrcyB3aGV0aGVyIGFuIG9iamVjdCBpcyBhIGRhdGEgc291cmNlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRGF0YVNvdXJjZSh2YWx1ZTogTnpTYWZlQW55KTogdmFsdWUgaXMgTnpHcmFwaERhdGEge1xuICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgaXMgYSBEYXRhU291cmNlIGJ5IG9ic2VydmluZyBpZiBpdCBoYXMgYSBjb25uZWN0IGZ1bmN0aW9uLiBDYW5ub3RcbiAgLy8gYmUgY2hlY2tlZCBhcyBhbiBgaW5zdGFuY2VvZiBEYXRhU291cmNlYCBzaW5jZSBwZW9wbGUgY291bGQgY3JlYXRlIHRoZWlyIG93biBzb3VyY2VzXG4gIC8vIHRoYXQgbWF0Y2ggdGhlIGludGVyZmFjZSwgYnV0IGRvbid0IGV4dGVuZCBEYXRhU291cmNlLlxuICByZXR1cm4gdmFsdWUgJiYgdHlwZW9mIHZhbHVlLmNvbm5lY3QgPT09ICdmdW5jdGlvbic7XG59XG5cbkBDb21wb25lbnQoe1xuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbiAgZW5jYXBzdWxhdGlvbjogVmlld0VuY2Fwc3VsYXRpb24uTm9uZSxcbiAgc2VsZWN0b3I6ICduei1ncmFwaCcsXG4gIGV4cG9ydEFzOiAnbnpHcmFwaCcsXG4gIHByb3ZpZGVyczogW3sgcHJvdmlkZTogTnpHcmFwaCwgdXNlRXhpc3Rpbmc6IE56R3JhcGhDb21wb25lbnQgfV0sXG4gIHRlbXBsYXRlOiBgXG4gICAgPG5nLWNvbnRlbnQ+PC9uZy1jb250ZW50PlxuICAgIDxzdmcgd2lkdGg9XCIxMDAlXCIgaGVpZ2h0PVwiMTAwJVwiPlxuICAgICAgPHN2ZzpkZWZzIG56LWdyYXBoLWRlZnM+PC9zdmc6ZGVmcz5cbiAgICAgIDxzdmc6ZyBbYXR0ci50cmFuc2Zvcm1dPVwidHJhbnNmb3JtU3R5bGVcIj5cbiAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0XT1cImdyb3VwVGVtcGxhdGVcIlxuICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IHJlbmRlck5vZGU6IHJlbmRlckluZm8sIHR5cGU6ICdyb290JyB9XCJcbiAgICAgICAgPjwvbmctY29udGFpbmVyPlxuICAgICAgPC9zdmc6Zz5cbiAgICA8L3N2Zz5cblxuICAgIDxuZy10ZW1wbGF0ZSAjZ3JvdXBUZW1wbGF0ZSBsZXQtcmVuZGVyTm9kZT1cInJlbmRlck5vZGVcIiBsZXQtdHlwZT1cInR5cGVcIj5cbiAgICAgIDxzdmc6ZyBbYXR0ci50cmFuc2Zvcm1dPVwidHlwZSA9PT0gJ3N1YicgPyBzdWJHcmFwaFRyYW5zZm9ybShyZW5kZXJOb2RlKSA6IG51bGxcIj5cbiAgICAgICAgPHN2ZzpnIGNsYXNzPVwiY29yZVwiIFthdHRyLnRyYW5zZm9ybV09XCJjb3JlVHJhbnNmb3JtKHJlbmRlck5vZGUpXCI+XG4gICAgICAgICAgPHN2ZzpnIGNsYXNzPVwibnotZ3JhcGgtZWRnZXNcIj5cbiAgICAgICAgICAgIEBmb3IgKGVkZ2Ugb2YgJGFzTnpHcmFwaEVkZ2VzKHJlbmRlck5vZGUuZWRnZXMpOyB0cmFjayBlZGdlVHJhY2tCeUZ1bikge1xuICAgICAgICAgICAgICA8Z1xuICAgICAgICAgICAgICAgIGNsYXNzPVwibnotZ3JhcGgtZWRnZVwiXG4gICAgICAgICAgICAgICAgbnotZ3JhcGgtZWRnZVxuICAgICAgICAgICAgICAgIFtlZGdlXT1cImVkZ2VcIlxuICAgICAgICAgICAgICAgIFtlZGdlVHlwZV09XCJuekdyYXBoTGF5b3V0Q29uZmlnPy5kZWZhdWx0RWRnZT8udHlwZVwiXG4gICAgICAgICAgICAgICAgW2N1c3RvbVRlbXBsYXRlXT1cImN1c3RvbUdyYXBoRWRnZVRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgPjwvZz5cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3N2ZzpnPlxuXG4gICAgICAgICAgPHN2ZzpnIGNsYXNzPVwibnotZ3JhcGgtbm9kZXNcIj5cbiAgICAgICAgICAgIEBmb3IgKG5vZGUgb2YgdHlwZWROb2RlcyhyZW5kZXJOb2RlLm5vZGVzKTsgdHJhY2sgbm9kZS5uYW1lKSB7XG4gICAgICAgICAgICAgIEBpZiAobm9kZS50eXBlID09PSAxKSB7XG4gICAgICAgICAgICAgICAgPGcgY2xhc3M9XCJuei1ncmFwaC1ub2RlXCIgbnotZ3JhcGgtbm9kZSBbbm9kZV09XCJub2RlXCIgW2N1c3RvbVRlbXBsYXRlXT1cIm5vZGVUZW1wbGF0ZVwiPjwvZz5cbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIEBpZiAobm9kZS50eXBlID09PSAwKSB7XG4gICAgICAgICAgICAgICAgPGcgY2xhc3M9XCJuei1ncmFwaC1ub2RlXCIgbnotZ3JhcGgtbm9kZSBbbm9kZV09XCJub2RlXCIgW2N1c3RvbVRlbXBsYXRlXT1cImdyb3VwTm9kZVRlbXBsYXRlXCI+PC9nPlxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgQGlmIChub2RlLmV4cGFuZGVkKSB7XG4gICAgICAgICAgICAgICAgPG5nLWNvbnRhaW5lclxuICAgICAgICAgICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiZ3JvdXBUZW1wbGF0ZVwiXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldENvbnRleHRdPVwieyByZW5kZXJOb2RlOiBub2RlLCB0eXBlOiAnc3ViJyB9XCJcbiAgICAgICAgICAgICAgICAvPlxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgPC9zdmc6Zz5cbiAgICAgICAgPC9zdmc6Zz5cbiAgICAgIDwvc3ZnOmc+XG4gICAgPC9uZy10ZW1wbGF0ZT5cbiAgYCxcbiAgaG9zdDoge1xuICAgICdbY2xhc3MubnotZ3JhcGhdJzogJ3RydWUnLFxuICAgICdbY2xhc3MubnotZ3JhcGgtYXV0by1zaXplXSc6ICduekF1dG9TaXplJ1xuICB9LFxuICBpbXBvcnRzOiBbTmdUZW1wbGF0ZU91dGxldCwgTnpHcmFwaEVkZ2VDb21wb25lbnQsIE56R3JhcGhOb2RlQ29tcG9uZW50LCBOekdyYXBoRGVmc0NvbXBvbmVudF0sXG4gIHN0YW5kYWxvbmU6IHRydWVcbn0pXG5leHBvcnQgY2xhc3MgTnpHcmFwaENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBBZnRlckNvbnRlbnRDaGVja2VkLCBPbkRlc3Ryb3ksIE56R3JhcGgge1xuICBzdGF0aWMgbmdBY2NlcHRJbnB1dFR5cGVfbnpBdXRvU2l6ZTogQm9vbGVhbklucHV0O1xuXG4gIEBWaWV3Q2hpbGRyZW4oTnpHcmFwaE5vZGVDb21wb25lbnQsIHsgcmVhZDogRWxlbWVudFJlZiB9KSBsaXN0T2ZOb2RlRWxlbWVudCE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZHJlbihOekdyYXBoTm9kZUNvbXBvbmVudCkgbGlzdE9mTm9kZUNvbXBvbmVudCE6IFF1ZXJ5TGlzdDxOekdyYXBoTm9kZUNvbXBvbmVudD47XG5cbiAgQENvbnRlbnRDaGlsZChOekdyYXBoTm9kZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIG5vZGVUZW1wbGF0ZT86IFRlbXBsYXRlUmVmPHtcbiAgICAkaW1wbGljaXQ6IE56R3JhcGhOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoR3JvdXBOb2RlRGlyZWN0aXZlLCB7IHN0YXRpYzogdHJ1ZSwgcmVhZDogVGVtcGxhdGVSZWYgfSkgZ3JvdXBOb2RlVGVtcGxhdGU/OiBUZW1wbGF0ZVJlZjx7XG4gICAgJGltcGxpY2l0OiBOekdyYXBoR3JvdXBOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoRWRnZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIGN1c3RvbUdyYXBoRWRnZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8e1xuICAgICRpbXBsaWNpdDogTnpHcmFwaEVkZ2U7XG4gIH0+O1xuICAvKipcbiAgICogUHJvdmlkZXMgYSBzdHJlYW0gY29udGFpbmluZyB0aGUgbGF0ZXN0IGRhdGEgYXJyYXkgdG8gcmVuZGVyLlxuICAgKiBEYXRhIHNvdXJjZSBjYW4gYmUgYW4gb2JzZXJ2YWJsZSBvZiBOekdyYXBoRGF0YSwgb3IgYSBOekdyYXBoRGF0YSB0byByZW5kZXIuXG4gICAqL1xuICBASW5wdXQoKSBuekdyYXBoRGF0YSE6IE56R3JhcGhEYXRhO1xuICBASW5wdXQoKSBuelJhbmtEaXJlY3Rpb246IE56UmFua0RpcmVjdGlvbiA9ICdMUic7XG4gIEBJbnB1dCgpIG56R3JhcGhMYXlvdXRDb25maWc/OiBOekdyYXBoTGF5b3V0Q29uZmlnO1xuICBASW5wdXQoKSBASW5wdXRCb29sZWFuKCkgbnpBdXRvU2l6ZSA9IGZhbHNlO1xuXG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoSW5pdGlhbGl6ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoUmVuZGVyZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuek5vZGVDbGljazogRXZlbnRFbWl0dGVyPE56R3JhcGhOb2RlIHwgTnpHcmFwaEdyb3VwTm9kZT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgcmVxdWVzdElkOiBudW1iZXIgPSAtMTtcbiAgdHJhbnNmb3JtU3R5bGUgPSAnJztcbiAgZ3JhcGhSZW5kZXJlZFN1YmplY3QkID0gbmV3IFJlcGxheVN1YmplY3Q8dm9pZD4oMSk7XG4gIHJlbmRlckluZm86IE56R3JhcGhHcm91cE5vZGUgPSB7IGxhYmVsSGVpZ2h0OiAwIH0gYXMgTnpHcmFwaEdyb3VwTm9kZTtcbiAgbWFwT2ZOb2RlQXR0cjogeyBba2V5OiBzdHJpbmddOiBOekdyYXBoTm9kZURlZiB9ID0ge307XG4gIG1hcE9mRWRnZUF0dHI6IHsgW2tleTogc3RyaW5nXTogTnpHcmFwaEVkZ2VEZWYgfSA9IHt9O1xuICB6b29tID0gMTtcblxuICBwdWJsaWMgcmVhZG9ubHkgdHlwZWROb2RlcyA9IG56VHlwZURlZmluaXRpb248QXJyYXk8TnpHcmFwaE5vZGUgfCBOekdyYXBoR3JvdXBOb2RlPj4oKTtcbiAgcHJpdmF0ZSBkYXRhU291cmNlPzogTnpHcmFwaERhdGE7XG4gIHByaXZhdGUgbGF5b3V0U2V0dGluZzogTnpMYXlvdXRTZXR0aW5nID0gTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkc7XG4gIC8qKiBEYXRhIHN1YnNjcmlwdGlvbiAqL1xuICBwcml2YXRlIF9kYXRhU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uIHwgbnVsbDtcbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgZWRnZVRyYWNrQnlGdW4gPSAoXzogbnVtYmVyLCBlZGdlOiBOekdyYXBoRWRnZSk6IHN0cmluZyA9PiBgJHtlZGdlLnZ9LSR7ZWRnZS53fWA7XG5cbiAgc3ViR3JhcGhUcmFuc2Zvcm0gPSAobm9kZTogTnpHcmFwaEdyb3VwTm9kZSk6IHN0cmluZyA9PiB7XG4gICAgY29uc3QgeCA9IG5vZGUueCAtIG5vZGUuY29yZUJveC53aWR0aCAvIDIuMDtcbiAgICBjb25zdCB5ID0gbm9kZS55IC0gbm9kZS5oZWlnaHQgLyAyLjAgKyBub2RlLnBhZGRpbmdUb3A7XG4gICAgcmV0dXJuIGB0cmFuc2xhdGUoJHt4fSwgJHt5fSlgO1xuICB9O1xuXG4gICRhc056R3JhcGhFZGdlcyA9IChkYXRhOiB1bmtub3duKTogTnpHcmFwaEVkZ2VbXSA9PiBkYXRhIGFzIE56R3JhcGhFZGdlW107XG5cbiAgY29yZVRyYW5zZm9ybSA9IChub2RlOiBOekdyYXBoR3JvdXBOb2RlKTogc3RyaW5nID0+IGB0cmFuc2xhdGUoMCwgJHtub2RlLnBhcmVudE5vZGVOYW1lID8gbm9kZS5sYWJlbEhlaWdodCA6IDB9KWA7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICAgIHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZixcbiAgICBASG9zdCgpIEBPcHRpb25hbCgpIHB1YmxpYyBub0FuaW1hdGlvbj86IE56Tm9BbmltYXRpb25EaXJlY3RpdmUsXG4gICAgQE9wdGlvbmFsKCkgcHVibGljIG56R3JhcGhab29tPzogTnpHcmFwaFpvb21EaXJlY3RpdmVcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZ3JhcGhSZW5kZXJlZFN1YmplY3QkLnBpcGUodGFrZSgxKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgLy8gT25seSB6b29taW5nIGlzIG5vdCBzZXQsIG1vdmUgZ3JhcGggdG8gY2VudGVyXG4gICAgICBpZiAoIXRoaXMubnpHcmFwaFpvb20pIHtcbiAgICAgICAgdGhpcy5maXRDZW50ZXIoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubnpHcmFwaEluaXRpYWxpemVkLmVtaXQodGhpcyk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgY29uc3QgeyBuekF1dG9GaXQsIG56UmFua0RpcmVjdGlvbiwgbnpHcmFwaERhdGEsIG56R3JhcGhMYXlvdXRDb25maWcgfSA9IGNoYW5nZXM7XG4gICAgaWYgKG56R3JhcGhMYXlvdXRDb25maWcpIHtcbiAgICAgIHRoaXMubGF5b3V0U2V0dGluZyA9IHRoaXMubWVyZ2VDb25maWcobnpHcmFwaExheW91dENvbmZpZy5jdXJyZW50VmFsdWUpO1xuICAgIH1cblxuICAgIGlmIChuekdyYXBoRGF0YSkge1xuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAhPT0gdGhpcy5uekdyYXBoRGF0YSkge1xuICAgICAgICB0aGlzLl9zd2l0Y2hEYXRhU291cmNlKHRoaXMubnpHcmFwaERhdGEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICgobnpBdXRvRml0ICYmICFuekF1dG9GaXQuZmlyc3RDaGFuZ2UpIHx8IChuelJhbmtEaXJlY3Rpb24gJiYgIW56UmFua0RpcmVjdGlvbi5maXJzdENoYW5nZSkpIHtcbiAgICAgIC8vIFJlbmRlciBncmFwaFxuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSEuZGF0YVNvdXJjZSkge1xuICAgICAgICB0aGlzLmRyYXdHcmFwaCh0aGlzLmRhdGFTb3VyY2UhLmRhdGFTb3VyY2UsIHtcbiAgICAgICAgICByYW5rRGlyZWN0aW9uOiB0aGlzLm56UmFua0RpcmVjdGlvbixcbiAgICAgICAgICBleHBhbmRlZDogdGhpcy5kYXRhU291cmNlIS5leHBhbnNpb25Nb2RlbC5zZWxlY3RlZCB8fCBbXVxuICAgICAgICB9KS50aGVuKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudENoZWNrZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAmJiAhdGhpcy5fZGF0YVN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5vYnNlcnZlUmVuZGVyQ2hhbmdlcygpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcblxuICAgIGlmICh0aGlzLmRhdGFTb3VyY2UgJiYgdHlwZW9mIHRoaXMuZGF0YVNvdXJjZS5kaXNjb25uZWN0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLmRhdGFTb3VyY2UuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gbnVsbDtcbiAgICB9XG4gICAgY2FuY2V