UNPKG

ng-terminal

Version:

NgTerminal is a terminal component on Angular 16 or higher.

638 lines 97 kB
import { Component, ViewChild, Input, Output, EventEmitter, ChangeDetectionStrategy, } from '@angular/core';
import { Terminal } from '@xterm/xterm';
import { FitAddon } from '@xterm/addon-fit';
import { Subject } from 'rxjs';
import { LinearRenderService, } from './linear-render.service';
import * as i0 from "@angular/core";
import * as i1 from "./logging.service";
import * as i2 from "angular-resizable-element";
import * as i3 from "@angular/common";
import * as i4 from "./global-style/global-style.component";
export class NgTerminalComponent {
    /**
     * A datsource is an observable where NgTerminal reads charactors.
     */
    set _dataSource(dataSource) {
        if (!dataSource)
            return;
        if (this.dataSourceSubscription != undefined)
            this.dataSourceSubscription.unsubscribe();
        this.dataSource = dataSource;
        this.dataSourceSubscription = this.dataSource.subscribe((data) => this.write(data));
    }
    /**
     * Toggle draggable.
     */
    set draggable(draggable) {
        this._draggable = draggable;
    }
    get draggable() {
        return this._draggable;
    }
    setMinWidth(width) {
        this._minWidthInput = width;
    }
    setMinHeight(height) {
        this._minHeightInput = height;
    }
    setDraggable(draggable) {
        this._draggable = draggable;
        this.lastDraggedPosition = undefined; // Reset position values
    }
    setXtermOptions(options) {
        this._xtermOptions = options;
        this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
    }
    setRows(rows) {
        if (this._rowsInput != rows) {
            this._rowsInput = rows;
            this.linearRender.pushAndHandle({
                time: new Date(),
                type: 'rowChanged',
            });
        }
    }
    setCols(cols) {
        if (this._colsInput != cols) {
            this._colsInput = cols;
            this.linearRender.pushAndHandle({
                time: new Date(),
                type: 'columnChanged',
            });
        }
    }
    setStyle(styleObject) {
        if (JSON.stringify(this._stylesInput ?? {}) !=
            JSON.stringify(styleObject ?? {})) {
            this._stylesInput = styleObject;
            this.linearRender.pushAndHandle({
                time: new Date(),
                type: 'none',
            });
        }
    }
    constructor(renderer, //Render is being used for fast rendering without markForCheck().
    hostRef, loggingService) {
        this.renderer = renderer;
        this.hostRef = hostRef;
        this.loggingService = loggingService;
        this.dataSubject = new Subject();
        this.keySubject = new Subject();
        this.keyInputSubjectSubscription = undefined;
        this.keyEventSubjectSubscription = undefined;
        this.allLogsSubjectSubscription = undefined;
        this.dataSourceSubscription = undefined;
        this.resizableObservers = [];
        this.dataSource = undefined;
        this.paddingSize = 5;
        this.stylesForResizeBox = { display: 'block' };
        /**
         * @deprecated use (data)='' instead.
         * An emitter emits printable characters pushed from xterm's onData() when a user typed on the terminal.
         */
        this.keyInputEmitter = new EventEmitter();
        /**
         * @deprecated use (key)='' instead.
         * An emitter emits key and keybaord event pushed from xterm's onKey() when a user typed on the terminal.
         */
        this.keyEventEmitter = new EventEmitter();
        /**
         * An emitter emits printable characters pushed from xterm's onData() when a user typed on the terminal.
         */
        this.dataEmitter = this.keyInputEmitter;
        /**
         * An emitter emits key and keybaord event pushed from xterm's onKey() when a user typed on the terminal.
         */
        this.keyEmitter = this.keyEventEmitter;
        /**
         * An wrapper of {@link ITerminalOptions} for Xterm.
         */
        this._xtermOptions = {};
        this.lastDraggedPosition = undefined;
        this._draggable = false;
        this._stylesInput = {};
        this.handleToCheckLazyContainer = undefined;
        this.lastDetectedWidth = 0;
        this.linearRender = new LinearRenderService(hostRef);
    }
    setup() {
        if (this.xterm) {
            this.xterm.onData((input) => {
                this.dataSubject.next(input);
            });
            this.xterm.onKey((e) => {
                this.keySubject.next(e);
            });
        }
        this.keyInputSubjectSubscription = this.dataSubject.subscribe((data) => {
            this.keyInputEmitter.emit(data);
        });
        this.keyEventSubjectSubscription = this.keySubject.subscribe((e) => {
            this.keyEventEmitter.emit(e);
        });
        this.setupResizeObservers();
        // if (ob3) this.resizableObservers.push(ob3);
        this.allLogsSubjectSubscription =
            this.linearRender.renderObservable.subscribe((change) => {
                if (change)
                    this.coordinateOuterAndTerminal(change);
                else
                    this.coordinateOuterAndTerminal(change);
                this.linearRender.handleNextOne();
            });
        this.linearRender.handleNextOne();
    }
    /**
     * set dimensions
     */
    setOuterDimensions(left, top, width, height) {
        this.linearRender.pushAndHandle({
            time: new Date(),
            type: 'dragged',
            dragged: { draggedWidth: `${width}px`, draggedHeight: `${height}px` },
        });
    }
    applyStylesToResizeBox() {
        Object.keys(this.stylesForResizeBox)
            .map((key) => {
            return { key, value: this.stylesForResizeBox[key] };
        })
            .forEach(({ key, value }) => {
            if (this.resizeBox) {
                if (value)
                    this.renderer.setStyle(this.resizeBox.nativeElement, key, value);
                else {
                    this.renderer.removeStyle(this.resizeBox.nativeElement, key);
                }
            }
        });
        this.stylesForResizeBox = this.stylesForResizeBox; //invalidate
    }
    ngOnInit() { }
    /**
     * It creates new terminal in #terminal.
     */
    ngAfterViewInit() {
        this.fitAddon = new FitAddon();
        this.xterm = new Terminal({
            allowProposedApi: true,
        });
        if (!this.terminalOuter.nativeElement.isConnected) {
            this.handleToCheckLazyContainer = setInterval(() => {
                if (this.terminalOuter.nativeElement.isConnected) {
                    try {
                        this.loggingService.log(() => console.debug("The container's been connected."));
                        this.xterm.open(this.terminalOuter.nativeElement);
                        this.xterm.loadAddon(this.fitAddon);
                        this.setup();
                        this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
                    }
                    finally {
                        if (this.handleToCheckLazyContainer)
                            clearInterval(this.handleToCheckLazyContainer);
                    }
                }
            }, 500);
        }
        else {
            this.xterm.open(this.terminalOuter.nativeElement);
            this.xterm.loadAddon(this.fitAddon);
            this.setup();
            this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
        }
    }
    ngOnChanges(changes) {
        this.loggingService.log(() => console.group('onChanges'));
        this.loggingService.log(() => console.debug('prop: ', changes));
        this.loggingService.log(() => console.groupEnd());
        if (changes?.['_rowsInput']) {
            if (changes?.['_rowsInput']?.previousValue !=
                changes?.['_rowsInput']?.currentValue) {
                this.linearRender.pushAndHandle({
                    time: new Date(),
                    type: 'rowChanged',
                });
            }
        }
        if (changes?.['_colsInput']) {
            if (changes?.['_colsInput']?.previousValue !=
                changes?.['_colsInput']?.currentValue) {
                this.linearRender.pushAndHandle({
                    time: new Date(),
                    type: 'columnChanged',
                });
            }
        }
        if (changes?.['draggable'])
            this.linearRender.pushAndHandle({ time: new Date(), type: 'none' });
    }
    /**
     * It serves a callback function to adjust the dimensions of the xterm-screen, xterm-view, and resize box
     * after making any changes to the outer box, rows, or columns, or when the resize box is being dragged.
     *
     * There several factors that affect dimensions, as I mentioned earlier.
     * Regardless of whether the draggable feature is on, if new row or column value is input, this value will be applied.
     * - Draggable = New specified Row/Column value > Full (Default)
     * @param change This argument represents a single change that occured.
     * @returns
     */
    coordinateOuterAndTerminal(change) {
        this.loggingService.log(() => console.debug(`changeList: ${JSON.stringify(change)}`));
        if (!this.xterm)
            return;
        const isHostElementVisible = this.hostRef.nativeElement?.offsetParent !== null;
        if (!isHostElementVisible) {
            // Do nothing if the host element is invisible.
            this.loggingService.log(() => console.debug('`display` of host element was set to `none`'));
            return;
        }
        this.doUpdateXtermStyles();
        this.doAdjustDimensionOfResizeBox(change);
        this.doAdjustSizeOfXtermScreen(change);
        this.doUpdateViewportAndResizeBoxWithPixcelUnit();
    }
    /**
     * apply options to the xterm terminal
     * @returns
     */
    doUpdateXtermStyles() {
        if (!this.xterm)
            return;
        this.xterm.options = { ...this._xtermOptions };
        // apply the theme to the background of the handle
        if (this._xtermOptions.theme?.background) {
            if (!this.resizeHandleStyleRule)
                this.resizeHandleStyleRule = this.findCssStyleRule('.resize-handle[');
            if (this.resizeHandleStyleRule)
                this.resizeHandleStyleRule.style.backgroundColor =
                    this._xtermOptions.theme.background;
        }
        if (this._xtermOptions.theme?.border) {
            if (!this.resizeHandleActiveStyleRule)
                this.resizeHandleActiveStyleRule =
                    this.findCssStyleRule('.handle-active');
            if (this.resizeHandleActiveStyleRule)
                this.resizeHandleActiveStyleRule.style.backgroundColor =
                    this._xtermOptions.theme.border;
        }
    }
    /**
     * If the resize handles are moved, the resize box adjusts to the new dimensions;
     * otherwise, it defaults to a maximized size.
     * @param change
     */
    doAdjustDimensionOfResizeBox(change) {
        this.stylesForResizeBox = {
            ...this.stylesForResizeBox,
            ...this._stylesInput,
            width: this.stylesForResizeBox.width,
            height: this.stylesForResizeBox.height,
        };
        // Reset styles of the resize element
        if (change.type === 'dragged') {
            const minWidth = this._minWidthInput ?? 24;
            const minHeight = this._minHeightInput ?? 24;
            const width = parseInt(change.dragged.draggedWidth) > minWidth
                ? change.dragged.draggedWidth
                : `${minWidth}px`;
            const height = parseInt(change.dragged.draggedHeight) > minHeight
                ? change.dragged.draggedHeight
                : `${minHeight}px`;
            this.stylesForResizeBox.width = width;
            this.stylesForResizeBox.height = height;
            this.lastDraggedPosition = {
                width,
                height,
            };
            this.applyStylesToResizeBox();
        }
        else if (!(this.draggable && this.lastDraggedPosition)) {
            // When `_colsInput` and `draggable` is not enabled,
            // it fits the size to the host element.
            const currentHostWidth = getComputedStyle(this.hostRef.nativeElement).width;
            const detectBoxWidth = getComputedStyle(this.detectBox.nativeElement).width;
            let smallParent = false;
            if (parseFloat(detectBoxWidth) < parseFloat(currentHostWidth)) {
                // the width of the parent is smaller than that of resize-box element
                smallParent = true;
            }
            if (smallParent) {
                // It's been written to solve https://github.com/qwefgh90/ng-terminal/issues/79
                // If the width of the flex-box (that is the parent of the host element) is smaller than that of child element, the host element is adjusted to the width of child element
                // host element: 1000px, resize-box(child): 985px -> host element: 985px, resize-box(child): 970px -> ... -> stop
                // This code check if the parent element (that is the parent of `<ng-terminal>), is smaller than `.resize-box`
                // and ensures that the width of the `<ng-terminal>` adjusts to match that of the parent element rather than the child elements, in the subsequent events.
                this.stylesForResizeBox.width = `${parseFloat(detectBoxWidth)}px`;
                this.applyStylesToResizeBox();
            }
            else {
                // but if the dimension of host element is resized, update width and height
                // If `_rowsInput` is specified, NgTerminal keep the current height; otherwise, the height is set to 100%
                if (!this._rowsInput)
                    this.stylesForResizeBox.height = '100%';
                if (!this._colsInput)
                    this.stylesForResizeBox.width = '100%';
                this.applyStylesToResizeBox();
            }
        }
    }
    /**
     * This function uses fitAddon() to adjust the dimension of xterm-screen to character unit
     * If the draggable value is true or there are no fixed values for the row or column,
     * it fits the xterm terminal boxes into the resize box;
     * otherwise, it resizes the xterm terminal with specified row and column values.
     */
    doAdjustSizeOfXtermScreen(change) {
        if (!this.xterm)
            return;
        if ((change.type == 'rowChanged' && this._rowsInput) ||
            (change.type == 'columnChanged' && this._colsInput)) {
            this.xterm.resize(this._colsInput ?? this.xterm.cols, this._rowsInput ?? this.xterm.rows);
        }
        else {
            if (this.xterm.element) {
                // The fitAddon.fit() operation doesn't recognize the padding values of terminalOuter.
                // It seems to be using the padding values of xterm element instead.
                // Therefore, we establish a brief time frame to adjust the padding values before and after executing fitAddon.fit().
                // If this line is removed, when dragging resize-box vertically, the width is decreased.
                this.xterm.element.style.paddingLeft = `${this.paddingSize}px`;
                this.printDimension('Before fitAddon.fit() of Xterm');
                this.fitAddon?.fit();
                this.printDimension('After fitAddon.fit() of Xterm');
                this.xterm.element.style.paddingLeft = `${0}px`;
            }
        }
    }
    /**
     * This functions sets width of the resize box, xterm-viewport and xterm-screen with specific pixel values.
     */
    doUpdateViewportAndResizeBoxWithPixcelUnit() {
        if (this.xterm?.element) {
            let xtermScreen = this.xterm.element.getElementsByClassName('xterm-screen')[0];
            let xtermViewport = this.xterm.element.getElementsByClassName('xterm-viewport')[0];
            const screenWidth = xtermScreen.clientWidth;
            const screenHeight = xtermScreen.clientHeight;
            const core = this.underlying._core;
            const scrollBarWidth = core.viewport.scrollBarWidth;
            const hostWidth = parseInt(getComputedStyle(this.hostRef.nativeElement).width);
            // It fixes a bug where the viewport's width isn't updated by fitAddon.fit()
            this.renderer.setStyle(xtermViewport, 'width', `${screenWidth + scrollBarWidth}px`);
            // It adjusts the dimension of the resize box to the xterm-screen element.
            const calulatedBoxWidth = screenWidth + scrollBarWidth + this.paddingSize * 2;
            const componentElement = this.hostRef.nativeElement;
            const componentWith = parseInt(getComputedStyle(componentElement).width);
            const restrictedWidth = calulatedBoxWidth > componentWith ? componentWith : calulatedBoxWidth;
            this.stylesForResizeBox = {
                ...this.stylesForResizeBox,
                width: `${restrictedWidth}px`,
                height: `${screenHeight + this.paddingSize * 2}px`,
            };
            this.applyStylesToResizeBox();
            this.printDimension('After update the dimensions for all boxes with pixel values');
        }
    }
    printDimension(title) {
        if (this.xterm?.element) {
            let resizeBox = this.resizeBox.nativeElement;
            let xtermScreen = this.xterm.element.getElementsByClassName('xterm-screen')[0];
            let xtermViewport = this.xterm.element.getElementsByClassName('xterm-viewport')[0];
            const screenWidth = xtermScreen.clientWidth;
            const screenHeight = xtermScreen.clientHeight;
            this.loggingService.log(() => console.group(`${title}`));
            this.loggingService.log(() => console.debug(`width(resizeBox): ${getComputedStyle(resizeBox).width},
width(viewport): ${getComputedStyle(xtermViewport).width},
width(screen): ${screenWidth}
scrollBarWidth: ${this.scrollBarWidth}`));
            this.loggingService.log(() => console.debug(`height(resizeBox): ${getComputedStyle(resizeBox).height},
height(viewport) ${getComputedStyle(xtermViewport).height},
height(screen): ${screenHeight}`));
            this.loggingService.log(() => console.groupEnd());
        }
    }
    /**
     * If pushAndHandle() were used, there could be an issue
     * because it can adjust the size of elements during a loop of ResizeObserver.
     */
    setupResizeObservers() {
        this.resizableObservers = [];
        let ob1 = this.observeXtermViewportDimension();
        let ob2 = this.observeHostDimension();
        if (ob1)
            this.resizableObservers.push(ob1);
        if (ob2)
            this.resizableObservers.push(ob2);
    }
    observeXtermViewportDimension() {
        let xtermViewport = this.terminalOuter.nativeElement.querySelector('.xterm-viewport');
        if (xtermViewport) {
            const resizeObserver = new ResizeObserver((entries) => {
                const outerDivWidth = this.terminalOuter.nativeElement?.clientWidth;
                const outerDivHeight = this.terminalOuter.nativeElement?.clientHeight;
                for (let entry of entries) {
                    if (entry.contentBoxSize.length > 0) {
                        let width = entry.target.clientWidth;
                        let height = entry.target.clientHeight;
                        if ((outerDivWidth && width > outerDivWidth) ||
                            (outerDivHeight && height > outerDivHeight)) {
                            this.loggingService.log(() => console.debug('Changes on a xterm viewport element will be handled.'));
                            this.linearRender.pushAndHandle({
                                time: new Date(),
                                type: 'xtermViewportExceedingOuterDiv',
                                xtermViewportExceedingOuterDiv: {
                                    width: `${width}`,
                                    height: `${height}`,
                                    outerDivWidth: `${outerDivWidth}`,
                                    outerDivHeight: `${outerDivHeight}`,
                                },
                            }, true);
                        }
                    }
                }
            });
            resizeObserver.observe(xtermViewport);
            return resizeObserver;
        }
        else {
            this.loggingService.log(() => console.error('Invalid state is detected. xterm element should exist below .terminal-outer.'));
        }
        return undefined;
    }
    observeHostDimension() {
        let hostElement = this.hostRef.nativeElement;
        let detectBox = this.detectBox.nativeElement;
        if (hostElement && detectBox) {
            const resizeObserver = new ResizeObserver((entries) => {
                for (let entry of entries) {
                    if (entry.target === hostElement) {
                        if (entry.contentBoxSize.length > 0) {
                            let width = getComputedStyle(entry.target).width;
                            let height = getComputedStyle(entry.target).height;
                            if (parseInt(width) >= 0 && parseInt(height) >= 0) {
                                this.loggingService.log(() => console.debug('Changes on a host element will be handled.'));
                                this.linearRender.pushAndHandle({
                                    time: new Date(),
                                    type: 'hostResized',
                                    hostResized: { width: `${width}`, height: `${height}` },
                                }, true);
                            }
                        }
                    }
                    if (entry.target === detectBox) {
                        if (entry.contentBoxSize.length > 0) {
                            let width = getComputedStyle(entry.target).width;
                            if (parseInt(width) >= 0 &&
                                parseInt(width) <= this.lastDetectedWidth) {
                                this.loggingService.log(() => console.debug('Changes on a detect-box element will be handled.'));
                                this.linearRender.pushAndHandle({
                                    time: new Date(),
                                    type: 'detectBoxResized',
                                    detectBoxResized: { width: `${width}` },
                                }, true);
                            }
                            this.lastDetectedWidth = parseInt(width);
                        }
                    }
                }
            });
            resizeObserver.observe(hostElement);
            resizeObserver.observe(detectBox);
            return resizeObserver;
        }
        else {
            this.loggingService.log(() => console.error('Invalid state is detected. xterm element should exist below .terminal-outer.'));
        }
        return undefined;
    }
    /**
     * clean all resources
     */
    ngOnDestroy() {
        this.resizableObservers.forEach((ob) => ob.disconnect());
        if (this.keyInputSubjectSubscription)
            this.keyInputSubjectSubscription.unsubscribe();
        if (this.dataSourceSubscription)
            this.dataSourceSubscription.unsubscribe();
        if (this.keyEventSubjectSubscription)
            this.keyEventSubjectSubscription.unsubscribe();
        if (this.allLogsSubjectSubscription)
            this.allLogsSubjectSubscription.unsubscribe();
        if (this.handleToCheckLazyContainer)
            clearInterval(this.handleToCheckLazyContainer);
        if (this.xterm)
            this.xterm.dispose();
        this.loggingService.log(() => console.debug('All resources has been cleaned up.'));
    }
    write(chars) {
        this.xterm?.write(chars);
    }
    get keyInput() {
        return this.dataSubject;
    }
    onData() {
        return this.dataSubject;
    }
    get keyEventInput() {
        return this.keySubject;
    }
    onKey() {
        return this.keySubject;
    }
    get underlying() {
        return this.xterm;
    }
    get isDraggableOnEdgeActivated() {
        // return this.displayOption.activateDraggableOnEdge != undefined && this.displayOption.fixedGrid == undefined;
        return this._draggable;
    }
    get scrollBarWidth() {
        const core = this.underlying._core;
        return core.viewport.scrollBarWidth;
    }
    /**
     * After user coordinate dimensions of terminal, it's called.
     * @param left
     * @param top
     * @param width
     * @param height
     */
    onResizeEnd(left, top, width, height) {
        this.setOuterDimensions(left, top, width, height);
    }
    /**
     * Before onResizeEnd is called, it valiates dimensions to change.
     * @param re dimension to be submitted from resizable stuff
     */
    validatorFactory() {
        const comp = this;
        return (re) => {
            if (this._draggable) {
                return true;
            }
            else
                return false;
        };
    }
    findCssStyleRule(containingSelector) {
        for (let i = 0; i < document.styleSheets.length; i++) {
            let sheet = document.styleSheets.item(i);
            if (sheet) {
                for (let i = 0; i < sheet.cssRules.length; i++) {
                    let rule = sheet.cssRules.item(i);
                    if ('selectorText' in rule)
                        if (rule.selectorText.includes(containingSelector))
                            return rule;
                }
            }
        }
        return undefined;
    }
}
NgTerminalComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgTerminalComponent, deps: [{ token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i1.LoggingService }], target: i0.ɵɵFactoryTarget.Component });
NgTerminalComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: NgTerminalComponent, selector: "ng-terminal", inputs: { _dataSource: ["dataSource", "_dataSource"], _rowsInput: ["rows", "_rowsInput"], _colsInput: ["cols", "_colsInput"], _minWidthInput: ["minWidth", "_minWidthInput"], _minHeightInput: ["minHeight", "_minHeightInput"], draggable: "draggable", _xtermOptions: ["xtermOptions", "_xtermOptions"] }, outputs: { keyInputEmitter: "keyInput", keyEventEmitter: "keyEvent", dataEmitter: "data", keyEmitter: "key" }, providers: [LinearRenderService], viewQueries: [{ propertyName: "terminalOuter", first: true, predicate: ["terminal"], descendants: true, static: true }, { propertyName: "resizeBox", first: true, predicate: ["resizeBox"], descendants: true, static: true }, { propertyName: "detectBox", first: true, predicate: ["detectBox"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<!-- Hierarchy: parent element(user) > host element(ng-terminal) > resize-box element > outer element -->\n<global-style></global-style>\n<div mwlResizable #resizeBox class=\"resize-box\" [validateResize]=\"validatorFactory()\" [enableGhostResize]=\"true\"\n    (resizeEnd)=\"onResizeEnd($event.rectangle.left, $event.rectangle.top, $event.rectangle.width??0, $event.rectangle.height??0)\">\n    <div #terminal class=\"terminal-outer\">\n    </div>\n    <div class=\"resize-handle resize-handle-top\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"{ top: false }\"></div>\n    <div class=\"resize-handle resize-handle-left\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"{ left: false }\"></div>\n    <div class=\"resize-handle resize-handle-right\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"isDraggableOnEdgeActivated ? { right: true } : { right: false }\"></div>\n    <div class=\"resize-handle resize-handle-bottom\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"isDraggableOnEdgeActivated ? { bottom: true } : { bottom: false }\"></div>\n</div>\n<div #detectBox style=\"width: 100%; height: 0px; position: absolute;\">\n</div>", styles: [".terminal-outer{box-sizing:border-box;height:100%;width:100%;padding:5px}:host{display:block;height:100%;width:100%}.resize-box{box-sizing:border-box;height:100%;width:100%;position:relative}div>.handle-active{z-index:100;background-color:#85858a!important}.resize-handle{background-color:#000}.resize-handle-top.handle-active,.resize-handle-bottom.handle-active{cursor:row-resize}.resize-handle-left.handle-active,.resize-handle-right.handle-active{cursor:col-resize}.resize-handle-top,.resize-handle-bottom{position:absolute;height:5px;width:100%}.resize-handle-top{top:0}.resize-handle-bottom{bottom:0}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;width:5px}.resize-handle-left{left:0;top:0}.resize-handle-right{right:0;top:0}\n"], dependencies: [{ kind: "directive", type: i2.ResizableDirective, selector: "[mwlResizable]", inputs: ["validateResize", "enableGhostResize", "resizeSnapGrid", "resizeCursors", "ghostElementPositioning", "allowNegativeResizes", "mouseMoveThrottleMS"], outputs: ["resizeStart", "resizing", "resizeEnd"], exportAs: ["mwlResizable"] }, { kind: "directive", type: i2.ResizeHandleDirective, selector: "[mwlResizeHandle]", inputs: ["resizeEdges", "resizableContainer"] }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4.GlobalStyleComponent, selector: "global-style" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: NgTerminalComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-terminal', providers: [LinearRenderService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Hierarchy: parent element(user) > host element(ng-terminal) > resize-box element > outer element -->\n<global-style></global-style>\n<div mwlResizable #resizeBox class=\"resize-box\" [validateResize]=\"validatorFactory()\" [enableGhostResize]=\"true\"\n    (resizeEnd)=\"onResizeEnd($event.rectangle.left, $event.rectangle.top, $event.rectangle.width??0, $event.rectangle.height??0)\">\n    <div #terminal class=\"terminal-outer\">\n    </div>\n    <div class=\"resize-handle resize-handle-top\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"{ top: false }\"></div>\n    <div class=\"resize-handle resize-handle-left\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"{ left: false }\"></div>\n    <div class=\"resize-handle resize-handle-right\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"isDraggableOnEdgeActivated ? { right: true } : { right: false }\"></div>\n    <div class=\"resize-handle resize-handle-bottom\" mwlResizeHandle [ngClass]=\"{'handle-active' : isDraggableOnEdgeActivated}\"\n        [resizeEdges]=\"isDraggableOnEdgeActivated ? { bottom: true } : { bottom: false }\"></div>\n</div>\n<div #detectBox style=\"width: 100%; height: 0px; position: absolute;\">\n</div>", styles: [".terminal-outer{box-sizing:border-box;height:100%;width:100%;padding:5px}:host{display:block;height:100%;width:100%}.resize-box{box-sizing:border-box;height:100%;width:100%;position:relative}div>.handle-active{z-index:100;background-color:#85858a!important}.resize-handle{background-color:#000}.resize-handle-top.handle-active,.resize-handle-bottom.handle-active{cursor:row-resize}.resize-handle-left.handle-active,.resize-handle-right.handle-active{cursor:col-resize}.resize-handle-top,.resize-handle-bottom{position:absolute;height:5px;width:100%}.resize-handle-top{top:0}.resize-handle-bottom{bottom:0}.resize-handle-left,.resize-handle-right{position:absolute;height:100%;width:5px}.resize-handle-left{left:0;top:0}.resize-handle-right{right:0;top:0}\n"] }]
        }], ctorParameters: function () { return [{ type: i0.Renderer2 }, { type: i0.ElementRef }, { type: i1.LoggingService }]; }, propDecorators: { keyInputEmitter: [{
                type: Output,
                args: ['keyInput']
            }], keyEventEmitter: [{
                type: Output,
                args: ['keyEvent']
            }], dataEmitter: [{
                type: Output,
                args: ['data']
            }], keyEmitter: [{
                type: Output,
                args: ['key']
            }], _dataSource: [{
                type: Input,
                args: ['dataSource']
            }], _rowsInput: [{
                type: Input,
                args: ['rows']
            }], _colsInput: [{
                type: Input,
                args: ['cols']
            }], _minWidthInput: [{
                type: Input,
                args: ['minWidth']
            }], _minHeightInput: [{
                type: Input,
                args: ['minHeight']
            }], draggable: [{
                type: Input,
                args: ['draggable']
            }], _xtermOptions: [{
                type: Input,
                args: ['xtermOptions']
            }], terminalOuter: [{
                type: ViewChild,
                args: ['terminal', { static: true }]
            }], resizeBox: [{
                type: ViewChild,
                args: ['resizeBox', { static: true }]
            }], detectBox: [{
                type: ViewChild,
                args: ['detectBox', { static: true }]
            }] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmctdGVybWluYWwuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmctdGVybWluYWwvc3JjL2xpYi9uZy10ZXJtaW5hbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZy10ZXJtaW5hbC9zcmMvbGliL25nLXRlcm1pbmFsLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsU0FBUyxFQUVULEtBQUssRUFDTCxNQUFNLEVBQ04sWUFBWSxFQUdaLHVCQUF1QixHQU94QixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQW9CLFFBQVEsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUMxRCxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFNUMsT0FBTyxFQUFFLE9BQU8sRUFBNEIsTUFBTSxNQUFNLENBQUM7QUFFekQsT0FBTyxFQUNMLG1CQUFtQixHQUVwQixNQUFNLHlCQUF5QixDQUFDOzs7Ozs7QUFVakMsTUFBTSxPQUFPLG1CQUFtQjtJQStDOUI7O09BRUc7SUFDSCxJQUNJLFdBQVcsQ0FBQyxVQUEwQztRQUN4RCxJQUFJLENBQUMsVUFBVTtZQUFFLE9BQU87UUFDeEIsSUFBSSxJQUFJLENBQUMsc0JBQXNCLElBQUksU0FBUztZQUMxQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDNUMsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FDL0QsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FDakIsQ0FBQztJQUNKLENBQUM7SUEwQkQ7O09BRUc7SUFDSCxJQUNJLFNBQVMsQ0FBQyxTQUFrQjtRQUM5QixJQUFJ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USxDQUFDLGtCQUFrQixDQUFDOzRCQUFFLE9BQU8sSUFBSSxDQUFDO2lCQUNuRTthQUNGO1NBQ0Y7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDOztpSEF4dEJVLG1CQUFtQjtxR0FBbkIsbUJBQW1CLGtjQUhuQixDQUFDLG1CQUFtQixDQUFDLHNYQ2pDbEMsKzBDQWdCTTs0RkRvQk8sbUJBQW1CO2tCQVAvQixTQUFTOytCQUNFLGFBQWEsYUFHWixDQUFDLG1CQUFtQixDQUFDLG1CQUNmLHVCQUF1QixDQUFDLE1BQU07c0pBeUIvQyxlQUFlO3NCQURkLE1BQU07dUJBQUMsVUFBVTtnQkFRbEIsZUFBZTtzQkFEZCxNQUFNO3VCQUFDLFVBQVU7Z0JBVWxCLFdBQVc7c0JBRFYsTUFBTTt1QkFBQyxNQUFNO2dCQU9kLFVBQVU7c0JBRFQsTUFBTTt1QkFBQyxLQUFLO2dCQU9ULFdBQVc7c0JBRGQsS0FBSzt1QkFBQyxZQUFZO2dCQWVuQixVQUFVO3NCQURULEtBQUs7dUJBQUMsTUFBTTtnQkFPYixVQUFVO3NCQURULEtBQUs7dUJBQUMsTUFBTTtnQkFPYixjQUFjO3NCQURiLEtBQUs7dUJBQUMsVUFBVTtnQkFPakIsZUFBZTtzQkFEZCxLQUFLO3VCQUFDLFdBQVc7Z0JBT2QsU0FBUztzQkFEWixLQUFLO3VCQUFDLFdBQVc7Z0JBU2xCLGFBQWE7c0JBRFosS0FBSzt1QkFBQyxjQUFjO2dCQUlyQixhQUFhO3NCQURaLFNBQVM7dUJBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRTtnQkFJdkMsU0FBUztzQkFEUixTQUFTO3VCQUFDLFdBQVcsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUU7Z0JBSXhDLFNBQVM7c0JBRFIsU0FBUzt1QkFBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ29tcG9uZW50LFxuICBPbkluaXQsXG4gIFZpZXdDaGlsZCxcbiAgRWxlbWVudFJlZixcbiAgSW5wdXQsXG4gIE91dHB1dCxcbiAgRXZlbnRFbWl0dGVyLFxuICBPbkRlc3Ryb3ksXG4gIEFmdGVyVmlld0luaXQsXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxuICBDaGFuZ2VEZXRlY3RvclJlZixcbiAgT25DaGFuZ2VzLFxuICBSZW5kZXJlcjIsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIGlzRGV2TW9kZSxcbiAgT3B0aW9uYWwsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgSVRlcm1pbmFsT3B0aW9ucywgVGVybWluYWwgfSBmcm9tICdAeHRlcm0veHRlcm0nO1xuaW1wb3J0IHsgRml0QWRkb24gfSBmcm9tICdAeHRlcm0vYWRkb24tZml0JztcbmltcG9ydCB7IE5nVGVybWluYWwgfSBmcm9tICcuL25nLXRlcm1pbmFsJztcbmltcG9ydCB7IFN1YmplY3QsIE9ic2VydmFibGUsIFN1YnNjcmlwdGlvbiB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgUmVzaXplRXZlbnQgfSBmcm9tICdhbmd1bGFyLXJlc2l6YWJsZS1lbGVtZW50JztcbmltcG9ydCB7XG4gIExpbmVhclJlbmRlclNlcnZpY2UsXG4gIFByb3BlcnR5Q2hhbmdlU2V0LFxufSBmcm9tICcuL2xpbmVhci1yZW5kZXIuc2VydmljZSc7XG5pbXBvcnQgeyBMb2dnaW5nU2VydmljZSB9IGZyb20gJy4vbG9nZ2luZy5zZXJ2aWNlJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnbmctdGVybWluYWwnLFxuICB0ZW1wbGF0ZVVybDogJy4vbmctdGVybWluYWwuY29tcG9uZW50Lmh0bWwnLFxuICBzdHlsZVVybHM6IFsnLi9uZy10ZXJtaW5hbC5jb21wb25lbnQuY3NzJ10sXG4gIHByb3ZpZGVyczogW0xpbmVhclJlbmRlclNlcnZpY2VdLFxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcbn0pXG5leHBvcnQgY2xhc3MgTmdUZXJtaW5hbENvbXBvbmVudFxuICBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzLCBBZnRlclZpZXdJbml0LCBOZ1Rlcm1pbmFsLCBPbkRlc3Ryb3lcbntcbiAgcHJpdmF0ZSBsaW5lYXJSZW5kZXI6IExpbmVhclJlbmRlclNlcnZpY2U7XG4gIHByaXZhdGUgeHRlcm0/OiBUZXJtaW5hbDtcbiAgcHJpdmF0ZSBmaXRBZGRvbj86IEZpdEFkZG9uO1xuICBwcml2YXRlIGRhdGFTdWJqZWN0OiBTdWJqZWN0PHN0cmluZz4gPSBuZXcgU3ViamVjdDxzdHJpbmc+KCk7XG4gIHByaXZhdGUga2V5U3ViamVjdCA9IG5ldyBTdWJqZWN0PHsga2V5OiBzdHJpbmc7IGRvbUV2ZW50OiBLZXlib2FyZEV2ZW50IH0+KCk7XG5cbiAgcHJpdmF0ZSBrZXlJbnB1dFN1YmplY3RTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb24gPSB1bmRlZmluZWQ7XG4gIHByaXZhdGUga2V5RXZlbnRTdWJqZWN0U3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uID0gdW5kZWZpbmVkO1xuICBwcml2YXRlIGFsbExvZ3NTdWJqZWN0U3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uID0gdW5kZWZpbmVkO1xuICBwcml2YXRlIGRhdGFTb3VyY2VTdWJzY3JpcHRpb24/OiBTdWJzY3JpcHRpb24gPSB1bmRlZmluZWQ7XG4gIHByaXZhdGUgcmVzaXphYmxlT2JzZXJ2ZXJzOiBSZXNpemVPYnNlcnZlcltdID0gW107XG4gIHByaXZhdGUgZGF0YVNvdXJjZT86IE9ic2VydmFibGU8c3RyaW5nPiA9IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSBwYWRkaW5nU2l6ZSA9IDU7XG4gIHN0eWxlc0ZvclJlc2l6ZUJveDogUGFydGlhbDxDU1NTdHlsZURlY2xhcmF0aW9uPiA9IHsgZGlzcGxheTogJ2Jsb2NrJyB9O1xuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgKGRhdGEpPScnIGluc3RlYWQuXG4gICAqIEFuIGVtaXR0ZXIgZW1pdHMgcHJpbnRhYmxlIGNoYXJhY3RlcnMgcHVzaGVkIGZyb20geHRlcm0ncyBvbkRhdGEoKSB3aGVuIGEgdXNlciB0eXBlZCBvbiB0aGUgdGVybWluYWwuXG4gICAqL1xuICBAT3V0cHV0KCdrZXlJbnB1dCcpXG4gIGtleUlucHV0RW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXI8c3RyaW5nPigpO1xuXG4gIC8qKlxuICAgKiBAZGVwcmVjYXRlZCB1c2UgKGtleSk9JycgaW5zdGVhZC5cbiAgICogQW4gZW1pdHRlciBlbWl0cyBrZXkgYW5kIGtleWJhb3JkIGV2ZW50IHB1c2hlZCBmcm9tIHh0ZXJtJ3Mgb25LZXkoKSB3aGVuIGEgdXNlciB0eXBlZCBvbiB0aGUgdGVybWluYWwuXG4gICAqL1xuICBAT3V0cHV0KCdrZXlFdmVudCcpXG4gIGtleUV2ZW50RW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXI8e1xuICAgIGtleTogc3RyaW5nO1xuICAgIGRvbUV2ZW50OiBLZXlib2FyZEV2ZW50O1xuICB9PigpO1xuXG4gIC8qKlxuICAgKiBBbiBlbWl0dGVyIGVtaXRzIHByaW50YWJsZSBjaGFyYWN0ZXJzIHB1c2hlZCBmcm9tIHh0ZXJtJ3Mgb25EYXRhKCkgd2hlbiBhIHVzZXIgdHlwZWQgb24gdGhlIHRlcm1pbmFsLlxuICAgKi9cbiAgQE91dHB1dCgnZGF0YScpXG4gIGRhdGFFbWl0dGVyID0gdGhpcy5rZXlJbnB1dEVtaXR0ZXI7XG5cbiAgLyoqXG4gICAqIEFuIGVtaXR0ZXIgZW1pdHMga2V5IGFuZCBrZXliYW9yZCBldmVudCBwdXNoZWQgZnJvbSB4dGVybSdzIG9uS2V5KCkgd2hlbiBhIHVzZXIgdHlwZWQgb24gdGhlIHRlcm1pbmFsLlxuICAgKi9cbiAgQE91dHB1dCgna2V5JylcbiAga2V5RW1pdHRlciA9IHRoaXMua2V5RXZlbnRFbWl0dGVyO1xuXG4gIC8qKlxuICAgKiBBIGRhdHNvdXJjZSBpcyBhbiBvYnNlcnZhYmxlIHdoZXJlIE5nVGVybWluYWwgcmVhZHMgY2hhcmFjdG9ycy5cbiAgICovXG4gIEBJbnB1dCgnZGF0YVNvdXJjZScpXG4gIHNldCBfZGF0YVNvdXJjZShkYXRhU291cmNlOiBPYnNlcnZhYmxlPHN0cmluZz4gfCB1bmRlZmluZWQpIHtcbiAgICBpZiAoIWRhdGFTb3VyY2UpIHJldHVybjtcbiAgICBpZiAodGhpcy5kYXRhU291cmNlU3Vic2NyaXB0aW9uICE9IHVuZGVmaW5lZClcbiAgICAgIHRoaXMuZGF0YVNvdXJjZVN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIHRoaXMuZGF0YVNvdXJjZSA9IGRhdGFTb3VyY2U7XG4gICAgdGhpcy5kYXRhU291cmNlU3Vic2NyaXB0aW9uID0gdGhpcy5kYXRhU291cmNlLnN1YnNjcmliZSgoZGF0YSkgPT5cbiAgICAgIHRoaXMud3JpdGUoZGF0YSlcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENoYW5nZSB0aGUgcm93IGNvdW50IG9mIGEgdGVybWluYWwgaW1tZWRpYXRlbHkuXG4gICAqL1xuICBASW5wdXQoJ3Jvd3MnKVxuICBfcm93c0lucHV0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBDaGFuZ2UgdGhlIGNvbHVtbiBjb3VudCBvZiBhIHRlcm1pbmFsIGltbWVkaWF0ZWx5LlxuICAgKi9cbiAgQElucHV0KCdjb2xzJylcbiAgX2NvbHNJbnB1dD86IG51bWJlcjtcblxuICAvKipcbiAgICogU2V0IHRoZSBtaW5pbXVtIHdpZHRoIHRvIGxpbWl0IGRyYWdnaW5nLlxuICAgKi9cbiAgQElucHV0KCdtaW5XaWR0aCcpXG4gIF9taW5XaWR0aElucHV0PzogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBTZXQgdGhlIG1pbmltdW0gaGVpZ2h0IHRvIGxpbWl0IGRyYWdnaW5nLlxuICAgKi9cbiAgQElucHV0KCdtaW5IZWlnaHQnKVxuICBfbWluSGVpZ2h0SW5wdXQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRvZ2dsZSBkcmFnZ2FibGUuXG4gICAqL1xuICBASW5wdXQoJ2RyYWdnYWJsZScpXG4gIHNldCBkcmFnZ2FibGUoZHJhZ2dhYmxlOiBib29sZWFuKSB7XG4gICAgdGhpcy5fZHJhZ2dhYmxlID0gZHJhZ2dhYmxlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFuIHdyYXBwZXIgb2Yge0BsaW5rIElUZXJtaW5hbE9wdGlvbnN9IGZvciBYdGVybS5cbiAgICovXG4gIEBJbnB1dCgneHRlcm1PcHRpb25zJylcbiAgX3h0ZXJtT3B0aW9uczogSVRlcm1pbmFsT3B0aW9ucyAmIHsgdGhlbWU/OiB7IGJvcmRlcj86IHN0cmluZyB9IH0gPSB7fTtcblxuICBAVmlld0NoaWxkKCd0ZXJtaW5hbCcsIHsgc3RhdGljOiB0cnVlIH0pXG4gIHRlcm1pbmFsT3V0ZXIhOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBAVmlld0NoaWxkKCdyZXNpemVCb3gnLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICByZXNpemVCb3ghOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBAVmlld0NoaWxkKCdkZXRlY3RCb3gnLCB7IHN0YXRpYzogdHJ1ZSB9KVxuICBkZXRlY3RCb3ghOiBFbGVtZW50UmVmPEhUTUxEaXZFbGVtZW50PjtcblxuICBnZXQgZHJhZ2dhYmxlKCkge1xuICAgIHJldHVybiB0aGlzLl9kcmFnZ2FibGU7XG4gIH1cblxuICBsYXN0RHJhZ2dlZFBvc2l0aW9uPzogeyB3aWR0aDogc3RyaW5nOyBoZWlnaHQ6IHN0cmluZyB9ID0gdW5kZWZpbmVkO1xuXG4gIF9kcmFnZ2FibGU6IGJvb2xlYW4gPSBmYWxzZTtcblxuICBfc3R5bGVzSW5wdXQ6IGFueSA9IHt9O1xuXG4gIHNldE1pbldpZHRoKHdpZHRoOiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLl9taW5XaWR0aElucHV0ID0gd2lkdGg7XG4gIH1cblxuICBzZXRNaW5IZWlnaHQoaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLl9taW5IZWlnaHRJbnB1dCA9IGhlaWdodDtcbiAgfVxuXG4gIHNldERyYWdnYWJsZShkcmFnZ2FibGU6IGJvb2xlYW4pOiB2b2lkIHtcbiAgICB0aGlzLl9kcmFnZ2FibGUgPSBkcmFnZ2FibGU7XG4gICAgdGhpcy5sYXN0RHJhZ2dlZFBvc2l0aW9uID0gdW5kZWZpbmVkOyAvLyBSZXNldCBwb3NpdGlvbiB2YWx1ZXNcbiAgfVxuXG4gIHNldFh0ZXJtT3B0aW9ucyhcbiAgICBvcHRpb25zOiBJVGVybWluYWxPcHRpb25zICYgeyB0aGVtZT86IHsgYm9yZGVyPzogc3RyaW5nIH0gfVxuICApOiB2b2lkIHtcbiAgICB0aGlzLl94dGVybU9wdGlvbnMgPSBvcHRpb25zO1xuICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoeyB0aW1lOiBuZXcgRGF0ZSgpLCB0eXBlOiAnbm9uZScgfSk7XG4gIH1cblxuICBzZXRSb3dzKHJvd3M6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICh0aGlzLl9yb3dzSW5wdXQgIT0gcm93cykge1xuICAgICAgdGhpcy5fcm93c0lucHV0ID0gcm93cztcbiAgICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoe1xuICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICB0eXBlOiAncm93Q2hhbmdlZCcsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzZXRDb2xzKGNvbHM6IG51bWJlcik6IHZvaWQge1xuICAgIGlmICh0aGlzLl9jb2xzSW5wdXQgIT0gY29scykge1xuICAgICAgdGhpcy5fY29sc0lucHV0ID0gY29scztcbiAgICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoe1xuICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICB0eXBlOiAnY29sdW1uQ2hhbmdlZCcsXG4gICAgICB9KTtcbiAgICB9XG4gIH1cblxuICBzZXRTdHlsZShzdHlsZU9iamVjdDogYW55KTogdm9pZCB7XG4gICAgaWYgKFxuICAgICAgSlNPTi5zdHJpbmdpZnkodGhpcy5fc3R5bGVzSW5wdXQgPz8ge30pICE9XG4gICAgICBKU09OLnN0cmluZ2lmeShzdHlsZU9iamVjdCA/PyB7fSlcbiAgICApIHtcbiAgICAgIHRoaXMuX3N0eWxlc0lucHV0ID0gc3R5bGVPYmplY3Q7XG4gICAgICB0aGlzLmxpbmVhclJlbmRlci5wdXNoQW5kSGFuZGxlKHtcbiAgICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgICAgdHlwZTogJ25vbmUnLFxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlVG9DaGVja0xhenlDb250YWluZXI/OiBSZXR1cm5UeXBlPHR5cGVvZiBzZXRJbnRlcnZhbD4gPSB1bmRlZmluZWQ7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSByZW5kZXJlcjogUmVuZGVyZXIyLCAvL1JlbmRlciBpcyBiZWluZyB1c2VkIGZvciBmYXN0IHJlbmRlcmluZyB3aXRob3V0IG1hcmtGb3JDaGVjaygpLlxuICAgIHByaXZhdGUgaG9zdFJlZjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4sXG4gICAgcHJpdmF0ZSBsb2dnaW5nU2VydmljZTogTG9nZ2luZ1NlcnZpY2UsXG4gICkge1xuICAgIHRoaXMubGluZWFyUmVuZGVyID0gbmV3IExpbmVhclJlbmRlclNlcnZpY2UoaG9zdFJlZik7XG4gIH1cblxuICBwcml2YXRlIHNldHVwKCkge1xuICAgIGlmICh0aGlzLnh0ZXJtKSB7XG4gICAgICB0aGlzLnh0ZXJtLm9uRGF0YSgoaW5wdXQpID0+IHtcbiAgICAgICAgdGhpcy5kYXRhU3ViamVjdC5uZXh0KGlucHV0KTtcbiAgICAgIH0pO1xuICAgICAgdGhpcy54dGVybS5vbktleSgoZSkgPT4ge1xuICAgICAgICB0aGlzLmtleVN1YmplY3QubmV4dChlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICB0aGlzLmtleUlucHV0U3ViamVjdFN1YnNjcmlwdGlvbiA9IHRoaXMuZGF0YVN1YmplY3Quc3Vic2NyaWJlKChkYXRhKSA9PiB7XG4gICAgICB0aGlzLmtleUlucHV0RW1pdHRlci5lbWl0KGRhdGEpO1xuICAgIH0pO1xuICAgIHRoaXMua2V5RXZlbnRTdWJqZWN0U3Vic2NyaXB0aW9uID0gdGhpcy5rZXlTdWJqZWN0LnN1YnNjcmliZSgoZSkgPT4ge1xuICAgICAgdGhpcy5rZXlFdmVudEVtaXR0ZXIuZW1pdChlKTtcbiAgICB9KTtcbiAgICB0aGlzLnNldHVwUmVzaXplT2JzZXJ2ZXJzKCk7XG4gICAgLy8gaWYgKG9iMykgdGhpcy5yZXNpemFibGVPYnNlcnZlcnMucHVzaChvYjMpO1xuICAgIHRoaXMuYWxsTG9nc1N1YmplY3RTdWJzY3JpcHRpb24gPVxuICAgICAgdGhpcy5saW5lYXJSZW5kZXIucmVuZGVyT2JzZXJ2YWJsZS5zdWJzY3JpYmUoKGNoYW5nZSkgPT4ge1xuICAgICAgICBpZiAoY2hhbmdlKSB0aGlzLmNvb3JkaW5hdGVPdXRlckFuZFRlcm1pbmFsKGNoYW5nZSk7XG4gICAgICAgIGVsc2UgdGhpcy5jb29yZGluYXRlT3V0ZXJBbmRUZXJtaW5hbChjaGFuZ2UpO1xuICAgICAgICB0aGlzLmxpbmVhclJlbmRlci5oYW5kbGVOZXh0T25lKCk7XG4gICAgICB9KTtcbiAgICB0aGlzLmxpbmVhclJlbmRlci5oYW5kbGVOZXh0T25lKCk7XG4gIH1cblxuICAvKipcbiAgICogc2V0IGRpbWVuc2lvbnNcbiAgICovXG4gIHByaXZhdGUgc2V0T3V0ZXJEaW1lbnNpb25zKFxuICAgIGxlZnQ6IG51bWJlcixcbiAgICB0b3A6IG51bWJlcixcbiAgICB3aWR0aDogbnVtYmVyLFxuICAgIGhlaWdodDogbnVtYmVyXG4gICkge1xuICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoe1xuICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgIHR5cGU6ICdkcmFnZ2VkJyxcbiAgICAgIGRyYWdnZWQ6IHsgZHJhZ2dlZFdpZHRoOiBgJHt3aWR0aH1weGAsIGRyYWdnZWRIZWlnaHQ6IGAke2hlaWdodH1weGAgfSxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXBwbHlTdHlsZXNUb1Jlc2l6ZUJveCgpIHtcbiAgICBPYmplY3Qua2V5cyh0aGlzLnN0eWxlc0ZvclJlc2l6ZUJveClcbiAgICAgIC5tYXAoKGtleSkgPT4ge1xuICAgICAgICByZXR1cm4geyBrZXksIHZhbHVlOiAodGhpcy5zdHlsZXNGb3JSZXNpemVCb3ggYXMgU3RyaW5nVG9TdHJpbmcpW2tleV0gfTtcbiAgICAgIH0pXG4gICAgICAuZm9yRWFjaCgoeyBrZXksIHZhbHVlIH0pID0+IHtcbiAgICAgICAgaWYgKHRoaXMucmVzaXplQm94KSB7XG4gICAgICAgICAgaWYgKHZhbHVlKVxuICAgICAgICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZSh0aGlzLnJlc2l6ZUJveC5uYXRpdmVFbGVtZW50LCBrZXksIHZhbHVlKTtcbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMucmVuZGVyZXIucmVtb3ZlU3R5bGUodGhpcy5yZXNpemVCb3gubmF0aXZlRWxlbWVudCwga2V5KTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIHRoaXMuc3R5bGVzRm9yUmVzaXplQm94ID0gdGhpcy5zdHlsZXNGb3JSZXNpemVCb3g7IC8vaW52YWxpZGF0ZVxuICB9XG5cbiAgbmdPbkluaXQoKSB7fVxuXG4gIC8qKlxuICAgKiBJdCBjcmVhdGVzIG5ldyB0ZXJtaW5hbCBpbiAjdGVybWluYWwuXG4gICAqL1xuICBuZ0FmdGVyVmlld0luaXQoKSB7XG4gICAgdGhpcy5maXRBZGRvbiA9IG5ldyBGaXRBZGRvbigpO1xuICAgIHRoaXMueHRlcm0gPSBuZXcgVGVybWluYWwoe1xuICAgICAgYWxsb3dQcm9wb3NlZEFwaTogdHJ1ZSxcbiAgICB9KTtcbiAgICBpZiAoISh0aGlzLnRlcm1pbmFsT3V0ZXIubmF0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudCkuaXNDb25uZWN0ZWQpIHtcbiAgICAgIHRoaXMuaGFuZGxlVG9DaGVja0xhenlDb250YWluZXIgPSBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgICAgIGlmICgodGhpcy50ZXJtaW5hbE91dGVyLm5hdGl2ZUVsZW1lbnQgYXMgSFRNTEVsZW1lbnQpLmlzQ29ubmVjdGVkKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZGVidWcoXCJUaGUgY29udGFpbmVyJ3MgYmVlbiBjb25uZWN0ZWQuXCIpKTtcbiAgICAgICAgICAgIHRoaXMueHRlcm0hLm9wZW4odGhpcy50ZXJtaW5hbE91dGVyLm5hdGl2ZUVsZW1lbnQpO1xuICAgICAgICAgICAgdGhpcy54dGVybSEubG9hZEFkZG9uKHRoaXMuZml0QWRkb24hISk7XG4gICAgICAgICAgICB0aGlzLnNldHVwKCk7XG4gICAgICAgICAgICB0aGlzLmxpbmVhclJlbmRlci5wdXNoQW5kSGFuZGxlKHsgdGltZTogbmV3IERhdGUoKSwgdHlwZTogJ25vbmUnIH0pO1xuICAgICAgICAgIH0gZmluYWxseSB7XG4gICAgICAgICAgICBpZiAodGhpcy5oYW5kbGVUb0NoZWNrTGF6eUNvbnRhaW5lcilcbiAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmhhbmRsZVRvQ2hlY2tMYXp5Q29udGFpbmVyKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sIDUwMCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMueHRlcm0ub3Blbih0aGlzLnRlcm1pbmFsT3V0ZXIubmF0aXZlRWxlbWVudCk7XG4gICAgICB0aGlzLnh0ZXJtLmxvYWRBZGRvbih0aGlzLmZpdEFkZG9uKTtcbiAgICAgIHRoaXMuc2V0dXAoKTtcbiAgICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoeyB0aW1lOiBuZXcgRGF0ZSgpLCB0eXBlOiAnbm9uZScgfSk7XG4gICAgfVxuICB9XG5cbiAgbmdPbkNoYW5nZXMoY2hhbmdlcz86IFNpbXBsZUNoYW5nZXMpIHtcbiAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmdyb3VwKCdvbkNoYW5nZXMnKSk7XG4gICAgdGhpcy5sb2dnaW5nU2VydmljZS5sb2coKCkgPT4gY29uc29sZS5kZWJ1ZygncHJvcDogJywgY2hhbmdlcykpO1xuICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZ3JvdXBFbmQoKSk7XG4gICAgaWYgKGNoYW5nZXM/LlsnX3Jvd3NJbnB1dCddKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGNoYW5nZXM/LlsnX3Jvd3NJbnB1dCddPy5wcmV2aW91c1ZhbHVlICE9XG4gICAgICAgIGNoYW5nZXM/LlsnX3Jvd3NJbnB1dCddPy5jdXJyZW50VmFsdWVcbiAgICAgICkge1xuICAgICAgICB0aGlzLmxpbmVhclJlbmRlci5wdXNoQW5kSGFuZGxlKHtcbiAgICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgIHR5cGU6ICdyb3dDaGFuZ2VkJyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChjaGFuZ2VzPy5bJ19jb2xzSW5wdXQnXSkge1xuICAgICAgaWYgKFxuICAgICAgICBjaGFuZ2VzPy5bJ19jb2xzSW5wdXQnXT8ucHJldmlvdXNWYWx1ZSAhPVxuICAgICAgICBjaGFuZ2VzPy5bJ19jb2xzSW5wdXQnXT8uY3VycmVudFZhbHVlXG4gICAgICApIHtcbiAgICAgICAgdGhpcy5saW5lYXJSZW5kZXIucHVzaEFuZEhhbmRsZSh7XG4gICAgICAgICAgdGltZTogbmV3IERhdGUoKSxcbiAgICAgICAgICB0eXBlOiAnY29sdW1uQ2hhbmdlZCcsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoY2hhbmdlcz8uWydkcmFnZ2FibGUnXSlcbiAgICAgIHRoaXMubGluZWFyUmVuZGVyLnB1c2hBbmRIYW5kbGUoeyB0aW1lOiBuZXcgRGF0ZSgpLCB0eXBlOiAnbm9uZScgfSk7XG4gIH1cblxuICByZXNpemVIYW5kbGVTdHlsZVJ1bGU/OiBDU1NTdHlsZVJ1bGU7XG4gIHJlc2l6ZUhhbmRsZUFjdGl2ZVN0eWxlUnVsZT86IENTU1N0eWxlUnVsZTtcblxuICAvKipcbiAgICogSXQgc2VydmVzIGEgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYWRqdXN0IHRoZSBkaW1lbnNpb25zIG9mIHRoZSB4dGVybS1zY3JlZW4sIHh0ZXJtLXZpZXcsIGFuZCByZXNpemUgYm94XG4gICAqIGFmdGVyIG1ha2luZyBhbnkgY2hhbmdlcyB0byB0aGUgb3V0ZXIgYm94LCByb3dzLCBvciBjb2x1bW5zLCBvciB3aGVuIHRoZSByZXNpemUgYm94IGlzIGJlaW5nIGRyYWdnZWQuXG4gICAqXG4gICAqIFRoZXJlIHNldmVyYWwgZmFjdG9ycyB0aGF0IGFmZmVjdCBkaW1lbnNpb25zLCBhcyBJIG1lbnRpb25lZCBlYXJsaWVyLlxuICAgKiBSZWdhcmRsZXNzIG9mIHdoZXRoZXIgdGhlIGRyYWdnYWJsZSBmZWF0dXJlIGlzIG9uLCBpZiBuZXcgcm93IG9yIGNvbHVtbiB2YWx1ZSBpcyBpbnB1dCwgdGhpcyB2YWx1ZSB3aWxsIGJlIGFwcGxpZWQuXG4gICAqIC0gRHJhZ2dhYmxlID0gTmV3IHNwZWNpZmllZCBSb3cvQ29sdW1uIHZhbHVlID4gRnVsbCAoRGVmYXVsdClcbiAgICogQHBhcmFtIGNoYW5nZSBUaGlzIGFyZ3VtZW50IHJlcHJlc2VudHMgYSBzaW5nbGUgY2hhbmdlIHRoYXQgb2NjdXJlZC5cbiAgICogQHJldHVybnNcbiAgICovXG4gIHByaXZhdGUgY29vcmRpbmF0ZU91dGVyQW5kVGVybWluYWwoY2hhbmdlOiBQcm9wZXJ0eUNoYW5nZVNldCkge1xuICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZGVidWcoYGNoYW5nZUxpc3Q6ICR7SlNPTi5zdHJpbmdpZnkoY2hhbmdlKX1gKSlcbiAgICBpZiAoIXRoaXMueHRlcm0pIHJldHVybjtcbiAgICBjb25zdCBpc0hvc3RFbGVtZW50VmlzaWJsZSA9XG4gICAgICB0aGlzLmhvc3RSZWYubmF0aXZlRWxlbWVudD8ub2Zmc2V0UGFyZW50ICE9PSBudWxsO1xuICAgIGlmICghaXNIb3N0RWxlbWVudFZpc2libGUpIHtcbiAgICAgIC8vIERvIG5vdGhpbmcgaWYgdGhlIGhvc3QgZWxlbWVudCBpcyBpbnZpc2libGUuXG4gICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmRlYnVnKCdgZGlzcGxheWAgb2YgaG9zdCBlbGVtZW50IHdhcyBzZXQgdG8gYG5vbmVgJykpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmRvVXBkYXRlWHRlcm1TdHlsZXMoKTtcbiAgICB0aGlzLmRvQWRqdXN0RGltZW5zaW9uT2ZSZXNpemVCb3goY2hhbmdlKTtcbiAgICB0aGlzLmRvQWRqdXN0U2l6ZU9mWHRlcm1TY3JlZW4oY2hhbmdlKTtcbiAgICB0aGlzLmRvVXBkYXRlVmlld3BvcnRBbmRSZXNpemVCb3hXaXRoUGl4Y2VsVW5pdCgpO1xuICB9XG5cbiAgLyoqXG4gICAqIGFwcGx5IG9wdGlvbnMgdG8gdGhlIHh0ZXJtIHRlcm1pbmFsXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBwcml2YXRlIGRvVXBkYXRlWHRlcm1TdHlsZXMoKSB7XG4gICAgaWYgKCF0aGlzLnh0ZXJtKSByZXR1cm47XG4gICAgdGhpcy54dGVybS5vcHRpb25zID0geyAuLi50aGlzLl94dGVybU9wdGlvbnMgfTtcbiAgICAvLyBhcHBseSB0aGUgdGhlbWUgdG8gdGhlIGJhY2tncm91bmQgb2YgdGhlIGhhbmRsZVxuICAgIGlmICh0aGlzLl94dGVybU9wdGlvbnMudGhlbWU/LmJhY2tncm91bmQpIHtcbiAgICAgIGlmICghdGhpcy5yZXNpemVIYW5kbGVTdHlsZVJ1bGUpXG4gICAgICAgIHRoaXMucmVzaXplSGFuZGxlU3R5bGVSdWxlID0gdGhpcy5maW5kQ3NzU3R5bGVSdWxlKCcucmVzaXplLWhhbmRsZVsnKTtcbiAgICAgIGlmICh0aGlzLnJlc2l6ZUhhbmRsZVN0eWxlUnVsZSlcbiAgICAgICAgdGhpcy5yZXNpemVIYW5kbGVTdHlsZVJ1bGUuc3R5bGUuYmFja2dyb3VuZENvbG9yID1cbiAgICAgICAgICB0aGlzLl94dGVybU9wdGlvbnMudGhlbWUuYmFja2dyb3VuZDtcbiAgICB9XG4gICAgaWYgKHRoaXMuX3h0ZXJtT3B0aW9ucy50aGVtZT8uYm9yZGVyKSB7XG4gICAgICBpZiAoIXRoaXMucmVzaXplSGFuZGxlQWN0aXZlU3R5bGVSdWxlKVxuICAgICAgICB0aGlzLnJlc2l6ZUhhbmRsZUFjdGl2ZVN0eWxlUnVsZSA9XG4gICAgICAgICAgdGhpcy5maW5kQ3NzU3R5bGVSdWxlKCcuaGFuZGxlLWFjdGl2ZScpO1xuICAgICAgaWYgKHRoaXMucmVzaXplSGFuZGxlQWN0aXZlU3R5bGVSdWxlKVxuICAgICAgICB0aGlzLnJlc2l6ZUhhbmRsZUFjdGl2ZVN0eWxlUnVsZS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPVxuICAgICAgICAgIHRoaXMuX3h0ZXJtT3B0aW9ucy50aGVtZS5ib3JkZXI7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIElmIHRoZSByZXNpemUgaGFuZGxlcyBhcmUgbW92ZWQsIHRoZSByZXNpemUgYm94IGFkanVzdHMgdG8gdGhlIG5ldyBkaW1lbnNpb25zO1xuICAgKiBvdGhlcndpc2UsIGl0IGRlZmF1bHRzIHRvIGEgbWF4aW1pemVkIHNpemUuXG4gICAqIEBwYXJhbSBjaGFuZ2VcbiAgICovXG4gIHByaXZhdGUgZG9BZGp1c3REaW1lbnNpb25PZlJlc2l6ZUJveChjaGFuZ2U6IFByb3BlcnR5Q2hhbmdlU2V0KSB7XG4gICAgdGhpcy5zdHlsZXNGb3JSZXNpemVCb3ggPSB7XG4gICAgICAuLi50aGlzLnN0eWxlc0ZvclJlc2l6ZUJveCxcbiAgICAgIC4uLnRoaXMuX3N0eWxlc0lucHV0LFxuICAgICAgd2lkdGg6IHRoaXMuc3R5bGVzRm9yUmVzaXplQm94LndpZHRoLFxuICAgICAgaGVpZ2h0OiB0aGlzLnN0eWxlc0ZvclJlc2l6ZUJveC5oZWlnaHQsXG4gICAgfTtcblxuICAgIC8vIFJlc2V0IHN0eWxlcyBvZiB0aGUgcmVzaXplIGVsZW1lbnRcbiAgICBpZiAoY2hhbmdlLnR5cGUgPT09ICdkcmFnZ2VkJykge1xuICAgICAgY29uc3QgbWluV2lkdGggPSB0aGlzLl9taW5XaWR0aElucHV0ID8/IDI0O1xuICAgICAgY29uc3QgbWluSGVpZ2h0ID0gdGhpcy5fbWluSGVpZ2h0SW5wdXQgPz8gMjQ7XG4gICAgICBjb25zdCB3aWR0aCA9XG4gICAgICAgIHBhcnNlSW50KGNoYW5nZS5kcmFnZ2VkLmRyYWdnZWRXaWR0aCkgPiBtaW5XaWR0aFxuICAgICAgICAgID8gY2hhbmdlLmRyYWdnZWQuZHJhZ2dlZFdpZHRoXG4gICAgICAgICAgOiBgJHttaW5XaWR0aH1weGA7XG4gICAgICBjb25zdCBoZWlnaHQgPVxuICAgICAgICBwYXJzZUludChjaGFuZ2UuZHJhZ2dlZC5kcmFnZ2VkSGVpZ2h0KSA+IG1pbkhlaWdodFxuICAgICAgICAgID8gY2hhbmdlLmRyYWdnZWQuZHJhZ2dlZEhlaWdodFxuICAgICAgICAgIDogYCR7bWluSGVpZ2h0fXB4YDtcbiAgICAgIHRoaXMuc3R5bGVzRm9yUmVzaXplQm94LndpZHRoID0gd2lkdGg7XG4gICAgICB0aGlzLnN0eWxlc0ZvclJlc2l6ZUJveC5oZWlnaHQgPSBoZWlnaHQ7XG4gICAgICB0aGlzLmxhc3REcmFnZ2VkUG9zaXRpb24gPSB7XG4gICAgICAgIHdpZHRoLFxuICAgICAgICBoZWlnaHQsXG4gICAgICB9O1xuICAgICAgdGhpcy5hcHBseVN0eWxlc1RvUmVzaXplQm94KCk7XG4gICAgfSBlbHNlIGlmICghKHRoaXMuZHJhZ2dhYmxlICYmIHRoaXMubGFzdERyYWdnZWRQb3NpdGlvbikpIHtcbiAgICAgIC8vIFdoZW4gYF9jb2xzSW5wdXRgIGFuZCBgZHJhZ2dhYmxlYCBpcyBub3QgZW5hYmxlZCxcbiAgICAgIC8vIGl0IGZpdHMgdGhlIHNpemUgdG8gdGhlIGhvc3QgZWxlbWVudC5cbiAgICAgIGNvbnN0IGN1cnJlbnRIb3N0V2lkdGggPSBnZXRDb21wdXRlZFN0eWxlKFxuICAgICAgICB0aGlzLmhvc3RSZWYubmF0aXZlRWxlbWVudFxuICAgICAgKS53aWR0aDtcbiAgICAgIGNvbnN0IGRldGVjdEJveFdpZHRoID0gZ2V0Q29tcHV0ZWRTdHlsZShcbiAgICAgICAgdGhpcy5kZXRlY3RCb3gubmF0aXZlRWxlbWVudFxuICAgICAgKS53aWR0aDtcbiAgICAgIGxldCBzbWFsbFBhcmVudCA9IGZhbHNlO1xuICAgICAgaWYgKHBhcnNlRmxvYXQoZGV0ZWN0Qm94V2lkdGgpIDwgcGFyc2VGbG9hdChjdXJyZW50SG9zdFdpZHRoKSkge1xuICAgICAgICAvLyB0aGUgd2lkdGggb2YgdGhlIHBhcmVudCBpcyBzbWFsbGVyIHRoYW4gdGhhdCBvZiByZXNpemUtYm94IGVsZW1lbnRcbiAgICAgICAgc21hbGxQYXJlbnQgPSB0cnVlO1xuICAgICAgfVxuICAgICAgaWYgKHNtYWxsUGFyZW50KSB7XG4gICAgICAgIC8vIEl0J3MgYmVlbiB3cml0dGVuIHRvIHNvbHZlIGh0dHBzOi8vZ2l0aHViLmNvbS9xd2VmZ2g5MC9uZy10ZXJtaW5hbC9pc3N1ZXMvNzlcbiAgICAgICAgLy8gSWYgdGhlIHdpZHRoIG9mIHRoZSBmbGV4LWJveCAodGhhdCBpcyB0aGUgcGFyZW50IG9mIHRoZSBob3N0IGVsZW1lbnQpIGlzIHNtYWxsZXIgdGhhbiB0aGF0IG9mIGNoaWxkIGVsZW1lbnQsIHRoZSBob3N0IGVsZW1lbnQgaXMgYWRqdXN0ZWQgdG8gdGhlIHdpZHRoIG9mIGNoaWxkIGVsZW1lbnRcbiAgICAgICAgLy8gaG9zdCBlbGVtZW50OiAxMDAwcHgsIHJlc2l6ZS1ib3goY2hpbGQpOiA5ODVweCAtPiBob3N0IGVsZW1lbnQ6IDk4NXB4LCByZXNpemUtYm94KGNoaWxkKTogOTcwcHggLT4gLi4uIC0+IHN0b3BcblxuICAgICAgICAvLyBUaGlzIGNvZGUgY2hlY2sgaWYgdGhlIHBhcmVudCBlbGVtZW50ICh0aGF0IGlzIHRoZSBwYXJlbnQgb2YgYDxuZy10ZXJtaW5hbD4pLCBpcyBzbWFsbGVyIHRoYW4gYC5yZXNpemUtYm94YFxuICAgICAgICAvLyBhbmQgZW5zdXJlcyB0aGF0IHRoZSB3aWR0aCBvZiB0aGUgYDxuZy10ZXJtaW5hbD5gIGFkanVzdHMgdG8gbWF0Y2ggdGhhdCBvZiB0aGUgcGFyZW50IGVsZW1lbnQgcmF0aGVyIHRoYW4gdGhlIGNoaWxkIGVsZW1lbnRzLCBpbiB0aGUgc3Vic2VxdWVudCBldmVudHMuXG4gICAgICAgIHRoaXMuc3R5bGVzRm9yUmVzaXplQm94LndpZHRoID0gYCR7cGFyc2VGbG9hdChkZXRlY3RCb3hXaWR0aCl9cHhgO1xuICAgICAgICB0aGlzLmFwcGx5U3R5bGVzVG9SZXNpemVCb3goKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGJ1dCBpZiB0aGUgZGltZW5zaW9uIG9mIGhvc3QgZWxlbWVudCBpcyByZXNpemVkLCB1cGRhdGUgd2lkdGggYW5kIGhlaWdodFxuICAgICAgICAvLyBJZiBgX3Jvd3NJbnB1dGAgaXMgc3BlY2lmaWVkLCBOZ1Rlcm1pbmFsIGtlZXAgdGhlIGN1cnJlbnQgaGVpZ2h0OyBvdGhlcndpc2UsIHRoZSBoZWlnaHQgaXMgc2V0IHRvIDEwMCVcbiAgICAgICAgaWYgKCF0aGlzLl9yb3dzSW5wdXQpIHRoaXMuc3R5bGVzRm9yUmVzaXplQm94LmhlaWdodCA9ICcxMDAlJztcbiAgICAgICAgaWYgKCF0aGlzLl9jb2xzSW5wdXQpIHRoaXMuc3R5bGVzRm9yUmVzaXplQm94LndpZHRoID0gJzEwMCUnO1xuICAgICAgICB0aGlzLmFwcGx5U3R5bGVzVG9SZXNpemVCb3goKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBmdW5jdGlvbiB1c2VzIGZpdEFkZG9uKCkgdG8gYWRqdXN0IHRoZSBkaW1lbnNpb24gb2YgeHRlcm0tc2NyZWVuIHRvIGNoYXJhY3RlciB1bml0XG4gICAqIElmIHRoZSBkcmFnZ2FibGUgdmFsdWUgaXMgdHJ1ZSBvciB0aGVyZSBhcmUgbm8gZml4ZWQgdmFsdWVzIGZvciB0aGUgcm93IG9yIGNvbHVtbixcbiAgICogaXQgZml0cyB0aGUgeHRlcm0gdGVybWluYWwgYm94ZXMgaW50byB0aGUgcmVzaXplIGJveDtcbiAgICogb3RoZXJ3aXNlLCBpdCByZXNpemVzIHRoZSB4dGVybSB0ZXJtaW5hbCB3aXRoIHNwZWNpZmllZCByb3cgYW5kIGNvbHVtbiB2YWx1ZXMuXG4gICAqL1xuICBwcml2YXRlIGRvQWRqdXN0U2l6ZU9mWHRlcm1TY3JlZW4oY2hhbmdlOiBQcm9wZXJ0eUNoYW5nZVNldCkge1xuICAgIGlmICghdGhpcy54dGVybSkgcmV0dXJuO1xuICAgIGlmIChcbiAgICAgIChjaGFuZ2UudHlwZSA9PSAncm93Q2hhbmdlZCcgJiYgdGhpcy5fcm93c0lucHV0KSB8fFxuICAgICAgKGNoYW5nZS50eXBlID09ICdjb2x1bW5DaGFuZ2VkJyAmJiB0aGlzLl9jb2xzSW5wdXQpXG4gICAgKSB7XG4gICAgICB0aGlzLnh0ZXJtLnJlc2l6ZShcbiAgICAgICAgdGhpcy5fY29sc0lucHV0ID8/IHRoaXMueHRlcm0uY29scyxcbiAgICAgICAgdGhpcy5fcm93c0lucHV0ID8/IHRoaXMueHRlcm0ucm93c1xuICAgICAgKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICBpZiAodGhpcy54dGVybS5lbGVtZW50KSB7XG4gICAgICAgIC8vIFRoZSBmaXRBZGRvbi5maXQoKSBvcGVyYXRpb24gZG9lc24ndCByZWNvZ25pemUgdGhlIHBhZGRpbmcgdmFsdWVzIG9mIHRlcm1pbmFsT3V0ZXIuXG4gICAgICAgIC8vIEl0IHNlZW1zIHRvIGJlIHVzaW5nIHRoZSBwYWRkaW5nIHZhbHVlcyBvZiB4dGVybSBlbGVtZW50IGluc3RlYWQuXG4gICAgICAgIC8vIFRoZXJlZm9yZSwgd2UgZXN0YWJsaXNoIGEgYnJpZWYgdGltZSBmcmFtZSB0byBhZGp1c3QgdGhlIHBhZGRpbmcgdmFsdWVzIGJlZm9yZSBhbmQgYWZ0ZXIgZXhlY3V0aW5nIGZpdEFkZG9uLmZpdCgpLlxuICAgICAgICAvLyBJZiB0aGlzIGxpbmUgaXMgcmVtb3ZlZCwgd2hlbiBkcmFnZ2luZyByZXNpemUtYm94IHZlcnRpY2FsbHksIHRoZSB3aWR0aCBpcyBkZWNyZWFzZWQuXG4gICAgICAgIHRoaXMueHRlcm0uZWxlbWVudC5zdHlsZS5wYWRkaW5nTGVmdCA9IGAke3RoaXMucGFkZGluZ1NpemV9cHhgO1xuICAgICAgICB0aGlzLnByaW50RGltZW5zaW9uKCdCZWZvcmUgZml0QWRkb24uZml0KCkgb2YgWHRlcm0nKTtcbiAgICAgICAgdGhpcy5maXRBZGRvbj8uZml0KCk7XG4gICAgICAgIHRoaXMucHJpbnREaW1lbnNpb24oJ0FmdGVyIGZpdEFkZG9uLmZpdCgpIG9mIFh0ZXJtJyk7XG4gICAgICAgIHRoaXMueHRlcm0uZWxlbWVudC5zdHlsZS5wYWRkaW5nTGVmdCA9IGAkezB9cHhgO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGZ1bmN0aW9ucyBzZXRzIHdpZHRoIG9mIHRoZSByZXNpemUgYm94LCB4dGVybS12aWV3cG9ydCBhbmQgeHRlcm0tc2NyZWVuIHdpdGggc3BlY2lmaWMgcGl4ZWwgdmFsdWVzLlxuICAgKi9cbiAgcHJpdmF0ZSBkb1VwZGF0ZVZpZXdwb3J0QW5kUmVzaXplQm94V2l0aFBpeGNlbFVuaXQoKSB7XG4gICAgaWYgKHRoaXMueHRlcm0/LmVsZW1lbnQpIHtcbiAgICAgIGxldCB4dGVybVNjcmVlbiA9XG4gICAgICAgIHRoaXMueHRlcm0uZWxlbWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCd4dGVybS1zY3JlZW4nKVswXTtcbiAgICAgIGxldCB4dGVybVZpZXdwb3J0ID1cbiAgICAgICAgdGhpcy54dGVybS5lbGVtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ3h0ZXJtLXZpZXdwb3J0JylbMF07XG4gICAgICBjb25zdCBzY3JlZW5XaWR0aCA9IHh0ZXJtU2NyZWVuLmNsaWVudFdpZHRoO1xuICAgICAgY29uc3Qgc2NyZWVuSGVpZ2h0ID0geHRlcm1TY3JlZW4uY2xpZW50SGVpZ2h0O1xuICAgICAgY29uc3QgY29yZSA9ICh0aGlzLnVuZGVybHlpbmcgYXMgYW55KS5fY29yZTtcbiAgICAgIGNvbnN0IHNjcm9sbEJhcldpZHRoOiBudW1iZXIgPSBjb3JlLnZpZXdwb3J0LnNjcm9sbEJhcldpZHRoIGFzIG51bWJlcjtcbiAgICAgIGNvbnN0IGhvc3RXaWR0aCA9IHBhcnNlSW50KFxuICAgICAgICBnZXRDb21wdXRlZFN0eWxlKHRoaXMuaG9zdFJlZi5uYXRpdmVFbGVtZW50KS53aWR0aFxuICAgICAgKTtcblxuICAgICAgLy8gSXQgZml4ZXMgYSBidWcgd2hlcmUgdGhlIHZpZXdwb3J0J3Mgd2lkdGggaXNuJ3QgdXBkYXRlZCBieSBmaXRBZGRvbi5maXQoKVxuICAgICAgdGhpcy5yZW5kZXJlci5zZXRTdHlsZShcbiAgICAgICAgeHRlcm1WaWV3cG9ydCxcbiAgICAgICAgJ3dpZHRoJyxcbiAgICAgICAgYCR7c2NyZWVuV2lkdGggKyBzY3JvbGxCYXJXaWR0aH1weGBcbiAgICAgICk7XG5cbiAgICAgIC8vIEl0IGFkanVzdHMgdGhlIGRpbWVuc2lvbiBvZiB0aGUgcmVzaXplIGJveCB0byB0aGUgeHRlcm0tc2NyZWVuIGVsZW1lbnQuXG4gICAgICBjb25zdCBjYWx1bGF0ZWRCb3hXaWR0aCA9XG4gICAgICAgIHNjcmVlbldpZHRoICsgc2Nyb2xsQmFyV2lkdGggKyB0aGlzLnBhZGRpbmdTaXplICogMjtcbiAgICAgIGNvbnN0IGNvbXBvbmVudEVsZW1lbnQgPSB0aGlzLmhvc3RSZWYubmF0aXZlRWxlbWVudCBhcyBIVE1MRWxlbWVudDtcbiAgICAgIGNvbnN0IGNvbXBvbmVudFdpdGggPSBwYXJzZUludChnZXRDb21wdXRlZFN0eWxlKGNvbXBvbmVudEVsZW1lbnQpLndpZHRoKTtcbiAgICAgIGNvbnN0IHJlc3RyaWN0ZWRXaWR0aCA9XG4gICAgICAgIGNhbHVsYXRlZEJveFdpZHRoID4gY29tcG9uZW50V2l0aCA/IGNvbXBvbmVudFdpdGggOiBjYWx1bGF0ZWRCb3hXaWR0aDtcblxuICAgICAgdGhpcy5zdHlsZXNGb3JSZXNpemVCb3ggPSB7XG4gICAgICAgIC4uLnRoaXMuc3R5bGVzRm9yUmVzaXplQm94LFxuICAgICAgICB3aWR0aDogYCR7cmVzdHJpY3RlZFdpZHRofXB4YCxcbiAgICAgICAgaGVpZ2h0OiBgJHtzY3JlZW5IZWlnaHQgKyB0aGlzLnBhZGRpbmdTaXplICogMn1weGAsXG4gICAgICB9O1xuICAgICAgdGhpcy5hcHBseVN0eWxlc1RvUmVzaXplQm94KCk7XG4gICAgICB0aGlzLnByaW50RGltZW5zaW9uKFxuICAgICAgICAnQWZ0ZXIgdXBkYXRlIHRoZSBkaW1lbnNpb25zIGZvciBhbGwgYm94ZXMgd2l0aCBwaXhlbCB2YWx1ZXMnXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgcHJpbnREaW1lbnNpb24odGl0bGU6IHN0cmluZykge1xuICAgIGlmICh0aGlzLnh0ZXJtPy5lbGVtZW50KSB7XG4gICAgICBsZXQgcmVzaXplQm94ID0gdGhpcy5yZXNpemVCb3gubmF0aXZlRWxlbWVudCBhcyBIVE1MRGl2RWxlbWVudDtcbiAgICAgIGxldCB4dGVybVNjcmVlbiA9XG4gICAgICAgIHRoaXMueHRlcm0uZWxlbWVudC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCd4dGVybS1zY3JlZW4nKVswXTtcbiAgICAgIGxldCB4dGVybVZpZXdwb3J0ID1cbiAgICAgICAgdGhpcy54dGVybS5lbGVtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ3h0ZXJtLXZpZXdwb3J0JylbMF07XG4gICAgICBjb25zdCBzY3JlZW5XaWR0aCA9IHh0ZXJtU2NyZWVuLmNsaWVudFdpZHRoO1xuICAgICAgY29uc3Qgc2NyZWVuSGVpZ2h0ID0geHRlcm1TY3JlZW4uY2xpZW50SGVpZ2h0O1xuXG4gICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmdyb3VwKGAke3RpdGxlfWApKTtcbiAgICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZGVidWcoYHdpZHRoKHJlc2l6ZUJveCk6ICR7Z2V0Q29tcHV0ZWRTdHlsZShyZXNpemVCb3gpLndpZHRofSxcbndpZHRoKHZpZXdwb3J0KTogJHtnZXRDb21wdXRlZFN0eWxlKHh0ZXJtVmlld3BvcnQpLndpZHRofSxcbndpZHRoKHNjcmVlbik6ICR7c2NyZWVuV2lkdGh9XG5zY3JvbGxCYXJXaWR0aDogJHt0aGlzLnNjcm9sbEJhcldpZHRofWApKTtcbiAgICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZGVidWcoYGhlaWdodChyZXNpemVCb3gpOiAke2dldENvbXB1dGVkU3R5bGUocmVzaXplQm94KS5oZWlnaHR9LFxuaGVpZ2h0KHZpZXdwb3J0KSAke2dldENvbXB1dGVkU3R5bGUoeHRlcm1WaWV3cG9ydCkuaGVpZ2h0fSxcbmhlaWdodChzY3JlZW4pOiAke3NjcmVlbkhlaWdodH1gKSk7XG4gICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmdyb3VwRW5kKCkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJZiBwdXNoQW5kSGFuZGxlKCkgd2VyZSB1c2VkLCB0aGVyZSBjb3VsZCBiZSBhbiBpc3N1ZVxuICAgKiBiZWNhdXNlIGl0IGNhbiBhZGp1c3QgdGhlIHNpemUgb2YgZWxlbWVudHMgZHVyaW5nIGEgbG9vcCBvZiBSZXNpemVPYnNlcnZlci5cbiAgICovXG4gIHByaXZhdGUgc2V0dXBSZXNpemVPYnNlcnZlcnMoKSB7XG4gICAgdGhpcy5yZXNpemFibGVPYnNlcnZlcnMgPSBbXTtcbiAgICBsZXQgb2IxID0gdGhpcy5vYnNlcnZlWHRlcm1WaWV3cG9ydERpbWVuc2lvbigpO1xuICAgIGxldCBvYjIgPSB0aGlzLm9ic2VydmVIb3N0RGltZW5zaW9uKCk7XG4gICAgaWYgKG9iMSkgdGhpcy5yZXNpemFibGVPYnNlcnZlcnMucHVzaChvYjEpO1xuICAgIGlmIChvYjIpIHRoaXMucmVzaXphYmxlT2JzZXJ2ZXJzLnB1c2gob2IyKTtcbiAgfVxuXG4gIHByaXZhdGUgb2JzZXJ2ZVh0ZXJtVmlld3BvcnREaW1lbnNpb24oKSB7XG4gICAgbGV0IHh0ZXJtVmlld3BvcnQgPSB0aGlzLnRlcm1pbmFsT3V0ZXIubmF0aXZlRWxlbWVudC5xdWVyeVNlbGVjdG9yKFxuICAgICAgJy54dGVybS12aWV3cG9ydCdcbiAgICApIGFzIEhUTUxEaXZFbGVtZW50IHwgdW5kZWZpbmVkO1xuICAgIGlmICh4dGVybVZpZXdwb3J0KSB7XG4gICAgICBjb25zdCByZXNpemVPYnNlcnZlciA9IG5ldyBSZXNpemVPYnNlcnZlcigoZW50cmllcykgPT4ge1xuICAgICAgICBjb25zdCBvdXRlckRpdldpZHRoID0gKFxuICAgICAgICAgIHRoaXMudGVybWluYWxPdXRlci5uYXRpdmVFbGVtZW50IGFzIEhUTUxEaXZFbGVtZW50IHwgdW5kZWZpbmVkXG4gICAgICAgICk/LmNsaWVudFdpZHRoO1xuICAgICAgICBjb25zdCBvdXRlckRpdkhlaWdodCA9IChcbiAgICAgICAgICB0aGlzLnRlcm1pbmFsT3V0ZXIubmF0aXZlRWxlbWVudCBhcyBIVE1MRGl2RWxlbWVudCB8IHVuZGVmaW5lZFxuICAgICAgICApPy5jbGllbnRIZWlnaHQ7XG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICBpZiAoZW50cnkuY29udGVudEJveFNpemUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgbGV0IHdpZHRoOiBudW1iZXIgPSBlbnRyeS50YXJnZXQuY2xpZW50V2lkdGg7XG4gICAgICAgICAgICBsZXQgaGVpZ2h0OiBudW1iZXIgPSBlbnRyeS50YXJnZXQuY2xpZW50SGVpZ2h0O1xuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAob3V0ZXJEaXZXaWR0aCAmJiB3aWR0aCA+IG91dGVyRGl2V2lkdGgpIHx8XG4gICAgICAgICAgICAgIChvdXRlckRpdkhlaWdodCAmJiBoZWlnaHQgPiBvdXRlckRpdkhlaWdodClcbiAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmRlYnVnKFxuICAgICAgICAgICAgICAgICdDaGFuZ2VzIG9uIGEgeHRlcm0gdmlld3BvcnQgZWxlbWVudCB3aWxsIGJlIGhhbmRsZWQuJ1xuICAgICAgICAgICAgICApKTtcbiAgICAgICAgICAgICAgdGhpcy5saW5lYXJSZW5kZXIucHVzaEFuZEhhbmRsZShcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgdHlwZTogJ3h0ZXJtVmlld3BvcnRFeGNlZWRpbmdPdXRlckRpdicsXG4gICAgICAgICAgICAgICAgICB4dGVybVZpZXdwb3J0RXhjZWVkaW5nT3V0ZXJEaXY6IHtcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IGAke3dpZHRofWAsXG4gICAgICAgICAgICAgICAgICAgIGhlaWdodDogYCR7aGVpZ2h0fWAsXG4gICAgICAgICAgICAgICAgICAgIG91dGVyRGl2V2lkdGg6IGAke291dGVyRGl2V2lkdGh9YCxcbiAgICAgICAgICAgICAgICAgICAgb3V0ZXJEaXZIZWlnaHQ6IGAke291dGVyRGl2SGVpZ2h0fWAsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXNpemVPYnNlcnZlci5vYnNlcnZlKHh0ZXJtVmlld3BvcnQpO1xuICAgICAgcmV0dXJuIHJlc2l6ZU9ic2VydmVyO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmVycm9yKFxuICAgICAgICAnSW52YWxpZCBzdGF0ZSBpcyBkZXRlY3RlZC4geHRlcm0gZWxlbWVudCBzaG91bGQgZXhpc3QgYmVsb3cgLnRlcm1pbmFsLW91dGVyLidcbiAgICAgICkpO1xuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG5cbiAgbGFzdERldGVjdGVkV2lkdGggPSAwO1xuICBwcml2YXRlIG9ic2VydmVIb3N0RGltZW5zaW9uKCkge1xuICAgIGxldCBob3N0RWxlbWVudCA9IHRoaXMuaG9zdFJlZi5uYXRpdmVFbGVtZW50O1xuICAgIGxldCBkZXRlY3RCb3ggPSB0aGlzLmRldGVjdEJveC5uYXRpdmVFbGVtZW50O1xuICAgIGlmIChob3N0RWxlbWVudCAmJiBkZXRlY3RCb3gpIHtcbiAgICAgIGNvbnN0IHJlc2l6ZU9ic2VydmVyID0gbmV3IFJlc2l6ZU9ic2VydmVyKChlbnRyaWVzKSA9PiB7XG4gICAgICAgIGZvciAobGV0IGVudHJ5IG9mIGVudHJpZXMpIHtcbiAgICAgICAgICBpZiAoZW50cnkudGFyZ2V0ID09PSBob3N0RWxlbWVudCkge1xuICAgICAgICAgICAgaWYgKGVudHJ5LmNvbnRlbnRCb3hTaXplLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgbGV0IHdpZHRoID0gZ2V0Q29tcHV0ZWRTdHlsZShlbnRyeS50YXJnZXQpLndpZHRoO1xuICAgICAgICAgICAgICBsZXQgaGVpZ2h0ID0gZ2V0Q29tcHV0ZWRTdHlsZShlbnRyeS50YXJnZXQpLmhlaWdodDtcbiAgICAgICAgICAgICAgaWYgKHBhcnNlSW50KHdpZHRoKSA+PSAwICYmIHBhcnNlSW50KGhlaWdodCkgPj0gMCkge1xuICAgICAgICAgICAgICAgIHRoaXMubG9nZ2luZ1NlcnZpY2UubG9nKCgpID0+IGNvbnNvbGUuZGVidWcoJ0NoYW5nZXMgb24gYSBob3N0IGVsZW1lbnQgd2lsbCBiZSBoYW5kbGVkLicpKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxpbmVhclJlbmRlci5wdXNoQW5kSGFuZGxlKFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnaG9zdFJlc2l6ZWQnLFxuICAgICAgICAgICAgICAgICAgICBob3N0UmVzaXplZDogeyB3aWR0aDogYCR7d2lkdGh9YCwgaGVpZ2h0OiBgJHtoZWlnaHR9YCB9LFxuICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIHRydWVcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChlbnRyeS50YXJnZXQgPT09IGRldGVjdEJveCkge1xuICAgICAgICAgICAgaWYgKGVudHJ5LmNvbnRlbnRCb3hTaXplLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgbGV0IHdpZHRoID0gZ2V0Q29tcHV0ZWRTdHlsZShlbnRyeS50YXJnZXQpLndpZHRoO1xuICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgcGFyc2VJbnQod2lkdGgpID49IDAgJiZcbiAgICAgICAgICAgICAgICBwYXJzZUludCh3aWR0aCkgPD0gdGhpcy5sYXN0RGV0ZWN0ZWRXaWR0aFxuICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvZ2dpbmdTZXJ2aWNlLmxvZygoKSA9PiBjb25zb2xlLmRlYnVnKFxuICAgICAgICAgICAgICAgICAgJ0NoYW5nZXMgb24gYSBkZXRlY3QtYm94IGVsZW1lbnQgd2lsbCBiZSBoYW5kbGVkLidcbiAgICAgICAgICAgICAgICApKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxpbmVhclJlbmRlci5wdXNoQW5kSGFuZGxlKFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aW1lOiBuZXcgRGF0ZSgpLFxuICAgICAgICAgICAgICAgICAgICB0eXBlOiAnZGV0ZWN0Qm94UmVzaXplZCcsXG4gICAgICAgICAgICAgICAgICAgIGRldGVjdEJveFJlc2l6ZWQ6IHsgd2lkdGg6IGAke3dpZHRofWAgfSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0aGlzLmxhc3REZXRlY3RlZFdpZHRoID0gcGFyc2VJbnQod2lkdGgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgICByZXNpemVPYnNlcnZlci5vYnNlcnZlKGhvc3RFbGVtZW50KTtcbiAgICAgIHJlc2l6ZU9ic2VydmVyLm9ic2VydmUoZGV0ZWN0Qm94KTtcbiAgICAgIHJldHVybiByZXNpemVPYnNlcnZlcjtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5sb2dnaW5nU2VydmljZS5sb2coKCkgPT4gY29uc29sZS5lcnJvcihcbiAgICAgICAgJ0ludmFsaWQgc3RhdGUgaXMgZGV0ZWN0ZWQuIHh0ZXJtIGVsZW1lbnQgc2hvdWxkIGV4aXN0IGJlbG93IC50ZXJtaW5hbC1vdXRlci4nXG4gICAgICApKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICAvKipcbiAgICogY2xlYW4gYWxsIHJlc291cmNlc1xuICAgKi9cbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XG4gICAgdGhpcy5yZXNpemFibGVPYnNlcnZlcnMuZm9yRWFjaCgob2IpID0+IG9iLmRpc2Nvbm5lY3QoKSk7XG4gICAgaWYgKHRoaXMua2V5SW5wdXRTdWJqZWN0U3Vic2NyaXB0aW9uKVxuICAgICAgdGhpcy5rZXlJbnB1dFN1YmplY3RTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICBpZiAodGhpcy5kYXRhU291cmNlU3Vic2NyaXB0aW9uKSB0aGlzLmRhdGFTb3VyY2VTdWJzY3JpcHRpb24udW5zdWJzY3JpYmUoKTtcbiAgICBpZiAodGhpcy5rZXlFdmVudFN1YmplY3RTdWJzY3JpcHRpb24pXG4gICAgICB0aGlzLmtleUV2ZW50U3ViamVjdFN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIGlmICh0aGlzLmFsbExvZ3NTdWJqZWN0U3Vic2NyaXB0aW9uKVxuICAgICAgdGhpcy5hbGxMb2dzU3ViamVjdFN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgIGlmICh0aGlzLmhhbmRsZVRvQ2hlY2tMYXp5Q29udGFpbmVyKVxuICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmhhbmRsZVRvQ2hlY2tMYXp5Q29udGFpbmVyKTtcbiAgICBpZiAodGhpcy54dGVybSkgdGhpcy54dGVybS5kaXNwb3NlKCk7XG4gICAgdGhpcy5sb2dnaW5nU2VydmljZS5sb2coKCkgPT4gY29uc29sZS5kZWJ1ZygnQWxsIHJlc291cmNlcyBoYXMgYmVlbiBjbGVhbmVkIHVwLicpKTtcbiAgfVxuXG4gIHdyaXRlKGNoYXJzOiBzdHJpbmcpIHtcbiAgICB0aGlzLnh0ZXJtPy53cml0ZShjaGFycyk7XG4gIH1cblxuICBnZXQga2V5SW5wdXQoKTogT2JzZXJ2YWJsZTxzdHJpbmc+IHtcbiAgICByZXR1cm4gdGhpcy5kYXRhU3ViamVjdDtcbiAgfVxuXG4gIG9uRGF0YSgpOiBPYnNlcnZhYmxlPHN0cmluZz4ge1xuICAgIHJldHVybiB0aGlzLmRhdGFTdWJqZWN0O1xuICB9XG5cbiAgZ2V0IGtleUV2ZW50SW5wdXQoKTogT2JzZXJ2YWJsZTx7IGtleTogc3RyaW5nOyBkb21FdmVudDogS2V5Ym9hcmRFdmVudCB9PiB7XG4gICAgcmV0dXJuIHRoaXMua2V5U3ViamVjdDtcbiAgfVxuXG4gIG9uS2V5KCk6IE9ic2VydmFibGU8eyBrZXk6IHN0cmluZzsgZG9tRXZlbnQ6IEtleWJvYXJkRXZlbnQgfT4ge1xuICAgIHJldHVybiB0aGlzLmtleVN1YmplY3Q7XG4gIH1cblxuICBnZXQgdW5kZXJseWluZygpOiBUZXJtaW5hbCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMueHRlcm07XG4gIH1cblxuICBnZXQgaXNEcmFnZ2FibGVPbkVkZ2VBY3RpdmF0ZWQoKSB7XG4gICAgLy8gcmV0dXJuIHRoaXMuZGlzcGxheU9wdGlvbi5hY3RpdmF0ZURyYWdnYWJsZU9uRWRnZSAhPSB1bmRlZmluZWQgJiYgdGhpcy5kaXNwbGF5T3B0aW9uLmZpeGVkR3JpZCA9PSB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHRoaXMuX2RyYWdnYWJsZTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IHNjcm9sbEJhcldpZHRoKCkge1xuICAgIGNvbnN0IGNvcmUgPSAodGhpcy51bmRlcmx5aW5nIGFzIGFueSkuX2NvcmU7XG4gICAgcmV0dXJuIGNvcmUudmlld3BvcnQuc2Nyb2xsQmFyV2lkdGggYXMgbnVtYmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIEFmdGVyIHVzZXIgY29vcmRpbmF0ZSBkaW1lbnNpb25zIG9mIHRlcm1pbmFsLCBpdCdzIGNhbGxlZC5cbiAgICogQHBhcmFtIGxlZnRcbiAgICogQHBhcmFtIHRvcFxuICAgKiBAcGFyYW0gd2lkdGhcbiAgICogQHBhcmFtIGhlaWdodFxuICAgKi9cbiAgb25SZXNpemVFbmQobGVmdDogbnVtYmVyLCB0b3A6IG51bWJlciwgd2lkdGg6IG51bWJlciwgaGVpZ2h0OiBudW1iZXIpOiB2b2lkIHtcbiAgICB0aGlzLnNldE91dGVyRGltZW5zaW9ucyhsZWZ0LCB0b3AsIHdpZHRoLCBoZWlnaHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEJlZm9yZSBvblJlc2l6ZUVuZCBpcyBjYWxsZWQsIGl0IHZhbGlhdGVzIGRpbWVuc2lvbnMgdG8gY2hhbmdlLlxuICAgKiBAcGFyYW0gcmUgZGltZW5zaW9uIHRvIGJlIHN1Ym1pdHRlZCBmcm9tIHJlc2l6YWJsZSBzdHVmZlxuICAgKi9cbiAgdmFsaWRhdG9yRmFjdG9yeSgpOiAocmU6IFJlc2l6ZUV2ZW50KSA9PiBib29sZWFuIHtcbiAgICBjb25zdCBjb21wID0gdGhpcztcbiAgICByZXR1cm4gKHJlOiBSZXNpemVFdmVudCkgPT4ge1xuICAgICAgaWYgKHRoaXMuX2RyYWdnYWJsZSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSByZXR1cm4gZmFsc2U7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZmluZENzc1N0eWxlUnVsZShjb250YWluaW5nU2VsZWN0b3I6IHN0cmluZykge1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgZG9jdW1lbnQuc3R5bGVTaGVldHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGxldCBzaGVldCA9IGRvY3VtZW50LnN0eWxlU2hlZXRzLml0ZW0oaSk7XG4gICAgICBpZiAoc2hlZXQpIHtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBzaGVldC5jc3NSdWxlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgIGxldCBydWxlID0gc2hlZXQuY3NzUnVsZXMuaXRlbShpKSBhcyBDU1NTdHlsZVJ1bGU7XG4gICAgICAgICAgaWYgKCdzZWxlY3RvclRleHQnIGluIHJ1bGUpXG4gICAgICAgICAgICBpZiAocnVsZS5zZWxlY3RvclRleHQuaW5jbHVkZXMoY29udGFpbmluZ1NlbGVjdG9yKSkgcmV0dXJuIHJ1bGU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG5pbnRlcmZhY2UgU3RyaW5nVG9TdHJpbmcge1xuICBbaW5kZXg6IHN0cmluZ106IHN0cmluZztcbn1cbiIsIjwhLS0gSGllcmFyY2h5OiBwYXJlbnQgZWxlbWVudCh1c2VyKSA+IGhvc3QgZWxlbWVudChuZy10ZXJtaW5hbCkgPiByZXNpemUtYm94IGVsZW1lbnQgPiBvdXRlciBlbGVtZW50IC0tPlxuPGdsb2JhbC1zdHlsZT48L2dsb2JhbC1zdHlsZT5cbjxkaXYgbXdsUmVzaXphYmxlICNyZXNpemVCb3ggY2xhc3M9XCJyZXNpemUtYm94XCIgW3ZhbGlkYXRlUmVzaXplXT1cInZhbGlkYXRvckZhY3RvcnkoKVwiIFtlbmFibGVHaG9zdFJlc2l6ZV09XCJ0cnVlXCJcbiAgICAocmVzaXplRW5kKT1cIm9uUmVzaXplRW5kKCRldmVudC5yZWN0YW5nbGUubGVmdCwgJGV2ZW50LnJlY3RhbmdsZS50b3AsICRldmVudC5yZWN0YW5nbGUud2lkdGg/PzAsICRldmVudC5yZWN0YW5nbGUuaGVpZ2h0Pz8wKVwiPlxuICAgIDxkaXYgI3Rlcm1pbmFsIGNsYXNzPVwidGVybWluYWwtb3V0ZXJcIj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwicmVzaXplLWhhbmRsZSByZXNpemUtaGFuZGxlLXRvcFwiIG13bFJlc2l6ZUhhbmRsZSBbbmdDbGFzc109XCJ7J2hhbmRsZS1hY3RpdmUnIDogaXNEcmFnZ2FibGVPbkVkZ2VBY3RpdmF0ZWR9XCJcbiAgICAgICAgW3Jlc2l6ZUVkZ2VzXT1cInsgdG9wOiBmYWxzZSB9XCI+PC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInJlc2l6ZS1oYW5kbGUgcmVzaXplLWhhbmRsZS1sZWZ0XCIgbXdsUmVzaXplSGFuZGxlIFtuZ0NsYXNzXT1cInsnaGFuZGxlLWFjdGl2ZScgOiBpc0RyYWdnYWJsZU9uRWRnZUFjdGl2YXRlZH1cIlxuICAgICAgICBbcmVzaXplRWRnZXNdPVwieyBsZWZ0OiBmYWxzZSB9XCI+PC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInJlc2l6ZS1oYW5kbGUgcmVzaXplLWhhbmRsZS1yaWdodFwiIG13bFJlc2l6ZUhhbmRsZSBbbmdDbGFzc109XCJ7J2hhbmRsZS1hY3RpdmUnIDogaXNEcmFnZ2FibGVPbkVkZ2VBY3RpdmF0ZWR9XCJcbiAgICAgICAgW3Jlc2l6ZUVkZ2VzXT1cImlzRHJhZ2dhYmxlT25FZGdlQWN0aXZhdGVkID8geyByaWdodDogdHJ1ZSB9IDogeyByaWdodDogZmFsc2UgfVwiPjwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJyZXNpemUtaGFuZGxlIHJlc2l6ZS1oYW5kbGUtYm90dG9tXCIgbXdsUmVzaXplSGFuZGxlIFtuZ0NsYXNzXT1cInsnaGFuZGxlLWFjdGl2ZScgOiBpc0RyYWdnYWJsZU9uRWRnZUFjdGl2YXRlZH1cIlxuICAgICAgICBbcmVzaXplRWRnZXNdPVwiaXNEcmFnZ2FibGVPbkVkZ2VBY3RpdmF0ZWQgPyB7IGJvdHRvbTogdHJ1ZSB9IDogeyBib3R0b206IGZhbHNlIH1cIj48L2Rpdj5cbjwvZGl2PlxuPGRpdiAjZGV0ZWN0Qm94IHN0eWxlPVwid2lkdGg6IDEwMCU7IGhlaWdodDogMHB4OyBwb3NpdGlvbjogYWJzb2x1dGU7XCI+XG48L2Rpdj4iXX0=