UNPKG

ngx-tree-dnd

Version:

Angular 7 support tree with drag-and-drop sortable data tree. It`s fast and smart.

537 lines 45 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /* Copyright (C) 2018 Yaroslav Kikot This project is licensed under the terms of the MIT license. https://github.com/Zicrael/ngx-tree-dnd */ import { Injectable } from '@angular/core'; import { Subject, BehaviorSubject, Observable } from 'rxjs'; import * as i0 from "@angular/core"; export class NgxTreeService { constructor() { this.treeStorage = []; this.onDragStart = new Subject(); this.onDragEnter = new Subject(); this.onDragLeave = new Subject(); this.onDrop = new Subject(); this.onDrag = new Subject(); this.onAllowDrop = new Subject(); this.onDragEnd = new Subject(); this.onAddItem = new Subject(); this.onRenameItem = new Subject(); this.onStartRenameItem = new Subject(); this.onFinishRenameItem = new Subject(); this.onStartDeleteItem = new Subject(); this.onFinishDeleteItem = new Subject(); this.onCancelDeleteItem = new Subject(); this.config = new BehaviorSubject(null); // set default config this.defaulConfig = { showActionButtons: true, showAddButtons: true, showRenameButtons: true, showDeleteButtons: true, showRootActionButtons: true, enableExpandButtons: true, enableDragging: true, rootTitle: 'Root', validationText: 'Enter valid name', minCharacterLength: 1, setItemsAsLinks: false, setFontSize: 16, setIconSize: 14 }; } /* get data and set it on observable. if data = null set empty data array */ /** * @param {?} item * @return {?} */ getLocalData(item) { /** @type {?} */ const data = new Observable(observer => { this.treeStorage = item; if (this.treeStorage && this.treeStorage !== null) { observer.next(this.treeStorage); } else { this.treeStorage = JSON.parse('[]'); observer.next(this.treeStorage); } }); return data; } /* Element finder, it`s find element by id in tree. Returns: finded element, parent array. Watch out, this is recursive method. */ /** * @private * @param {?} list * @param {?} id * @param {?=} parent * @return {?} */ elementFinder(list, id, parent) { for (const item of list) { if (item.id === id) { this.findingResults = { foundItem: item, itemsList: list }; if (parent) { this.findingResults.parentItem = parent; } break; } else { if (item.childrens.length > 0) { this.elementFinder(item.childrens, id, item); } } } } /* Add new item to tree. Its accepts 'type' for detect add root element or children. Emit onAddItem Subject. */ /** * @param {?} id * @param {?} name * @param {?=} parent * @return {?} */ addNewItem(id, name, parent) { /** @type {?} */ let pos = 1; if (parent && parent.childrens.length !== 0) { /** @type {?} */ const parentPrevChildren = parent.childrens.length - 1; /** @type {?} */ const newItemPosition = parent.childrens[parentPrevChildren].options.position + 1; pos = newItemPosition; } /** @type {?} */ const createObj = { id, name, options: { position: pos, edit: true }, childrens: [] }; if (parent != null) { this.elementFinder(this.treeStorage, parent ? parent.id : null); this.findingResults && this.findingResults.foundItem.childrens.push(createObj); } else { this.treeStorage.push(createObj); } /** @type {?} */ const eventEmit = { element: createObj, parent: parent ? this.findingResults.foundItem : 'root' }; this.onAddItem.next(eventEmit); this.clearAction(); } /* Delete element. It`s accepts 'id' for find item on tree. Emit onStartDeleteItem Subject before delete. Emit onFinishDeleteItem Subject after submit delete. Emit onCancelDeleteItem Subject after on cancel delete. */ /** * @param {?} id * @return {?} */ deleteItem(id) { this.elementFinder(this.treeStorage, id); /** @type {?} */ const eventEmit = { element: this.findingResults.foundItem, parent: this.findingResults.parentItem || 'root' }; this.onStartDeleteItem.next(eventEmit); /** @type {?} */ let text; if (this.findingResults.foundItem.name) { text = `Do you really want to delete '${this.findingResults.foundItem.name}'?`; } else { text = `Cancel creating a new item?`; } if (confirm(text)) { this.onFinishDeleteItem.next(eventEmit); /** @type {?} */ const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); this.findingResults.itemsList.splice(i, 1); } else { this.onCancelDeleteItem.next(eventEmit); } this.clearAction(); } /* Trigger start rename element. It`s accepts 'name' and 'id' for find item on tree and set the name. Emit onRenameItem Subject. */ /** * @param {?} element * @return {?} */ startRenameItem(element) { this.elementFinder(this.treeStorage, element.id); // event emit /** @type {?} */ const eventEmit = { element: this.findingResults.foundItem, parent: this.findingResults.parentItem || 'root' }; this.onStartRenameItem.next(eventEmit); } /* Rename element. It`s accepts 'name' and 'id' for find item on tree and set the name. Emit onRenameItem Subject. */ /** * @param {?} name * @param {?} id * @return {?} */ finishRenameItem(name, id) { this.elementFinder(this.treeStorage, id); // code this.findingResults.foundItem.name = name; this.findingResults.foundItem.options.edit = false; // event emit /** @type {?} */ const eventEmit = { element: this.findingResults.foundItem, parent: this.findingResults.parentItem || 'root' }; this.onFinishRenameItem.next(eventEmit); this.clearAction(); } /* Event: ondragstart; On start dragging find element my id and set option currentlyDragging true. */ /** * @param {?} eventObj * @return {?} */ startDragging(eventObj) { this.switchDropButton(true, this.treeStorage); this.onDragStart.next(eventObj); } /* Event: ondrag; Trigger dragging element */ /** * @param {?} eventObj * @return {?} */ onDragProcess(eventObj) { this.onDrag.next(eventObj); } /* Event: ondragend; detect end of drag action */ /** * @param {?} eventObj * @return {?} */ dragEndAction(eventObj) { this.removeDestenationBorders(this.treeStorage); this.switchDropButton(false, this.treeStorage); this.onDragEnd.next(eventObj); } /* Event: enterdropzone; Entering drop zone for styling items. */ /** * @param {?} eventObj * @return {?} */ enterDropZone(eventObj) { this.onDragEnter.next(eventObj); } /* Event: dragover; Detect hover on dropable elements */ /** * @param {?} eventObj * @return {?} */ onDragOver(eventObj) { /** @type {?} */ const el = ((/** @type {?} */ (eventObj.target))); if (el && el.id !== this.isDragging.id) { /** @type {?} */ const elementHalfHeight = eventObj.event.toElement.offsetHeight / 2; if (eventObj.event.offsetY < elementHalfHeight) { el.options.destenationBottom = false; el.options.destenationTop = true; } else { el.options.destenationBottom = true; el.options.destenationTop = false; } this.onAllowDrop.next(eventObj); } } /* Event: leavedropzone; Leave drop zone for restyling items. */ /** * @param {?} eventObj * @return {?} */ leaveDropZone(eventObj) { this.removeDestenationBorders(this.treeStorage); this.onDragLeave.next(eventObj); } /* Event: ondrop; Its use where draggable item drop not on allowed for drop zone: set item option currentlyDragging false. return false. */ /** * @param {?} eventObj * @return {?} */ onDropItem(eventObj) { if (eventObj.target) { /** @type {?} */ const elementHalfHeight = eventObj.event.toElement.offsetHeight / 2; if (eventObj.event.offsetY < elementHalfHeight) { this.changeItemPosition(eventObj.target, 'up'); } else { this.changeItemPosition(eventObj.target, 'down'); } this.onDrop.next(eventObj); } else { /** @type {?} */ const dropZoneId = parseInt(eventObj.event.target.getAttribute('data-id'), null); this.elementFinder(this.treeStorage, this.isDragging.id); /** @type {?} */ const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); /** @type {?} */ const copyItem = this.findingResults.itemsList.splice(i, 1)[0]; this.elementFinder(this.treeStorage, dropZoneId); this.findingResults.foundItem.childrens.push(copyItem); // this.sortTree(); eventObj.target = this.findingResults.foundItem; this.onDrop.next(eventObj); } this.removeDestenationBorders(this.treeStorage); this.switchDropButton(false, this.treeStorage); this.clearAction(); } /* change position of items need set direction before use */ /** * @private * @param {?} el * @param {?} direction * @return {?} */ changeItemPosition(el, direction) { setTimeout(() => { this.elementFinder(this.treeStorage, this.isDragging.id); /** @type {?} */ const i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); /** @type {?} */ const copyItem = this.findingResults.itemsList.splice(i, 1)[0]; // end test /** @type {?} */ const positionTarget = el.options.position; this.elementFinder(this.treeStorage, el.id); if (direction === 'up') { for (const items of this.findingResults.itemsList) { if (items.options.position >= positionTarget) { items.options.position = items.options.position + 1; copyItem.options.position = positionTarget; } } } else { for (const items of this.findingResults.itemsList) { if (items.options.position <= positionTarget) { items.options.position = items.options.position - 1; } } } copyItem.options.position = positionTarget; this.findingResults.itemsList.push(copyItem); this.sortTree(); }); } // get position of item /** * @param {?} item * @return {?} */ getItemPosition(item) { this.elementFinder(this.treeStorage, item.id); /** @type {?} */ let position = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); return ++position; } // sort tree byposition /** * @return {?} */ sortTree() { this.sortElements(this.treeStorage); } // part of sortTree() /** * @private * @param {?} tree * @return {?} */ sortElements(tree) { tree.sort(this.compate); for (const item of tree) { if (item.childrens.length > 0) { this.sortElements(item.childrens); } } } // part of sortTree() /** * @private * @param {?} a * @param {?} b * @return {?} */ compate(a, b) { if (a.options.position < b.options.position) { return -1; } if (a.options.position > b.options.position) { return 1; } return 0; } // clear selectedElement && isDragging from element finder. /** * @return {?} */ clearAction() { this.findingResults = null; } /** * @private * @param {?} data * @return {?} */ removeDestenationBorders(data) { for (const item of data) { item.options.destenationBottom = false; item.options.destenationTop = false; if (item.childrens.length > 0) { this.removeDestenationBorders(item.childrens); } } } /** * @private * @param {?} bool * @param {?} data * @return {?} */ switchDropButton(bool, data) { for (const el of data) { el.options.showActionButtons = !bool; if (el.id !== this.isDragging.id) { el.options.showDropChildZone = bool; } if (el.childrens.length > 0) { this.switchDropButton(bool, el.childrens); } } } } NgxTreeService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] }, ]; /** @nocollapse */ NgxTreeService.ctorParameters = () => []; /** @nocollapse */ NgxTreeService.ngInjectableDef = i0.defineInjectable({ factory: function NgxTreeService_Factory() { return new NgxTreeService(); }, token: NgxTreeService, providedIn: "root" }); if (false) { /** @type {?} */ NgxTreeService.prototype.treeStorage; /** * @type {?} * @private */ NgxTreeService.prototype.findingResults; /** @type {?} */ NgxTreeService.prototype.isDragging; /** @type {?} */ NgxTreeService.prototype.dragEvent; /** @type {?} */ NgxTreeService.prototype.direction; /** @type {?} */ NgxTreeService.prototype.lastExpandState; /** @type {?} */ NgxTreeService.prototype.onDragStart; /** @type {?} */ NgxTreeService.prototype.onDragEnter; /** @type {?} */ NgxTreeService.prototype.onDragLeave; /** @type {?} */ NgxTreeService.prototype.onDrop; /** @type {?} */ NgxTreeService.prototype.onDrag; /** @type {?} */ NgxTreeService.prototype.onAllowDrop; /** @type {?} */ NgxTreeService.prototype.onDragEnd; /** @type {?} */ NgxTreeService.prototype.onAddItem; /** @type {?} */ NgxTreeService.prototype.onRenameItem; /** @type {?} */ NgxTreeService.prototype.onStartRenameItem; /** @type {?} */ NgxTreeService.prototype.onFinishRenameItem; /** @type {?} */ NgxTreeService.prototype.onStartDeleteItem; /** @type {?} */ NgxTreeService.prototype.onFinishDeleteItem; /** @type {?} */ NgxTreeService.prototype.onCancelDeleteItem; /** @type {?} */ NgxTreeService.prototype.config; /** @type {?} */ NgxTreeService.prototype.defaulConfig; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRyZWUtZG5kLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtdHJlZS1kbmQvIiwic291cmNlcyI6WyJsaWIvbmd4LXRyZWUtZG5kLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBS0EsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUM7O0FBTTVELE1BQU0sT0FBTyxjQUFjO0lBMkJ6QjtRQTFCQSxnQkFBVyxHQUFnQixFQUFFLENBQUM7UUFTOUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGdCQUFXLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNqQyxnQkFBVyxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDakMsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNsQyxzQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3ZDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsc0JBQWlCLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUN2Qyx1QkFBa0IsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3hDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsV0FBTSxHQUFHLElBQUksZUFBZSxDQUFNLElBQUksQ0FBQyxDQUFDO1FBSXRDLHFCQUFxQjtRQUNyQixJQUFJ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Y2VzQ29udGVudCI6WyIvKlxuIENvcHlyaWdodCAoQykgMjAxOCBZYXJvc2xhdiBLaWtvdFxuIFRoaXMgcHJvamVjdCBpcyBsaWNlbnNlZCB1bmRlciB0aGUgdGVybXMgb2YgdGhlIE1JVCBsaWNlbnNlLlxuIGh0dHBzOi8vZ2l0aHViLmNvbS9aaWNyYWVsL25neC10cmVlLWRuZFxuICovXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBTdWJqZWN0LCBCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IFRyZWVNb2RlbCwgVHJlZUNvbmZpZywgRmluZGluZ1Jlc3VsdHMgfSBmcm9tICcuL21vZGVscy90cmVlLXZpZXcubW9kZWwnO1xuXG5ASW5qZWN0YWJsZSh7XG4gIHByb3ZpZGVkSW46ICdyb290J1xufSlcbmV4cG9ydCBjbGFzcyBOZ3hUcmVlU2VydmljZSB7XG4gIHRyZWVTdG9yYWdlOiBUcmVlTW9kZWxbXSA9IFtdO1xuICBwcml2YXRlIGZpbmRpbmdSZXN1bHRzOiBGaW5kaW5nUmVzdWx0cztcbiAgLy8gbGlzdE9mU2VsZWN0ZWRFbGVtZW50OiBUcmVlTW9kZWxbXTtcbiAgLy8gcGFyZW50T2ZTZWxlY3RlZDogVHJlZU1vZGVsO1xuICAvLyBwcml2YXRlIHNlbGVjdGVkRWxlbWVudDogVHJlZU1vZGVsO1xuICBpc0RyYWdnaW5nOiBUcmVlTW9kZWw7XG4gIGRyYWdFdmVudDoge307XG4gIGRpcmVjdGlvbjogc3RyaW5nO1xuICBsYXN0RXhwYW5kU3RhdGU6IGJvb2xlYW47XG4gIG9uRHJhZ1N0YXJ0ID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkRyYWdFbnRlciA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25EcmFnTGVhdmUgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJvcCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25EcmFnID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkFsbG93RHJvcCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25EcmFnRW5kID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkFkZEl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uUmVuYW1lSXRlbSA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25TdGFydFJlbmFtZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRmluaXNoUmVuYW1lSXRlbSA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25TdGFydERlbGV0ZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRmluaXNoRGVsZXRlSXRlbSA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25DYW5jZWxEZWxldGVJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBjb25maWcgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGFueT4obnVsbCk7XG4gIGRlZmF1bENvbmZpZzogVHJlZUNvbmZpZztcblxuICBjb25zdHJ1Y3RvcigpIHtcbiAgICAvLyBzZXQgZGVmYXVsdCBjb25maWdcbiAgICB0aGlzLmRlZmF1bENvbmZpZyA9IHtcbiAgICAgIHNob3dBY3Rpb25CdXR0b25zOiB0cnVlLFxuICAgICAgc2hvd0FkZEJ1dHRvbnM6IHRydWUsXG4gICAgICBzaG93UmVuYW1lQnV0dG9uczogdHJ1ZSxcbiAgICAgIHNob3dEZWxldGVCdXR0b25zOiB0cnVlLFxuICAgICAgc2hvd1Jvb3RBY3Rpb25CdXR0b25zOiB0cnVlLFxuICAgICAgZW5hYmxlRXhwYW5kQnV0dG9uczogdHJ1ZSxcbiAgICAgIGVuYWJsZURyYWdnaW5nOiB0cnVlLFxuICAgICAgcm9vdFRpdGxlOiAnUm9vdCcsXG4gICAgICB2YWxpZGF0aW9uVGV4dDogJ0VudGVyIHZhbGlkIG5hbWUnLFxuICAgICAgbWluQ2hhcmFjdGVyTGVuZ3RoOiAxLFxuICAgICAgc2V0SXRlbXNBc0xpbmtzOiBmYWxzZSxcbiAgICAgIHNldEZvbnRTaXplOiAxNixcbiAgICAgIHNldEljb25TaXplOiAxNFxuICAgIH07XG4gIH1cblxuICAvKlxuICAgIGdldCBkYXRhIGFuZCBzZXQgaXQgb24gb2JzZXJ2YWJsZS5cbiAgICBpZiBkYXRhID0gbnVsbCBzZXQgZW1wdHkgZGF0YSBhcnJheVxuICAqL1xuICBwdWJsaWMgZ2V0TG9jYWxEYXRhKGl0ZW0pIHtcbiAgICBjb25zdCBkYXRhID0gbmV3IE9ic2VydmFibGUob2JzZXJ2ZXIgPT4ge1xuICAgIHRoaXMudHJlZVN0b3JhZ2UgPSBpdGVtO1xuICAgICAgaWYgKCB0aGlzLnRyZWVTdG9yYWdlICYmIHRoaXMudHJlZVN0b3JhZ2UgIT09IG51bGwgKSB7XG4gICAgICAgIG9ic2VydmVyLm5leHQodGhpcy50cmVlU3RvcmFnZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnRyZWVTdG9yYWdlICA9IEpTT04ucGFyc2UoJ1tdJyk7XG4gICAgICAgIG9ic2VydmVyLm5leHQodGhpcy50cmVlU3RvcmFnZSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cblxuICAvKlxuICAgRWxlbWVudCBmaW5kZXIsIGl0YHMgZmluZCBlbGVtZW50IGJ5IGlkIGluIHRyZWUuXG4gICBSZXR1cm5zOiBmaW5kZWQgZWxlbWVudCwgcGFyZW50IGFycmF5LlxuICAgV2F0Y2ggb3V0LCB0aGlzIGlzIHJlY3Vyc2l2ZSBtZXRob2QuXG4gICovXG4gICBwcml2YXRlIGVsZW1lbnRGaW5kZXIobGlzdCwgaWQsIHBhcmVudD8pIHtcbiAgICAgZm9yIChjb25zdCBpdGVtIG9mIGxpc3QpIHtcbiAgICAgICBpZiAoaXRlbS5pZCA9PT0gaWQpIHtcbiAgICAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMgPSB7XG4gICAgICAgICAgIGZvdW5kSXRlbTogaXRlbSxcbiAgICAgICAgICAgaXRlbXNMaXN0OiBsaXN0XG4gICAgICAgICB9XG4gICAgICAgICBpZiAocGFyZW50KSB7XG4gICAgICAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMucGFyZW50SXRlbSA9IHBhcmVudDtcbiAgICAgICAgIH1cbiAgICAgICAgIGJyZWFrO1xuICAgICAgIH0gZWxzZSB7XG4gICAgICAgICBpZiAoaXRlbS5jaGlsZHJlbnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICB0aGlzLmVsZW1lbnRGaW5kZXIoaXRlbS5jaGlsZHJlbnMsIGlkLCBpdGVtKTtcbiAgICAgICAgIH1cbiAgICAgICB9XG4gICAgIH1cblxuICB9XG5cblxuICAgLypcbiAgIEFkZCBuZXcgaXRlbSB0byB0cmVlLlxuICAgSXRzIGFjY2VwdHMgJ3R5cGUnIGZvciBkZXRlY3QgYWRkIHJvb3QgZWxlbWVudCBvciBjaGlsZHJlbi5cbiAgIEVtaXQgb25BZGRJdGVtIFN1YmplY3QuXG4gICovXG4gIHB1YmxpYyBhZGROZXdJdGVtKGlkLCBuYW1lLCBwYXJlbnQ/KSB7XG4gICAgbGV0IHBvcyA9IDE7XG4gICAgaWYgKHBhcmVudCAmJiBwYXJlbnQuY2hpbGRyZW5zLmxlbmd0aCAhPT0gMCkge1xuICAgICAgY29uc3QgcGFyZW50UHJldkNoaWxkcmVuID0gcGFyZW50LmNoaWxkcmVucy5sZW5ndGggLSAxO1xuICAgICAgY29uc3QgbmV3SXRlbVBvc2l0aW9uID0gcGFyZW50LmNoaWxkcmVuc1twYXJlbnRQcmV2Q2hpbGRyZW5dLm9wdGlvbnMucG9zaXRpb24gKyAxO1xuICAgICAgcG9zID0gbmV3SXRlbVBvc2l0aW9uO1xuICAgIH1cbiAgICBjb25zdCBjcmVhdGVPYmo6IFRyZWVNb2RlbCA9IHtcbiAgICAgIGlkLFxuICAgICAgbmFtZSxcbiAgICAgIG9wdGlvbnM6ICB7XG4gICAgICAgIHBvc2l0aW9uOiBwb3MsXG4gICAgICAgIGVkaXQ6IHRydWVcbiAgICAgIH0sXG4gICAgICBjaGlsZHJlbnM6IFtdXG4gICAgfTtcbiAgICBcbiAgICBpZihwYXJlbnQgIT0gbnVsbCkge1xuICAgICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIHBhcmVudCA/IHBhcmVudC5pZCA6IG51bGwpO1xuICAgICAgdGhpcy5maW5kaW5nUmVzdWx0cyAmJiB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbS5jaGlsZHJlbnMucHVzaChjcmVhdGVPYmopO1xuICAgIH1cbiAgICBlbHNle1xuICAgICAgdGhpcy50cmVlU3RvcmFnZS5wdXNoKGNyZWF0ZU9iaik7XG4gICAgfVxuICAgIFxuICAgIGNvbnN0IGV2ZW50RW1pdCA9IHtcbiAgICAgIGVsZW1lbnQ6IGNyZWF0ZU9iaixcbiAgICAgIHBhcmVudDogcGFyZW50ID8gdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0gOiAncm9vdCdcbiAgICB9O1xuXG4gICAgdGhpcy5vbkFkZEl0ZW0ubmV4dChldmVudEVtaXQpO1xuICAgIHRoaXMuY2xlYXJBY3Rpb24oKTtcbiAgfVxuXG4gIC8qXG4gICBEZWxldGUgZWxlbWVudC5cbiAgIEl0YHMgYWNjZXB0cyAnaWQnIGZvciBmaW5kIGl0ZW0gb24gdHJlZS5cbiAgIEVtaXQgb25TdGFydERlbGV0ZUl0ZW0gU3ViamVjdCBiZWZvcmUgZGVsZXRlLlxuICAgRW1pdCBvbkZpbmlzaERlbGV0ZUl0ZW0gU3ViamVjdCBhZnRlciBzdWJtaXQgZGVsZXRlLlxuICAgRW1pdCBvbkNhbmNlbERlbGV0ZUl0ZW0gU3ViamVjdCBhZnRlciBvbiBjYW5jZWwgZGVsZXRlLlxuICAqL1xuICBwdWJsaWMgZGVsZXRlSXRlbShpZCkge1xuICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBpZCk7XG4gICAgY29uc3QgZXZlbnRFbWl0ID0ge1xuICAgICAgZWxlbWVudDogdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0sXG4gICAgICBwYXJlbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMucGFyZW50SXRlbSB8fCAncm9vdCdcbiAgICB9O1xuICAgIHRoaXMub25TdGFydERlbGV0ZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICAgIGxldCB0ZXh0OiBzdHJpbmc7XG4gICAgaWYoIHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLm5hbWUgKSB7XG4gICAgICB0ZXh0ID0gYERvIHlvdSByZWFsbHkgd2FudCB0byBkZWxldGUgJyR7dGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0ubmFtZX0nP2A7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRleHQgPSBgQ2FuY2VsIGNyZWF0aW5nIGEgbmV3IGl0ZW0/YDtcbiAgICB9XG4gICAgaWYoY29uZmlybSh0ZXh0KSkge1xuICAgICAgdGhpcy5vbkZpbmlzaERlbGV0ZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICAgICAgY29uc3QgaSA9IHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0LmluZGV4T2YodGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0pO1xuICAgICAgdGhpcy5maW5kaW5nUmVzdWx0cy5pdGVtc0xpc3Quc3BsaWNlKGksIDEpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm9uQ2FuY2VsRGVsZXRlSXRlbS5uZXh0KGV2ZW50RW1pdCk7XG4gICAgfVxuICAgIHRoaXMuY2xlYXJBY3Rpb24oKTtcbiAgfVxuXG4gIC8qXG4gICBUcmlnZ2VyIHN0YXJ0IHJlbmFtZSBlbGVtZW50LlxuICAgSXRgcyBhY2NlcHRzICduYW1lJyBhbmQgJ2lkJyBmb3IgZmluZCBpdGVtIG9uIHRyZWUgYW5kIHNldCB0aGUgbmFtZS5cbiAgIEVtaXQgb25SZW5hbWVJdGVtIFN1YmplY3QuXG4gICovXG4gcHVibGljIHN0YXJ0UmVuYW1lSXRlbShlbGVtZW50KSB7XG4gICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIGVsZW1lbnQuaWQpO1xuICAgIC8vIGV2ZW50IGVtaXRcbiAgICBjb25zdCBldmVudEVtaXQgPSB7XG4gICAgICBlbGVtZW50OiB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbSxcbiAgICAgIHBhcmVudDogdGhpcy5maW5kaW5nUmVzdWx0cy5wYXJlbnRJdGVtIHx8ICdyb290J1xuICAgIH07XG4gICAgdGhpcy5vblN0YXJ0UmVuYW1lSXRlbS5uZXh0KGV2ZW50RW1pdCk7XG4gIH1cblxuICAvKlxuICAgUmVuYW1lIGVsZW1lbnQuXG4gICBJdGBzIGFjY2VwdHMgJ25hbWUnIGFuZCAnaWQnIGZvciBmaW5kIGl0ZW0gb24gdHJlZSBhbmQgc2V0IHRoZSBuYW1lLlxuICAgRW1pdCBvblJlbmFtZUl0ZW0gU3ViamVjdC5cbiAgKi9cbiAgcHVibGljIGZpbmlzaFJlbmFtZUl0ZW0obmFtZSwgaWQpIHtcbiAgICB0aGlzLmVsZW1lbnRGaW5kZXIodGhpcy50cmVlU3RvcmFnZSwgaWQpO1xuICAgIC8vIGNvZGVcbiAgICB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbS5uYW1lID0gbmFtZTtcbiAgICB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbS5vcHRpb25zLmVkaXQgPSBmYWxzZTtcbiAgICAvLyBldmVudCBlbWl0XG4gICAgY29uc3QgZXZlbnRFbWl0ID0ge1xuICAgICAgZWxlbWVudDogdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0sXG4gICAgICBwYXJlbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMucGFyZW50SXRlbSB8fCAncm9vdCdcbiAgICB9O1xuICAgIHRoaXMub25GaW5pc2hSZW5hbWVJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgRXZlbnQ6IG9uZHJhZ3N0YXJ0O1xuICAgT24gc3RhcnQgZHJhZ2dpbmcgZmluZCBlbGVtZW50IG15IGlkIGFuZCBzZXQgb3B0aW9uIGN1cnJlbnRseURyYWdnaW5nIHRydWUuXG4gICovXG4gIHB1YmxpYyBzdGFydERyYWdnaW5nKGV2ZW50T2JqKSB7XG4gICAgdGhpcy5zd2l0Y2hEcm9wQnV0dG9uKHRydWUsIHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgIHRoaXMub25EcmFnU3RhcnQubmV4dChldmVudE9iaik7XG4gIH1cblxuICAvKlxuICAgRXZlbnQ6IG9uZHJhZztcbiAgIFRyaWdnZXIgZHJhZ2dpbmcgZWxlbWVudFxuICAqL1xuICBwdWJsaWMgb25EcmFnUHJvY2VzcyhldmVudE9iaikge1xuICAgIHRoaXMub25EcmFnLm5leHQoZXZlbnRPYmopO1xuICB9XG5cbiAgLypcbiAgIEV2ZW50OiBvbmRyYWdlbmQ7XG4gICBkZXRlY3QgZW5kIG9mIGRyYWcgYWN0aW9uXG4gICovXG4gIHB1YmxpYyBkcmFnRW5kQWN0aW9uKGV2ZW50T2JqKSB7XG4gICAgdGhpcy5yZW1vdmVEZXN0ZW5hdGlvbkJvcmRlcnModGhpcy50cmVlU3RvcmFnZSk7XG4gICAgdGhpcy5zd2l0Y2hEcm9wQnV0dG9uKGZhbHNlLCB0aGlzLnRyZWVTdG9yYWdlKTtcbiAgICB0aGlzLm9uRHJhZ0VuZC5uZXh0KGV2ZW50T2JqKTtcbiAgfVxuXG4gIC8qXG4gICAgRXZlbnQ6IGVudGVyZHJvcHpvbmU7XG4gICAgRW50ZXJpbmcgZHJvcCB6b25lIGZvciBzdHlsaW5nIGl0ZW1zLlxuICAqL1xuICBwdWJsaWMgZW50ZXJEcm9wWm9uZShldmVudE9iaikge1xuICAgIHRoaXMub25EcmFnRW50ZXIubmV4dChldmVudE9iaik7XG4gIH1cblxuXG4gIC8qXG4gICAgRXZlbnQ6IGRyYWdvdmVyO1xuICAgIERldGVjdCBob3ZlciBvbiBkcm9wYWJsZSBlbGVtZW50c1xuICAqL1xuICBwdWJsaWMgb25EcmFnT3ZlcihldmVudE9iaikge1xuICAgIGNvbnN0IGVsID0gKGV2ZW50T2JqLnRhcmdldCBhcyBUcmVlTW9kZWwpO1xuICAgIGlmIChlbCAmJiBlbC5pZCAhPT0gdGhpcy5pc0RyYWdnaW5nLmlkICkge1xuICAgICAgY29uc3QgZWxlbWVudEhhbGZIZWlnaHQgPSBldmVudE9iai5ldmVudC50b0VsZW1lbnQub2Zmc2V0SGVpZ2h0IC8gMjtcbiAgICAgIGlmIChldmVudE9iai5ldmVudC5vZmZzZXRZIDwgZWxlbWVudEhhbGZIZWlnaHQpIHtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvbkJvdHRvbSA9IGZhbHNlO1xuICAgICAgICBlbC5vcHRpb25zLmRlc3RlbmF0aW9uVG9wID0gdHJ1ZTtcbiAgICAgIH0gZWxzZSAge1xuICAgICAgICBlbC5vcHRpb25zLmRlc3RlbmF0aW9uQm90dG9tID0gdHJ1ZTtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvblRvcCA9IGZhbHNlO1xuICAgICAgfVxuICAgICAgdGhpcy5vbkFsbG93RHJvcC5uZXh0KGV2ZW50T2JqKTtcbiAgICB9XG4gIH1cblxuICAvKlxuICAgIEV2ZW50OiBsZWF2ZWRyb3B6b25lO1xuICAgIExlYXZlIGRyb3Agem9uZSBmb3IgcmVzdHlsaW5nIGl0ZW1zLlxuICAqL1xuICBwdWJsaWMgbGVhdmVEcm9wWm9uZShldmVudE9iaikge1xuICAgICAgdGhpcy5yZW1vdmVEZXN0ZW5hdGlvbkJvcmRlcnModGhpcy50cmVlU3RvcmFnZSk7XG4gICAgICB0aGlzLm9uRHJhZ0xlYXZlLm5leHQoZXZlbnRPYmopO1xuICB9XG5cbiAgLypcbiAgICBFdmVudDogb25kcm9wO1xuICAgIEl0cyB1c2Ugd2hlcmUgZHJhZ2dhYmxlIGl0ZW0gZHJvcCBub3Qgb24gYWxsb3dlZCBmb3IgZHJvcCB6b25lOlxuICAgIHNldCBpdGVtIG9wdGlvbiBjdXJyZW50bHlEcmFnZ2luZyBmYWxzZS5cbiAgICByZXR1cm4gZmFsc2UuXG4gKi9cbiAgcHVibGljIG9uRHJvcEl0ZW0oZXZlbnRPYmopIHtcbiAgICBpZiAoIGV2ZW50T2JqLnRhcmdldCApIHtcbiAgICAgIGNvbnN0IGVsZW1lbnRIYWxmSGVpZ2h0ID0gZXZlbnRPYmouZXZlbnQudG9FbGVtZW50Lm9mZnNldEhlaWdodCAvIDI7XG4gICAgICAgIGlmICggIGV2ZW50T2JqLmV2ZW50Lm9mZnNldFkgPCBlbGVtZW50SGFsZkhlaWdodCApIHtcbiAgICAgICAgICB0aGlzLmNoYW5nZUl0ZW1Qb3NpdGlvbihldmVudE9iai50YXJnZXQsICd1cCcpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMuY2hhbmdlSXRlbVBvc2l0aW9uKGV2ZW50T2JqLnRhcmdldCwgJ2Rvd24nKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm9uRHJvcC5uZXh0KGV2ZW50T2JqKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZHJvcFpvbmVJZCA9IHBhcnNlSW50KGV2ZW50T2JqLmV2ZW50LnRhcmdldC5nZXRBdHRyaWJ1dGUoJ2RhdGEtaWQnKSwgbnVsbCk7XG4gICAgICB0aGlzLmVsZW1lbnRGaW5kZXIodGhpcy50cmVlU3RvcmFnZSwgdGhpcy5pc0RyYWdnaW5nLmlkKTtcbiAgICAgIGNvbnN0IGkgPSB0aGlzLmZpbmRpbmdSZXN1bHRzLml0ZW1zTGlzdC5pbmRleE9mKHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtKTtcbiAgICAgIGNvbnN0IGNvcHlJdGVtID0gdGhpcy5maW5kaW5nUmVzdWx0cy5pdGVtc0xpc3Quc3BsaWNlKGksIDEpWzBdO1xuICAgICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIGRyb3Bab25lSWQpO1xuICAgICAgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0uY2hpbGRyZW5zLnB1c2goY29weUl0ZW0pO1xuICAgICAgLy8gdGhpcy5zb3J0VHJlZSgpO1xuICAgICAgZXZlbnRPYmoudGFyZ2V0ID0gdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW07XG4gICAgICB0aGlzLm9uRHJvcC5uZXh0KGV2ZW50T2JqKTtcbiAgICB9XG4gICAgdGhpcy5yZW1vdmVEZXN0ZW5hdGlvbkJvcmRlcnModGhpcy50cmVlU3RvcmFnZSk7XG4gICAgdGhpcy5zd2l0Y2hEcm9wQnV0dG9uKGZhbHNlLCB0aGlzLnRyZWVTdG9yYWdlKTtcbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgIGNoYW5nZSBwb3NpdGlvbiBvZiBpdGVtc1xuICAgIG5lZWQgc2V0IGRpcmVjdGlvbiBiZWZvcmUgdXNlXG4gICovXG4gIHByaXZhdGUgY2hhbmdlSXRlbVBvc2l0aW9uKGVsLCBkaXJlY3Rpb24pIHtcbiAgICBzZXRUaW1lb3V0KCAoKSA9PiB7XG4gICAgICB0aGlzLmVsZW1lbnRGaW5kZXIodGhpcy50cmVlU3RvcmFnZSwgdGhpcy5pc0RyYWdnaW5nLmlkKTtcbiAgICAgIGNvbnN0IGkgPSB0aGlzLmZpbmRpbmdSZXN1bHRzLml0ZW1zTGlzdC5pbmRleE9mKHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtKTtcbiAgICAgIGNvbnN0IGNvcHlJdGVtID0gdGhpcy5maW5kaW5nUmVzdWx0cy5pdGVtc0xpc3Quc3BsaWNlKGksIDEpWzBdO1xuICAgICAgLy8gZW5kIHRlc3RcbiAgICAgIGNvbnN0IHBvc2l0aW9uVGFyZ2V0ID0gZWwub3B0aW9ucy5wb3NpdGlvbjtcbiAgICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBlbC5pZCk7XG4gICAgICBpZiAoZGlyZWN0aW9uID09PSAndXAnKSB7XG4gICAgICAgIGZvciAoY29uc3QgaXRlbXMgb2YgdGhpcy5maW5kaW5nUmVzdWx0cy5pdGVtc0xpc3QpIHtcbiAgICAgICAgICBpZiAoIGl0ZW1zLm9wdGlvbnMucG9zaXRpb24gPj0gcG9zaXRpb25UYXJnZXQgKSB7XG4gICAgICAgICAgICBpdGVtcy5vcHRpb25zLnBvc2l0aW9uID0gaXRlbXMub3B0aW9ucy5wb3NpdGlvbiArIDE7XG4gICAgICAgICAgICBjb3B5SXRlbS5vcHRpb25zLnBvc2l0aW9uID0gcG9zaXRpb25UYXJnZXQ7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBmb3IgKGNvbnN0IGl0ZW1zIG9mIHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0KSB7XG4gICAgICAgICAgaWYgKCBpdGVtcy5vcHRpb25zLnBvc2l0aW9uIDw9ICBwb3NpdGlvblRhcmdldCApIHtcbiAgICAgICAgICAgIGl0ZW1zLm9wdGlvbnMucG9zaXRpb24gPSBpdGVtcy5vcHRpb25zLnBvc2l0aW9uIC0gMTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNvcHlJdGVtLm9wdGlvbnMucG9zaXRpb24gPSBwb3NpdGlvblRhcmdldDtcbiAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0LnB1c2goY29weUl0ZW0pO1xuICAgICAgdGhpcy5zb3J0VHJlZSgpO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gZ2V0IHBvc2l0aW9uIG9mIGl0ZW1cbiAgcHVibGljIGdldEl0ZW1Qb3NpdGlvbihpdGVtKSB7XG4gICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIGl0ZW0uaWQpO1xuICAgIGxldCBwb3NpdGlvbiA9IHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0LmluZGV4T2YodGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0pO1xuICAgIHJldHVybiArK3Bvc2l0aW9uO1xuICB9XG5cbiAgLy8gc29ydCB0cmVlIGJ5cG9zaXRpb25cbiAgcHVibGljIHNvcnRUcmVlKCkge1xuICAgIHRoaXMuc29ydEVsZW1lbnRzKHRoaXMudHJlZVN0b3JhZ2UpO1xuICB9XG5cbiAgLy8gcGFydCBvZiBzb3J0VHJlZSgpXG4gIHByaXZhdGUgc29ydEVsZW1lbnRzICh0cmVlKSB7XG4gICAgdHJlZS5zb3J0KCB0aGlzLmNvbXBhdGUgKTtcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgdHJlZSApIHtcbiAgICAgIGlmIChpdGVtLmNoaWxkcmVucy5sZW5ndGggPiAwKSB7XG4gICAgICAgdGhpcy5zb3J0RWxlbWVudHMoaXRlbS5jaGlsZHJlbnMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIHBhcnQgb2Ygc29ydFRyZWUoKVxuICBwcml2YXRlIGNvbXBhdGUoYSwgYikge1xuICAgICAgaWYgKGEub3B0aW9ucy5wb3NpdGlvbiA8IGIub3B0aW9ucy5wb3NpdGlvbikge1xuICAgICAgICByZXR1cm4gLTE7XG4gICAgICB9XG4gICAgICBpZiAoYS5vcHRpb25zLnBvc2l0aW9uID4gYi5vcHRpb25zLnBvc2l0aW9uKSB7XG4gICAgICAgIHJldHVybiAxO1xuICAgICAgfVxuICAgICAgcmV0dXJuIDA7XG4gIH1cblxuICAvLyBjbGVhciBzZWxlY3RlZEVsZW1lbnQgJiYgaXNEcmFnZ2luZyBmcm9tIGVsZW1lbnQgZmluZGVyLlxuICBwdWJsaWMgY2xlYXJBY3Rpb24oKSB7XG4gICAgdGhpcy5maW5kaW5nUmVzdWx0cyA9IG51bGw7XG4gIH1cblxuICBwcml2YXRlIHJlbW92ZURlc3RlbmF0aW9uQm9yZGVycyhkYXRhKSB7XG4gICAgZm9yIChjb25zdCBpdGVtIG9mIGRhdGEpIHtcbiAgICAgIGl0ZW0ub3B0aW9ucy5kZXN0ZW5hdGlvbkJvdHRvbSA9IGZhbHNlO1xuICAgICAgaXRlbS5vcHRpb25zLmRlc3RlbmF0aW9uVG9wID0gZmFsc2U7XG4gICAgICBpZiAoaXRlbS5jaGlsZHJlbnMubGVuZ3RoID4gMCkge1xuICAgICAgICB0aGlzLnJlbW92ZURlc3RlbmF0aW9uQm9yZGVycyhpdGVtLmNoaWxkcmVucyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBzd2l0Y2hEcm9wQnV0dG9uKGJvb2wsIGRhdGEpIHtcbiAgICBmb3IgKGNvbnN0IGVsIG9mIGRhdGEpIHtcbiAgICAgIGVsLm9wdGlvbnMuc2hvd0FjdGlvbkJ1dHRvbnMgPSAhYm9vbDtcbiAgICAgIGlmIChlbC5pZCAhPT0gdGhpcy5pc0RyYWdnaW5nLmlkKSB7XG4gICAgICAgIGVsLm9wdGlvbnMuc2hvd0Ryb3BDaGlsZFpvbmUgPSBib29sO1xuICAgICAgfVxuICAgICAgaWYgKGVsLmNoaWxkcmVucy5sZW5ndGggPiAwKSB7XG4gICAgICAgIHRoaXMuc3dpdGNoRHJvcEJ1dHRvbihib29sLCBlbC5jaGlsZHJlbnMpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuIl19