UNPKG

ngx-multi-selector

Version:

A small plugin which generates multi-selector control, it supports web api loading. Only supported angular 5.

564 lines 63.6 kB
import * as tslib_1 from "tslib"; var NgxMultiSelectorComponent_1; import { Component, ElementRef, Input, ViewChild, TemplateRef, forwardRef } from '@angular/core'; import { NG_VALUE_ACCESSOR } from '@angular/forms'; import { EMPTY, of, ReplaySubject, timer } from 'rxjs'; import { debounce, distinctUntilChanged, map, switchMap } from 'rxjs/operators'; let NgxMultiSelectorComponent = NgxMultiSelectorComponent_1 = class NgxMultiSelectorComponent { //#endregion //#region Constructor /* * Initiate components with injectors (as available) * */ constructor() { //#region Properties /* * Delay time between 2 item search requests. * */ this._defaultItemsInterval = 150; /* * Character which is used for separating selected items. * Default: , * */ this._separationCharacter = ','; /* * Maximum items that can be displayed in context menu. * */ this._maximumContextItems = 0; /* * How many items can be selected. * */ this._maximumSelectableItems = 0; /* * How much time should component raise another one about its changes. * */ this._loadItemsInterval = this._defaultItemsInterval; this._selectedItems = []; this.items = []; // By default, items amount is limited to 10. this._maximumSelectableItems = 10; this._updateAvailableItemsSubject = new ReplaySubject(1); this._updateAvailableItemsSubscription = this._updateAvailableItemsSubject .pipe(debounce((command) => { if (command.shouldIgnoreInterval) { return EMPTY; } return timer(this._loadItemsInterval); }), map((command) => { // Format keyword. let keyword = this._keyword; if (keyword && keyword.length) { keyword = keyword.trim(); } return { keyword, command }; }), distinctUntilChanged((previous, next) => { // Get current command. const nextCommand = next.command; if (!nextCommand.shouldIgnoreDuplicate) { // Values are equal, it will not emit the current value return previous.keyword === next.keyword; } // Values are different, so it will emit return false; }), switchMap((model) => { return this.loadAvailableItemsAsync(model.keyword); })) .subscribe(availableItems => { this._availableItems = [...availableItems]; }); } //#endregion //#region Accessors /* * Keyword is used for searching for items. * */ get keyword() { return this._keyword; } /* * Keyword is used for searching for items. * */ set keyword(value) { this._keyword = value; // Initialize control update command. const command = { shouldIgnoreDuplicate: false, shouldIgnoreInterval: false }; this._updateAvailableItemsSubject .next(command); } /* * Character which is used for dividing searched items. * */ set separationCharacter(value) { if (!value || !value.length) { this._separationCharacter = ','; return; } this._separationCharacter = value; } /* * Items which have been selected. * */ get selectedItems() { return this._selectedItems; } /* * Get selected items. * */ set selectedItems(values) { if (!values || values.length < 0) { this._selectedItems = []; return; } this._selectedItems = values; } /* * How much time should component raise another one about its changes. * */ set interval(value) { if (value < this._defaultItemsInterval) { this._loadItemsInterval = this._defaultItemsInterval; return; } this._loadItemsInterval = value; } /* * List of item which should be displayed on drop-down menu. * */ set items(values) { if (this.loadAvailableItemsAsyncHandler && this._updateAvailableItemsSubject) { this._updateAvailableItemsSubject.next(null); return; } if (!values || !values.length || !(values instanceof Array)) { this._originalItems = []; this._availableItems = []; return; } this._originalItems = values; this._availableItems = values; } /* * Get available items for displaying in drop-down list. * */ get items() { return this._availableItems; } /* * Get the maximum items that can be displayed in context menu. * */ get maximumContextItem() { return this._maximumContextItems; } /* * How many items should be shown to be selected. * */ set maximumContextItems(maximumItems) { if (maximumItems < 0) { maximumItems = 0; } this._maximumContextItems = maximumItems; } /* * Get maximum selectable items. * */ get maximumSelectableItems() { return this._maximumSelectableItems; } /* * Update the maximum selectable items. * */ set maximumSelectableItems(value) { if (value < 0 || isNaN(value)) { this._maximumSelectableItems = 0; return; } this._maximumSelectableItems = value; } /* * @deprecated * Please consider using key-property instead. * Key which is for recognizing whether item is in the chosen list or not. * */ set key(value) { this._key = value; } /* * Please consider using key-property instead. * Key which is for recognizing whether item is in the chosen list or not. * */ set keyProperty(value) { this._key = value; } /* * Which property should be used as display. * Null is about using object as display. * */ set displayProperty(value) { this._displayProperty = value; } /* * Which property should be used as selected value. * Null is about using object as selected value. * */ set valueProperty(value) { this._valueProperty = value; } //#endregion //#region Methods ngOnDestroy() { if (this._updateAvailableItemsSubscription && !this._updateAvailableItemsSubscription.closed) { this._updateAvailableItemsSubscription.unsubscribe(); } } /* * Check whether item has been chosen or not. * */ hasItemSelected(item) { return this.loadSelectedItemIndex(item) != -1; } /* * Find chosen item index in array. * */ loadSelectedItemIndex(item) { // Items list is empty. if (this._selectedItems == null || this._selectedItems.length < 1) { return -1; } // Get item index. const itemIndex = this._selectedItems.findIndex(selectedItem => this.loadItemUniqueValue(selectedItem) === this.loadItemUniqueValue(item)); return itemIndex; } /* * Get title which is used for being displayed on search box. * */ loadSelectedItemsTitle() { if (this.selectedItems == null || this.selectedItems.length < 1) { return ''; } // Find separation character. let separationCharacter = this._separationCharacter; if (!separationCharacter) { separationCharacter = ','; } return this.selectedItems .map(selectedItem => this.loadItemDisplay(selectedItem)) .join(separationCharacter) .slice(0, 255); } /* * Clear chosen items list. * */ deleteSelectedItems(shouldRaiseOnChangeCallback) { // Initiate new array. this.selectedItems = new Array(); if (shouldRaiseOnChangeCallback) { this.ngOnChangeCallback(this.selectedItems); } } /* * Find selected value and delete it. * */ deleteSelectedValue(value) { // Get index of value. if (!this.selectedItems || !this.selectedItems.length) { return; } const itemIndex = this.selectedItems.findIndex(selectedItem => this.loadItemValue(selectedItem) == value); if (itemIndex < 0) { return; } // Remove item from list. const selectedValues = [...this.selectedItems]; selectedValues.splice(itemIndex, 1); if (!selectedValues || !selectedValues.length) { this.selectedItems = null; this.ngOnChangeCallback(null); } else { this.selectedItems = selectedValues; this.ngOnChangeCallback(this.selectedItems.map(selectedItem => this.loadItemValue(selectedItem))); } } /* * Select an item in list. * */ clickSelectItem(item) { // Enlist of selected items. let selectedItems; if (!this.selectedItems) { selectedItems = []; } else { selectedItems = [...this.selectedItems]; } // Get item in the selected value. const itemIndex = this.loadSelectedItemIndex(item); // Item hasn't been chosen. if (itemIndex == null || itemIndex < 0) { // Maximum selected item exceeded. if (this.maximumSelectableItems != null && (this.maximumSelectableItems > 0 && selectedItems.length >= this.maximumSelectableItems)) { return; } // Get item value. selectedItems.push(item); this.selectedItems = selectedItems; this.ngOnChangeCallback(selectedItems.map(selectedItem => this.loadItemValue(selectedItem))); return; } selectedItems.splice(itemIndex, 1); if (!selectedItems || !selectedItems.length) { this.selectedItems = null; this.ngOnChangeCallback(this.selectedItems); } else { this.selectedItems = selectedItems; this.ngOnChangeCallback(this.selectedItems); } } /* * Close drop-down menu. * */ close() { // Drop-down menu is invalid. if (this.multiSelectorDropDown == null) { return; } // Find drop-down native element. const nativeElement = this.multiSelectorDropDown.nativeElement; if (nativeElement == null) { return; } // Remove class .open from classes list. nativeElement.classList.remove('open'); } /* * Open drop-down menu. * */ open() { // Component has been disabled. if (this.disabled) { return; } // Drop-down menu is invalid. if (this.multiSelectorDropDown == null) { return; } // Find drop-down native element. const nativeElement = this.multiSelectorDropDown.nativeElement; if (nativeElement == null) { return; } // Remove class .open from classes list. this.multiSelectorDropDown.nativeElement.classList.add('open'); } /* * Callback which is fired when component receives information from external source. * */ writeValue(selectedValues) { // No value has been selected. if (!selectedValues || !selectedValues.length) { this.selectedItems = null; return; } this.selectedItems = selectedValues; } /* * Callback which is fired when on-change register has been initiated. * */ registerOnChange(fn) { this.ngOnChangeCallback = fn; } /* * Callback which is fired when on-touch register has been initiated. * */ registerOnTouched(fn) { this.ngOnTouchedCallback = fn; } /* * Set item to be disabled | enabled. * */ setDisabledState(isDisabled) { this.disabled = isDisabled; } /* * Load available items asynchronously. * This function will be used in offline mode. * */ loadAvailableItemsAsync(keyword) { // Make the keyword to be upper cased. const upperCasedKeyword = (keyword == null) ? null : keyword.toUpperCase(); // Get the handler. const loadAvailableItemsAsyncHandler = this.loadAvailableItemsAsyncHandler; // No handler is defined for remote data loading. if (!loadAvailableItemsAsyncHandler) { // Load available items locally. return of([...this._originalItems]) .pipe(map((items) => { if (!items || !items.length) { return []; } return items .filter(item => { // Get the display property. const itemDisplay = this.loadItemDisplay(item); if (!upperCasedKeyword) { return items; } return itemDisplay.toString().toUpperCase().indexOf(upperCasedKeyword) !== -1; }); })); } // Load available items remotely. return this.loadAvailableItemsAsyncHandler(keyword); } /* * Load item display. * */ loadItemDisplay(item) { // Get the display property. const displayProperty = this._displayProperty; if (!displayProperty || !displayProperty.length) { return item.toString(); } return item[displayProperty]; } /* * Load item value. * */ loadItemValue(item) { // Get defined key. const valueProperty = this._valueProperty; if (!valueProperty || !valueProperty.length) { return item; } return item[valueProperty]; } /* * Base on key to get item unique value. * */ loadItemUniqueValue(item) { if (!item) { return item; } // Get key. const key = this._key; if (!key || key.length < 1) { return item; } return item[key]; } ngOnInit() { if (!this.loadAvailableItemsAsyncHandler) { return; } if (!this._updateAvailableItemsSubject) { return; } const updateControlCommand = { shouldIgnoreDuplicate: true, shouldIgnoreInterval: true }; return this._updateAvailableItemsSubject.next(updateControlCommand); } }; tslib_1.__decorate([ Input('load-available-items-handler'), tslib_1.__metadata("design:type", Function) ], NgxMultiSelectorComponent.prototype, "loadAvailableItemsAsyncHandler", void 0); tslib_1.__decorate([ ViewChild('multiSelectorDropdownMenu', { static: false }), tslib_1.__metadata("design:type", ElementRef) ], NgxMultiSelectorComponent.prototype, "multiSelectorDropDown", void 0); tslib_1.__decorate([ Input('is-clear-button-available'), tslib_1.__metadata("design:type", Boolean) ], NgxMultiSelectorComponent.prototype, "shouldClearButtonAvailable", void 0); tslib_1.__decorate([ Input('is-search-box-available'), tslib_1.__metadata("design:type", Boolean) ], NgxMultiSelectorComponent.prototype, "shouldSearchBoxAvailable", void 0); tslib_1.__decorate([ Input('placeholder-search-drop-down'), tslib_1.__metadata("design:type", String) ], NgxMultiSelectorComponent.prototype, "placeholderSearchDropDown", void 0); tslib_1.__decorate([ Input('placeholder-title-drop-down'), tslib_1.__metadata("design:type", String) ], NgxMultiSelectorComponent.prototype, "placeholderTitleDropDown", void 0); tslib_1.__decorate([ Input('disabled'), tslib_1.__metadata("design:type", Boolean) ], NgxMultiSelectorComponent.prototype, "disabled", void 0); tslib_1.__decorate([ Input('item-template'), tslib_1.__metadata("design:type", TemplateRef) ], NgxMultiSelectorComponent.prototype, "itemTemplate", void 0); tslib_1.__decorate([ Input('separation-character'), tslib_1.__metadata("design:type", String), tslib_1.__metadata("design:paramtypes", [String]) ], NgxMultiSelectorComponent.prototype, "separationCharacter", null); tslib_1.__decorate([ Input('interval'), tslib_1.__metadata("design:type", Number), tslib_1.__metadata("design:paramtypes", [Number]) ], NgxMultiSelectorComponent.prototype, "interval", null); tslib_1.__decorate([ Input('items'), tslib_1.__metadata("design:type", Array), tslib_1.__metadata("design:paramtypes", [Array]) ], NgxMultiSelectorComponent.prototype, "items", null); tslib_1.__decorate([ Input('limit-item-amount'), tslib_1.__metadata("design:type", Number), tslib_1.__metadata("design:paramtypes", [Number]) ], NgxMultiSelectorComponent.prototype, "maximumContextItems", null); tslib_1.__decorate([ Input('limit-item-selection'), tslib_1.__metadata("design:type", Number), tslib_1.__metadata("design:paramtypes", [Number]) ], NgxMultiSelectorComponent.prototype, "maximumSelectableItems", null); tslib_1.__decorate([ Input('key'), tslib_1.__metadata("design:type", String), tslib_1.__metadata("design:paramtypes", [String]) ], NgxMultiSelectorComponent.prototype, "key", null); tslib_1.__decorate([ Input('key-property'), tslib_1.__metadata("design:type", String), tslib_1.__metadata("design:paramtypes", [String]) ], NgxMultiSelectorComponent.prototype, "keyProperty", null); tslib_1.__decorate([ Input('display-property'), tslib_1.__metadata("design:type", String), tslib_1.__metadata("design:paramtypes", [String]) ], NgxMultiSelectorComponent.prototype, "displayProperty", null); tslib_1.__decorate([ Input('value-property'), tslib_1.__metadata("design:type", String), tslib_1.__metadata("design:paramtypes", [String]) ], NgxMultiSelectorComponent.prototype, "valueProperty", null); NgxMultiSelectorComponent = NgxMultiSelectorComponent_1 = tslib_1.__decorate([ Component({ selector: 'ngx-multi-selector', exportAs: 'ngx-multi-selector', template: "<div class=\"dropdown\">\r\n\r\n <!--Text input-->\r\n <div #multiSelectorDropdownMenu\r\n class=\"input-group ngx-multi-selector\">\r\n <div class=\"dropdown-toggle\"\r\n [attr.data-toggle]=\"disabled ? '': 'dropdown'\"\r\n aria-haspopup=\"true\"\r\n aria-expanded=\"false\"\r\n [attr.disabled]=\"disabled\">\r\n <input class=\"form-control ngx-multi-selector-title-box\"\r\n [class.disabled]=\"disabled\"\r\n [placeholder]=\"!placeholderTitleDropDown ? '' : placeholderTitleDropDown\"\r\n readonly=\"readonly\"\r\n [value]=\"loadSelectedItemsTitle()\">\r\n </div>\r\n <span class=\"input-group-addon\"\r\n *ngIf=\"shouldClearButtonAvailable\"\r\n [class.disabled]=\"disabled\"\r\n (click)=\"deleteSelectedItems()\">\r\n <span class=\"glyphicon glyphicon-remove\"></span>\r\n </span>\r\n\r\n <!--Dropdown-->\r\n <span class=\"input-group-addon dropdown-toggle\"\r\n [attr.data-toggle]=\"disabled ? '': 'dropdown'\"\r\n [class.disabled]=\"disabled\"\r\n aria-haspopup=\"true\"\r\n aria-expanded=\"false\">\r\n <span class=\"caret\"></span>\r\n </span>\r\n\r\n <!--Dropdown menu-->\r\n <ul class=\"dropdown-menu\"\r\n (click)=\"$event.stopPropagation();\">\r\n <li *ngIf=\"shouldSearchBoxAvailable\">\r\n <div class=\"col-lg-12\">\r\n <div class=\"form-group\">\r\n <div class=\"input-group\">\r\n <input class=\"form-control\"\r\n [(ngModel)]=\"keyword\"\r\n [placeholder]=\"!placeholderSearchDropDown ? '' : placeholderSearchDropDown\">\r\n <span class=\"input-group-addon\">\r\n <span class=\"glyphicon glyphicon-search\"></span>\r\n </span>\r\n </div>\r\n </div>\r\n </div>\r\n </li>\r\n\r\n <ng-template ngFor\r\n let-item\r\n let-i=\"index\"\r\n [ngForOf]=\"items\">\r\n\r\n <ng-container *ngIf=\"maximumContextItem < 1 || (maximumContextItem > 0 && i < maximumContextItem)\">\r\n <!--Item template-->\r\n <ng-template [ngTemplateOutlet]=\"itemTemplate || defaultItemTemplate\"\r\n [ngTemplateOutletContext]=\"{item:item, index:i, selected: hasItemSelected(item), instance: this}\">\r\n </ng-template>\r\n </ng-container>\r\n\r\n </ng-template>\r\n </ul>\r\n </div>\r\n</div>\r\n\r\n<!--Default item template-->\r\n<ng-template #defaultItemTemplate\r\n let-item=\"item\"\r\n let-i=\"index\"\r\n let-selected=\"selected\"\r\n let-instance=\"instance\">\r\n\r\n <li [class.active]=\"hasItemSelected(item)\"\r\n (click)=\"instance.clickSelectItem(item)\">\r\n <a href=\"javascript:void(0);\">\r\n <span class=\"glyphicon glyphicon-check\"\r\n *ngIf=\"selected\"></span>\r\n {{loadItemDisplay(item)}}\r\n </a>\r\n </li>\r\n</ng-template>\r\n", providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => NgxMultiSelectorComponent_1), multi: true } ], styles: [".ngx-multi-selector .dropdown-menu{width:100%}.ngx-multi-selector input.ngx-multi-selector-title-box{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;background-color:#fff!important;cursor:default}.ngx-multi-selector .input-group-addon.disabled,.ngx-multi-selector .input-group-addon:disabled,.ngx-multi-selector input.ngx-multi-selector-title-box.disabled,.ngx-multi-selector input.ngx-multi-selector-title-box:disabled{background-color:#eee!important;cursor:not-allowed;pointer-events:none}"] }), tslib_1.__metadata("design:paramtypes", []) ], NgxMultiSelectorComponent); export { NgxMultiSelectorComponent }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW11bHRpLXNlbGVjdG9yLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiJuZzovL25neC1tdWx0aS1zZWxlY3Rvci8iLCJzb3VyY2VzIjpbImxpYi9uZ3gtbXVsdGktc2VsZWN0b3IuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxVQUFVLEVBQ1YsS0FBSyxFQUNMLFNBQVMsRUFDVCxXQUFXLEVBQUUsVUFBVSxFQUN4QixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQXVCLGlCQUFpQixFQUFDLE1BQU0sZ0JBQWdCLENBQUM7QUFDdkUsT0FBTyxFQUFrQixLQUFLLEVBQWMsRUFBRSxFQUFFLGFBQWEsRUFBeUIsS0FBSyxFQUFDLE1BQU0sTUFBTSxDQUFDO0FBQ3pHLE9BQU8sRUFBQyxRQUFRLEVBQUUsb0JBQW9CLEVBQUUsR0FBRyxFQUFFLFNBQVMsRUFBQyxNQUFNLGdCQUFnQixDQUFBO0FBaUI3RSxJQUFhLHlCQUF5QixpQ0FBdEMsTUFBYSx5QkFBeUI7SUFzVHBDLFlBQVk7SUFFWixxQkFBcUI7SUFFckI7O1FBRUk7SUFDSjtRQTNUQSxvQkFBb0I7UUFFcEI7O1lBRUk7UUFDYSwwQkFBcUIsR0FBRyxHQUFHLENBQUM7UUFPN0M7OztZQUdJO1FBQ0kseUJBQW9CLEdBQUcsR0FBRyxDQUFDO1FBa0JuQzs7WUFFSTtRQUNJLHlCQUFvQixHQUFHLENBQUMsQ0FBQztRQUVqQzs7WUFFSTtRQUNJLDRCQUF1QixHQUFHLENBQUMsQ0FBQztRQW9GcEM7O1lBRUk7UUFDSSx1QkFBa0IsR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQUM7UUEyTHRELElBQUksQ0FBQyxjQUFjLEdBQUcsRUFBRSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBRWhCLDZDQUE2QztRQUM3QyxJQUFJLENBQUMsdUJBQXVCLEdBQUcsRUFBRSxDQUFDO1FBRWxDLElBQUksQ0FBQyw0QkFB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QUFRLEVBQUUsb0JBQW9CO1FBQzlCLFFBQVEsRUFBRSxvQkFBb0I7UUFDOUIsdWpHQUFnRDtRQUVoRCxTQUFTLEVBQUU7WUFDVDtnQkFDRSxPQUFPLEVBQUUsaUJBQWlCO2dCQUMxQixXQUFXLEVBQUUsVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLDJCQUF5QixDQUFDO2dCQUN4RCxLQUFLLEVBQUUsSUFBSTthQUNaO1NBQ0Y7O0tBQ0YsQ0FBQzs7R0FFVyx5QkFBeUIsQ0FxckJyQztTQXJyQlkseUJBQXlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgRWxlbWVudFJlZixcclxuICBJbnB1dCxcclxuICBWaWV3Q2hpbGQsXHJcbiAgVGVtcGxhdGVSZWYsIGZvcndhcmRSZWYsIE9uRGVzdHJveSwgT25Jbml0XHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7Q29udHJvbFZhbHVlQWNjZXNzb3IsIE5HX1ZBTFVFX0FDQ0VTU09SfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XHJcbmltcG9ydCB7QmVoYXZpb3JTdWJqZWN0LCBFTVBUWSwgT2JzZXJ2YWJsZSwgb2YsIFJlcGxheVN1YmplY3QsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiwgdGltZXJ9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQge2RlYm91bmNlLCBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgbWFwLCBzd2l0Y2hNYXB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJ1xyXG5pbXBvcnQge0lVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZH0gZnJvbSAnLi91cGRhdGUtbXVsdGktc2VsZWN0b3ItY29tbWFuZC5pbnRlcmZhY2UnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICduZ3gtbXVsdGktc2VsZWN0b3InLFxyXG4gIGV4cG9ydEFzOiAnbmd4LW11bHRpLXNlbGVjdG9yJyxcclxuICB0ZW1wbGF0ZVVybDogJ25neC1tdWx0aS1zZWxlY3Rvci5jb21wb25lbnQuaHRtbCcsXHJcbiAgc3R5bGVVcmxzOiBbJ25neC1tdWx0aS1zZWxlY3Rvci5jb21wb25lbnQuc2NzcyddLFxyXG4gIHByb3ZpZGVyczogW1xyXG4gICAge1xyXG4gICAgICBwcm92aWRlOiBOR19WQUxVRV9BQ0NFU1NPUixcclxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gTmd4TXVsdGlTZWxlY3RvckNvbXBvbmVudCksXHJcbiAgICAgIG11bHRpOiB0cnVlXHJcbiAgICB9XHJcbiAgXVxyXG59KVxyXG5cclxuZXhwb3J0IGNsYXNzIE5neE11bHRpU2VsZWN0b3JDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uRGVzdHJveSwgQ29udHJvbFZhbHVlQWNjZXNzb3Ige1xyXG5cclxuICAvLyNyZWdpb24gUHJvcGVydGllc1xyXG5cclxuICAvKlxyXG4gICogRGVsYXkgdGltZSBiZXR3ZWVuIDIgaXRlbSBzZWFyY2ggcmVxdWVzdHMuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgX2RlZmF1bHRJdGVtc0ludGVydmFsID0gMTUwO1xyXG5cclxuICAvKlxyXG4gICogTGlzdCBvZiBpdGVtcyB3aGljaCBoYXZlIGJlZW4gc2VsZWN0ZWQuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX3NlbGVjdGVkSXRlbXM6IEFycmF5PGFueT47XHJcblxyXG4gIC8qXHJcbiAgKiBDaGFyYWN0ZXIgd2hpY2ggaXMgdXNlZCBmb3Igc2VwYXJhdGluZyBzZWxlY3RlZCBpdGVtcy5cclxuICAqIERlZmF1bHQ6ICxcclxuICAqICovXHJcbiAgcHJpdmF0ZSBfc2VwYXJhdGlvbkNoYXJhY3RlciA9ICcsJztcclxuXHJcbiAgLypcclxuICAqIEtleXdvcmQgd2hpY2ggaXMgZm9yIHNlYXJjaGluZyBmb3IgYXZhaWxhYmxlIGl0ZW1zLlxyXG4gICogRGVmYXVsdDogbnVsbC5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfa2V5d29yZDogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogTGlzdCBvZiBpdGVtcyB0aGF0IG9yaWdpbmFsbHkgc2V0LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9vcmlnaW5hbEl0ZW1zOiBhbnlbXTtcclxuXHJcbiAgLypcclxuICAqIExpc3Qgb2YgaXRlbSB3aGljaCBzaG91bGQgYmUgZGlzcGxheWVkIG9uIGRyb3AtZG93biBtZW51LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9hdmFpbGFibGVJdGVtczogYW55W107XHJcblxyXG4gIC8qXHJcbiAgKiBNYXhpbXVtIGl0ZW1zIHRoYXQgY2FuIGJlIGRpc3BsYXllZCBpbiBjb250ZXh0IG1lbnUuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX21heGltdW1Db250ZXh0SXRlbXMgPSAwO1xyXG5cclxuICAvKlxyXG4gICogSG93IG1hbnkgaXRlbXMgY2FuIGJlIHNlbGVjdGVkLlxyXG4gICogKi9cclxuICBwcml2YXRlIF9tYXhpbXVtU2VsZWN0YWJsZUl0ZW1zID0gMDtcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGV0aGVyIGl0ZW0gaXMgc2VsZWN0ZWQgb3Igbm90LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9rZXk6IHN0cmluZztcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGF0IHByb3BlcnR5IHNob3VsZCBiZSB1c2VkIGZvciBkaXNwbGF5LlxyXG4gICogKi9cclxuICBwcml2YXRlIF9kaXNwbGF5UHJvcGVydHk6IHN0cmluZztcclxuXHJcbiAgLypcclxuICAqIFByb3BlcnR5IHdoaWNoIGlzIGZvciBkZXRlcm1pbmluZyB3aGF0IHByb3BlcnR5IHNob3VsZCBiZSB1c2VkIGFzIHNlbGVjdGVkIHZhbHVlLlxyXG4gICogKi9cclxuICBwcml2YXRlIF92YWx1ZVByb3BlcnR5OiBzdHJpbmc7XHJcblxyXG4gIC8qXHJcbiAgKiBIYW5kbGUgZm9yIGxvYWRpbmcgYXZhaWxhYmxlIGl0ZW1zIGFzeW5jaHJvbm91c2x5LlxyXG4gICogKi9cclxuICBASW5wdXQoJ2xvYWQtYXZhaWxhYmxlLWl0ZW1zLWhhbmRsZXInKVxyXG4gIHB1YmxpYyByZWFkb25seSBsb2FkQXZhaWxhYmxlSXRlbXNBc3luY0hhbmRsZXI6IChrZXl3b3JkOiBzdHJpbmcpID0+IE9ic2VydmFibGU8YW55W10+O1xyXG5cclxuICAvKlxyXG4gICogRW1pdCBhIGtleXdvcmQgZm9yIHVwZGF0aW5nIGF2YWlsYWJsZSBpdGVtcy5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfdXBkYXRlQXZhaWxhYmxlSXRlbXNTdWJqZWN0OiBTdWJqZWN0PElVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZD47XHJcblxyXG4gIC8qXHJcbiAgKiBTdWJzY3JpcHRpb24gYWJvdXQgY29udHJvbCB1cGRhdGUgbWFuYWdlbWVudC5cclxuICAqICovXHJcbiAgcHJpdmF0ZSBfdXBkYXRlQXZhaWxhYmxlSXRlbXNTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcclxuXHJcbiAgLypcclxuICAqIEluamVjdG9yIG9mIG11bHRpLXNlbGVjdG9yIGRyb3AtZG93biBtZW51LlxyXG4gICogKi9cclxuICBAVmlld0NoaWxkKCdtdWx0aVNlbGVjdG9yRHJvcGRvd25NZW51Jywge3N0YXRpYzogZmFsc2V9KVxyXG4gIHB1YmxpYyBtdWx0aVNlbGVjdG9yRHJvcERvd246IEVsZW1lbnRSZWY7XHJcblxyXG4gIC8qXHJcbiAgKiBXaGV0aGVyIGNsZWFyIGJ1dHRvbiBzaG91bGQgYmUgYXZhaWxhYmxlIG9yIG5vdC5cclxuICAqICovXHJcbiAgQElucHV0KCdpcy1jbGVhci1idXR0b24tYXZhaWxhYmxlJylcclxuICBwdWJsaWMgc2hvdWxkQ2xlYXJCdXR0b25BdmFpbGFibGU6IGJvb2xlYW47XHJcblxyXG4gIC8qXHJcbiAgKiBXaGV0aGVyIHNlYXJjaCBib3ggc2hvdWxkIGJlIGF2YWlsYWJsZSBvciBub3QuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgnaXMtc2VhcmNoLWJveC1hdmFpbGFibGUnKVxyXG4gIHB1YmxpYyBzaG91bGRTZWFyY2hCb3hBdmFpbGFibGU6IGJvb2xlYW47XHJcblxyXG4gIC8qXHJcbiAgKiBQbGFjZSBob2xkZXIgb2Ygc2VhcmNoIGJveCBpbiBkcm9wLWRvd24gbGlzdC5cclxuICAqICovXHJcbiAgQElucHV0KCdwbGFjZWhvbGRlci1zZWFyY2gtZHJvcC1kb3duJylcclxuICBwdWJsaWMgcGxhY2Vob2xkZXJTZWFyY2hEcm9wRG93bjogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogUGxhY2UgaG9sZGVyIG9mIHRpdGxlLlxyXG4gICogKi9cclxuICBASW5wdXQoJ3BsYWNlaG9sZGVyLXRpdGxlLWRyb3AtZG93bicpXHJcbiAgcHVibGljIHBsYWNlaG9sZGVyVGl0bGVEcm9wRG93bjogc3RyaW5nO1xyXG5cclxuICAvKlxyXG4gICogIFdoZXRoZXIgY29tcG9uZW50IGlzIGRpc2FibGVkIG9yIG5vdC5cclxuICAqICovXHJcbiAgQElucHV0KCdkaXNhYmxlZCcpXHJcbiAgcHVibGljIGRpc2FibGVkOiBib29sZWFuO1xyXG4gIC8qXHJcbiAgKiBDdXN0b20gaXRlbSB0ZW1wbGF0ZS5cclxuICAqICovXHJcbiAgQElucHV0KCdpdGVtLXRlbXBsYXRlJylcclxuICBwdWJsaWMgaXRlbVRlbXBsYXRlOiBUZW1wbGF0ZVJlZjxhbnk+O1xyXG5cclxuICAvKlxyXG4gICogQ2FsbGJhY2sgd2hpY2ggaXMgZm9yIHJhaXNpbmcgdG91Y2hlZCBldmVudCBmcm9tIHRoZSBjdXJyZW50IGNvbXBvbmVudC5cclxuICAqICovXHJcbiAgcHJvdGVjdGVkIG5nT25Ub3VjaGVkQ2FsbGJhY2s6ICgpID0+IHZvaWQ7XHJcblxyXG4gIC8qXHJcbiAgKiBDYWxsYmFjayB3aGljaCBpcyBmb3IgcmFpc2luZyBtb2RlbCBjaGFuZ2UgZXZlbnQgZnJvbSB0aGUgY3VycmVudCBjb21wb25lbnQuXHJcbiAgKiAqL1xyXG4gIHByb3RlY3RlZCBuZ09uQ2hhbmdlQ2FsbGJhY2s6IChfOiBhbnkpID0+IHZvaWQ7XHJcblxyXG4gIC8qXHJcbiAgKiBIb3cgbXVjaCB0aW1lIHNob3VsZCBjb21wb25lbnQgcmFpc2UgYW5vdGhlciBvbmUgYWJvdXQgaXRzIGNoYW5nZXMuXHJcbiAgKiAqL1xyXG4gIHByaXZhdGUgX2xvYWRJdGVtc0ludGVydmFsID0gdGhpcy5fZGVmYXVsdEl0ZW1zSW50ZXJ2YWw7XHJcblxyXG4gIC8vI2VuZHJlZ2lvblxyXG5cclxuICAvLyNyZWdpb24gQWNjZXNzb3JzXHJcblxyXG4gIC8qXHJcbiAgKiBLZXl3b3JkIGlzIHVzZWQgZm9yIHNlYXJjaGluZyBmb3IgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBnZXQga2V5d29yZCgpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMuX2tleXdvcmQ7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICogS2V5d29yZCBpcyB1c2VkIGZvciBzZWFyY2hpbmcgZm9yIGl0ZW1zLlxyXG4gICogKi9cclxuICBwdWJsaWMgc2V0IGtleXdvcmQodmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5fa2V5d29yZCA9IHZhbHVlO1xyXG5cclxuICAgIC8vIEluaXRpYWxpemUgY29udHJvbCB1cGRhdGUgY29tbWFuZC5cclxuICAgIGNvbnN0IGNvbW1hbmQ6IElVcGRhdGVNdWx0aVNlbGVjdG9yQ29tbWFuZCA9IHtcclxuICAgICAgc2hvdWxkSWdub3JlRHVwbGljYXRlOiBmYWxzZSxcclxuICAgICAgc2hvdWxkSWdub3JlSW50ZXJ2YWw6IGZhbHNlXHJcbiAgICB9O1xyXG5cclxuICAgIHRoaXMuX3VwZGF0ZUF2YWlsYWJsZUl0ZW1zU3ViamVjdFxyXG4gICAgICAubmV4dChjb21tYW5kKTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBDaGFyYWN0ZXIgd2hpY2ggaXMgdXNlZCBmb3IgZGl2aWRpbmcgc2VhcmNoZWQgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgnc2VwYXJhdGlvbi1jaGFyYWN0ZXInKVxyXG4gIHB1YmxpYyBzZXQgc2VwYXJhdGlvbkNoYXJhY3Rlcih2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICBpZiAoIXZhbHVlIHx8ICF2YWx1ZS5sZW5ndGgpIHtcclxuICAgICAgdGhpcy5fc2VwYXJhdGlvbkNoYXJhY3RlciA9ICcsJztcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX3NlcGFyYXRpb25DaGFyYWN0ZXIgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBJdGVtcyB3aGljaCBoYXZlIGJlZW4gc2VsZWN0ZWQuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBnZXQgc2VsZWN0ZWRJdGVtcygpOiBhbnlbXSB7XHJcbiAgICByZXR1cm4gdGhpcy5fc2VsZWN0ZWRJdGVtcztcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBHZXQgc2VsZWN0ZWQgaXRlbXMuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBzZXQgc2VsZWN0ZWRJdGVtcyh2YWx1ZXM6IGFueVtdKSB7XHJcbiAgICBpZiAoIXZhbHVlcyB8fCB2YWx1ZXMubGVuZ3RoIDwgMCkge1xyXG4gICAgICB0aGlzLl9zZWxlY3RlZEl0ZW1zID0gW107XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl9zZWxlY3RlZEl0ZW1zID0gdmFsdWVzO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAqIEhvdyBtdWNoIHRpbWUgc2hvdWxkIGNvbXBvbmVudCByYWlzZSBhbm90aGVyIG9uZSBhYm91dCBpdHMgY2hhbmdlcy5cclxuICAqICovXHJcbiAgQElucHV0KCdpbnRlcnZhbCcpXHJcbiAgcHVibGljIHNldCBpbnRlcnZhbCh2YWx1ZTogbnVtYmVyKSB7XHJcblxyXG4gICAgaWYgKHZhbHVlIDwgdGhpcy5fZGVmYXVsdEl0ZW1zSW50ZXJ2YWwpIHtcclxuICAgICAgdGhpcy5fbG9hZEl0ZW1zSW50ZXJ2YWwgPSB0aGlzLl9kZWZhdWx0SXRlbXNJbnRlcnZhbDtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuX2xvYWRJdGVtc0ludGVydmFsID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICogTGlzdCBvZiBpdGVtIHdoaWNoIHNob3VsZCBiZSBkaXNwbGF5ZWQgb24gZHJvcC1kb3duIG1lbnUuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgnaXRlbXMnKVxyXG4gIHB1YmxpYyBzZXQgaXRlbXModmFsdWVzOiBBcnJheTxhbnk+KSB7XHJcblxyXG4gICAgaWYgKHRoaXMubG9hZEF2YWlsYWJsZUl0ZW1zQXN5bmNIYW5kbGVyICYmIHRoaXMuX3VwZGF0ZUF2YWlsYWJsZUl0ZW1zU3ViamVjdCkge1xyXG4gICAgICB0aGlzLl91cGRhdGVBdmFpbGFibGVJdGVtc1N1YmplY3QubmV4dChudWxsKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKCF2YWx1ZXMgfHwgIXZhbHVlcy5sZW5ndGggfHwgISh2YWx1ZXMgaW5zdGFuY2VvZiBBcnJheSkpIHtcclxuICAgICAgdGhpcy5fb3JpZ2luYWxJdGVtcyA9IFtdO1xyXG4gICAgICB0aGlzLl9hdmFpbGFibGVJdGVtcyA9IFtdO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fb3JpZ2luYWxJdGVtcyA9IHZhbHVlcztcclxuICAgIHRoaXMuX2F2YWlsYWJsZUl0ZW1zID0gdmFsdWVzO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAqIEdldCBhdmFpbGFibGUgaXRlbXMgZm9yIGRpc3BsYXlpbmcgaW4gZHJvcC1kb3duIGxpc3QuXHJcbiAgKiAqL1xyXG4gIHB1YmxpYyBnZXQgaXRlbXMoKTogYW55W10ge1xyXG4gICAgcmV0dXJuIHRoaXMuX2F2YWlsYWJsZUl0ZW1zO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAqIEdldCB0aGUgbWF4aW11bSBpdGVtcyB0aGF0IGNhbiBiZSBkaXNwbGF5ZWQgaW4gY29udGV4dCBtZW51LlxyXG4gICogKi9cclxuICBwdWJsaWMgZ2V0IG1heGltdW1Db250ZXh0SXRlbSgpOiBudW1iZXIge1xyXG4gICAgcmV0dXJuIHRoaXMuX21heGltdW1Db250ZXh0SXRlbXM7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICogSG93IG1hbnkgaXRlbXMgc2hvdWxkIGJlIHNob3duIHRvIGJlIHNlbGVjdGVkLlxyXG4gICogKi9cclxuICBASW5wdXQoJ2xpbWl0LWl0ZW0tYW1vdW50JylcclxuICBwdWJsaWMgc2V0IG1heGltdW1Db250ZXh0SXRlbXMobWF4aW11bUl0ZW1zOiBudW1iZXIpIHtcclxuICAgIGlmIChtYXhpbXVtSXRlbXMgPCAwKSB7XHJcbiAgICAgIG1heGltdW1JdGVtcyA9IDA7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5fbWF4aW11bUNvbnRleHRJdGVtcyA9IG1heGltdW1JdGVtcztcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBHZXQgbWF4aW11bSBzZWxlY3RhYmxlIGl0ZW1zLlxyXG4gICogKi9cclxuICBwdWJsaWMgZ2V0IG1heGltdW1TZWxlY3RhYmxlSXRlbXMoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLl9tYXhpbXVtU2VsZWN0YWJsZUl0ZW1zO1xyXG4gIH1cclxuXHJcbiAgLypcclxuICAqIFVwZGF0ZSB0aGUgbWF4aW11bSBzZWxlY3RhYmxlIGl0ZW1zLlxyXG4gICogKi9cclxuICBASW5wdXQoJ2xpbWl0LWl0ZW0tc2VsZWN0aW9uJylcclxuICBwdWJsaWMgc2V0IG1heGltdW1TZWxlY3RhYmxlSXRlbXModmFsdWU6IG51bWJlcikge1xyXG4gICAgaWYgKHZhbHVlIDwgMCB8fCBpc05hTih2YWx1ZSkpIHtcclxuICAgICAgdGhpcy5fbWF4aW11bVNlbGVjdGFibGVJdGVtcyA9IDA7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLl9tYXhpbXVtU2VsZWN0YWJsZUl0ZW1zID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICAvKlxyXG4gICogQGRlcHJlY2F0ZWRcclxuICAqIFBsZWFzZSBjb25zaWRlciB1c2luZyBrZXktcHJvcGVydHkgaW5zdGVhZC5cclxuICAqIEtleSB3aGljaCBpcyBmb3IgcmVjb2duaXppbmcgd2hldGhlciBpdGVtIGlzIGluIHRoZSBjaG9zZW4gbGlzdCBvciBub3QuXHJcbiAgKiAqL1xyXG4gIEBJbnB1dCgna2V5JylcclxuICBwcm90ZWN0ZWQgc2V0IGtleSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9rZXkgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBQbGVhc2UgY29uc2lkZXIgdXNpbmcga2V5LXByb3BlcnR5IGluc3RlYWQuXHJcbiAgKiBLZXkgd2hpY2ggaXMgZm9yIHJlY29nbml6aW5nIHdoZXRoZXIgaXRlbSBpcyBpbiB0aGUgY2hvc2VuIGxpc3Qgb3Igbm90LlxyXG4gICogKi9cclxuICBASW5wdXQoJ2tleS1wcm9wZXJ0eScpXHJcbiAgcHJvdGVjdGVkIHNldCBrZXlQcm9wZXJ0eSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9rZXkgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBXaGljaCBwcm9wZXJ0eSBzaG91bGQgYmUgdXNlZCBhcyBkaXNwbGF5LlxyXG4gICogTnVsbCBpcyBhYm91dCB1c2luZyBvYmplY3QgYXMgZGlzcGxheS5cclxuICAqICovXHJcbiAgQElucHV0KCdkaXNwbGF5LXByb3BlcnR5JylcclxuICBwcm90ZWN0ZWQgc2V0IGRpc3BsYXlQcm9wZXJ0eSh2YWx1ZTogc3RyaW5nKSB7XHJcbiAgICB0aGlzLl9kaXNwbGF5UHJvcGVydHkgPSB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8qXHJcbiAgKiBXaGljaCBwcm9wZXJ0eSBzaG91bGQgYmUgdXNlZCBhcyBzZWxlY3RlZCB2YWx1ZS5cclxuICAqIE51bGwgaXMgYWJvdXQgdXNpbmcgb2JqZWN0IGFzIHNlbGVjdGVkIHZhbHVlLlxyXG4gICogKi9cclxuICBASW5wdXQoJ3ZhbHVlLXByb3BlcnR5JylcclxuICBwcm90ZWN0ZWQgc2V0IHZhbHVlUHJvcGVydHkodmFsdWU6IHN0cmluZykge1xyXG4gICAgdGhpcy5fdmFsdWVQcm9wZXJ0eSA9IHZhbHVlO1xyXG4gIH1cclxuXHJcblxyXG4gIC8vI2VuZHJlZ2lvblxyXG5cclxuICAvLyNyZWdpb24gQ29uc3RydWN0b3JcclxuXHJcbiAgLypcclxuICAqIEluaXRpYXRlIGNvbXBvbmVudHMgd2l0aCBpbmplY3RvcnMgKGFzIGF2YWlsYWJsZSlcclxuICAqICovXHJcbiAgcHVibGljIGNvbnN0cnVjdG9yKCkge1xyXG4gICAgdGhpcy5fc2VsZWN0ZWRJdGVtcyA9IFtdO1xyXG4gICAgdGhpcy5pdGVtcyA9IFtdO1xyXG5cclxuICAgIC8vIEJ5IGRlZmF1bHQsIGl0ZW1zIGFtb3VudCBpcyBsaW1pdGVkIHRvIDEwLlxyXG4gICAgdGhpcy5fbWF4aW11bVNlbGVjdGFibGVJdGVtcyA9IDEwO1xyXG5cclxuICAgIHRoaXMuX3VwZGF0ZUF2YWlsYWJsZUl0ZW1zU3ViamVjdCA9IG5ldyBSZXBsYXlTdWJqZWN0KDEpO1xyXG4gICAgdGhpcy5fdXBkYXRlQXZhaWxhYmxlSXRlbXNTdWJzY3JpcHRpb24gPSB0aGlzLl91cGRhdGVBdmFpbG