ng-zorro-antd
Version:
An enterprise-class UI components based on Ant Design and Angular
479 lines (471 loc) • 60 kB
JavaScript
/**
* 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, booleanAttribute } from '@angular/core';
import { ReplaySubject, Subject, forkJoin } from 'rxjs';
import { finalize, take, takeUntil } from 'rxjs/operators';
import { buildGraph } from 'dagre-compound';
import { cancelRequestAnimationFrame } from 'ng-zorro-antd/core/polyfill';
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: "18.0.1", 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: "18.0.1", type: NzGraphComponent, isStandalone: true, selector: "nz-graph", inputs: { nzGraphData: "nzGraphData", nzRankDirection: "nzRankDirection", nzGraphLayoutConfig: "nzGraphLayoutConfig", nzAutoSize: ["nzAutoSize", "nzAutoSize", booleanAttribute] }, 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 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", 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,
args: [{ transform: booleanAttribute }]
}], nzGraphInitialized: [{
type: Output
}], nzGraphRendered: [{
type: Output
}], nzNodeClick: [{
type: Output
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhcGguY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vY29tcG9uZW50cy9ncmFwaC9ncmFwaC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDbkQsT0FBTyxFQUVMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixZQUFZLEVBQ1osSUFBSSxFQUNKLEtBQUssRUFJTCxRQUFRLEVBQ1IsTUFBTSxFQUdOLFdBQVcsRUFDWCxZQUFZLEVBQ1osaUJBQWlCLEVBQ2pCLGdCQUFnQixFQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQWMsYUFBYSxFQUFFLE9BQU8sRUFBZ0IsUUFBUSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNELE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUc1QyxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUcxRSxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFbEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNsQyxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUN6RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVB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QWlCO3NCQUExRSxZQUFZO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRTtnQkFDcEIsbUJBQW1CO3NCQUF0RCxZQUFZO3VCQUFDLG9CQUFvQjtnQkFFdUMsWUFBWTtzQkFBcEYsWUFBWTt1QkFBQyxvQkFBb0IsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRTtnQkFHTyxpQkFBaUI7c0JBQTlGLFlBQVk7dUJBQUMseUJBQXlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBR0gsdUJBQXVCO3NCQUEvRixZQUFZO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO2dCQU85RCxXQUFXO3NCQUFuQixLQUFLO2dCQUNHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csbUJBQW1CO3NCQUEzQixLQUFLO2dCQUNrQyxVQUFVO3NCQUFqRCxLQUFLO3VCQUFDLEVBQUUsU0FBUyxFQUFFLGdCQUFnQixFQUFFO2dCQUVuQixrQkFBa0I7c0JBQXBDLE1BQU07Z0JBQ1ksZUFBZTtzQkFBakMsTUFBTTtnQkFDWSxXQUFXO3NCQUE3QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVc2Ugb2YgdGhpcyBzb3VyY2UgY29kZSBpcyBnb3Zlcm5lZCBieSBhbiBNSVQtc3R5bGUgbGljZW5zZSB0aGF0IGNhbiBiZVxuICogZm91bmQgaW4gdGhlIExJQ0VOU0UgZmlsZSBhdCBodHRwczovL2dpdGh1Yi5jb20vTkctWk9SUk8vbmctem9ycm8tYW50ZC9ibG9iL21hc3Rlci9MSUNFTlNFXG4gKi9cblxuaW1wb3J0IHsgTmdUZW1wbGF0ZU91dGxldCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBBZnRlckNvbnRlbnRDaGVja2VkLFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gIENvbXBvbmVudCxcbiAgQ29udGVudENoaWxkLFxuICBFbGVtZW50UmVmLFxuICBFdmVudEVtaXR0ZXIsXG4gIEhvc3QsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT25Jbml0LFxuICBPcHRpb25hbCxcbiAgT3V0cHV0LFxuICBRdWVyeUxpc3QsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFRlbXBsYXRlUmVmLFxuICBWaWV3Q2hpbGRyZW4sXG4gIFZpZXdFbmNhcHN1bGF0aW9uLFxuICBib29sZWFuQXR0cmlidXRlXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCwgU3ViamVjdCwgU3Vic2NyaXB0aW9uLCBmb3JrSm9pbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmluYWxpemUsIHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgYnVpbGRHcmFwaCB9IGZyb20gJ2RhZ3JlLWNvbXBvdW5kJztcblxuaW1wb3J0IHsgTnpOb0FuaW1hdGlvbkRpcmVjdGl2ZSB9IGZyb20gJ25nLXpvcnJvLWFudGQvY29yZS9uby1hbmltYXRpb24nO1xuaW1wb3J0IHsgY2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL3BvbHlmaWxsJztcbmltcG9ydCB7IE56U2FmZUFueSB9IGZyb20gJ25nLXpvcnJvLWFudGQvY29yZS90eXBlcyc7XG5cbmltcG9ydCB7IGNhbGN1bGF0ZVRyYW5zZm9ybSB9IGZyb20gJy4vY29yZS91dGlscyc7XG5pbXBvcnQgeyBOekdyYXBoRGF0YSB9IGZyb20gJy4vZGF0YS1zb3VyY2UvZ3JhcGgtZGF0YS1zb3VyY2UnO1xuaW1wb3J0IHsgTnpHcmFwaCB9IGZyb20gJy4vZ3JhcGgnO1xuaW1wb3J0IHsgTnpHcmFwaERlZnNDb21wb25lbnQgfSBmcm9tICcuL2dyYXBoLWRlZnMuY29tcG9uZW50JztcbmltcG9ydCB7IE56R3JhcGhFZGdlQ29tcG9uZW50IH0gZnJvbSAnLi9ncmFwaC1lZGdlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOekdyYXBoRWRnZURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtZWRnZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnpHcmFwaEdyb3VwTm9kZURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtZ3JvdXAtbm9kZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnpHcmFwaE5vZGVDb21wb25lbnQgfSBmcm9tICcuL2dyYXBoLW5vZGUuY29tcG9uZW50JztcbmltcG9ydCB7IE56R3JhcGhOb2RlRGlyZWN0aXZlIH0gZnJvbSAnLi9ncmFwaC1ub2RlLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBOekdyYXBoWm9vbURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtem9vbS5kaXJlY3RpdmUnO1xuaW1wb3J0IHtcbiAgTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkcsXG4gIE56R3JhcGhEYXRhRGVmLFxuICBOekdyYXBoRWRnZSxcbiAgTnpHcmFwaEVkZ2VEZWYsXG4gIE56R3JhcGhHcm91cE5vZGUsXG4gIE56R3JhcGhMYXlvdXRDb25maWcsXG4gIE56R3JhcGhOb2RlLFxuICBOekdyYXBoTm9kZURlZixcbiAgTnpHcmFwaE9wdGlvbixcbiAgTnpMYXlvdXRTZXR0aW5nLFxuICBOelJhbmtEaXJlY3Rpb24sXG4gIG56VHlwZURlZmluaXRpb25cbn0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuXG4vKiogQ2hlY2tzIHdoZXRoZXIgYW4gb2JqZWN0IGlzIGEgZGF0YSBzb3VyY2UuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEYXRhU291cmNlKHZhbHVlOiBOelNhZmVBbnkpOiB2YWx1ZSBpcyBOekdyYXBoRGF0YSB7XG4gIC8vIENoZWNrIGlmIHRoZSB2YWx1ZSBpcyBhIERhdGFTb3VyY2UgYnkgb2JzZXJ2aW5nIGlmIGl0IGhhcyBhIGNvbm5lY3QgZnVuY3Rpb24uIENhbm5vdFxuICAvLyBiZSBjaGVja2VkIGFzIGFuIGBpbnN0YW5jZW9mIERhdGFTb3VyY2VgIHNpbmNlIHBlb3BsZSBjb3VsZCBjcmVhdGUgdGhlaXIgb3duIHNvdXJjZXNcbiAgLy8gdGhhdCBtYXRjaCB0aGUgaW50ZXJmYWNlLCBidXQgZG9uJ3QgZXh0ZW5kIERhdGFTb3VyY2UuXG4gIHJldHVybiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUuY29ubmVjdCA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBzZWxlY3RvcjogJ256LWdyYXBoJyxcbiAgZXhwb3J0QXM6ICduekdyYXBoJyxcbiAgcHJvdmlkZXJzOiBbeyBwcm92aWRlOiBOekdyYXBoLCB1c2VFeGlzdGluZzogTnpHcmFwaENvbXBvbmVudCB9XSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgPHN2ZyB3aWR0aD1cIjEwMCVcIiBoZWlnaHQ9XCIxMDAlXCI+XG4gICAgICA8c3ZnOmRlZnMgbnotZ3JhcGgtZGVmcz48L3N2ZzpkZWZzPlxuICAgICAgPHN2ZzpnIFthdHRyLnRyYW5zZm9ybV09XCJ0cmFuc2Zvcm1TdHlsZVwiPlxuICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiZ3JvdXBUZW1wbGF0ZVwiXG4gICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgcmVuZGVyTm9kZTogcmVuZGVySW5mbywgdHlwZTogJ3Jvb3QnIH1cIlxuICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICA8L3N2ZzpnPlxuICAgIDwvc3ZnPlxuXG4gICAgPG5nLXRlbXBsYXRlICNncm91cFRlbXBsYXRlIGxldC1yZW5kZXJOb2RlPVwicmVuZGVyTm9kZVwiIGxldC10eXBlPVwidHlwZVwiPlxuICAgICAgPHN2ZzpnIFthdHRyLnRyYW5zZm9ybV09XCJ0eXBlID09PSAnc3ViJyA/IHN1YkdyYXBoVHJhbnNmb3JtKHJlbmRlck5vZGUpIDogbnVsbFwiPlxuICAgICAgICA8c3ZnOmcgY2xhc3M9XCJjb3JlXCIgW2F0dHIudHJhbnNmb3JtXT1cImNvcmVUcmFuc2Zvcm0ocmVuZGVyTm9kZSlcIj5cbiAgICAgICAgICA8c3ZnOmcgY2xhc3M9XCJuei1ncmFwaC1lZGdlc1wiPlxuICAgICAgICAgICAgQGZvciAoZWRnZSBvZiAkYXNOekdyYXBoRWRnZXMocmVuZGVyTm9kZS5lZGdlcyk7IHRyYWNrIGVkZ2VUcmFja0J5RnVuKSB7XG4gICAgICAgICAgICAgIDxnXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJuei1ncmFwaC1lZGdlXCJcbiAgICAgICAgICAgICAgICBuei1ncmFwaC1lZGdlXG4gICAgICAgICAgICAgICAgW2VkZ2VdPVwiZWRnZVwiXG4gICAgICAgICAgICAgICAgW2VkZ2VUeXBlXT1cIm56R3JhcGhMYXlvdXRDb25maWc/LmRlZmF1bHRFZGdlPy50eXBlXCJcbiAgICAgICAgICAgICAgICBbY3VzdG9tVGVtcGxhdGVdPVwiY3VzdG9tR3JhcGhFZGdlVGVtcGxhdGVcIlxuICAgICAgICAgICAgICA+PC9nPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvc3ZnOmc+XG5cbiAgICAgICAgICA8c3ZnOmcgY2xhc3M9XCJuei1ncmFwaC1ub2Rlc1wiPlxuICAgICAgICAgICAgQGZvciAobm9kZSBvZiB0eXBlZE5vZGVzKHJlbmRlck5vZGUubm9kZXMpOyB0cmFjayBub2RlLm5hbWUpIHtcbiAgICAgICAgICAgICAgQGlmIChub2RlLnR5cGUgPT09IDEpIHtcbiAgICAgICAgICAgICAgICA8ZyBjbGFzcz1cIm56LWdyYXBoLW5vZGVcIiBuei1ncmFwaC1ub2RlIFtub2RlXT1cIm5vZGVcIiBbY3VzdG9tVGVtcGxhdGVdPVwibm9kZVRlbXBsYXRlXCI+PC9nPlxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgQGlmIChub2RlLnR5cGUgPT09IDApIHtcbiAgICAgICAgICAgICAgICA8ZyBjbGFzcz1cIm56LWdyYXBoLW5vZGVcIiBuei1ncmFwaC1ub2RlIFtub2RlXT1cIm5vZGVcIiBbY3VzdG9tVGVtcGxhdGVdPVwiZ3JvdXBOb2RlVGVtcGxhdGVcIj48L2c+XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBAaWYgKG5vZGUuZXhwYW5kZWQpIHtcbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJncm91cFRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IHJlbmRlck5vZGU6IG5vZGUsIHR5cGU6ICdzdWInIH1cIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3N2ZzpnPlxuICAgICAgICA8L3N2ZzpnPlxuICAgICAgPC9zdmc6Zz5cbiAgICA8L25nLXRlbXBsYXRlPlxuICBgLFxuICBob3N0OiB7XG4gICAgJ1tjbGFzcy5uei1ncmFwaF0nOiAndHJ1ZScsXG4gICAgJ1tjbGFzcy5uei1ncmFwaC1hdXRvLXNpemVdJzogJ256QXV0b1NpemUnXG4gIH0sXG4gIGltcG9ydHM6IFtOZ1RlbXBsYXRlT3V0bGV0LCBOekdyYXBoRWRnZUNvbXBvbmVudCwgTnpHcmFwaE5vZGVDb21wb25lbnQsIE56R3JhcGhEZWZzQ29tcG9uZW50XSxcbiAgc3RhbmRhbG9uZTogdHJ1ZVxufSlcbmV4cG9ydCBjbGFzcyBOekdyYXBoQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyQ29udGVudENoZWNrZWQsIE9uRGVzdHJveSwgTnpHcmFwaCB7XG4gIEBWaWV3Q2hpbGRyZW4oTnpHcmFwaE5vZGVDb21wb25lbnQsIHsgcmVhZDogRWxlbWVudFJlZiB9KSBsaXN0T2ZOb2RlRWxlbWVudCE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZHJlbihOekdyYXBoTm9kZUNvbXBvbmVudCkgbGlzdE9mTm9kZUNvbXBvbmVudCE6IFF1ZXJ5TGlzdDxOekdyYXBoTm9kZUNvbXBvbmVudD47XG5cbiAgQENvbnRlbnRDaGlsZChOekdyYXBoTm9kZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIG5vZGVUZW1wbGF0ZT86IFRlbXBsYXRlUmVmPHtcbiAgICAkaW1wbGljaXQ6IE56R3JhcGhOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoR3JvdXBOb2RlRGlyZWN0aXZlLCB7IHN0YXRpYzogdHJ1ZSwgcmVhZDogVGVtcGxhdGVSZWYgfSkgZ3JvdXBOb2RlVGVtcGxhdGU/OiBUZW1wbGF0ZVJlZjx7XG4gICAgJGltcGxpY2l0OiBOekdyYXBoR3JvdXBOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoRWRnZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIGN1c3RvbUdyYXBoRWRnZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8e1xuICAgICRpbXBsaWNpdDogTnpHcmFwaEVkZ2U7XG4gIH0+O1xuICAvKipcbiAgICogUHJvdmlkZXMgYSBzdHJlYW0gY29udGFpbmluZyB0aGUgbGF0ZXN0IGRhdGEgYXJyYXkgdG8gcmVuZGVyLlxuICAgKiBEYXRhIHNvdXJjZSBjYW4gYmUgYW4gb2JzZXJ2YWJsZSBvZiBOekdyYXBoRGF0YSwgb3IgYSBOekdyYXBoRGF0YSB0byByZW5kZXIuXG4gICAqL1xuICBASW5wdXQoKSBuekdyYXBoRGF0YSE6IE56R3JhcGhEYXRhO1xuICBASW5wdXQoKSBuelJhbmtEaXJlY3Rpb246IE56UmFua0RpcmVjdGlvbiA9ICdMUic7XG4gIEBJbnB1dCgpIG56R3JhcGhMYXlvdXRDb25maWc/OiBOekdyYXBoTGF5b3V0Q29uZmlnO1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgbnpBdXRvU2l6ZSA9IGZhbHNlO1xuXG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoSW5pdGlhbGl6ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoUmVuZGVyZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuek5vZGVDbGljazogRXZlbnRFbWl0dGVyPE56R3JhcGhOb2RlIHwgTnpHcmFwaEdyb3VwTm9kZT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgcmVxdWVzdElkOiBudW1iZXIgPSAtMTtcbiAgdHJhbnNmb3JtU3R5bGUgPSAnJztcbiAgZ3JhcGhSZW5kZXJlZFN1YmplY3QkID0gbmV3IFJlcGxheVN1YmplY3Q8dm9pZD4oMSk7XG4gIHJlbmRlckluZm86IE56R3JhcGhHcm91cE5vZGUgPSB7IGxhYmVsSGVpZ2h0OiAwIH0gYXMgTnpHcmFwaEdyb3VwTm9kZTtcbiAgbWFwT2ZOb2RlQXR0cjogeyBba2V5OiBzdHJpbmddOiBOekdyYXBoTm9kZURlZiB9ID0ge307XG4gIG1hcE9mRWRnZUF0dHI6IHsgW2tleTogc3RyaW5nXTogTnpHcmFwaEVkZ2VEZWYgfSA9IHt9O1xuICB6b29tID0gMTtcblxuICBwdWJsaWMgcmVhZG9ubHkgdHlwZWROb2RlcyA9IG56VHlwZURlZmluaXRpb248QXJyYXk8TnpHcmFwaE5vZGUgfCBOekdyYXBoR3JvdXBOb2RlPj4oKTtcbiAgcHJpdmF0ZSBkYXRhU291cmNlPzogTnpHcmFwaERhdGE7XG4gIHByaXZhdGUgbGF5b3V0U2V0dGluZzogTnpMYXlvdXRTZXR0aW5nID0gTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkc7XG4gIC8qKiBEYXRhIHN1YnNjcmlwdGlvbiAqL1xuICBwcml2YXRlIF9kYXRhU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uIHwgbnVsbDtcbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgZWRnZVRyYWNrQnlGdW4gPSAoXzogbnVtYmVyLCBlZGdlOiBOekdyYXBoRWRnZSk6IHN0cmluZyA9PiBgJHtlZGdlLnZ9LSR7ZWRnZS53fWA7XG5cbiAgc3ViR3JhcGhUcmFuc2Zvcm0gPSAobm9kZTogTnpHcmFwaEdyb3VwTm9kZSk6IHN0cmluZyA9PiB7XG4gICAgY29uc3QgeCA9IG5vZGUueCAtIG5vZGUuY29yZUJveC53aWR0aCAvIDIuMDtcbiAgICBjb25zdCB5ID0gbm9kZS55IC0gbm9kZS5oZWlnaHQgLyAyLjAgKyBub2RlLnBhZGRpbmdUb3A7XG4gICAgcmV0dXJuIGB0cmFuc2xhdGUoJHt4fSwgJHt5fSlgO1xuICB9O1xuXG4gICRhc056R3JhcGhFZGdlcyA9IChkYXRhOiB1bmtub3duKTogTnpHcmFwaEVkZ2VbXSA9PiBkYXRhIGFzIE56R3JhcGhFZGdlW107XG5cbiAgY29yZVRyYW5zZm9ybSA9IChub2RlOiBOekdyYXBoR3JvdXBOb2RlKTogc3RyaW5nID0+IGB0cmFuc2xhdGUoMCwgJHtub2RlLnBhcmVudE5vZGVOYW1lID8gbm9kZS5sYWJlbEhlaWdodCA6IDB9KWA7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBjZHI6IENoYW5nZURldGVjdG9yUmVmLFxuICAgIHByaXZhdGUgZWxlbWVudFJlZjogRWxlbWVudFJlZixcbiAgICBASG9zdCgpIEBPcHRpb25hbCgpIHB1YmxpYyBub0FuaW1hdGlvbj86IE56Tm9BbmltYXRpb25EaXJlY3RpdmUsXG4gICAgQE9wdGlvbmFsKCkgcHVibGljIG56R3JhcGhab29tPzogTnpHcmFwaFpvb21EaXJlY3RpdmVcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZ3JhcGhSZW5kZXJlZFN1YmplY3QkLnBpcGUodGFrZSgxKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgLy8gT25seSB6b29taW5nIGlzIG5vdCBzZXQsIG1vdmUgZ3JhcGggdG8gY2VudGVyXG4gICAgICBpZiAoIXRoaXMubnpHcmFwaFpvb20pIHtcbiAgICAgICAgdGhpcy5maXRDZW50ZXIoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubnpHcmFwaEluaXRpYWxpemVkLmVtaXQodGhpcyk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgY29uc3QgeyBuekF1dG9GaXQsIG56UmFua0RpcmVjdGlvbiwgbnpHcmFwaERhdGEsIG56R3JhcGhMYXlvdXRDb25maWcgfSA9IGNoYW5nZXM7XG4gICAgaWYgKG56R3JhcGhMYXlvdXRDb25maWcpIHtcbiAgICAgIHRoaXMubGF5b3V0U2V0dGluZyA9IHRoaXMubWVyZ2VDb25maWcobnpHcmFwaExheW91dENvbmZpZy5jdXJyZW50VmFsdWUpO1xuICAgIH1cblxuICAgIGlmIChuekdyYXBoRGF0YSkge1xuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAhPT0gdGhpcy5uekdyYXBoRGF0YSkge1xuICAgICAgICB0aGlzLl9zd2l0Y2hEYXRhU291cmNlKHRoaXMubnpHcmFwaERhdGEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICgobnpBdXRvRml0ICYmICFuekF1dG9GaXQuZmlyc3RDaGFuZ2UpIHx8IChuelJhbmtEaXJlY3Rpb24gJiYgIW56UmFua0RpcmVjdGlvbi5maXJzdENoYW5nZSkpIHtcbiAgICAgIC8vIFJlbmRlciBncmFwaFxuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSEuZGF0YVNvdXJjZSkge1xuICAgICAgICB0aGlzLmRyYXdHcmFwaCh0aGlzLmRhdGFTb3VyY2UhLmRhdGFTb3VyY2UsIHtcbiAgICAgICAgICByYW5rRGlyZWN0aW9uOiB0aGlzLm56UmFua0RpcmVjdGlvbixcbiAgICAgICAgICBleHBhbmRlZDogdGhpcy5kYXRhU291cmNlIS5leHBhbnNpb25Nb2RlbC5zZWxlY3RlZCB8fCBbXVxuICAgICAgICB9KS50aGVuKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudENoZWNrZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAmJiAhdGhpcy5fZGF0YVN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5vYnNlcnZlUmVuZGVyQ2hhbmdlcygpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcblxuICAgIGlmICh0aGlzLmRhdGFTb3VyY2UgJiYgdHlwZW9mIHRoaXMuZGF0YVNvdXJjZS5kaXNjb25uZWN0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLmRhdGFTb3VyY2UuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gbnVsbDtcbiAgICB9XG4gICAgY2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMucmVxdWVzdElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlIGdyYXBoIHRvIGNlbnRlciBhbmQgc2NhbGUgYXV0b21hdGljYWxseVxuICAgKi9cbiAgZml0Q2VudGVyKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgeCwgeSwgayB9