UNPKG

ngx-dynamic-dashboard

Version:
381 lines 55.6 kB
import { Component, EventEmitter, Output } from '@angular/core'; import { GadgetInstanceService } from './grid.service'; import { ConfigurationService } from '../services/configuration.service'; import { GadgetConfigModel } from '../gadgets/_common/gadget-config-model'; import { AddGadgetService } from '../add-gadget/service'; import { ToastService } from '../toast/toast.service'; import { MenuEventService } from '../menu/menu-service'; export class GridComponent { /** * Todo - split model and board operations. This class should really focus on an individual board model's operations * within the grid. The board specific operations should be moved to the board component. * @param _gadgetInstanceService * @param _procmonConfigurationService */ constructor(_gadgetInstanceService, _configurationService, _gadgetLibraryService, _toastService, _menuEventService) { this._gadgetInstanceService = _gadgetInstanceService; this._configurationService = _configurationService; this._gadgetLibraryService = _gadgetLibraryService; this._toastService = _toastService; this._menuEventService = _menuEventService; this.boardUpdateEvent = new EventEmitter(); this.model = {}; this.noGadgets = true; this.dropZone1 = null; this.dropZone2 = null; this.dropZone3 = null; this.gadgetLibrary = []; /** todo * Temporary objects for experimenting with AI * @type */ this.gridInsertionPosition = { x: 0, y: 0 }; this.removeOldListeners(); this.setupEventListeners(); this.initializeBoard(); this.getGadgetLibrary(); } /** * todo - This is a temporary attempt to avoid emitting events from stale listeners. * Most severe symptom is when you drill down and then change the layout. * Multiple events are triggered per action due to the services not * getting destroyed when coming into the main board from a child route. The end result is multiple gadget instances * appearing. The following code improves the condition but there still are issues with multiple gadgets appearing * when changing the layout. * */ removeOldListeners() { this._gadgetInstanceService.unSubscribeAll(); this._menuEventService.unSubscribeAll(); } setupEventListeners() { const gadgetRemoveEventSubscriber = this._gadgetInstanceService .listenForInstanceRemovedEventsFromGadgets().subscribe((message) => { this.saveBoard('Gadget Removed From Board: ' + message, false); }); const menuEventSubscriber = this._menuEventService.listenForMenuEvents().subscribe((event) => { const edata = event['data']; switch (event['name']) { case 'boardChangeLayoutEvent': this.updateBoardLayout(edata); break; case 'boardSelectEvent': this.loadBoard(edata); break; case 'boardCreateEvent': this.createBoard(edata); break; case 'boardEditEvent': this.editBoard(edata); break; case 'boardDeleteEvent': this.deleteBoard(edata); break; case 'boardAddGadgetEvent': this.addGadget(edata); break; case 'boardAIAddGadgetEvent': this.addGadgetUsingArtificialIntelligence(edata); break; } }); this._gadgetInstanceService.addSubscriber(gadgetRemoveEventSubscriber); this._menuEventService.addSubscriber(menuEventSubscriber); } /** * * This is experimental code that deals with AI */ getGadgetLibrary() { this._gadgetLibraryService.getGadgetLibrary().subscribe(data => { this.gadgetLibrary.length = 0; const me = this; data.library.forEach(function (item) { me.gadgetLibrary.push(item); }); }); } getGadgetFromLibrary(gadgetType) { let gadgetObject = null; this.gadgetLibrary.forEach(gadget => { if (gadgetType.localeCompare(gadget['componentType']) === 0) { gadgetObject = gadget; } }); return gadgetObject; } addGadgetUsingArtificialIntelligence(aiObject) { /** todo * make confidence code configurable */ if (aiObject && aiObject.operation) { switch (aiObject.operation) { case 'get_storage': this.addGadget(this.getGadgetFromLibrary('StorageObjectListComponent')); break; case 'get_cpu': this.addGadget(this.getGadgetFromLibrary('CPUGadgetComponent')); break; } } } /** * This is the end of the experimental AI code. */ updateGadgetPositionInBoard($event, columnNumber, rowNumber, type) { console.log($event['item']['data']); console.log(columnNumber + ' ' + rowNumber); let moveComplete = false; this.getModel().rows.forEach(row => { let colpos = 0; row.columns.forEach(column => { let gadgetpos = 0; if (column.gadgets) { column.gadgets.forEach(_gadget => { if (_gadget.instanceId === $event['item']['data'] && !moveComplete) { const gadget = column.gadgets.splice(gadgetpos, 1); if (!this.getModel().rows[rowNumber].columns[columnNumber].gadgets) { this.getModel().rows[rowNumber].columns[columnNumber].gadgets = []; } this.getModel().rows[rowNumber].columns[columnNumber].gadgets.push(gadget[0]); this.saveBoard('drag drop operation', false); moveComplete = true; } gadgetpos++; }); colpos++; } }); }); } createBoard(name) { this.loadNewBoard(name); } editBoard(name) { } deleteBoard(name) { this._configurationService.deleteBoard(name).subscribe(data => { this.initializeBoard(); }, error => console.error('Deletion error', error), () => console.debug('Board Deletion: ' + name)); } addGadget(gadget) { const _gadget = Object.assign({}, gadget); _gadget.instanceId = new Date().getTime(); _gadget.config = new GadgetConfigModel(gadget.config); this.setGadgetInsertPosition(); const x = this.gridInsertionPosition.x; const y = this.gridInsertionPosition.y; if (!this.getModel().rows[x].columns[y].gadgets) { this.getModel().rows[x].columns[y].gadgets = []; } this.getModel().rows[x].columns[y].gadgets.push(_gadget); this.saveBoard('Adding Gadget To The Board', false); } updateBoardLayout(structure) { console.log('IN UPDATE BOARD LAYOUT'); // user selected the currently selected layout if (structure.id === this.getModel().id) { return; } // copy the current board's model const _model = Object.assign({}, this.getModel()); // get just the columns that contain gadgets from all rows const originalColumns = this.readColumnsFromOriginalModel(_model); // reset the copied model's rows, which include columns _model.rows.length = 0; // copy the contents of the requested structure into the temporary model // we now have a board model we can populate with the original board's gadgets Object.assign(_model.rows, structure.rows); _model.structure = structure.structure; _model.id = structure.id; let originalColumnIndexToStartProcessingFrom = 0; /* For each column from the original board, copy its gadgets to the new structure. The requested layout may have more or less columns than defined by the original layout. So the fillGridStructure method will copy column content into the target. If there are more columns than the target, the fillGridStructure will return the count of remaining columns to be processed and then process those. */ while (originalColumnIndexToStartProcessingFrom < originalColumns.length) { originalColumnIndexToStartProcessingFrom = this.fillGridStructure(_model, originalColumns, originalColumnIndexToStartProcessingFrom); } // This will copy the just processed model and present it to the board this.setModel(_model); // clear temporary object for (const member in _model) { delete _model[member]; } // persist the board change this.saveBoard('Grid Layout Update', false); } enableConfigMode() { this._gadgetInstanceService.enableConfigureMode(); } setModel(model) { this.model = Object.assign({}, model); } getModel() { return this.model; } onDrop(data) { console.log(data); } updateGridState() { let gadgetCount = 0; if (this.getModel().rows) { this.getModel().rows.forEach(function (row) { row.columns.forEach(function (column) { if (column.gadgets) { column.gadgets.forEach(function (gadget) { gadgetCount++; }); } }); }); } this.noGadgets = !gadgetCount; this.dashedStyle = { 'border-style': this.noGadgets ? 'dashed' : 'none', 'border-width': this.noGadgets ? '2px' : 'none', 'border-color': this.noGadgets ? 'darkgray' : 'none', 'padding': this.noGadgets ? '5px' : 'none' }; } readColumnsFromOriginalModel(_model) { const columns = []; _model.rows.forEach(function (row) { row.columns.forEach(function (col) { columns.push(col); }); }); return columns; } fillGridStructure(destinationModelStructure, originalColumns, counter) { const me = this; destinationModelStructure.rows.forEach(function (row) { row.columns.forEach(function (destinationColumn) { if (!destinationColumn.gadgets) { destinationColumn.gadgets = []; } if (originalColumns[counter]) { me.copyGadgets(originalColumns[counter], destinationColumn); counter++; } }); }); return counter; } copyGadgets(source, target) { if (source.gadgets && source.gadgets.length > 0) { let w = source.gadgets.shift(); while (w) { target.gadgets.push(w); w = source.gadgets.shift(); } } } initializeBoard() { this._configurationService.getBoards().subscribe(boards => { if (boards && boards instanceof Array && boards.length) { this.boards = boards.sort((a, b) => { return a.boardInstanceId - b.boardInstanceId; }); this.loadBoard(this.boards[0].title); } else { this.loadDefaultBoard(); } }); } loadBoard(boardTitle) { this.clearGridModelAndGadgetInstanceStructures(); const selectedBoard = this.boards.find(board => board.title === boardTitle); this.setModel(selectedBoard); this.updateServicesAndGridWithModel(); this.boardUpdateEvent.emit(boardTitle); } loadDefaultBoard() { this.clearGridModelAndGadgetInstanceStructures(); this._configurationService.getDefaultBoard().subscribe((board) => { this.setModel(board); this.updateServicesAndGridWithModel(); this.saveBoard('Initialization of a default board', true); }); } loadNewBoard(name) { this.clearGridModelAndGadgetInstanceStructures(); this._configurationService.getDefaultBoard().subscribe((res) => { this.setModel(res); this.getModel().title = name; this.getModel().boardInstanceId = new Date().getTime(); this.updateServicesAndGridWithModel(); this.saveBoard('Initialization of a new board', true); }); } updateServicesAndGridWithModel() { this._gadgetInstanceService.setCurrentModel(this.getModel()); this._configurationService.setCurrentModel(this.getModel()); this.updateGridState(); } saveBoard(operation, alertBoardListenerThatTheMenuShouldBeUpdated) { this.updateServicesAndGridWithModel(); this._configurationService.saveBoard(this.getModel()).subscribe(result => { this._toastService.sendMessage(this.getModel().title + ' has been updated!', ''); if (alertBoardListenerThatTheMenuShouldBeUpdated) { this._menuEventService.raiseGridEvent({ name: 'boardUpdateEvent', data: this.getModel().title }); } }, error => console.error('Error' + error), () => console.debug('Saving configuration to store!')); } clearGridModelAndGadgetInstanceStructures() { // clear gadgetInstances this._gadgetInstanceService.clearAllInstances(); // clear current model for (const prop in this.getModel()) { if (this.model.hasOwnProperty(prop)) { delete this.model[prop]; } } } setGadgetInsertPosition() { for (let x = 0; x < this.getModel().rows.length; x++) { for (let y = 0; y < this.getModel().rows[x].columns.length; y++) { if (this.getModel().rows[x].columns[y].gadgets && this.getModel().rows[x].columns[y].gadgets.length === 0) { this.gridInsertionPosition.x = x; this.gridInsertionPosition.y = y; return; } } } // we go here because the board is either empty or full // insert in the top left most cell this.gridInsertionPosition.y = 0; if (this.noGadgets) { // there are no gadgets so insert in top row this.gridInsertionPosition.x = 0; } else { // board is full so insert in the last row this.gridInsertionPosition.x = this.getModel().rows.length - 1; } } } GridComponent.decorators = [ { type: Component, args: [{ moduleId: module.id, selector: 'dashboard-grid', template: "<div class=\"ui centered stackable grid\" style=\"margin-left: 5px; margin-right: 5px\"\n>\n <div *ngFor=\"let row of model.rows; let r = index\" [ngClass]=\"{'short-row': row.columns.length > 3, 'tall-row': row.columns.length <= 3 }\"\n class=\"row\">\n\n <ng-container cdkDropListGroup>\n <div (cdkDropListDropped)=\"updateGadgetPositionInBoard($event, c , r, 'column')\" *ngFor=\"let col of row.columns; let c = index\" cdkDropList\n class=\"{{col.styleClass}} column\">\n\n <div *ngIf=\"!col.gadgets || col.gadgets.length== 0\" [ngClass]=\"{'short-row': row.columns.length > 3, 'tall-row': row.columns.length <= 3 }\"\n class=\"ui center aligned massive info message\"\n style=\"text-align:center\">\n\n <span style=\"font-size: .75em\">Add Gadget!</span>\n\n </div>\n\n <dashboard-grid-cell *ngFor=\"let cellGadget of col.gadgets\" [cdkDragData]=\"cellGadget.instanceId\" [gadgetConfig]=\"cellGadget.config\"\n [gadgetInstanceId]=\"cellGadget.instanceId\"\n [gadgetTags]=\"cellGadget.tags\"\n [gadgetType]=\"cellGadget.componentType\"\n cdkDrag\n class=\"target-box\"\n style=\"display:inline-block; width:100%\"\n >\n <div *cdkDragPlaceholder class=\"target-box-placeholder\"></div>\n </dashboard-grid-cell>\n </div>\n </ng-container>\n </div>\n</div>\n<dashboard-toast></dashboard-toast>\n", styles: [".ui.info.message{background-color:#c8cbce;color:#fff}.ui.attached.info.message,.ui.info.message{box-shadow:inset 0 0 0 0 #c8cbce,0 0 0 0 transparent}.short-row{min-height:150px}.tall-row{min-height:370px}.target-box-placeholder{background:transparent;border:none;min-height:400px;transition:transform .25s cubic-bezier(0,0,.2,1)}.target-box{align-items:center;box-sizing:border-box;color:rgba(0,0,0,.87);cursor:move;display:inline-block;flex-direction:row;font-size:14px;justify-content:center;padding:5px}"] },] } ]; GridComponent.ctorParameters = () => [ { type: GadgetInstanceService }, { type: ConfigurationService }, { type: AddGadgetService }, { type: ToastService }, { type: MenuEventService } ]; GridComponent.propDecorators = { boardUpdateEvent: [{ type: Output }] }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3JpZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiL1VzZXJzL2JlbmxpL3dvcmtzcGFjZXMvbmd4LWR5bmFtaWMtZGFzaGJvYXJkLWZyYW1ld29yay9wcm9qZWN0cy9uZ3gtZHluYW1pYy1kYXNoYm9hcmQvc3JjLyIsInNvdXJjZXMiOlsiZGFzaGJvYXJkL2dyaWQvZ3JpZC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFDLFNBQVMsRUFBRSxZQUFZLEVBQVMsTUFBTSxFQUFDLE1BQU0sZUFBZSxDQUFDO0FBQ3JFLE9BQU8sRUFBQyxxQkFBcUIsRUFBQyxNQUFNLGdCQUFnQixDQUFDO0FBQ3JELE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLG1DQUFtQyxDQUFDO0FBQ3ZFLE9BQU8sRUFBQyxpQkFBaUIsRUFBQyxNQUFNLHdDQUF3QyxDQUFDO0FBQ3pFLE9BQU8sRUFBQyxnQkFBZ0IsRUFBQyxNQUFNLHVCQUF1QixDQUFDO0FBQ3ZELE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSx3QkFBd0IsQ0FBQztBQUNwRCxPQUFPLEVBQUMsZ0JBQWdCLEVBQUMsTUFBTSxzQkFBc0IsQ0FBQztBQVd0RCxNQUFNLE9BQU8sYUFBYTtJQXlCdEI7Ozs7O09BS0c7SUFFSCxZQUFvQixzQkFBNkMsRUFDN0MscUJBQTJDLEVBQzNDLHFCQUF1QyxFQUN2QyxhQUEyQixFQUMzQixpQkFBbUM7UUFKbkMsMkJBQXNCLEdBQXRCLHNCQUFzQixDQUF1QjtRQUM3QywwQkFBcUIsR0FBckIscUJBQXFCLENBQXNCO1FBQzNDLDBCQUFxQixHQUFyQixxQkFBcUIsQ0FBa0I7UUFDdkMsa0JBQWEsR0FBYixhQUFhLENBQWM7UUFDM0Isc0JBQWlCLEdBQWpCLGlCQUFpQixDQUFrQjtRQWxDN0MscUJBQWdCLEdBQXNCLElBQUksWUFBWSxFQUFFLENBQUM7UUFFbkUsVUFBSyxHQUFlLEVBQUUsQ0FBQztRQUN2QixjQUFTLEdBQUcsSUFBSSxDQUFDO1FB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QUMsQ0FBQztRQUVqQyxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDaEIsNENBQTRDO1lBQzVDLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1NBQ3BDO2FBQU07WUFDSCwwQ0FBMEM7WUFDMUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDbEU7SUFDTCxDQUFDOzs7WUF4ZUosU0FBUyxTQUFDO2dCQUNQLFFBQVEsRUFBRSxNQUFNLENBQUMsRUFBRTtnQkFDbkIsUUFBUSxFQUFFLGdCQUFnQjtnQkFDMUIsK3NEQUEwQjs7YUFFN0I7OztZQWZPLHFCQUFxQjtZQUNyQixvQkFBb0I7WUFFcEIsZ0JBQWdCO1lBQ2hCLFlBQVk7WUFDWixnQkFBZ0I7OzsrQkFhbkIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7Q29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPdXRwdXR9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtHYWRnZXRJbnN0YW5jZVNlcnZpY2V9IGZyb20gJy4vZ3JpZC5zZXJ2aWNlJztcbmltcG9ydCB7Q29uZmlndXJhdGlvblNlcnZpY2V9IGZyb20gJy4uL3NlcnZpY2VzL2NvbmZpZ3VyYXRpb24uc2VydmljZSc7XG5pbXBvcnQge0dhZGdldENvbmZpZ01vZGVsfSBmcm9tICcuLi9nYWRnZXRzL19jb21tb24vZ2FkZ2V0LWNvbmZpZy1tb2RlbCc7XG5pbXBvcnQge0FkZEdhZGdldFNlcnZpY2V9IGZyb20gJy4uL2FkZC1nYWRnZXQvc2VydmljZSc7XG5pbXBvcnQge1RvYXN0U2VydmljZX0gZnJvbSAnLi4vdG9hc3QvdG9hc3Quc2VydmljZSc7XG5pbXBvcnQge01lbnVFdmVudFNlcnZpY2V9IGZyb20gJy4uL21lbnUvbWVudS1zZXJ2aWNlJztcbmltcG9ydCB7SUV2ZW50fSBmcm9tICcuLi9tZW51L0lFdmVudCc7XG5pbXBvcnQge0NvbHVtbiwgQm9hcmR9IGZyb20gJy4vQm9hcmQnO1xuXG5cbkBDb21wb25lbnQoe1xuICAgIG1vZHVsZUlkOiBtb2R1bGUuaWQsXG4gICAgc2VsZWN0b3I6ICdkYXNoYm9hcmQtZ3JpZCcsXG4gICAgdGVtcGxhdGVVcmw6ICcuL2dyaWQuaHRtbCcsXG4gICAgc3R5bGVVcmxzOiBbJy4vc3R5bGVzLWdyaWQuY3NzJ11cbn0pXG5leHBvcnQgY2xhc3MgR3JpZENvbXBvbmVudCB7XG5cbiAgICBAT3V0cHV0KCkgYm9hcmRVcGRhdGVFdmVudDogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbiAgICBtb2RlbDogQm9hcmQgPSA8YW55Pnt9O1xuICAgIG5vR2FkZ2V0cyA9IHRydWU7XG4gICAgZGFzaGVkU3R5bGU6IHt9O1xuICAgIGRyb3Bab25lMTogYW55ID0gbnVsbDtcbiAgICBkcm9wWm9uZTI6IGFueSA9IG51bGw7XG4gICAgZHJvcFpvbmUzOiBhbnkgPSBudWxsO1xuXG4gICAgZ2FkZ2V0TGlicmFyeTogYW55W10gPSBbXTtcblxuICAgIHByaXZhdGUgYm9hcmRzOiBCb2FyZFtdO1xuXG4gICAgLyoqIHRvZG9cbiAgICAgKiBUZW1wb3Jhcnkgb2JqZWN0cyBmb3IgZXhwZXJpbWVudGluZyB3aXRoIEFJXG4gICAgICogQHR5cGVcbiAgICAgKi9cblxuICAgIGdyaWRJbnNlcnRpb25Qb3NpdGlvbiA9IHtcbiAgICAgICAgeDogMCxcbiAgICAgICAgeTogMFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUb2RvIC0gc3BsaXQgbW9kZWwgYW5kIGJvYXJkIG9wZXJhdGlvbnMuIFRoaXMgY2xhc3Mgc2hvdWxkIHJlYWxseSBmb2N1cyBvbiBhbiBpbmRpdmlkdWFsIGJvYXJkIG1vZGVsJ3Mgb3BlcmF0aW9uc1xuICAgICAqIHdpdGhpbiB0aGUgZ3JpZC4gVGhlIGJvYXJkIHNwZWNpZmljIG9wZXJhdGlvbnMgc2hvdWxkIGJlIG1vdmVkIHRvIHRoZSBib2FyZCBjb21wb25lbnQuXG4gICAgICogQHBhcmFtIF9nYWRnZXRJbnN0YW5jZVNlcnZpY2VcbiAgICAgKiBAcGFyYW0gX3Byb2Ntb25Db25maWd1cmF0aW9uU2VydmljZVxuICAgICAqL1xuXG4gICAgY29uc3RydWN0b3IocHJpdmF0ZSBfZ2FkZ2V0SW5zdGFuY2VTZXJ2aWNlOiBHYWRnZXRJbnN0YW5jZVNlcnZpY2UsXG4gICAgICAgICAgICAgICAgcHJpdmF0ZSBfY29uZmlndXJhdGlvblNlcnZpY2U6IENvbmZpZ3VyYXRpb25TZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgX2dhZGdldExpYnJhcnlTZXJ2aWNlOiBBZGRHYWRnZXRTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgX3RvYXN0U2VydmljZTogVG9hc3RTZXJ2aWNlLFxuICAgICAgICAgICAgICAgIHByaXZhdGUgX21lbnVFdmVudFNlcnZpY2U6IE1lbnVFdmVudFNlcnZpY2UpIHtcblxuXG4gICAgICAgIHRoaXMucmVtb3ZlT2xkTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMuc2V0dXBFdmVudExpc3RlbmVycygpO1xuICAgICAgICB0aGlzLmluaXRpYWxpemVCb2FyZCgpO1xuICAgICAgICB0aGlzLmdldEdhZGdldExpYnJhcnkoKTtcblxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIHRvZG8gLSBUaGlzIGlzIGEgdGVtcG9yYXJ5IGF0dGVtcHQgdG8gYXZvaWQgZW1pdHRpbmcgZXZlbnRzIGZyb20gc3RhbGUgbGlzdGVuZXJzLlxuICAgICAqIE1vc3Qgc2V2ZXJlIHN5bXB0b20gaXMgd2hlbiB5b3UgZHJpbGwgZG93biBhbmQgdGhlbiBjaGFuZ2UgdGhlIGxheW91dC5cbiAgICAgKiBNdWx0aXBsZSBldmVudHMgYXJlIHRyaWdnZXJlZCBwZXIgYWN0aW9uIGR1ZSB0byB0aGUgc2VydmljZXMgbm90XG4gICAgICogZ2V0dGluZyBkZXN0cm95ZWQgd2hlbiBjb21pbmcgaW50byB0aGUgbWFpbiBib2FyZCBmcm9tIGEgY2hpbGQgcm91dGUuIFRoZSBlbmQgcmVzdWx0IGlzIG11bHRpcGxlIGdhZGdldCBpbnN0YW5jZXNcbiAgICAgKiBhcHBlYXJpbmcuIFRoZSBmb2xsb3dpbmcgY29kZSBpbXByb3ZlcyB0aGUgY29uZGl0aW9uIGJ1dCB0aGVyZSBzdGlsbCBhcmUgaXNzdWVzIHdpdGggbXVsdGlwbGUgZ2FkZ2V0cyBhcHBlYXJpbmdcbiAgICAgKiB3aGVuIGNoYW5naW5nIHRoZSBsYXlvdXQuXG4gICAgICpcbiAgICAgKi9cbiAgICByZW1vdmVPbGRMaXN0ZW5lcnMoKSB7XG5cbiAgICAgICAgdGhpcy5fZ2FkZ2V0SW5zdGFuY2VTZXJ2aWNlLnVuU3Vic2NyaWJlQWxsKCk7XG4gICAgICAgIHRoaXMuX21lbnVFdmVudFNlcnZpY2UudW5TdWJzY3JpYmVBbGwoKTtcblxuICAgIH1cblxuICAgIHNldHVwRXZlbnRMaXN0ZW5lcnMoKSB7XG5cbiAgICAgICAgY29uc3QgZ2FkZ2V0UmVtb3ZlRXZlbnRTdWJzY3JpYmVyID0gdGhpcy5fZ2FkZ2V0SW5zdGFuY2VTZXJ2aWNlXG4gICAgICAgICAgICAubGlzdGVuRm9ySW5zdGFuY2VSZW1vdmVkRXZlbnRzRnJvbUdhZGdldHMoKS5zdWJzY3JpYmUoKG1lc3NhZ2U6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc2F2ZUJvYXJkKCdHYWRnZXQgUmVtb3ZlZCBGcm9tIEJvYXJkOiAnICsgbWVzc2FnZSwgZmFsc2UpO1xuICAgICAgICB9KTtcblxuXG4gICAgICAgIGNvbnN0IG1lbnVFdmVudFN1YnNjcmliZXIgPSB0aGlzLl9tZW51RXZlbnRTZXJ2aWNlLmxpc3RlbkZvck1lbnVFdmVudHMoKS5zdWJzY3JpYmUoKGV2ZW50OiBJRXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVkYXRhID0gZXZlbnRbJ2RhdGEnXTtcblxuICAgICAgICAgICAgc3dpdGNoIChldmVudFsnbmFtZSddKSB7XG4gICAgICAgICAgICAgICAgY2FzZSAnYm9hcmRDaGFuZ2VMYXlvdXRFdmVudCc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudXBkYXRlQm9hcmRMYXlvdXQoZWRhdGEpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdib2FyZFNlbGVjdEV2ZW50JzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkQm9hcmQoZWRhdGEpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdib2FyZENyZWF0ZUV2ZW50JzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jcmVhdGVCb2FyZChlZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2JvYXJkRWRpdEV2ZW50JzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lZGl0Qm9hcmQoZWRhdGEpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdib2FyZERlbGV0ZUV2ZW50JzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kZWxldGVCb2FyZChlZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2JvYXJkQWRkR2FkZ2V0RXZlbnQnOlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZEdhZGdldChlZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2JvYXJkQUlBZGRHYWRnZXRFdmVudCc6XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWRkR2FkZ2V0VXNpbmdBcnRpZmljaWFsSW50ZWxsaWdlbmNlKGVkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuX2dhZGdldEluc3RhbmNlU2VydmljZS5hZGRTdWJzY3JpYmVyKGdhZGdldFJlbW92ZUV2ZW50U3Vic2NyaWJlcik7XG4gICAgICAgIHRoaXMuX21lbnVFdmVudFNlcnZpY2UuYWRkU3Vic2NyaWJlcihtZW51RXZlbnRTdWJzY3JpYmVyKTtcblxuICAgIH1cblxuICAgIC8qKlxuICAgICAqXG4gICAgICogVGhpcyBpcyBleHBlcmltZW50YWwgY29kZSB0aGF0IGRlYWxzIHdpdGggQUlcbiAgICAgKi9cbiAgICBnZXRHYWRnZXRMaWJyYXJ5KCkge1xuXG4gICAgICAgIHRoaXMuX2dhZGdldExpYnJhcnlTZXJ2aWNlLmdldEdhZGdldExpYnJhcnkoKS5zdWJzY3JpYmUoZGF0YSA9PiB7XG4gICAgICAgICAgICB0aGlzLmdhZGdldExpYnJhcnkubGVuZ3RoID0gMDtcbiAgICAgICAgICAgIGNvbnN0IG1lID0gdGhpcztcbiAgICAgICAgICAgIGRhdGEubGlicmFyeS5mb3JFYWNoKGZ1bmN0aW9uIChpdGVtKSB7XG4gICAgICAgICAgICAgICAgbWUuZ2FkZ2V0TGlicmFyeS5wdXNoKGl0ZW0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIGdldEdhZGdldEZyb21MaWJyYXJ5KGdhZGdldFR5cGU6IHN0cmluZykge1xuXG4gICAgICAgIGxldCBnYWRnZXRPYmplY3QgPSBudWxsO1xuICAgICAgICB0aGlzLmdhZGdldExpYnJhcnkuZm9yRWFjaChnYWRnZXQgPT4ge1xuXG5cbiAgICAgICAgICAgIGlmIChnYWRnZXRUeXBlLmxvY2FsZUNvbXBhcmUoZ2FkZ2V0Wydjb21wb25lbnRUeXBlJ10pID09PSAwKSB7XG5cbiAgICAgICAgICAgICAgICBnYWRnZXRPYmplY3QgPSBnYWRnZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gZ2FkZ2V0T2JqZWN0O1xuICAgIH1cblxuICAgIGFkZEdhZGdldFVzaW5nQXJ0aWZpY2lhbEludGVsbGlnZW5jZShhaU9iamVjdDogYW55KSB7XG5cbiAgICAgICAgLyoqIHRvZG9cbiAgICAgICAgICogbWFrZSBjb25maWRlbmNlIGNvZGUgY29uZmlndXJhYmxlXG4gICAgICAgICAqL1xuICAgICAgICBpZiAoYWlPYmplY3QgJiYgYWlPYmplY3Qub3BlcmF0aW9uKSB7XG4gICAgICAgICAgICBzd2l0Y2ggKGFpT2JqZWN0Lm9wZXJhdGlvbikge1xuICAgICAgICAgICAgICAgIGNhc2UgJ2dldF9zdG9yYWdlJzpcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5hZGRHYWRnZXQodGhpcy5nZXRHYWRnZXRGcm9tTGlicmFyeSgnU3RvcmFnZU9iamVjdExpc3RDb21wb25lbnQnKSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2dldF9jcHUnOlxuICAgICAgICAgICAgICAgICAgICB0aGlzLmFkZEdhZGdldCh0aGlzLmdldEdhZGdldEZyb21MaWJyYXJ5KCdDUFVHYWRnZXRDb21wb25lbnQnKSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVGhpcyBpcyB0aGUgZW5kIG9mIHRoZSBleHBlcmltZW50YWwgQUkgY29kZS5cbiAgICAgKi9cblxuICAgIHVwZGF0ZUdhZGdldFBvc2l0aW9uSW5Cb2FyZCgkZXZlbnQsIGNvbHVtbk51bWJlciwgcm93TnVtYmVyLCB0eXBlKSB7XG5cbiAgICAgICAgY29uc29sZS5sb2coJGV2ZW50WydpdGVtJ11bJ2RhdGEnXSk7XG4gICAgICAgIGNvbnNvbGUubG9nKGNvbHVtbk51bWJlciArICcgJyArIHJvd051bWJlcik7XG5cbiAgICAgICAgbGV0IG1vdmVDb21wbGV0ZSA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuZ2V0TW9kZWwoKS5yb3dzLmZvckVhY2gocm93ID0+IHtcblxuICAgICAgICAgICAgbGV0IGNvbHBvcyA9IDA7XG5cbiAgICAgICAgICAgIHJvdy5jb2x1bW5zLmZvckVhY2goY29sdW1uID0+IHtcblxuICAgICAgICAgICAgICAgIGxldCBnYWRnZXRwb3MgPSAwO1xuXG4gICAgICAgICAgICAgICAgaWYgKGNvbHVtbi5nYWRnZXRzKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgY29sdW1uLmdhZGdldHMuZm9yRWFjaChfZ2FkZ2V0ID0+IHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKF9nYWRnZXQuaW5zdGFuY2VJZCA9PT0gJGV2ZW50WydpdGVtJ11bJ2RhdGEnXSAmJiAhbW92ZUNvbXBsZXRlKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBnYWRnZXQgPSBjb2x1bW4uZ2FkZ2V0cy5zcGxpY2UoZ2FkZ2V0cG9zLCAxKTtcblxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLmdldE1vZGVsKCkucm93c1tyb3dOdW1iZXJdLmNvbHVtbnNbY29sdW1uTnVtYmVyXS5nYWRnZXRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0TW9kZWwoKS5yb3dzW3Jvd051bWJlcl0uY29sdW1uc1tjb2x1bW5OdW1iZXJdLmdhZGdldHMgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5nZXRNb2RlbCgpLnJvd3Nbcm93TnVtYmVyXS5jb2x1bW5zW2NvbHVtbk51bWJlcl0uZ2FkZ2V0cy5wdXNoKGdhZGdldFswXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5zYXZlQm9hcmQoJ2RyYWcgZHJvcCBvcGVyYXRpb24nLCBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbW92ZUNvbXBsZXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGdhZGdldHBvcysrO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgY29scG9zKys7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyBjcmVhdGVCb2FyZChuYW1lOiBzdHJpbmcpIHtcbiAgICAgICAgdGhpcy5sb2FkTmV3Qm9hcmQobmFtZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGVkaXRCb2FyZChuYW1lOiBzdHJpbmcpIHtcblxuICAgIH1cblxuICAgIHB1YmxpYyBkZWxldGVCb2FyZChuYW1lOiBzdHJpbmcpIHtcblxuICAgICAgICB0aGlzLl9jb25maWd1cmF0aW9uU2VydmljZS5kZWxldGVCb2FyZChuYW1lKS5zdWJzY3JpYmUoZGF0YSA9PiB7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmluaXRpYWxpemVCb2FyZCgpO1xuXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZXJyb3IgPT4gY29uc29sZS5lcnJvcignRGVsZXRpb24gZXJyb3InLCBlcnJvciksXG4gICAgICAgICAgICAoKSA9PiBjb25zb2xlLmRlYnVnKCdCb2FyZCBEZWxldGlvbjogJyArIG5hbWUpKTtcblxuICAgIH1cblxuICAgIHB1YmxpYyBhZGRHYWRnZXQoZ2FkZ2V0OiBhbnkpIHtcbiAgICAgICAgY29uc3QgX2dhZGdldCA9IE9iamVjdC5hc3NpZ24oe30sIGdhZGdldCk7XG5cbiAgICAgICAgX2dhZGdldC5pbnN0YW5jZUlkID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgIF9nYWRnZXQuY29uZmlnID0gbmV3IEdhZGdldENvbmZpZ01vZGVsKGdhZGdldC5jb25maWcpO1xuXG4gICAgICAgIHRoaXMuc2V0R2FkZ2V0SW5zZXJ0UG9zaXRpb24oKTtcblxuICAgICAgICBjb25zdCB4ID0gdGhpcy5ncmlkSW5zZXJ0aW9uUG9zaXRpb24ueDtcbiAgICAgICAgY29uc3QgeSA9IHRoaXMuZ3JpZEluc2VydGlvblBvc2l0aW9uLnk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmdldE1vZGVsKCkucm93c1t4XS5jb2x1bW5zW3ldLmdhZGdldHMpIHtcblxuICAgICAgICAgICAgdGhpcy5nZXRNb2RlbCgpLnJvd3NbeF0uY29sdW1uc1t5XS5nYWRnZXRzID0gW107XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5nZXRNb2RlbCgpLnJvd3NbeF0uY29sdW1uc1t5XS5nYWRnZXRzLnB1c2goX2dhZGdldCk7XG5cbiAgICAgICAgdGhpcy5zYXZlQm9hcmQoJ0FkZGluZyBHYWRnZXQgVG8gVGhlIEJvYXJkJywgZmFsc2UpO1xuXG4gICAgfVxuXG4gICAgcHVibGljIHVwZGF0ZUJvYXJkTGF5b3V0KHN0cnVjdHVyZSkge1xuXG4gICAgICAgIGNvbnNvbGUubG9nKCdJTiBVUERBVEUgQk9BUkQgTEFZT1VUJyk7XG5cbiAgICAgICAgLy8gdXNlciBzZWxlY3RlZCB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGxheW91dFxuICAgICAgICBpZiAoc3RydWN0dXJlLmlkID09PSB0aGlzLmdldE1vZGVsKCkuaWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGNvcHkgdGhlIGN1cnJlbnQgYm9hcmQncyBtb2RlbFxuICAgICAgICBjb25zdCBfbW9kZWwgPSBPYmplY3QuYXNzaWduKHt9LCB0aGlzLmdldE1vZGVsKCkpO1xuXG4gICAgICAgIC8vIGdldCBqdXN0IHRoZSBjb2x1bW5zIHRoYXQgY29udGFpbiBnYWRnZXRzIGZyb20gYWxsIHJvd3NcbiAgICAgICAgY29uc3Qgb3JpZ2luYWxDb2x1bW5zOiBhbnlbXSA9IHRoaXMucmVhZENvbHVtbnNGcm9tT3JpZ2luYWxNb2RlbChfbW9kZWwpO1xuXG4gICAgICAgIC8vIHJlc2V0IHRoZSBjb3BpZWQgbW9kZWwncyByb3dzLCB3aGljaCBpbmNsdWRlIGNvbHVtbnNcbiAgICAgICAgX21vZGVsLnJvd3MubGVuZ3RoID0gMDtcblxuICAgICAgICAvLyBjb3B5IHRoZSBjb250ZW50cyBvZiB0aGUgcmVxdWVzdGVkIHN0cnVjdHVyZSBpbnRvIHRoZSB0ZW1wb3JhcnkgbW9kZWxcbiAgICAgICAgLy8gd2Ugbm93IGhhdmUgYSBib2FyZCBtb2RlbCB3ZSBjYW4gcG9wdWxhdGUgd2l0aCB0aGUgb3JpZ2luYWwgYm9hcmQncyBnYWRnZXRzXG4gICAgICAgIE9iamVjdC5hc3NpZ24oX21vZGVsLnJvd3MsIHN0cnVjdHVyZS5yb3dzKTtcbiAgICAgICAgX21vZGVsLnN0cnVjdHVyZSA9IHN0cnVjdHVyZS5zdHJ1Y3R1cmU7XG4gICAgICAgIF9tb2RlbC5pZCA9IHN0cnVjdHVyZS5pZDtcblxuICAgICAgICBsZXQgb3JpZ2luYWxDb2x1bW5JbmRleFRvU3RhcnRQcm9jZXNzaW5nRnJvbSA9IDA7XG5cbiAgICAgICAgLyogRm9yIGVhY2ggY29sdW1uIGZyb20gdGhlIG9yaWdpbmFsIGJvYXJkLCBjb3B5IGl0cyBnYWRnZXRzIHRvIHRoZSBuZXcgc3RydWN0dXJlLlxuICAgICAgICAgVGhlIHJlcXVlc3RlZCBsYXlvdXQgbWF5IGhhdmUgbW9yZSBvciBsZXNzIGNvbHVtbnMgdGhhbiBkZWZpbmVkIGJ5IHRoZSBvcmlnaW5hbCBsYXlvdXQuIFNvIHRoZSBmaWxsR3JpZFN0cnVjdHVyZSBtZXRob2RcbiAgICAgICAgIHdpbGwgY29weSBjb2x1bW4gY29udGVudCBpbnRvIHRoZSB0YXJnZXQuIElmIHRoZXJlIGFyZSBtb3JlIGNvbHVtbnMgdGhhbiB0aGUgdGFyZ2V0LFxuICAgICAgICAgdGhlIGZpbGxHcmlkU3RydWN0dXJlIHdpbGwgcmV0dXJuIHRoZSBjb3VudCBvZiByZW1haW5pbmcgY29sdW1ucyB0byBiZSBwcm9jZXNzZWQgYW5kIHRoZW4gcHJvY2VzcyB0aG9zZS5cbiAgICAgICAgICovXG4gICAgICAgIHdoaWxlIChvcmlnaW5hbENvbHVtbkluZGV4VG9TdGFydFByb2Nlc3NpbmdGcm9tIDwgb3JpZ2luYWxDb2x1bW5zLmxlbmd0aCkge1xuICAgICAgICAgICAgb3JpZ2luYWxDb2x1bW5JbmRleFRvU3RhcnRQcm9jZXNzaW5nRnJvbSA9IHRoaXMuZmlsbEdyaWRTdHJ1Y3R1cmUoXG4gICAgICAgICAgICAgICAgX21vZGVsLFxuICAgICAgICAgICAgICAgIG9yaWdpbmFsQ29sdW1ucyxcbiAgICAgICAgICAgICAgICBvcmlnaW5hbENvbHVtbkluZGV4VG9TdGFydFByb2Nlc3NpbmdGcm9tKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRoaXMgd2lsbCBjb3B5IHRoZSBqdXN0IHByb2Nlc3NlZCBtb2RlbCBhbmQgcHJlc2VudCBpdCB0byB0aGUgYm9hcmRcbiAgICAgICAgdGhpcy5zZXRNb2RlbChfbW9kZWwpO1xuXG4gICAgICAgIC8vIGNsZWFyIHRlbXBvcmFyeSBvYmplY3RcbiAgICAgICAgZm9yIChjb25zdCBtZW1iZXIgaW4gX21vZGVsKSB7XG4gICAgICAgICAgICBkZWxldGUgX21vZGVsW21lbWJlcl07XG4gICAgICAgIH1cblxuICAgICAgICAvLyBwZXJzaXN0IHRoZSBib2FyZCBjaGFuZ2VcbiAgICAgICAgdGhpcy5zYXZlQm9hcmQoJ0dyaWQgTGF5b3V0IFVwZGF0ZScsIGZhbHNlKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZW5hYmxlQ29uZmlnTW9kZSgpIHtcblxuICAgICAgICB0aGlzLl9nYWRnZXRJbnN0YW5jZVNlcnZpY2UuZW5hYmxlQ29uZmlndXJlTW9kZSgpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzZXRNb2RlbChtb2RlbDogQm9hcmQpIHtcblxuICAgICAgICB0aGlzLm1vZGVsID0gT2JqZWN0LmFzc2lnbih7fSwgbW9kZWwpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRNb2RlbCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubW9kZWw7XG4gICAgfVxuXG4gICAgcHVibGljIG9uRHJvcChkYXRhKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGRhdGEpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlR3JpZFN0YXRlKCkge1xuXG4gICAgICAgIGxldCBnYWRnZXRDb3VudCA9IDA7XG5cbiAgICAgICAgaWYgKHRoaXMuZ2V0TW9kZWwoKS5yb3dzKSB7XG4gICAgICAgICAgICB0aGlzLmdldE1vZGVsKCkucm93cy5mb3JFYWNoKGZ1bmN0aW9uIChyb3cpIHtcbiAgICAgICAgICAgICAgICByb3cuY29sdW1ucy5mb3JFYWNoKGZ1bmN0aW9uIChjb2x1bW4pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbHVtbi5nYWRnZXRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2x1bW4uZ2FkZ2V0cy5mb3JFYWNoKGZ1bmN0aW9uIChnYWRnZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBnYWRnZXRDb3VudCsrO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5ub0dhZGdldHMgPSAhZ2FkZ2V0Q291bnQ7XG5cbiAgICAgICAgdGhpcy5kYXNoZWRTdHlsZSA9IHtcbiAgICAgICAgICAgICdib3JkZXItc3R5bGUnOiB0aGlzLm5vR2FkZ2V0cyA/ICdkYXNoZWQnIDogJ25vbmUnLFxuICAgICAgICAgICAgJ2JvcmRlci13aWR0aCc6IHRoaXMubm9HYWRnZXRzID8gJzJweCcgOiAnbm9uZScsXG4gICAgICAgICAgICAnYm9yZGVyLWNvbG9yJzogdGhpcy5ub0dhZGdldHMgPyAnZGFya2dyYXknIDogJ25vbmUnLFxuICAgICAgICAgICAgJ3BhZGRpbmcnOiB0aGlzLm5vR2FkZ2V0cyA/ICc1cHgnIDogJ25vbmUnXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSByZWFkQ29sdW1uc0Zyb21PcmlnaW5hbE1vZGVsKF9tb2RlbCkge1xuXG4gICAgICAgIGNvbnN0IGNvbHVtbnMgPSBbXTtcbiAgICAgICAgX21vZGVsLnJvd3MuZm9yRWFjaChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgICAgICByb3cuY29sdW1ucy5mb3JFYWNoKGZ1bmN0aW9uIChjb2wpIHtcbiAgICAgICAgICAgICAgICBjb2x1bW5zLnB1c2goY29sKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGNvbHVtbnM7XG5cbiAgICB9XG5cbiAgICBwcml2YXRlIGZpbGxHcmlkU3RydWN0dXJlKGRlc3RpbmF0aW9uTW9kZWxTdHJ1Y3R1cmUsIG9yaWdpbmFsQ29sdW1uczogQ29sdW1uW10sIGNvdW50ZXI6IG51bWJlcikge1xuXG4gICAgICAgIGNvbnN0IG1lID0gdGhpcztcblxuICAgICAgICBkZXN0aW5hdGlvbk1vZGVsU3RydWN0dXJlLnJvd3MuZm9yRWFjaChmdW5jdGlvbiAocm93KSB7XG4gICAgICAgICAgICByb3cuY29sdW1ucy5mb3JFYWNoKGZ1bmN0aW9uIChkZXN0aW5hdGlvbkNvbHVtbikge1xuICAgICAgICAgICAgICAgIGlmICghZGVzdGluYXRpb25Db2x1bW4uZ2FkZ2V0cykge1xuICAgICAgICAgICAgICAgICAgICBkZXN0aW5hdGlvbkNvbHVtbi5nYWRnZXRzID0gW107XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChvcmlnaW5hbENvbHVtbnNbY291bnRlcl0pIHtcbiAgICAgICAgICAgICAgICAgICAgbWUuY29weUdhZGdldHMob3JpZ2luYWxDb2x1bW5zW2NvdW50ZXJdLCBkZXN0aW5hdGlvbkNvbHVtbik7XG4gICAgICAgICAgICAgICAgICAgIGNvdW50ZXIrKztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG