UNPKG

ng-zorro-antd

Version:

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

473 lines 59.9 kB
/**
 * 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, Input, Output, TemplateRef, ViewChildren, ViewEncapsulation, booleanAttribute, inject } from '@angular/core';
import { ReplaySubject, Subject, forkJoin } from 'rxjs';
import { finalize, take, takeUntil } from 'rxjs/operators';
import { buildGraph } from 'dagre-compound';
import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation';
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 { NzGraphZoomDirective } from './graph-zoom.directive';
import { NZ_GRAPH_LAYOUT_SETTING, nzTypeDefinition } from './interface';
import * as i0 from "@angular/core";
/** 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) {
        this.cdr = cdr;
        this.elementRef = elementRef;
        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})`;
        this.noAnimation = inject(NzNoAnimationDirective, { host: true, optional: true });
        this.nzGraphZoom = inject(NzGraphZoomDirective, { optional: true });
    }
    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.2.1", ngImport: i0, type: NzGraphComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.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(edge)) {
              <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.2.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(edge)) {
              <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 }], 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JhcGguY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vY29tcG9uZW50cy9ncmFwaC9ncmFwaC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztHQUdHO0FBRUgsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDbkQsT0FBTyxFQUVMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsWUFBWSxFQUNaLFVBQVUsRUFDVixZQUFZLEVBQ1osS0FBSyxFQUlMLE1BQU0sRUFHTixXQUFXLEVBQ1gsWUFBWSxFQUNaLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsTUFBTSxFQUNQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBYyxhQUFhLEVBQUUsT0FBTyxFQUFnQixRQUFRLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDbEYsT0FBTyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTVDLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLGlDQUFpQyxDQUFDO0FBQ3pFLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBRzFFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUVsRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQ2xDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBQzlELE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3pFLE9BQU8sRUFBRSxvQkFBb0Is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QUFZO3FCQUMzQztvQkFDRCxPQUFPLEVBQUUsQ0FBQyxnQkFBZ0IsRUFBRSxvQkFBb0IsRUFBRSxvQkFBb0IsRUFBRSxvQkFBb0IsQ0FBQztvQkFDN0YsVUFBVSxFQUFFLElBQUk7aUJBQ2pCOytHQUUyRCxpQkFBaUI7c0JBQTFFLFlBQVk7dUJBQUMsb0JBQW9CLEVBQUUsRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFO2dCQUNwQixtQkFBbUI7c0JBQXRELFlBQVk7dUJBQUMsb0JBQW9CO2dCQUV1QyxZQUFZO3NCQUFwRixZQUFZO3VCQUFDLG9CQUFvQixFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsV0FBVyxFQUFFO2dCQUdPLGlCQUFpQjtzQkFBOUYsWUFBWTt1QkFBQyx5QkFBeUIsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFdBQVcsRUFBRTtnQkFHSCx1QkFBdUI7c0JBQS9GLFlBQVk7dUJBQUMsb0JBQW9CLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxXQUFXLEVBQUU7Z0JBTzlELFdBQVc7c0JBQW5CLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxtQkFBbUI7c0JBQTNCLEtBQUs7Z0JBQ2tDLFVBQVU7c0JBQWpELEtBQUs7dUJBQUMsRUFBRSxTQUFTLEVBQUUsZ0JBQWdCLEVBQUU7Z0JBRW5CLGtCQUFrQjtzQkFBcEMsTUFBTTtnQkFDWSxlQUFlO3NCQUFqQyxNQUFNO2dCQUNZLFdBQVc7c0JBQTdCLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vZ2l0aHViLmNvbS9ORy1aT1JSTy9uZy16b3Jyby1hbnRkL2Jsb2IvbWFzdGVyL0xJQ0VOU0VcbiAqL1xuXG5pbXBvcnQgeyBOZ1RlbXBsYXRlT3V0bGV0IH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7XG4gIEFmdGVyQ29udGVudENoZWNrZWQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgQ29tcG9uZW50LFxuICBDb250ZW50Q2hpbGQsXG4gIEVsZW1lbnRSZWYsXG4gIEV2ZW50RW1pdHRlcixcbiAgSW5wdXQsXG4gIE9uQ2hhbmdlcyxcbiAgT25EZXN0cm95LFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgUXVlcnlMaXN0LFxuICBTaW1wbGVDaGFuZ2VzLFxuICBUZW1wbGF0ZVJlZixcbiAgVmlld0NoaWxkcmVuLFxuICBWaWV3RW5jYXBzdWxhdGlvbixcbiAgYm9vbGVhbkF0dHJpYnV0ZSxcbiAgaW5qZWN0XG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgUmVwbGF5U3ViamVjdCwgU3ViamVjdCwgU3Vic2NyaXB0aW9uLCBmb3JrSm9pbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmluYWxpemUsIHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgYnVpbGRHcmFwaCB9IGZyb20gJ2RhZ3JlLWNvbXBvdW5kJztcblxuaW1wb3J0IHsgTnpOb0FuaW1hdGlvbkRpcmVjdGl2ZSB9IGZyb20gJ25nLXpvcnJvLWFudGQvY29yZS9uby1hbmltYXRpb24nO1xuaW1wb3J0IHsgY2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lIH0gZnJvbSAnbmctem9ycm8tYW50ZC9jb3JlL3BvbHlmaWxsJztcbmltcG9ydCB7IE56U2FmZUFueSB9IGZyb20gJ25nLXpvcnJvLWFudGQvY29yZS90eXBlcyc7XG5cbmltcG9ydCB7IGNhbGN1bGF0ZVRyYW5zZm9ybSB9IGZyb20gJy4vY29yZS91dGlscyc7XG5pbXBvcnQgeyBOekdyYXBoRGF0YSB9IGZyb20gJy4vZGF0YS1zb3VyY2UvZ3JhcGgtZGF0YS1zb3VyY2UnO1xuaW1wb3J0IHsgTnpHcmFwaCB9IGZyb20gJy4vZ3JhcGgnO1xuaW1wb3J0IHsgTnpHcmFwaERlZnNDb21wb25lbnQgfSBmcm9tICcuL2dyYXBoLWRlZnMuY29tcG9uZW50JztcbmltcG9ydCB7IE56R3JhcGhFZGdlQ29tcG9uZW50IH0gZnJvbSAnLi9ncmFwaC1lZGdlLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOekdyYXBoRWRnZURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtZWRnZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnpHcmFwaEdyb3VwTm9kZURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtZ3JvdXAtbm9kZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgTnpHcmFwaE5vZGVDb21wb25lbnQgfSBmcm9tICcuL2dyYXBoLW5vZGUuY29tcG9uZW50JztcbmltcG9ydCB7IE56R3JhcGhOb2RlRGlyZWN0aXZlIH0gZnJvbSAnLi9ncmFwaC1ub2RlLmRpcmVjdGl2ZSc7XG5pbXBvcnQgeyBOekdyYXBoWm9vbURpcmVjdGl2ZSB9IGZyb20gJy4vZ3JhcGgtem9vbS5kaXJlY3RpdmUnO1xuaW1wb3J0IHtcbiAgTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkcsXG4gIE56R3JhcGhEYXRhRGVmLFxuICBOekdyYXBoRWRnZSxcbiAgTnpHcmFwaEVkZ2VEZWYsXG4gIE56R3JhcGhHcm91cE5vZGUsXG4gIE56R3JhcGhMYXlvdXRDb25maWcsXG4gIE56R3JhcGhOb2RlLFxuICBOekdyYXBoTm9kZURlZixcbiAgTnpHcmFwaE9wdGlvbixcbiAgTnpMYXlvdXRTZXR0aW5nLFxuICBOelJhbmtEaXJlY3Rpb24sXG4gIG56VHlwZURlZmluaXRpb25cbn0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuXG4vKiogQ2hlY2tzIHdoZXRoZXIgYW4gb2JqZWN0IGlzIGEgZGF0YSBzb3VyY2UuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEYXRhU291cmNlKHZhbHVlOiBOelNhZmVBbnkpOiB2YWx1ZSBpcyBOekdyYXBoRGF0YSB7XG4gIC8vIENoZWNrIGlmIHRoZSB2YWx1ZSBpcyBhIERhdGFTb3VyY2UgYnkgb2JzZXJ2aW5nIGlmIGl0IGhhcyBhIGNvbm5lY3QgZnVuY3Rpb24uIENhbm5vdFxuICAvLyBiZSBjaGVja2VkIGFzIGFuIGBpbnN0YW5jZW9mIERhdGFTb3VyY2VgIHNpbmNlIHBlb3BsZSBjb3VsZCBjcmVhdGUgdGhlaXIgb3duIHNvdXJjZXNcbiAgLy8gdGhhdCBtYXRjaCB0aGUgaW50ZXJmYWNlLCBidXQgZG9uJ3QgZXh0ZW5kIERhdGFTb3VyY2UuXG4gIHJldHVybiB2YWx1ZSAmJiB0eXBlb2YgdmFsdWUuY29ubmVjdCA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuQENvbXBvbmVudCh7XG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxuICBlbmNhcHN1bGF0aW9uOiBWaWV3RW5jYXBzdWxhdGlvbi5Ob25lLFxuICBzZWxlY3RvcjogJ256LWdyYXBoJyxcbiAgZXhwb3J0QXM6ICduekdyYXBoJyxcbiAgcHJvdmlkZXJzOiBbeyBwcm92aWRlOiBOekdyYXBoLCB1c2VFeGlzdGluZzogTnpHcmFwaENvbXBvbmVudCB9XSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8bmctY29udGVudD48L25nLWNvbnRlbnQ+XG4gICAgPHN2ZyB3aWR0aD1cIjEwMCVcIiBoZWlnaHQ9XCIxMDAlXCI+XG4gICAgICA8c3ZnOmRlZnMgbnotZ3JhcGgtZGVmcz48L3N2ZzpkZWZzPlxuICAgICAgPHN2ZzpnIFthdHRyLnRyYW5zZm9ybV09XCJ0cmFuc2Zvcm1TdHlsZVwiPlxuICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRdPVwiZ3JvdXBUZW1wbGF0ZVwiXG4gICAgICAgICAgW25nVGVtcGxhdGVPdXRsZXRDb250ZXh0XT1cInsgcmVuZGVyTm9kZTogcmVuZGVySW5mbywgdHlwZTogJ3Jvb3QnIH1cIlxuICAgICAgICA+PC9uZy1jb250YWluZXI+XG4gICAgICA8L3N2ZzpnPlxuICAgIDwvc3ZnPlxuXG4gICAgPG5nLXRlbXBsYXRlICNncm91cFRlbXBsYXRlIGxldC1yZW5kZXJOb2RlPVwicmVuZGVyTm9kZVwiIGxldC10eXBlPVwidHlwZVwiPlxuICAgICAgPHN2ZzpnIFthdHRyLnRyYW5zZm9ybV09XCJ0eXBlID09PSAnc3ViJyA/IHN1YkdyYXBoVHJhbnNmb3JtKHJlbmRlck5vZGUpIDogbnVsbFwiPlxuICAgICAgICA8c3ZnOmcgY2xhc3M9XCJjb3JlXCIgW2F0dHIudHJhbnNmb3JtXT1cImNvcmVUcmFuc2Zvcm0ocmVuZGVyTm9kZSlcIj5cbiAgICAgICAgICA8c3ZnOmcgY2xhc3M9XCJuei1ncmFwaC1lZGdlc1wiPlxuICAgICAgICAgICAgQGZvciAoZWRnZSBvZiAkYXNOekdyYXBoRWRnZXMocmVuZGVyTm9kZS5lZGdlcyk7IHRyYWNrIGVkZ2VUcmFja0J5RnVuKGVkZ2UpKSB7XG4gICAgICAgICAgICAgIDxnXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJuei1ncmFwaC1lZGdlXCJcbiAgICAgICAgICAgICAgICBuei1ncmFwaC1lZGdlXG4gICAgICAgICAgICAgICAgW2VkZ2VdPVwiZWRnZVwiXG4gICAgICAgICAgICAgICAgW2VkZ2VUeXBlXT1cIm56R3JhcGhMYXlvdXRDb25maWc/LmRlZmF1bHRFZGdlPy50eXBlXCJcbiAgICAgICAgICAgICAgICBbY3VzdG9tVGVtcGxhdGVdPVwiY3VzdG9tR3JhcGhFZGdlVGVtcGxhdGVcIlxuICAgICAgICAgICAgICA+PC9nPlxuICAgICAgICAgICAgfVxuICAgICAgICAgIDwvc3ZnOmc+XG5cbiAgICAgICAgICA8c3ZnOmcgY2xhc3M9XCJuei1ncmFwaC1ub2Rlc1wiPlxuICAgICAgICAgICAgQGZvciAobm9kZSBvZiB0eXBlZE5vZGVzKHJlbmRlck5vZGUubm9kZXMpOyB0cmFjayBub2RlLm5hbWUpIHtcbiAgICAgICAgICAgICAgQGlmIChub2RlLnR5cGUgPT09IDEpIHtcbiAgICAgICAgICAgICAgICA8ZyBjbGFzcz1cIm56LWdyYXBoLW5vZGVcIiBuei1ncmFwaC1ub2RlIFtub2RlXT1cIm5vZGVcIiBbY3VzdG9tVGVtcGxhdGVdPVwibm9kZVRlbXBsYXRlXCI+PC9nPlxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgQGlmIChub2RlLnR5cGUgPT09IDApIHtcbiAgICAgICAgICAgICAgICA8ZyBjbGFzcz1cIm56LWdyYXBoLW5vZGVcIiBuei1ncmFwaC1ub2RlIFtub2RlXT1cIm5vZGVcIiBbY3VzdG9tVGVtcGxhdGVdPVwiZ3JvdXBOb2RlVGVtcGxhdGVcIj48L2c+XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBAaWYgKG5vZGUuZXhwYW5kZWQpIHtcbiAgICAgICAgICAgICAgICA8bmctY29udGFpbmVyXG4gICAgICAgICAgICAgICAgICBbbmdUZW1wbGF0ZU91dGxldF09XCJncm91cFRlbXBsYXRlXCJcbiAgICAgICAgICAgICAgICAgIFtuZ1RlbXBsYXRlT3V0bGV0Q29udGV4dF09XCJ7IHJlbmRlck5vZGU6IG5vZGUsIHR5cGU6ICdzdWInIH1cIlxuICAgICAgICAgICAgICAgIC8+XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICA8L3N2ZzpnPlxuICAgICAgICA8L3N2ZzpnPlxuICAgICAgPC9zdmc6Zz5cbiAgICA8L25nLXRlbXBsYXRlPlxuICBgLFxuICBob3N0OiB7XG4gICAgJ1tjbGFzcy5uei1ncmFwaF0nOiAndHJ1ZScsXG4gICAgJ1tjbGFzcy5uei1ncmFwaC1hdXRvLXNpemVdJzogJ256QXV0b1NpemUnXG4gIH0sXG4gIGltcG9ydHM6IFtOZ1RlbXBsYXRlT3V0bGV0LCBOekdyYXBoRWRnZUNvbXBvbmVudCwgTnpHcmFwaE5vZGVDb21wb25lbnQsIE56R3JhcGhEZWZzQ29tcG9uZW50XSxcbiAgc3RhbmRhbG9uZTogdHJ1ZVxufSlcbmV4cG9ydCBjbGFzcyBOekdyYXBoQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIEFmdGVyQ29udGVudENoZWNrZWQsIE9uRGVzdHJveSwgTnpHcmFwaCB7XG4gIEBWaWV3Q2hpbGRyZW4oTnpHcmFwaE5vZGVDb21wb25lbnQsIHsgcmVhZDogRWxlbWVudFJlZiB9KSBsaXN0T2ZOb2RlRWxlbWVudCE6IFF1ZXJ5TGlzdDxFbGVtZW50UmVmPjtcbiAgQFZpZXdDaGlsZHJlbihOekdyYXBoTm9kZUNvbXBvbmVudCkgbGlzdE9mTm9kZUNvbXBvbmVudCE6IFF1ZXJ5TGlzdDxOekdyYXBoTm9kZUNvbXBvbmVudD47XG5cbiAgQENvbnRlbnRDaGlsZChOekdyYXBoTm9kZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIG5vZGVUZW1wbGF0ZT86IFRlbXBsYXRlUmVmPHtcbiAgICAkaW1wbGljaXQ6IE56R3JhcGhOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoR3JvdXBOb2RlRGlyZWN0aXZlLCB7IHN0YXRpYzogdHJ1ZSwgcmVhZDogVGVtcGxhdGVSZWYgfSkgZ3JvdXBOb2RlVGVtcGxhdGU/OiBUZW1wbGF0ZVJlZjx7XG4gICAgJGltcGxpY2l0OiBOekdyYXBoR3JvdXBOb2RlO1xuICB9PjtcbiAgQENvbnRlbnRDaGlsZChOekdyYXBoRWRnZURpcmVjdGl2ZSwgeyBzdGF0aWM6IHRydWUsIHJlYWQ6IFRlbXBsYXRlUmVmIH0pIGN1c3RvbUdyYXBoRWRnZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8e1xuICAgICRpbXBsaWNpdDogTnpHcmFwaEVkZ2U7XG4gIH0+O1xuICAvKipcbiAgICogUHJvdmlkZXMgYSBzdHJlYW0gY29udGFpbmluZyB0aGUgbGF0ZXN0IGRhdGEgYXJyYXkgdG8gcmVuZGVyLlxuICAgKiBEYXRhIHNvdXJjZSBjYW4gYmUgYW4gb2JzZXJ2YWJsZSBvZiBOekdyYXBoRGF0YSwgb3IgYSBOekdyYXBoRGF0YSB0byByZW5kZXIuXG4gICAqL1xuICBASW5wdXQoKSBuekdyYXBoRGF0YSE6IE56R3JhcGhEYXRhO1xuICBASW5wdXQoKSBuelJhbmtEaXJlY3Rpb246IE56UmFua0RpcmVjdGlvbiA9ICdMUic7XG4gIEBJbnB1dCgpIG56R3JhcGhMYXlvdXRDb25maWc/OiBOekdyYXBoTGF5b3V0Q29uZmlnO1xuICBASW5wdXQoeyB0cmFuc2Zvcm06IGJvb2xlYW5BdHRyaWJ1dGUgfSkgbnpBdXRvU2l6ZSA9IGZhbHNlO1xuXG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoSW5pdGlhbGl6ZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuekdyYXBoUmVuZGVyZWQgPSBuZXcgRXZlbnRFbWl0dGVyPE56R3JhcGhDb21wb25lbnQ+KCk7XG4gIEBPdXRwdXQoKSByZWFkb25seSBuek5vZGVDbGljazogRXZlbnRFbWl0dGVyPE56R3JhcGhOb2RlIHwgTnpHcmFwaEdyb3VwTm9kZT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgcmVxdWVzdElkOiBudW1iZXIgPSAtMTtcbiAgdHJhbnNmb3JtU3R5bGUgPSAnJztcbiAgZ3JhcGhSZW5kZXJlZFN1YmplY3QkID0gbmV3IFJlcGxheVN1YmplY3Q8dm9pZD4oMSk7XG4gIHJlbmRlckluZm86IE56R3JhcGhHcm91cE5vZGUgPSB7IGxhYmVsSGVpZ2h0OiAwIH0gYXMgTnpHcmFwaEdyb3VwTm9kZTtcbiAgbWFwT2ZOb2RlQXR0cjogeyBba2V5OiBzdHJpbmddOiBOekdyYXBoTm9kZURlZiB9ID0ge307XG4gIG1hcE9mRWRnZUF0dHI6IHsgW2tleTogc3RyaW5nXTogTnpHcmFwaEVkZ2VEZWYgfSA9IHt9O1xuICB6b29tID0gMTtcblxuICBwdWJsaWMgcmVhZG9ubHkgdHlwZWROb2RlcyA9IG56VHlwZURlZmluaXRpb248QXJyYXk8TnpHcmFwaE5vZGUgfCBOekdyYXBoR3JvdXBOb2RlPj4oKTtcbiAgcHJpdmF0ZSBkYXRhU291cmNlPzogTnpHcmFwaERhdGE7XG4gIHByaXZhdGUgbGF5b3V0U2V0dGluZzogTnpMYXlvdXRTZXR0aW5nID0gTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkc7XG4gIC8qKiBEYXRhIHN1YnNjcmlwdGlvbiAqL1xuICBwcml2YXRlIF9kYXRhU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uIHwgbnVsbDtcbiAgcHJpdmF0ZSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgZWRnZVRyYWNrQnlGdW4gPSAoZWRnZTogTnpHcmFwaEVkZ2UpOiBzdHJpbmcgPT4gYCR7ZWRnZS52fS0ke2VkZ2Uud31gO1xuXG4gIHN1YkdyYXBoVHJhbnNmb3JtID0gKG5vZGU6IE56R3JhcGhHcm91cE5vZGUpOiBzdHJpbmcgPT4ge1xuICAgIGNvbnN0IHggPSBub2RlLnggLSBub2RlLmNvcmVCb3gud2lkdGggLyAyLjA7XG4gICAgY29uc3QgeSA9IG5vZGUueSAtIG5vZGUuaGVpZ2h0IC8gMi4wICsgbm9kZS5wYWRkaW5nVG9wO1xuICAgIHJldHVybiBgdHJhbnNsYXRlKCR7eH0sICR7eX0pYDtcbiAgfTtcblxuICAkYXNOekdyYXBoRWRnZXMgPSAoZGF0YTogdW5rbm93bik6IE56R3JhcGhFZGdlW10gPT4gZGF0YSBhcyBOekdyYXBoRWRnZVtdO1xuXG4gIGNvcmVUcmFuc2Zvcm0gPSAobm9kZTogTnpHcmFwaEdyb3VwTm9kZSk6IHN0cmluZyA9PiBgdHJhbnNsYXRlKDAsICR7bm9kZS5wYXJlbnROb2RlTmFtZSA/IG5vZGUubGFiZWxIZWlnaHQgOiAwfSlgO1xuXG4gIG5vQW5pbWF0aW9uID0gaW5qZWN0KE56Tm9BbmltYXRpb25EaXJlY3RpdmUsIHsgaG9zdDogdHJ1ZSwgb3B0aW9uYWw6IHRydWUgfSk7XG4gIG56R3JhcGhab29tID0gaW5qZWN0KE56R3JhcGhab29tRGlyZWN0aXZlLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgY2RyOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWZcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuZ3JhcGhSZW5kZXJlZFN1YmplY3QkLnBpcGUodGFrZSgxKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoKCkgPT4ge1xuICAgICAgLy8gT25seSB6b29taW5nIGlzIG5vdCBzZXQsIG1vdmUgZ3JhcGggdG8gY2VudGVyXG4gICAgICBpZiAoIXRoaXMubnpHcmFwaFpvb20pIHtcbiAgICAgICAgdGhpcy5maXRDZW50ZXIoKTtcbiAgICAgIH1cbiAgICAgIHRoaXMubnpHcmFwaEluaXRpYWxpemVkLmVtaXQodGhpcyk7XG4gICAgfSk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgY29uc3QgeyBuekF1dG9GaXQsIG56UmFua0RpcmVjdGlvbiwgbnpHcmFwaERhdGEsIG56R3JhcGhMYXlvdXRDb25maWcgfSA9IGNoYW5nZXM7XG4gICAgaWYgKG56R3JhcGhMYXlvdXRDb25maWcpIHtcbiAgICAgIHRoaXMubGF5b3V0U2V0dGluZyA9IHRoaXMubWVyZ2VDb25maWcobnpHcmFwaExheW91dENvbmZpZy5jdXJyZW50VmFsdWUpO1xuICAgIH1cblxuICAgIGlmIChuekdyYXBoRGF0YSkge1xuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAhPT0gdGhpcy5uekdyYXBoRGF0YSkge1xuICAgICAgICB0aGlzLl9zd2l0Y2hEYXRhU291cmNlKHRoaXMubnpHcmFwaERhdGEpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICgobnpBdXRvRml0ICYmICFuekF1dG9GaXQuZmlyc3RDaGFuZ2UpIHx8IChuelJhbmtEaXJlY3Rpb24gJiYgIW56UmFua0RpcmVjdGlvbi5maXJzdENoYW5nZSkpIHtcbiAgICAgIC8vIFJlbmRlciBncmFwaFxuICAgICAgaWYgKHRoaXMuZGF0YVNvdXJjZSEuZGF0YVNvdXJjZSkge1xuICAgICAgICB0aGlzLmRyYXdHcmFwaCh0aGlzLmRhdGFTb3VyY2UhLmRhdGFTb3VyY2UsIHtcbiAgICAgICAgICByYW5rRGlyZWN0aW9uOiB0aGlzLm56UmFua0RpcmVjdGlvbixcbiAgICAgICAgICBleHBhbmRlZDogdGhpcy5kYXRhU291cmNlIS5leHBhbnNpb25Nb2RlbC5zZWxlY3RlZCB8fCBbXVxuICAgICAgICB9KS50aGVuKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gIH1cblxuICBuZ0FmdGVyQ29udGVudENoZWNrZWQoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuZGF0YVNvdXJjZSAmJiAhdGhpcy5fZGF0YVN1YnNjcmlwdGlvbikge1xuICAgICAgdGhpcy5vYnNlcnZlUmVuZGVyQ2hhbmdlcygpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcblxuICAgIGlmICh0aGlzLmRhdGFTb3VyY2UgJiYgdHlwZW9mIHRoaXMuZGF0YVNvdXJjZS5kaXNjb25uZWN0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICB0aGlzLmRhdGFTb3VyY2UuZGlzY29ubmVjdCgpO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9kYXRhU3Vic2NyaXB0aW9uKSB7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uLnVuc3Vic2NyaWJlKCk7XG4gICAgICB0aGlzLl9kYXRhU3Vic2NyaXB0aW9uID0gbnVsbDtcbiAgICB9XG4gICAgY2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRoaXMucmVxdWVzdElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBNb3ZlIGdyYXBoIHRvIGNlbnRlciBhbmQgc2NhbGUgYXV0b21hdGljYWxseVxuICAgKi9cbiAgZml0Q2VudGVyKCk6IHZvaWQge1xuICAgIGNvbnN0IHsgeCwgeSwgayB9ID0gY2FsY3VsYXRlVHJhbnNmb3JtKFxuICAgICAgdGhpcy5lbGVtZW50UmVmLm5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3Rvcignc3ZnJyksXG4gICAgICB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKCdzdmcgPiBnJylcbiAgICApITtcbiAgICBpZiAoaykge1xuICAgICAgdGhpcy56b29tID0gaztcbiAgICAgIHRoaXMudHJhbnNmb3JtU3R5bGUgPSBgdHJhbnNsYXRlKCR7eH0sICR7eX0pc2NhbGUoJHtrfSlgO1xuICAgIH1cbiAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgfVxuXG4gIC8qKlxuICAgKiByZS1EcmF3IGdyYXBoXG4gICAqXG4gICAqIEBwYXJhbSBkYXRhXG4gICAqIEBwYXJhbSBvcHRpb25zXG4gICAqIEBwYXJhbSBuZWVkUmVzaXplXG4gICAqL1xuICBkcmF3R3JhcGgoZGF0YTogTnpHcmFwaERhdGFEZWYsIG9wdGlvbnM6IE56R3JhcGhPcHRpb24sIG5lZWRSZXNpemU6IGJvb2xlYW4gPSBmYWxzZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXNvbHZlID0+IHtcbiAgICAgIHRoaXMucmVxdWVzdElkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgY29uc3QgcmVuZGVySW5mbyA9IHRoaXMuYnVpbGRHcmFwaEluZm8oZGF0YSwgb3B0aW9ucyk7XG4gICAgICAgIC8vIFRPRE9cbiAgICAgICAgLy8gTmVlZCBiZXR0ZXIgcGVyZm9ybWFuY2VcbiAgICAgICAgdGhpcy5yZW5kZXJJbmZvID0gcmVuZGVySW5mbztcbiAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgIHRoaXMucmVxdWVzdElkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHtcbiAgICAgICAgICB0aGlzLmRyYXdOb2RlcyghdGhpcy5ub0FuaW1hdGlvbj8ubnpOb0FuaW1hdGlvbikudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAvLyBVcGRhdGUgZWxlbWVudFxuICAgICAgICAgICAgdGhpcy5jZHIubWFya0ZvckNoZWNrKCk7XG4gICAgICAgICAgICBpZiAobmVlZFJlc2l6ZSkge1xuICAgICAgICAgICAgICB0aGlzLnJlc2l6ZU5vZGVTaXplKCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZGF0YVNvdXJjZTogTnpHcmFwaERhdGFEZWYgPSB0aGlzLmRhdGFTb3VyY2UhLmRhdGFTb3VyY2UhO1xuICAgICAgICAgICAgICAgIHRoaXMuZHJhd0dyYXBoKGRhdGFTb3VyY2UsIG9wdGlvbnMsIGZhbHNlKS50aGVuKCgpID0+IHJlc29sdmUoKSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhpcy5ncmFwaFJlbmRlcmVkU3ViamVjdCQubmV4dCgpO1xuICAgICAgICAgICAgICB0aGlzLm56R3JhcGhSZW5kZXJlZC5lbWl0KHRoaXMpO1xuICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICB0aGlzLmNkci5tYXJrRm9yQ2hlY2soKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWRyYXcgYWxsIG5vZGVzXG4gICAqXG4gICAqIEBwYXJhbSBhbmltYXRlXG4gICAqL1xuICBkcmF3Tm9kZXMoYW5pbWF0ZTogYm9vbGVhbiA9IHRydWUpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICByZXR1cm4gbmV3IFByb21pc2UocmVzb2x2ZSA9PiB7XG4gICAgICBpZiAoYW5pbWF0ZSkge1xuICAgICAgICB0aGlzLm1ha2VOb2Rlc0FuaW1hdGlvbigpLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMubGlzdE9mTm9kZUNvbXBvbmVudC5tYXAobm9kZSA9PiB7XG4gICAgICAgICAgbm9kZS5tYWtlTm9BbmltYXRpb24oKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJlc29sdmUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzaXplTm9kZVNpemUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4ge1xuICAgICAgY29uc3QgZGF0YVNvdXJjZTogTnpHcmFwaERhdGFEZWYgPSB0aGlzLmRhdGFTb3VyY2UhLmRhdGFTb3VyY2UhO1xuICAgICAgbGV0IHNjYWxlID0gdGhpcy5uekdyYXBoWm9vbT8ubnpab29tIHx8IHRoaXMuem9vbSB8fCAxO1xuICAgICAgdGhpcy5saXN0T2ZOb2RlRWxlbWVudC5mb3JFYWNoKG5vZGVFbGUgPT4ge1xuICAgICAgICBjb25zdCBjb250ZW50RWxlID0gbm9kZUVsZS5uYXRpdmVFbGVtZW50O1xuICAgICAgICBpZiAoY29udGVudEVsZSkge1xuICAgICAgICAgIGxldCB3aWR0aDogbnVtYmVyO1xuICAgICAgICAgIGxldCBoZWlnaHQ6IG51bWJlcjtcbiAgICAgICAgICAvLyBDaGVjayBpZiBmb3JlaWduT2JqZWN0IGlzIHNldFxuICAgICAgICAgIGNvbnN0IGNsaWVudFJlY3QgPSBjb250ZW50RWxlLnF1ZXJ5U2VsZWN0b3IoJ2ZvcmVpZ25PYmplY3QgPiA6Zmlyc3QtY2hpbGQnKT8uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgaWYgKGNsaWVudFJlY3QpIHtcbiAgICAgICAgICAgIHdpZHRoID0gY2xpZW50UmVjdC53aWR0aDtcbiAgICAgICAgICAgIGhlaWdodCA9IGNsaWVudFJlY3QuaGVpZ2h0O1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zdCBiQm94UmVjdCA9IGNvbnRlbnRFbGUuZ2V0QkJveCgpO1xuICAgICAgICAgICAgd2lkdGggPSBiQm94UmVjdC53aWR0aDtcbiAgICAgICAgICAgIGhlaWdodCA9IGJCb3hSZWN0LmhlaWdodDtcbiAgICAgICAgICAgIC8vIGdldEJCb3ggd2lsbCByZXR1cm4gYWN0dWFsIHZhbHVlXG4gICAgICAgICAgICBzY2FsZSA9IDE7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIEVsZW1lbnQgaWQgdHlwZSBpcyBzdHJpbmdcbiAgICAgICAgICBjb25zdCBub2RlID0gZGF0YVNvdXJjZS5ub2Rlcy5maW5kKG4gPT4gYCR7bi5pZH1gID09PSBub2RlRWxlLm5hdGl2ZUVsZW1lbnQuaWQpO1xuICAgICAgICAgIGlmIChub2RlICYmIHdpZHRoICYmIGhlaWdodCkge1xuICAgICAgICAgICAgbm9kZS5oZWlnaHQgPSBoZWlnaHQgLyBzY2FsZTtcbiAgICAgICAgICAgIG5vZGUud2lkdGggPSB3aWR0aCAvIHNjYWxlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXNvbHZlKCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3dpdGNoIHRvIHRoZSBwcm92aWRlZCBkYXRhIHNvdXJjZSBieSByZXNldHRpbmcgdGhlIGRhdGEgYW5kIHVuc3Vic2NyaWJpbmcgZnJvbSB0aGUgY3VycmVudFxuICAgKiByZW5kZXIgY2hhbmdlIHN1YnNjcmlwdGlvbiBpZiBvbmUgZXhpc3RzLiBJZiB0aGUgZGF0YSBzb3VyY2UgaXMgbnVsbCwgaW50ZXJwcmV0IHRoaXMgYnlcbiAgICogY2xlYXJpbmcgdGhlIG5vZGUgb3V0bGV0LiBPdGhlcndpc2Ugc3RhcnQgbGlzdGVuaW5nIGZvciBuZXcgZGF0YS5cbiAgICovXG4gIHByaXZhdGUgX3N3aXRjaERhdGFTb3VyY2UoZGF0YVNvdXJjZTogTnpHcmFwaERhdGEpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5kYXRhU291cmNlICYmIHR5cGVvZiB0aGlzLmRhdGFTb3VyY2UuZGlzY29ubmVjdCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgdGhpcy5uekdyYXBoRGF0YS5kaXNjb25uZWN0KCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2RhdGFTdWJzY3JpcHRpb24pIHtcbiAgICAgIHRoaXMuX2RhdGFTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICAgIHRoaXMuX2RhdGFTdWJzY3JpcHRpb24gPSBudWxsO1xuICAgIH1cblxuICAgIHRoaXMuZGF0YVNvdXJjZSA9IGRhdGFTb3VyY2U7XG4gICAgdGhpcy5vYnNlcnZlUmVuZGVyQ2hhbmdlcygpO1xuICB9XG5cbiAgLyoqIFNldCB1cCBhIHN1YnNjcmlwdGlvbiBmb3IgdGhlIGRhdGEgcHJvdmlkZWQgYnkgdGhlIGRhdGEgc291cmNlLiAqL1xuICBwcml2YXRlIG9ic2VydmVSZW5kZXJDaGFuZ2VzKCk6IHZvaWQge1xuICAgIGxldCBkYXRhU3RyZWFtOiBPYnNlcnZhYmxlPE56R3JhcGhEYXRhRGVmPiB8IHVuZGVmaW5lZDtcbiAgICBsZXQgZ3JhcGhPcHRpb25zOiBOekdyYXBoT3B0aW9uID0ge1xuICAgICAgcmFua0RpcmVjdGlvbjogdGhpcy5uelJhbmtEaXJlY3Rpb25cbiAgICB9O1xuICAgIGlmIChpc0RhdGFTb3VyY2UodGhpcy5kYXRhU291cmNlKSkge1xuICAgICAgZGF0YVN0cmVhbSA9IHRoaXMuZGF0YVNvdXJjZS5jb25uZWN0KCk7XG4gICAgfVxuXG4gICAgaWYgKGRhdGFTdHJlYW0pIHtcbiAgICAgIHRoaXMuX2RhdGFTdWJzY3JpcHRpb24gPSBkYXRhU3RyZWFtLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKS5zdWJzY3JpYmUoZGF0YSA9PiB7XG4gICAgICAgIGdyYXBoT3B0aW9ucyA9IHtcbiAgICAgICAgICByYW5rRGlyZWN0aW9uOiB0aGlzLm56UmFua0RpcmVjdGlvbixcbiAgICAgICAgICBleHBhbmRlZDogdGhpcy5uekdyYXBoRGF0YS5leHBhbnNpb25Nb2RlbC5zZWxlY3RlZFxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmRyYXdHcmFwaChkYXRhLCBncmFwaE9wdGlvbnMsIHRoaXMubnpBdXRvU2l6ZSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgdGhpcy5jZHIuZGV0ZWN0Q2hhbmdlcygpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBFcnJvcihgQSB2YWxpZCBkYXRhIHNvdXJjZSBtdXN0IGJlIHByb3ZpZGVkLmApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgcmVuZGVySW5mbyBhbmQgcHJlcGFyZSBzb21lIGRhdGFcbiAgICpcbiAgICogQHBhcmFtIGRhdGFcbiAgICogQHBhcmFtIG9wdGlvbnNcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgYnVpbGRHcmFwaEluZm8oZGF0YTogTnpHcmFwaERhdGFEZWYsIG9wdGlvbnM6IE56R3JhcGhPcHRpb24pOiBOekdyYXBoR3JvdXBOb2RlIHtcbiAgICB0aGlzLnBhcnNlSW5mbyhkYXRhKTtcbiAgICBjb25zdCByZW5kZXJJbmZvID0gYnVpbGRHcmFwaChkYXRhLCBvcHRpb25zLCB0aGlzLmxheW91dFNldHRpbmcpIGFzIE56R3JhcGhHcm91cE5vZGU7XG4gICAgY29uc3QgZGlnID0gKG5vZGVzOiBBcnJheTxOekdyYXBoTm9kZSB8IE56R3JhcGhHcm91cE5vZGU+KTogdm9pZCA9PiB7XG4gICAgICBub2Rlcy5mb3JFYWNoKG5vZGUgPT4ge1xuICAgICAgICBjb25zdCB7IHgsIHkgfSA9IG5vZGU7XG4gICAgICAgIG5vZGUueE9mZnNldCA9IHg7XG4gICAgICAgIG5vZGUueU9mZnNldCA9IHk7XG4gICAgICAgIGlmIChub2RlLnR5cGUgPT09IDEgJiYgdGhpcy5tYXBPZk5vZGVBdHRyLmhhc093blByb3BlcnR5KG5vZGUubmFtZSkpIHtcbiAgICAgICAgICBPYmplY3QuYXNzaWduKG5vZGUsIHRoaXMubWFwT2ZOb2RlQXR0cltub2RlLm5hbWVdKTtcbiAgICAgICAgfSBlbHNlIGlmIChub2RlLnR5cGUgPT09IDApIHtcbiAgICAgICAgICAobm9kZSBhcyBOekdyYXBoR3JvdXBOb2RlKS5lZGdlcy5mb3JFYWNoKGVkZ2UgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMubWFwT2ZFZGdlQXR0ci5oYXNPd25Qcm9wZXJ0eShgJHtlZGdlLnZ9LSR7ZWRnZS53fWApKSB7XG4gICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oZWRnZSwgdGhpcy5tYXBPZkVkZ2VBdHRyW2Ake2VkZ2Uudn0tJHtlZGdlLnd9YF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGRpZyhub2RlLm5vZGVzKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfTtcbiAgICBkaWcocmVuZGVySW5mby5ub2Rlcyk7XG4gICAgLy8gQXNzaWduIGRhdGEgdG8gZWRnZXMgb2Ygcm9vdCBncmFwaFxuICAgIHJlbmRlckluZm8uZWRnZXMuZm9yRWFjaChlZGdlID0+IHtcbiAgICAgIGlmICh0aGlzLm1hcE9mRWRnZUF0dHIuaGFzT3duUHJvcGVydHkoYCR7ZWRnZS52fS0ke2VkZ2Uud31gKSkge1xuICAgICAgICBPYmplY3QuYXNzaWduKGVkZ2UsIHRoaXMubWFwT2ZFZGdlQXR0cltgJHtlZGdlLnZ9LSR7ZWRnZS53fWBdKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gcmVuZGVySW5mbztcbiAgfVxuXG4gIC8qKlxuICAgKiBQbGF5IHdpdGggYW5pbWF0aW9uXG4gICAqXG4gICAqIEBwcml2YXRlXG4gICAqL1xuICBwcml2YXRlIG1ha2VOb2Rlc0FuaW1hdGlvbigpOiBPYnNlcnZhYmxlPHZvaWRbXT4ge1xuICAgIHJldHVybiBmb3JrSm9pbih0aGlzLmxpc3RPZk5vZGVDb21wb25lbnQubWFwKG5vZGUgPT4gbm9kZS5tYWtlQW5pbWF0aW9uKCkpKS5waXBlKFxuICAgICAgZmluYWxpemUoKCkgPT4ge1xuICAgICAgICB0aGlzLmNkci5kZXRlY3RDaGFuZ2VzKCk7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIHBhcnNlSW5mbyhkYXRhOiBOekdyYXBoRGF0YURlZik6IHZvaWQge1xuICAgIGRhdGEubm9kZXMuZm9yRWFjaChuID0+IHtcbiAgICAgIHRoaXMubWFwT2ZOb2RlQXR0cltuLmlkXSA9IG47XG4gICAgfSk7XG4gICAgZGF0YS5lZGdlcy5mb3JFYWNoKGUgPT4ge1xuICAgICAgdGhpcy5tYXBPZkVkZ2VBdHRyW2Ake2Uudn0tJHtlLnd9YF0gPSBlO1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIE1lcmdlIGNvbmZpZyB3aXRoIHVzZXIgaW5wdXRzXG4gICAqXG4gICAqIEBwYXJhbSBjb25maWdcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHByaXZhdGUgbWVyZ2VDb25maWcoY29uZmlnOiBOekdyYXBoTGF5b3V0Q29uZmlnKTogTnpMYXlvdXRTZXR0aW5nIHtcbiAgICBjb25zdCBncmFwaE1ldGEgPSBjb25maWc/LmxheW91dCB8fCB7fTtcbiAgICBjb25zdCBzdWJTY2VuZU1ldGEgPSBjb25maWc/LnN1YlNjZW5lIHx8IHt9O1xuICAgIGNvbnN0IGRlZmF1bHROb2RlTWV0YSA9IGNvbmZpZz8uZGVmYXVsdE5vZGUgfHwge307XG4gICAgY29uc3QgZGVmYXVsdENvbXBvdW5kTm9kZU1ldGEgPSBjb25maWc/LmRlZmF1bHRDb21wb3VuZE5vZGUgfHwge307XG4gICAgY29uc3QgYnJpZGdlID0gTlpfR1JBUEhfTEFZT1VUX1NFVFRJTkcubm9kZVNpemUuYnJpZGdlO1xuXG4gICAgY29uc3QgZ3JhcGg6IE56TGF5b3V0U2V0dGluZ1snZ3JhcGgnXSA9IHsgbWV0YTogeyAuLi5OWl9HUkFQSF9MQVlPVVRfU0VUVElORy5ncmFwaC5tZXRhLCAuLi5ncmFwaE1ldGEgfSB9O1xuICAgIGNvbnN0IHN1YlNjZW5lOiBOekxheW91dFNldHRpbmdbJ3N1YlNjZW5lJ10gPSB7XG4gICAgICBtZXRhOiB7IC4uLk5aX0dSQVBIX0xBWU9VVF9TRVRUSU5HLnN1YlNjZW5lLm1ldGEsIC4uLnN1YlNjZW5lTWV0YSB9XG4gICAgfTtcbiAgICBjb25zdCBub2RlU2l6ZTogTnpMYXlvdXRTZXR0aW5nWydub2RlU2l6ZSddID0ge1xuICAgICAgbWV0YTogeyAuLi5OWl9HUkFQSF9MQVlPVVRfU0VUVElORy5ub2RlU2l6ZS5tZXRhLCAuLi5kZWZhdWx0Q29tcG91bmROb2RlTWV0YSB9LFxuICAgICAgbm9kZTogeyAuLi5OWl9HUkFQSF9MQVlPVVRfU0VUVElORy5ub2RlU2l6ZS5ub2RlLCAuLi5kZWZhdWx0Tm9kZU1ldGEgfSxcbiAgICAgIGJyaWRnZVxuICAgIH07XG5cbiAgICByZXR1cm4geyBncmFwaCwgc3ViU2NlbmUsIG5vZGVTaXplIH07XG4gIH1cbn1cbiJdfQ==