UNPKG

ngx-mat-dropdown

Version:
581 lines 56.6 kB
/**
 * @fileoverview added by tsickle
 * Generated from: lib/mat-select-search/mat-select-search.component.ts
 * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
 */
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, forwardRef, Inject, Input, ViewChild, HostBinding, Optional } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { MatSelect } from '@angular/material/select';
import { delay, take, takeUntil } from 'rxjs/operators';
import { Subject } from 'rxjs';
import { MatOption } from '@angular/material/core';
export class MatSelectSearchComponent {
    /**
     * @param {?} matSelect
     * @param {?} changeDetectorRef
     * @param {?=} matOption
     */
    constructor(matSelect, changeDetectorRef, matOption = null) {
        this.matSelect = matSelect;
        this.changeDetectorRef = changeDetectorRef;
        this.matOption = matOption;
        /**
         * Label of the search placeholder
         */
        this.placeholderLabel = 'Search';
        this.multiple = false;
        this.showSearch = true;
        /**
         * Label to be shown when no entries are found. Set to null if no message should be shown.
         */
        this.noEntriesFoundLabel = 'No Data';
        this.onChange = (/**
         * @param {?} _
         * @return {?}
         */
        (_) => { });
        this.onTouched = (/**
         * @param {?} _
         * @return {?}
         */
        (_) => { });
        /**
         * Whether the backdrop class has been set
         */
        this.overlayClassSet = false;
        /**
         * Event that emits when the current value changes
         */
        this.change = new EventEmitter();
        this.AllClicked = new EventEmitter();
        /**
         * Subject that emits when the component has been destroyed.
         */
        this._onDestroy = new Subject();
    }
    //@ViewChild('innerSelectall', { read: ElementRef }) innerSelectall: ElementRef;
    /**
     * @return {?}
     */
    get isInsideMatOption() {
        return !!this.matOption;
    }
    /**
     * Current search value
     * @return {?}
     */
    get value() {
        return this._value;
    }
    /**
     * @return {?}
     */
    ngOnInit() {
        // set custom panel class
        /** @type {?} */
        const panelClass = 'mat-select-search-panel';
        if (this.matSelect.panelClass) {
            if (Array.isArray(this.matSelect.panelClass)) {
                this.matSelect.panelClass.push(panelClass);
            }
            else if (typeof this.matSelect.panelClass === 'string') {
                this.matSelect.panelClass = [this.matSelect.panelClass, panelClass];
            }
            else if (typeof this.matSelect.panelClass === 'object') {
                this.matSelect.panelClass[panelClass] = true;
            }
        }
        else {
            this.matSelect.panelClass = panelClass;
        }
        // set custom mat-option class if the component was placed inside a mat-option
        if (this.matOption) {
            this.matOption.disabled = true;
            this.matOption._getHostElement().classList.add('contains-mat-select-search');
        }
        // when the select dropdown panel is opened or closed
        this.matSelect.openedChange
            // .pipe(takeUntil(this._onDestroy))
            .pipe(delay(1), takeUntil(this._onDestroy))
            .subscribe((/**
         * @param {?} opened
         * @return {?}
         */
        (opened) => {
            if (opened) {
                // focus the search field when opening
                this.getWidth();
                this._focus();
            }
            else {
                // clear it when closing
                this._reset();
            }
        }));
        // set the first item active after the options changed
        this.matSelect.openedChange
            .pipe(take(1))
            .pipe(takeUntil(this._onDestroy))
            .subscribe((/**
         * @return {?}
         */
        () => {
            this._options = this.matSelect.options;
            this._options.changes
                .pipe(takeUntil(this._onDestroy))
                .subscribe((/**
             * @return {?}
             */
            () => {
                /** @type {?} */
                const keyManager = this.matSelect._keyManager;
                if (keyManager && this.matSelect.panelOpen) {
                    // avoid "expression has been changed" error
                    setTimeout((/**
                     * @return {?}
                     */
                    () => {
                        keyManager.setFirstItemActive();
                        this.getWidth();
                        // set no entries found class on mat option
                        if (this.matOption) {
                            if (this._noEntriesFound()) {
                                this.matOption._getHostElement().classList.add('mat-select-search-no-entries-found');
                            }
                            else {
                                this.matOption._getHostElement().classList.remove('mat-select-search-no-entries-found');
                            }
                        }
                    }), 1);
                }
            }));
        }));
        // detect changes when the input changes
        this.change
            .pipe(takeUntil(this._onDestroy))
            .subscribe((/**
         * @return {?}
         */
        () => {
            this.changeDetectorRef.detectChanges();
        }));
        this.initMultipleHandling();
    }
    /**
     * @return {?}
     */
    ngOnDestroy() {
        this._onDestroy.next();
        this._onDestroy.complete();
    }
    /**
     * @return {?}
     */
    ngAfterViewInit() {
        setTimeout((/**
         * @return {?}
         */
        () => {
            this.setOverlayClass();
        }));
        this.matSelect.openedChange
            .pipe(take(1), takeUntil(this._onDestroy)).subscribe((/**
         * @return {?}
         */
        () => {
            this.matSelect.options.changes
                .pipe(takeUntil(this._onDestroy))
                .subscribe((/**
             * @return {?}
             */
            () => {
                this.changeDetectorRef.markForCheck();
            }));
        }));
    }
    /**
     * @param {?} event
     * @return {?}
     */
    _handleKeydown(event) {
        if (event.keyCode === 32) {
            // do not propagate spaces to MatSelect, as this would select the currently active option
            event.stopPropagation();
        }
    }
    /**
     * @param {?} value
     * @return {?}
     */
    writeValue(value) {
        /** @type {?} */
        const valueChanged = value !== this._value;
        if (valueChanged) {
            this._value = value;
            this.change.emit({ type: 'Text', val: value });
        }
    }
    /**
     * @param {?} value
     * @return {?}
     */
    onInputChange(value) {
        /** @type {?} */
        const valueChanged = value !== this._value;
        if (valueChanged) {
            this._value = value;
            this.onChange({ type: 'Text', val: value });
            this.change.emit({ type: 'Text', val: value });
        }
    }
    /**
     * @param {?} value
     * @return {?}
     */
    onBlur(value) {
        this.writeValue(value);
        this.onTouched();
    }
    /**
     * @param {?} fn
     * @return {?}
     */
    registerOnChange(fn) {
        this.onChange = fn;
    }
    /**
     * @param {?} fn
     * @return {?}
     */
    registerOnTouched(fn) {
        this.onTouched = fn;
    }
    /**
     * @return {?}
     */
    _focus() {
        if (!this.searchSelectInput || !this.matSelect.panel) {
            return;
        }
        // save and restore scrollTop of panel, since it will be reset by focus()
        // note: this is hacky
        /** @type {?} */
        const panel = this.matSelect.panel.nativeElement;
        /** @type {?} */
        const scrollTop = panel.scrollTop;
        // focus
        this.searchSelectInput.nativeElement.focus();
        panel.scrollTop = scrollTop;
    }
    /**
     * Resets the current search value
     * {boolean} focus whether to focus after resetting
     *
     * @param {?=} focus
     * @return {?}
     */
    _reset(focus) {
        if (!this.searchSelectInput) {
            return;
        }
        this.searchSelectInput.nativeElement.value = '';
        this.onInputChange('');
        if (focus) {
            this._focus();
        }
    }
    /**
     * Sets the overlay class  to correct offsetY
     * so that the selected option is at the position of the select box when opening
     * @private
     * @return {?}
     */
    setOverlayClass() {
        if (this.overlayClassSet) {
            return;
        }
        /** @type {?} */
        const overlayClasses = ['cdk-overlay-pane-select-search'];
        if (!this.matOption) {
            // add offset to panel if component is not placed inside mat-option
            overlayClasses.push('cdk-overlay-pane-select-search-with-offset');
        }
        this.matSelect.overlayDir.attach
            .pipe(takeUntil(this._onDestroy))
            .subscribe((/**
         * @return {?}
         */
        () => {
            // note: this is hacky, but currently there is no better way to do this
            // note: this is hacky, but currently there is no better way to do this
            /** @type {?} */
            let element;
            /** @type {?} */
            let overlayElement;
            if (this.searchSelectInput) {
                element = this.searchSelectInput.nativeElement;
                while (element = element.parentElement) {
                    if (element.classList.contains('cdk-overlay-pane')) {
                        overlayElement = element;
                        break;
                    }
                }
            }
            if (overlayElement) {
                overlayClasses.forEach((/**
                 * @param {?} overlayClass
                 * @return {?}
                 */
                overlayClass => {
                    overlayElement.classList.add(overlayClass);
                }));
            }
        }));
        this.overlayClassSet = true;
    }
    /**
     * Initializes handling <mat-select [multiple]="true">
     * Note: to improve this code, mat-select should be extended to allow disabling resetting the selection while filtering.
     * @private
     * @return {?}
     */
    initMultipleHandling() {
        // if <mat-select [multiple]="true">
        // store previously selected values and restore them when they are deselected
        // because the option is not available while we are currently filtering
        this.matSelect.valueChange
            .pipe(takeUntil(this._onDestroy))
            .subscribe((/**
         * @param {?} values
         * @return {?}
         */
        (values) => {
            if (this.matSelect.multiple) {
                /** @type {?} */
                let restoreSelectedValues = false;
                if (this._value && this._value.length
                    && this.previousSelectedValues && Array.isArray(this.previousSelectedValues)) {
                    if (!values || !Array.isArray(values)) {
                        values = [];
                    }
                    /** @type {?} */
                    const optionValues = this.matSelect.options.map((/**
                     * @param {?} option
                     * @return {?}
                     */
                    option => option.value));
                    this.previousSelectedValues.forEach((/**
                     * @param {?} previousValue
                     * @return {?}
                     */
                    previousValue => {
                        if (values.indexOf(previousValue) === -1 && optionValues.indexOf(previousValue) === -1) {
                            // if a value that was selected before is deselected and not found in the options, it was deselected
                            // due to the filtering, so we restore it.
                            values.push(previousValue);
                            restoreSelectedValues = true;
                        }
                    }));
                }
                if (restoreSelectedValues) {
                    this.matSelect._onChange(values);
                }
                this.previousSelectedValues = values;
            }
        }));
    }
    /**
     * @private
     * @return {?}
     */
    getWidth() {
        if (!this.innerSelectSearch || !this.innerSelectSearch.nativeElement) {
            return;
        }
        /** @type {?} */
        let element = this.innerSelectSearch.nativeElement;
        /** @type {?} */
        let panelElement;
        while (element = element.parentElement) {
            if (element.classList.contains('mat-select-panel')) {
                panelElement = element;
                break;
            }
        }
        if (panelElement) {
            this.innerSelectSearch.nativeElement.style.width = panelElement.clientWidth + 'px';
        }
        ////innerSelectall
        //if (!this.innerSelectall || !this.innerSelectall.nativeElement) {
        //    return;
        //}
        //let Selectallelement: HTMLElement = this.innerSelectall.nativeElement;
        //let SelectallpanelElement: HTMLElement;
        //while (Selectallelement = Selectallelement.parentElement) {
        //    if (Selectallelement.classList.contains('mat-select-panel')) {
        //        SelectallpanelElement = Selectallelement;
        //        break;
        //    }
        //}
        //if (SelectallpanelElement) {
        //    this.innerSelectall.nativeElement.style.width = SelectallpanelElement.clientWidth + 'px';
        //}
    }
    /**
     * @return {?}
     */
    _noEntriesFound() {
        if (!this._options) {
            return;
        }
        if (this.matOption) {
            return this.noEntriesFoundLabel && this.value && this._options.length === 1;
        }
        else {
            return this.noEntriesFoundLabel && this.value && this._options.length === 0;
        }
    }
    /**
     * @param {?} change
     * @param {?} check
     * @return {?}
     */
    toggleSelection(change, check) {
        if (change.checked) {
            //this.model.update.emit(this.values);
            this.onChange({ type: 'Check', val: change.checked });
            this.change.emit({ type: 'Check', val: change.checked });
        }
        else {
            this.onChange({ type: 'Check', val: change.checked });
            this.change.emit({ type: 'Check', val: change.checked });
        }
    }
    /**
     * @param {?} check
     * @return {?}
     */
    ischecked(check) {
        console.log(this.matSelect.options, this.matSelect.value);
        /** @type {?} */
        let selected = this.matSelect.selected;
        return this.matSelect.options && selected && selected.length > 0 && this.matSelect.options.length == selected.length;
    }
    /**
     * @return {?}
     */
    isIndeterminate() {
        /** @type {?} */
        let selected = this.matSelect.selected;
        return this.matSelect.options && selected.length > 0 && selected.length < this.matSelect.options.length;
    }
}
MatSelectSearchComponent.decorators = [
    { type: Component, args: [{
                selector: 'mat-select-search',
                template: "\r\n<input *ngIf=\"showSearch\" matInput class=\"mat-select-search-input mat-select-search-hidden\" />\r\n<input matInput class=\"mat-select-checkbox mat-select-search-hidden\"*ngIf=\"multiple\"  />\r\n\r\n<div #innerSelectSearch class=\"mat-select-search-inner\" *ngIf=\"showSearch\"\r\n     [ngClass]=\"{'mat-select-search-inner-multiple': matSelect.multiple}\">\r\n    <input matInput autocomplete=\"off\"\r\n           class=\"mat-select-search-input\"\r\n           #searchSelectInput\r\n           (keydown)=\"_handleKeydown($event)\"\r\n           (input)=\"onInputChange($event.target.value)\"\r\n           (blur)=\"onBlur($event.target.value)\"\r\n           placeholder=\"Search\" />\r\n    <button mat-button *ngIf=\"value\"\r\n            mat-icon-button\r\n            aria-label=\"Clear\"\r\n            (click)=\"_reset(true)\"\r\n            class=\"mat-select-search-clear\">\r\n        <mat-icon>close</mat-icon>\r\n    </button>\r\n</div>\r\n\r\n<div *ngIf=\"noEntriesFoundLabel && value && _options?.length === 0\"\r\n     class=\"mat-select-search-no-entries-found\">\r\n    {{noEntriesFoundLabel}}\r\n</div>\r\n",
                providers: [
                    {
                        provide: NG_VALUE_ACCESSOR,
                        useExisting: forwardRef((/**
                         * @return {?}
                         */
                        () => MatSelectSearchComponent)),
                        multi: true
                    }
                ],
                changeDetection: ChangeDetectionStrategy.OnPush,
                styles: [".mat-select-search-hidden{visibility:hidden}.mat-select-search-inner{position:absolute;top:0;width:calc(100% + 3px);border-bottom:1px solid #ccc;background:#fff;z-index:100;font-size:inherit;box-shadow:none;border-radius:0;-webkit-transform:translate3d(0,0,0)}.mat-select-search-inner.mat-select-search-inner-multiple{width:100%}::ng-deep .mat-select-search-panel{transform:none!important;overflow-x:hidden}.mat-select-search-input{padding:10px 30px 10px 10px;box-sizing:border-box}.mat-select-checkbox{padding:10px;box-sizing:border-box}.mat-select-search-no-entries-found{padding:10px}.mat-select-search-clear{position:absolute;right:4px;top:5px}:host.mat-select-search-inside-mat-option .mat-select-search-input{padding-top:0;padding-bottom:0;height:3em;line-height:3em}:host.mat-select-search-inside-mat-option .mat-select-checkbox{padding-top:0;padding-bottom:0;height:3em;line-height:3em}:host.mat-select-search-inside-mat-option .mat-select-search-clear{top:3px}::ng-deep .cdk-overlay-pane-select-search.cdk-overlay-pane-select-search-with-offset{margin-top:0}::ng-deep .mat-option[aria-disabled=true].contains-mat-select-search{position:static;padding:0}::ng-deep .mat-option[aria-disabled=true].contains-mat-select-search .mat-icon{margin-right:0}::ng-deep .mat-option[aria-disabled=true].contains-mat-select-search .mat-option-pseudo-checkbox{display:none}::ng-deep .mat-option[aria-disabled=true].contains-mat-select-search.mat-select-search-no-entries-found{height:6em}.mat-select-all-inner{position:absolute;top:52px;width:calc(100% + 3px);background:#fff;z-index:100;font-size:inherit;box-shadow:none;border-radius:0;-webkit-transform:translate3d(0,0,0)}"]
            }] }
];
/** @nocollapse */
MatSelectSearchComponent.ctorParameters = () => [
    { type: MatSelect, decorators: [{ type: Inject, args: [MatSelect,] }] },
    { type: ChangeDetectorRef },
    { type: MatOption, decorators: [{ type: Optional }, { type: Inject, args: [MatOption,] }] }
];
MatSelectSearchComponent.propDecorators = {
    placeholderLabel: [{ type: Input }],
    multiple: [{ type: Input, args: ['multiple',] }],
    showSearch: [{ type: Input, args: ['showSearch',] }],
    noEntriesFoundLabel: [{ type: Input }],
    searchSelectInput: [{ type: ViewChild, args: ['searchSelectInput', { read: ElementRef },] }],
    innerSelectSearch: [{ type: ViewChild, args: ['innerSelectSearch', { read: ElementRef },] }],
    isInsideMatOption: [{ type: HostBinding, args: ['class.mat-select-search-inside-mat-option',] }]
};
if (false) {
    /**
     * Label of the search placeholder
     * @type {?}
     */
    MatSelectSearchComponent.prototype.placeholderLabel;
    /** @type {?} */
    MatSelectSearchComponent.prototype.multiple;
    /** @type {?} */
    MatSelectSearchComponent.prototype.showSearch;
    /**
     * Label to be shown when no entries are found. Set to null if no message should be shown.
     * @type {?}
     */
    MatSelectSearchComponent.prototype.noEntriesFoundLabel;
    /**
     * Reference to the search input field
     * @type {?}
     */
    MatSelectSearchComponent.prototype.searchSelectInput;
    /** @type {?} */
    MatSelectSearchComponent.prototype.innerSelectSearch;
    /**
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype._value;
    /** @type {?} */
    MatSelectSearchComponent.prototype.onChange;
    /** @type {?} */
    MatSelectSearchComponent.prototype.onTouched;
    /**
     * Reference to the MatSelect options
     * @type {?}
     */
    MatSelectSearchComponent.prototype._options;
    /**
     * Previously selected values when using <mat-select [multiple]="true">
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype.previousSelectedValues;
    /**
     * Whether the backdrop class has been set
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype.overlayClassSet;
    /**
     * Event that emits when the current value changes
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype.change;
    /**
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype.AllClicked;
    /**
     * Subject that emits when the component has been destroyed.
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype._onDestroy;
    /** @type {?} */
    MatSelectSearchComponent.prototype.matSelect;
    /**
     * @type {?}
     * @private
     */
    MatSelectSearchComponent.prototype.changeDetectorRef;
    /** @type {?} */
    MatSelectSearchComponent.prototype.matOption;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0LXNlbGVjdC1zZWFyY2guY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6Im5nOi8vbmd4LW1hdC1kcm9wZG93bi8iLCJzb3VyY2VzIjpbImxpYi9tYXQtc2VsZWN0LXNlYXJjaC9tYXQtc2VsZWN0LXNlYXJjaC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxPQUFPLEVBRUgsdUJBQXVCLEVBQUUsaUJBQWlCLEVBQzFDLFNBQVMsRUFBRSxVQUFVLEVBQUUsWUFBWSxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUM5RCxTQUFTLEVBQ1QsV0FBVyxFQUNYLFFBQVEsRUFDWCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQXdCLGlCQUFpQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDekUsT0FBTyxFQUFHLFNBQVMsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBR3RELE9BQU8sRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBZW5ELE1BQU0sT0FBTyx3QkFBd0I7Ozs7OztJQTJDakMsWUFBc0MsU0FBb0IsRUFDOUMsaUJBQW9DLEVBQXdDLFlBQXVCLElBQUk7UUFEN0UsY0FBUyxHQUFULFNBQVMsQ0FBVztRQUM5QyxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQXdDLGNBQVMsR0FBVCxTQUFTLENBQWtCOzs7O1FBekMxRyxxQkFBZ0IsR0FBRyxRQUFRLENBQUM7UUFDbEIsYUFBUSxHQUFZLEtBQUssQ0FBQztRQUN4QixlQUFVLEdBQVksSUFBSSxDQUFDOzs7O1FBRXZDLHdCQUFtQixHQUFHLFNBQVMsQ0FBQztRQWdCekMsYUFBUTs7OztRQUFhLENBQUMsQ0FBTSxFQUFFLEVBQUUsR0FBRyxDQUFDLEVBQUM7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Qzs7Ozs7SUFFekMsOENBQWlEOzs7Ozs7SUFFakQsOENBQXlDOztJQUc3Qiw2Q0FBOEM7Ozs7O0lBQ3RELHFEQUE0Qzs7SUFBRSw2Q0FBaUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xyXG4gICAgQWZ0ZXJWaWV3SW5pdCxcclxuICAgIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LCBDaGFuZ2VEZXRlY3RvclJlZixcclxuICAgIENvbXBvbmVudCwgRWxlbWVudFJlZiwgRXZlbnRFbWl0dGVyLCBmb3J3YXJkUmVmLCBJbmplY3QsIElucHV0LCBPbkRlc3Ryb3ksIE9uSW5pdCwgUXVlcnlMaXN0LFxyXG4gICAgVmlld0NoaWxkLFxyXG4gICAgSG9zdEJpbmRpbmcsXHJcbiAgICBPcHRpb25hbFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsdWVBY2Nlc3NvciwgTkdfVkFMVUVfQUNDRVNTT1IgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7ICBNYXRTZWxlY3QgfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9zZWxlY3QnO1xyXG5pbXBvcnQgeyAgIE1hdENoZWNrYm94Q2hhbmdlIH0gZnJvbSAnQGFuZ3VsYXIvbWF0ZXJpYWwvY2hlY2tib3gnO1xyXG5cclxuaW1wb3J0IHsgZGVsYXksIHRha2UsIHRha2VVbnRpbCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyBNYXRPcHRpb24gfSBmcm9tICdAYW5ndWxhci9tYXRlcmlhbC9jb3JlJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gICAgc2VsZWN0b3I6ICdtYXQtc2VsZWN0LXNlYXJjaCcsXHJcbiAgICB0ZW1wbGF0ZVVybDogJy4vbWF0LXNlbGVjdC1zZWFyY2guY29tcG9uZW50Lmh0bWwnLFxyXG4gICAgc3R5bGVVcmxzOiBbJy4vbWF0LXNlbGVjdC1zZWFyY2guY29tcG9uZW50LnNjc3MnXSxcclxuICAgIHByb3ZpZGVyczogW1xyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgcHJvdmlkZTogTkdfVkFMVUVfQUNDRVNTT1IsXHJcbiAgICAgICAgICAgIHVzZUV4aXN0aW5nOiBmb3J3YXJkUmVmKCgpID0+IE1hdFNlbGVjdFNlYXJjaENvbXBvbmVudCksXHJcbiAgICAgICAgICAgIG11bHRpOiB0cnVlXHJcbiAgICAgICAgfVxyXG4gICAgXSxcclxuICAgIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYXRTZWxlY3RTZWFyY2hDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQWZ0ZXJWaWV3SW5pdCwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xyXG5cclxuICAgIC8qKiBMYWJlbCBvZiB0aGUgc2VhcmNoIHBsYWNlaG9sZGVyICovXHJcbiAgICBASW5wdXQoKSBwbGFjZWhvbGRlckxhYmVsID0gJ1NlYXJjaCc7XHJcbiAgICBASW5wdXQoJ211bHRpcGxlJykgbXVsdGlwbGU6IGJvb2xlYW4gPSBmYWxzZTtcclxuICAgIEBJbnB1dCgnc2hvd1NlYXJjaCcpIHNob3dTZWFyY2g6IGJvb2xlYW4gPSB0cnVlO1xyXG4gICAgLyoqIExhYmVsIHRvIGJlIHNob3duIHdoZW4gbm8gZW50cmllcyBhcmUgZm91bmQuIFNldCB0byBudWxsIGlmIG5vIG1lc3NhZ2Ugc2hvdWxkIGJlIHNob3duLiAqL1xyXG4gICAgQElucHV0KCkgbm9FbnRyaWVzRm91bmRMYWJlbCA9ICdObyBEYXRhJztcclxuXHJcbiAgICAvKiogUmVmZXJlbmNlIHRvIHRoZSBzZWFyY2ggaW5wdXQgZmllbGQgKi9cclxuICAgIEBWaWV3Q2hpbGQoJ3NlYXJjaFNlbGVjdElucHV0JywgeyByZWFkOiBFbGVtZW50UmVmIH0pIHNlYXJjaFNlbGVjdElucHV0OiBFbGVtZW50UmVmO1xyXG4gICAgQFZpZXdDaGlsZCgnaW5uZXJTZWxlY3RTZWFyY2gnLCB7IHJlYWQ6IEVsZW1lbnRSZWZ9KSBpbm5lclNlbGVjdFNlYXJjaDogRWxlbWVudFJlZjtcclxuICAgIC8vQFZpZXdDaGlsZCgnaW5uZXJTZWxlY3RhbGwnLCB7IHJlYWQ6IEVsZW1lbnRSZWYgfSkgaW5uZXJTZWxlY3RhbGw6IEVsZW1lbnRSZWY7XHJcbiAgICBASG9zdEJpbmRpbmcoJ2NsYXNzLm1hdC1zZWxlY3Qtc2VhcmNoLWluc2lkZS1tYXQtb3B0aW9uJylcclxuICAgIGdldCBpc0luc2lkZU1hdE9wdGlvbigpOiBib29sZWFuIHtcclxuICAgICAgICByZXR1cm4gISF0aGlzLm1hdE9wdGlvbjtcclxuICAgIH1cclxuICAgIC8qKiBDdXJyZW50IHNlYXJjaCB2YWx1ZSAqL1xyXG4gICAgZ2V0IHZhbHVlKCk6IHN0cmluZyB7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMuX3ZhbHVlO1xyXG4gICAgfVxyXG4gICAgcHJpdmF0ZSBfdmFsdWU6IHN0cmluZztcclxuXHJcbiAgICBvbkNoYW5nZTogRnVuY3Rpb24gPSAoXzogYW55KSA9PiB7IH07XHJcbiAgICBvblRvdWNoZWQ6IEZ1bmN0aW9uID0gKF86IGFueSkgPT4geyB9O1xyXG5cclxuICAgIC8qKiBSZWZlcmVuY2UgdG8gdGhlIE1hdFNlbGVjdCBvcHRpb25zICovXHJcbiAgICBwdWJsaWMgX29wdGlvbnM6IFF1ZXJ5TGlzdDxNYXRPcHRpb24+O1xyXG5cclxuICAgIC8qKiBQcmV2aW91c2x5IHNlbGVjdGVkIHZhbHVlcyB3aGVuIHVzaW5nIDxtYXQtc2VsZWN0IFttdWx0aXBsZV09XCJ0cnVlXCI+Ki9cclxuICAgIHByaXZhdGUgcHJldmlvdXNTZWxlY3RlZFZhbHVlczogYW55W107XHJcblxyXG4gICAgLyoqIFdoZXRoZXIgdGhlIGJhY2tkcm9wIGNsYXNzIGhhcyBiZWVuIHNldCAqL1xyXG4gICAgcHJpdmF0ZSBvdmVybGF5Q2xhc3NTZXQgPSBmYWxzZTtcclxuXHJcbiAgICAvKiogRXZlbnQgdGhhdCBlbWl0cyB3aGVuIHRoZSBjdXJyZW50IHZhbHVlIGNoYW5nZXMgKi9cclxuICAgIHByaXZhdGUgY2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcblxyXG4gICAgcHJpdmF0ZSBBbGxDbGlja2VkID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xyXG4gICAgLyoqIFN1YmplY3QgdGhhdCBlbWl0cyB3aGVuIHRoZSBjb21wb25lbnQgaGFzIGJlZW4gZGVzdHJveWVkLiAqL1xyXG4gICAgcHJpdmF0ZSBfb25EZXN0cm95ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuXHJcblxyXG4gICAgY29uc3RydWN0b3IoQEluamVjdChNYXRTZWxlY3QpIHB1YmxpYyBtYXRTZWxlY3Q6IE1hdFNlbGVjdCxcclxuICAgICAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZiwgQE9wdGlvbmFsKCkgQEluamVjdChNYXRPcHRpb24pIHB1YmxpYyBtYXRPcHRpb246IE1hdE9wdGlvbiA9IG51bGwpIHtcclxuXHJcblxyXG4gICAgfVxyXG5cclxuICAgIG5nT25Jbml0KCkge1xyXG4gICAgICAgIC8vIHNldCBjdXN0b20gcGFuZWwgY2xhc3NcclxuICAgICAgICBjb25zdCBwYW5lbENsYXNzID0gJ21hdC1zZWxlY3Qtc2VhcmNoLXBhbmVsJztcclxuICAgICAgICBpZiAodGhpcy5tYXRTZWxlY3QucGFuZWxDbGFzcykge1xyXG4gICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh0aGlzLm1hdFNlbGVjdC5wYW5lbENsYXNzKSkge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5tYXRTZWxlY3QucGFuZWxDbGFzcy5wdXNoKHBhbmVsQ2xhc3MpO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB0aGlzLm1hdFNlbGVjdC5wYW5lbENsYXNzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5tYXRTZWxlY3QucGFuZWxDbGFzcyA9IFt0aGlzLm1hdFNlbGVjdC5wYW5lbENsYXNzLCBwYW5lbENsYXNzXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdGhpcy5tYXRTZWxlY3QucGFuZWxDbGFzcyA9PT0gJ29iamVjdCcpIHtcclxuICAgICAgICAgICAgICAgIHRoaXMubWF0U2VsZWN0LnBhbmVsQ2xhc3NbcGFuZWxDbGFzc10gPSB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgdGhpcy5tYXRTZWxlY3QucGFuZWxDbGFzcyA9IHBhbmVsQ2xhc3M7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIHNldCBjdXN0b20gbWF0LW9wdGlvbiBjbGFzcyBpZiB0aGUgY29tcG9uZW50IHdhcyBwbGFjZWQgaW5zaWRlIGEgbWF0LW9wdGlvblxyXG4gICAgICAgIGlmICh0aGlzLm1hdE9wdGlvbikge1xyXG4gICAgICAgICAgICB0aGlzLm1hdE9wdGlvbi5kaXNhYmxlZCA9IHRydWU7XHJcbiAgICAgICAgICAgIHRoaXMubWF0T3B0aW9uLl9nZXRIb3N0RWxlbWVudCgpLmNsYXNzTGlzdC5hZGQoJ2NvbnRhaW5zLW1hdC1zZWxlY3Qtc2VhcmNoJyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIHdoZW4gdGhlIHNlbGVjdCBkcm9wZG93biBwYW5lbCBpcyBvcGVuZWQgb3IgY2xvc2VkXHJcbiAgICAgICAgdGhpcy5tYXRTZWxlY3Qub3BlbmVkQ2hhbmdlXHJcbiAgICAgICAgICAgIC8vIC5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIGRlbGF5KDEpLFxyXG4gICAgICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSlcclxuICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChvcGVuZWQpID0+IHtcclxuICAgICAgICAgICAgICAgIGlmIChvcGVuZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBmb2N1cyB0aGUgc2VhcmNoIGZpZWxkIHdoZW4gb3BlbmluZ1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0V2lkdGgoKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZm9jdXMoKTtcclxuXHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIGNsZWFyIGl0IHdoZW4gY2xvc2luZ1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3Jlc2V0KCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBzZXQgdGhlIGZpcnN0IGl0ZW0gYWN0aXZlIGFmdGVyIHRoZSBvcHRpb25zIGNoYW5nZWRcclxuICAgICAgICB0aGlzLm1hdFNlbGVjdC5vcGVuZWRDaGFuZ2VcclxuICAgICAgICAgICAgLnBpcGUodGFrZSgxKSlcclxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgdGhpcy5fb3B0aW9ucyA9IHRoaXMubWF0U2VsZWN0Lm9wdGlvbnM7XHJcbiAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgIHRoaXMuX29wdGlvbnMuY2hhbmdlc1xyXG4gICAgICAgICAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxyXG4gICAgICAgICAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBrZXlNYW5hZ2VyID0gdGhpcy5tYXRTZWxlY3QuX2tleU1hbmFnZXI7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChrZXlNYW5hZ2VyICYmIHRoaXMubWF0U2VsZWN0LnBhbmVsT3Blbikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYXZvaWQgXCJleHByZXNzaW9uIGhhcyBiZWVuIGNoYW5nZWRcIiBlcnJvclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAga2V5TWFuYWdlci5zZXRGaXJzdEl0ZW1BY3RpdmUoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmdldFdpZHRoKCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHNldCBubyBlbnRyaWVzIGZvdW5kIGNsYXNzIG9uIG1hdCBvcHRpb25cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXRPcHRpb24pIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuX25vRW50cmllc0ZvdW5kKCkpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWF0T3B0aW9uLl9nZXRIb3N0RWxlbWVudCgpLmNsYXNzTGlzdC5hZGQoJ21hdC1zZWxlY3Qtc2VhcmNoLW5vLWVudHJpZXMtZm91bmQnKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMubWF0T3B0aW9uLl9nZXRIb3N0RWxlbWVudCgpLmNsYXNzTGlzdC5yZW1vdmUoJ21hdC1zZWxlY3Qtc2VhcmNoLW5vLWVudHJpZXMtZm91bmQnKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sIDEpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gZGV0ZWN0IGNoYW5nZXMgd2hlbiB0aGUgaW5wdXQgY2hhbmdlc1xyXG4gICAgICAgIHRoaXMuY2hhbmdlXHJcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLl9vbkRlc3Ryb3kpKVxyXG4gICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICAgICAgICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5pbml0TXVsdGlwbGVIYW5kbGluZygpO1xyXG4gICAgfVxyXG5cclxuICAgIG5nT25EZXN0cm95KCkge1xyXG4gICAgICAgIHRoaXMuX29uRGVzdHJveS5uZXh0KCk7XHJcbiAgICAgICAgdGhpcy5fb25EZXN0cm95LmNvbXBsZXRlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgbmdBZnRlclZpZXdJbml0KCkge1xyXG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICAgICAgICB0aGlzLnNldE92ZXJsYXlDbGFzcygpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMubWF0U2VsZWN0Lm9wZW5lZENoYW5nZVxyXG4gICAgICAgICAgICAucGlwZShcclxuICAgICAgICAgICAgICAgIHRha2UoMSksXHJcbiAgICAgICAgICAgICAgICB0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KVxyXG4gICAgICAgICAgICApLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgICAgICAgICB0aGlzLm1hdFNlbGVjdC5vcHRpb25zLmNoYW5nZXNcclxuICAgICAgICAgICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSlcclxuICAgICAgICAgICAgICAgICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jaGFuZ2VEZXRlY3RvclJlZi5tYXJrRm9yQ2hlY2soKTtcclxuICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gIFxyXG4gICAgX2hhbmRsZUtleWRvd24oZXZlbnQ6IEtleWJvYXJkRXZlbnQpIHtcclxuICAgICAgICBpZiAoZXZlbnQua2V5Q29kZSA9PT0gMzIpIHtcclxuICAgICAgICAgICAgLy8gZG8gbm90IHByb3BhZ2F0ZSBzcGFjZXMgdG8gTWF0U2VsZWN0LCBhcyB0aGlzIHdvdWxkIHNlbGVjdCB0aGUgY3VycmVudGx5IGFjdGl2ZSBvcHRpb25cclxuICAgICAgICAgICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgIH1cclxuXHJcblxyXG4gICAgd3JpdGVWYWx1ZSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICAgICAgY29uc3QgdmFsdWVDaGFuZ2VkID0gdmFsdWUgIT09IHRoaXMuX3ZhbHVlO1xyXG4gICAgICAgIGlmICh2YWx1ZUNoYW5nZWQpIHtcclxuICAgICAgICAgICAgdGhpcy5fdmFsdWUgPSB2YWx1ZTtcclxuICAgICAgICAgICAgdGhpcy5jaGFuZ2UuZW1pdCh7IHR5cGU6ICdUZXh0JywgdmFsOiB2YWx1ZSB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgb25JbnB1dENoYW5nZSh2YWx1ZSkge1xyXG4gICAgICAgIGNvbnN0IHZhbHVlQ2hhbmdlZCA9IHZhbHVlICE9PSB0aGlzLl92YWx1ZTtcclxuICAgICAgICBpZiAodmFsdWVDaGFuZ2VkKSB7XHJcbiAgICAgICAgICAgIHRoaXMuX3ZhbHVlID0gdmFsdWU7XHJcbiAgICAgICAgICAgIHRoaXMub25DaGFuZ2UoeyB0eXBlOiAnVGV4dCcsIHZhbDogdmFsdWUgfSk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhbmdlLmVtaXQoeyB0eXBlOiAnVGV4dCcsIHZhbDogdmFsdWUgfSk7XHJcbiAgICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIG9uQmx1cih2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICAgICAgdGhpcy53cml0ZVZhbHVlKHZhbHVlKTtcclxuICAgICAgICB0aGlzLm9uVG91Y2hlZCgpO1xyXG4gICAgfVxyXG5cclxuICAgIHJlZ2lzdGVyT25DaGFuZ2UoZm46IEZ1bmN0aW9uKSB7XHJcbiAgICAgICAgdGhpcy5vbkNoYW5nZSA9IGZuO1xyXG4gICAgfVxyXG5cclxuICAgIHJlZ2lzdGVyT25Ub3VjaGVkKGZuOiBGdW5jdGlvbikge1xyXG4gICAgICAgIHRoaXMub25Ub3VjaGVkID0gZm47XHJcbiAgICB9XHJcblxyXG4gICBcclxuICAgIHB1YmxpYyBfZm9jdXMoKSB7XHJcbiAgICAgICAgaWYgKCF0aGlzLnNlYXJjaFNlbGVjdElucHV0IHx8ICF0aGlzLm1hdFNlbGVjdC5wYW5lbCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIHNhdmUgYW5kIHJlc3RvcmUgc2Nyb2xsVG9wIG9mIHBhbmVsLCBzaW5jZSBpdCB3aWxsIGJlIHJlc2V0IGJ5IGZvY3VzKClcclxuICAgICAgICAvLyBub3RlOiB0aGlzIGlzIGhhY2t5XHJcbiAgICAgICAgY29uc3QgcGFuZWwgPSB0aGlzLm1hdFNlbGVjdC5wYW5lbC5uYXRpdmVFbGVtZW50O1xyXG4gICAgICAgIGNvbnN0IHNjcm9sbFRvcCA9IHBhbmVsLnNjcm9sbFRvcDtcclxuXHJcbiAgICAgICAgLy8gZm9jdXNcclxuICAgICAgICB0aGlzLnNlYXJjaFNlbGVjdElucHV0Lm5hdGl2ZUVsZW1lbnQuZm9jdXMoKTtcclxuXHJcbiAgICAgICAgcGFuZWwuc2Nyb2xsVG9wID0gc2Nyb2xsVG9wO1xyXG4gICAgfVxyXG5cclxuICAgIC8qKlxyXG4gICAgICogUmVzZXRzIHRoZSBjdXJyZW50IHNlYXJjaCB2YWx1ZVxyXG4gICAgICoge2Jvb2xlYW59IGZvY3VzIHdoZXRoZXIgdG8gZm9jdXMgYWZ0ZXIgcmVzZXR0aW5nXHJcbiAgICAgKiBcclxuICAgICAqL1xyXG4gICAgcHVibGljIF9yZXNldChmb2N1cz86IGJvb2xlYW4pIHtcclxuICAgICAgICBpZiAoIXRoaXMuc2VhcmNoU2VsZWN0SW5wdXQpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnNlYXJjaFNlbGVjdElucHV0Lm5hdGl2ZUVsZW1lbnQudmFsdWUgPSAnJztcclxuICAgICAgICB0aGlzLm9uSW5wdXRDaGFuZ2UoJycpO1xyXG4gICAgICAgIGlmIChmb2N1cykge1xyXG4gICAgICAgICAgICB0aGlzLl9mb2N1cygpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIFNldHMgdGhlIG92ZXJsYXkgY2xhc3MgIHRvIGNvcnJlY3Qgb2Zmc2V0WVxyXG4gICAgICogc28gdGhhdCB0aGUgc2VsZWN0ZWQgb3B0aW9uIGlzIGF0IHRoZSBwb3NpdGlvbiBvZiB0aGUgc2VsZWN0IGJveCB3aGVuIG9wZW5pbmdcclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBzZXRPdmVybGF5Q2xhc3MoKSB7XHJcbiAgICAgICAgaWYgKHRoaXMub3ZlcmxheUNsYXNzU2V0KSB7XHJcbiAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgICAgY29uc3Qgb3ZlcmxheUNsYXNzZXM6IHN0cmluZ1tdID0gWydjZGstb3ZlcmxheS1wYW5lLXNlbGVjdC1zZWFyY2gnXTtcclxuXHJcbiAgICAgICAgaWYgKCF0aGlzLm1hdE9wdGlvbikge1xyXG4gICAgICAgICAgICAvLyBhZGQgb2Zmc2V0IHRvIHBhbmVsIGlmIGNvbXBvbmVudCBpcyBub3QgcGxhY2VkIGluc2lkZSBtYXQtb3B0aW9uXHJcbiAgICAgICAgICAgIG92ZXJsYXlDbGFzc2VzLnB1c2goJ2Nkay1vdmVybGF5LXBhbmUtc2VsZWN0LXNlYXJjaC13aXRoLW9mZnNldCcpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdGhpcy5tYXRTZWxlY3Qub3ZlcmxheURpci5hdHRhY2hcclxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuX29uRGVzdHJveSkpXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKCkgPT4ge1xyXG4gICAgICAgICAgICAgICAgLy8gbm90ZTogdGhpcyBpcyBoYWNreSwgYnV0IGN1cnJlbnRseSB0aGVyZSBpcyBubyBiZXR0ZXIgd2F5IHRvIGRvIHRoaXNcclxuXHJcbiAgICAgICAgICAgICAgICBsZXQgZWxlbWVudDogSFRNTEVsZW1lbnQ7XHJcbiAgICAgICAgICAgICAgICBsZXQgb3ZlcmxheUVsZW1lbnQ6IEhUTUxFbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc2VhcmNoU2VsZWN0SW5wdXQpIHtcclxuICAgICAgICAgICAgICAgICAgICBlbGVtZW50ID0gdGhpcy5zZWFyY2hTZWxlY3RJbnB1dC5uYXRpdmVFbGVtZW50O1xyXG4gICAgICAgICAgICAgICAgICAgIHdoaWxlIChlbGVtZW50ID0gZWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChlbGVtZW50LmNsYXNzTGlzdC5jb250YWlucygnY2RrLW92ZXJsYXktcGFuZScpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvdmVybGF5RWxlbWVudCA9IGVsZW1lbnQ7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGlmIChvdmVybGF5RWxlbWVudCkge1xyXG4gICAgICAgICAgICAgICAgICAgIG92ZXJsYXlDbGFzc2VzLmZvckVhY2gob3ZlcmxheUNsYXNzID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgb3ZlcmxheUVsZW1lbnQuY2xhc3NMaXN0LmFkZChvdmVybGF5Q2xhc3MpO1xyXG4gICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgdGhpcy5vdmVybGF5Q2xhc3NTZXQgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuXHJcbiAgICAvKipcclxuICAgICAqIEluaXRpYWxpemVzIGhhbmRsaW5nIDxtYXQtc2VsZWN0IFttdWx0aXBsZV09XCJ0cnVlXCI+XHJcbiAgICAgKiBOb3RlOiB0byBpbXByb3ZlIHRoaXMgY29kZSwgbWF0LXNlbGVjdCBzaG91bGQgYmUgZXh0ZW5kZWQgdG8gYWxsb3cgZGlzYWJsaW5nIHJlc2V0dGluZyB0aGUgc2VsZWN0aW9uIHdoaWxlIGZpbHRlcmluZy5cclxuICAgICAqL1xyXG4gICAgcHJpdmF0ZSBpbml0TXVsdGlwbGVIYW5kbGluZygpIHtcclxuICAgICAgICAvLyBpZiA8bWF0LXNlbGVjdCBbbXVsdGlwbGVdPVwidHJ1ZVwiPlxyXG4gICAgICAgIC8vIHN0b3JlIHByZXZpb3VzbHkgc2VsZWN0ZWQgdmFsdWVzIGFuZCByZXN0b3JlIHRoZW0gd2hlbiB0aGV5IGFyZSBkZXNlbGVjdGVkXHJcbiAgICAgICAgLy8gYmVjYXVzZSB0aGUgb3B0aW9uIGlzIG5vdCBhdmFpbGFibGUgd2hpbGUgd2UgYXJlIGN1cnJlbnRseSBmaWx0ZXJpbmdcclxuICAgICAgICB0aGlzLm1hdFNlbGVjdC52YWx1ZUNoYW5nZVxyXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5fb25EZXN0cm95KSlcclxuICAgICAgICAgICAgLnN1YnNjcmliZSgodmFsdWVzKSA9PiB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5tYXRTZWxlY3QubXVsdGlwbGUpIHtcclxuICAgICAgICAgICAgICAgICAgICBsZXQgcmVzdG9yZVNlbGVjdGVkVmFsdWVzID0gZmFsc2U7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuX3ZhbHVlICYmIHRoaXMuX3ZhbHVlLmxlbmd0aFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAmJiB0aGlzLnByZXZpb3VzU2VsZWN0ZWRWYWx1ZXMgJiYgQXJyYXkuaXNBcnJheSh0aGlzLnByZXZpb3VzU2VsZWN0ZWRWYWx1ZXMpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghdmFsdWVzIHx8ICFBcnJheS5pc0FycmF5KHZhbHVlcykpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IFtdO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG9wdGlvblZhbHVlcyA9IHRoaXMubWF0U2VsZWN0Lm9wdGlvbnMubWFwKG9wdGlvbiA9PiBvcHRpb24udmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnByZXZpb3VzU2VsZWN0ZWRWYWx1ZXMuZm9yRWFjaChwcmV2aW91c1ZhbHVlID0+IHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2YWx1ZXMuaW5kZXhPZihwcmV2aW91c1ZhbHVlKSA9PT0gLTEgJiYgb3B0aW9uVmFsdWVzLmluZGV4T2YocHJldmlvdXNWYWx1ZSkgPT09IC0xKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaWYgYSB2YWx1ZSB0aGF0IHdhcyBzZWxlY3RlZCBiZWZvcmUgaXMgZGVzZWxlY3RlZCBhbmQgbm90IGZvdW5kIGluIHRoZSBvcHRpb25zLCBpdCB3YXMgZGVzZWxlY3RlZFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGR1ZSB0byB0aGUgZmlsdGVyaW5nLCBzbyB3ZSByZXN0b3JlIGl0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlcy5wdXNoKHByZXZpb3VzVmFsdWUpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3RvcmVTZWxlY3RlZFZhbHVlcyA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlc3RvcmVTZWxlY3RlZFZhbHVlcykge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLm1hdFNlbGVjdC5fb25DaGFuZ2UodmFsdWVzKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMucHJldmlvdXNTZWxlY3RlZFZhbHVlcyA9IHZhbHVlcztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJpdmF0ZSBnZXRXaWR0aCgpIHtcclxuICAgICAgICBpZiAoIXRoaXMuaW5uZXJTZWxlY3RTZWFyY2ggfHwgIXRoaXMuaW5uZXJTZWxlY3RTZWFyY2gubmF0aXZlRWxlbWVudCkge1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGxldCBlbGVtZW50OiBIVE1MRWxlbWVudCA9IHRoaXMuaW5uZXJTZWxlY3RTZWFyY2gubmF0aXZlRWxlbWVudDtcclxuICAgICAgICBsZXQgcGFuZWxFbGVtZW50OiBIVE1MRWxlbWVudDtcclxuICAgICAgICB3aGlsZSAoZWxlbWVudCA9IGVsZW1lbnQucGFyZW50RWxlbWVudCkge1xyXG4gICAgICAgICAgICBpZiAoZWxlbWVudC5jbGFzc0xpc3QuY29udGFpbnMoJ21hdC1zZWxlY3QtcGFuZWwnKSkge1xyXG4gICAgICAgICAgICAgICAgcGFuZWxFbGVtZW50ID0gZWxlbWVudDtcclxuICAgICAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChwYW5lbEVsZW1lbnQpIHtcclxuICAgICAgICAgICAgdGhpcy5pbm5lclNlbGVjdFNlYXJjaC5uYXRpdmVFbGVtZW50LnN0eWxlLndpZHRoID0gcGFuZWxFbGVtZW50LmNsaWVudFdpZHRoICsgJ3B4JztcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vLy9pbm5lclNlbGVjdGFsbFxyXG4gICAgICAgIC8vaWYgKCF0aGlzLmlubmVyU2VsZWN0YWxsIHx8ICF0aGlzLmlubmVyU2VsZWN0YWxsLm5hdGl2ZUVsZW1lbnQpIHtcclxuICAgICAgICAvLyAgICByZXR1cm47XHJcbiAgICAgICAgLy99XHJcbiAgICAgICAgLy9sZXQgU2VsZWN0YWxsZWxlbWVudDogSFRNTEVsZW1lbnQgPSB0aGlzLmlubmVyU2VsZWN0YWxsLm5hdGl2ZUVsZW1lbnQ7XHJcbiAgICAgICAgLy9sZXQgU2VsZWN0YWxscGFuZWxFbGVtZW50OiBIVE1MRWxlbWVudDtcclxuICAgICAgICAvL3doaWxlIChTZWxlY3RhbGxlbGVtZW50ID0gU2VsZWN0YWxsZWxlbWVudC5wYXJlbnRFbGVtZW50KSB7XHJcbiAgICAgICAgLy8gICAgaWYgKFNlbGVjdGFsbGVsZW1lbnQuY2xhc3NMaXN0LmNvbnRhaW5zKCdtYXQtc2VsZWN0LXBhbmVsJykpIHtcclxuICAgICAgICAvLyAgICAgICAgU2VsZWN0YWxscGFuZWxFbGVtZW50ID0gU2VsZWN0YWxsZWxlbWVudDtcclxuICAgICAgICAvLyAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgLy8gICAgfVxyXG4gICAgICAgIC8vfVxyXG4gICAgICAgIC8vaWYgKFNlbGVjdGFsbHBhbmVsRWxlbWVudCkge1xyXG4gICAgICAgIC8vICAgIHRoaXMuaW5uZXJTZWxlY3RhbGwubmF0aXZlRWxlbWVudC5zdHlsZS53aWR0aCA9IFNlbGVjdGFsbHBhbmVsRWxlbWVudC5jbGllbnRXaWR0aCArICdweCc7XHJcbiAgICAgICAgLy99XHJcbiAgICB9XHJcblxyXG4gICAgcHVibGljIF9ub0VudHJpZXNGb3VuZCgpOiBib29sZWFuIHtcclxuICAgICAgICBpZiAoIXRoaXMuX29wdGlvbnMpIHtcclxuICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodGhpcy5tYXRPcHRpb24pIHtcclxuICAgICAgICAgICAgcmV0dXJuIHRoaXMubm9FbnRyaWVzRm91bmRMYWJlbCAmJiB0aGlzLnZhbHVlICYmIHRoaXMuX29wdGlvbnMubGVuZ3RoID09PSAxO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzLm5vRW50cmllc0ZvdW5kTGFiZWwgJiYgdGhpcy52YWx1ZSAmJiB0aGlzLl9vcHRpb25zLmxlbmd0aCA9PT0gMDtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbiAgICB0b2dnbGVTZWxlY3Rpb24oY2hhbmdlOiBNYXRDaGVja2JveENoYW5nZSwgY2hlY2spOiB2b2lkIHtcclxuICAgICAgICBpZiAoY2hhbmdlLmNoZWNrZWQpIHtcclxuICAgICAgICAgICAgLy90aGlzLm1vZGVsLnVwZGF0ZS5lbWl0KHRoaXMudmFsdWVzKTtcclxuICAgICAgICAgICAgdGhpcy5vbkNoYW5nZSh7IHR5cGU6ICdDaGVjaycsIHZhbDogY2hhbmdlLmNoZWNrZWQgfSk7XHJcbiAgICAgICAgICAgIHRoaXMuY2hhbmdlLmVtaXQoeyB0eXBlOiAnQ2hlY2snLCB2YWw6IGNoYW5nZS5jaGVja2VkIH0pO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRoaXMub25DaGFuZ2UoeyB0eXBlOiAnQ2hlY2snLCB2YWw6IGNoYW5nZS5jaGVja2VkIH0pO1xyXG4gICAgICAgICAgICB0aGlzLmNoYW5nZS5lbWl0KHsgdHlwZTogJ0NoZWNrJywgdmFsOiBjaGFuZ2UuY2hlY2tlZCB9KTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaXNjaGVja2VkKGNoZWNrKTogYm9vbGVhbiB7XHJcbiAgICAgICAgY29uc29sZS5sb2codGhpcy5tYXRTZWxlY3Qub3B0aW9ucywgdGhpcy5tYXRTZWxlY3QudmFsdWUpO1xyXG4gICAgICAgIGxldCBzZWxlY3RlZDogYW55ID0gdGhpcy5tYXRTZWxlY3Quc2VsZWN0ZWQ7XHJcbiAgICAgICAgcmV0dXJuIHRoaXMubWF0U2VsZWN0Lm9wdGlvbnMgJiYgc2VsZWN0ZWQgJiYgc2VsZWN0ZWQubGVuZ3RoID4gMCAmJiB0aGlzLm1hdFNlbGVjdC5vcHRpb25zLmxlbmd0aCA9PSBzZWxlY3RlZC5sZW5ndGg7XHJcbiAgICB9XHJcbiAgICBpc0luZGV0ZXJtaW5hdGUoKTogYm9vbGVhbiB7XHJcbiAgICAgICAgbGV0IHNlbGVjdGVkOiBhbnkgPSB0aGlzLm1hdFNlbGVjdC5zZWxlY3RlZDtcclxuICAgICAgICByZXR1cm4gdGhpcy5tYXRTZWxlY3Qub3B0aW9ucyAmJiBzZWxlY3RlZC5sZW5ndGggPiAwICYmIHNlbGVjdGVkLmxlbmd0aCA8IHRoaXMubWF0U2VsZWN0Lm9wdGlvbnMubGVuZ3RoO1xyXG4gICAgfVxyXG59XHJcbiJdfQ==