UNPKG

ngx-tree-dnd

Version:

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

848 lines 55.3 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import * as tslib_1 from "tslib"; /* 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"; var NgxTreeService = /** @class */ (function () { function NgxTreeService() { 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 */ /* get data and set it on observable. if data = null set empty data array */ /** * @param {?} item * @return {?} */ NgxTreeService.prototype.getLocalData = /* get data and set it on observable. if data = null set empty data array */ /** * @param {?} item * @return {?} */ function (item) { var _this = this; /** @type {?} */ var data = new Observable(function (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. */ /* 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 {?} */ NgxTreeService.prototype.elementFinder = /* 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 {?} */ function (list, id, parent) { var e_1, _a; try { for (var list_1 = tslib_1.__values(list), list_1_1 = list_1.next(); !list_1_1.done; list_1_1 = list_1.next()) { var item = list_1_1.value; 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); } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (list_1_1 && !list_1_1.done && (_a = list_1.return)) _a.call(list_1); } finally { if (e_1) throw e_1.error; } } }; /* Add new item to tree. Its accepts 'type' for detect add root element or children. Emit onAddItem Subject. */ /* 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 {?} */ NgxTreeService.prototype.addNewItem = /* 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 {?} */ function (id, name, parent) { /** @type {?} */ var pos = 1; if (parent && parent.childrens.length !== 0) { /** @type {?} */ var parentPrevChildren = parent.childrens.length - 1; /** @type {?} */ var newItemPosition = parent.childrens[parentPrevChildren].options.position + 1; pos = newItemPosition; } /** @type {?} */ var createObj = { id: id, name: 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 {?} */ var 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. */ /* 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 {?} */ NgxTreeService.prototype.deleteItem = /* 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 {?} */ function (id) { this.elementFinder(this.treeStorage, id); /** @type {?} */ var eventEmit = { element: this.findingResults.foundItem, parent: this.findingResults.parentItem || 'root' }; this.onStartDeleteItem.next(eventEmit); /** @type {?} */ var 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 {?} */ var 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. */ /* 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 {?} */ NgxTreeService.prototype.startRenameItem = /* 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 {?} */ function (element) { this.elementFinder(this.treeStorage, element.id); // event emit /** @type {?} */ var 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. */ /* 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 {?} */ NgxTreeService.prototype.finishRenameItem = /* 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 {?} */ function (name, id) { this.elementFinder(this.treeStorage, id); // code this.findingResults.foundItem.name = name; this.findingResults.foundItem.options.edit = false; // event emit /** @type {?} */ var 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. */ /* Event: ondragstart; On start dragging find element my id and set option currentlyDragging true. */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.startDragging = /* Event: ondragstart; On start dragging find element my id and set option currentlyDragging true. */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { this.switchDropButton(true, this.treeStorage); this.onDragStart.next(eventObj); }; /* Event: ondrag; Trigger dragging element */ /* Event: ondrag; Trigger dragging element */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.onDragProcess = /* Event: ondrag; Trigger dragging element */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { this.onDrag.next(eventObj); }; /* Event: ondragend; detect end of drag action */ /* Event: ondragend; detect end of drag action */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.dragEndAction = /* Event: ondragend; detect end of drag action */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { this.removeDestenationBorders(this.treeStorage); this.switchDropButton(false, this.treeStorage); this.onDragEnd.next(eventObj); }; /* Event: enterdropzone; Entering drop zone for styling items. */ /* Event: enterdropzone; Entering drop zone for styling items. */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.enterDropZone = /* Event: enterdropzone; Entering drop zone for styling items. */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { this.onDragEnter.next(eventObj); }; /* Event: dragover; Detect hover on dropable elements */ /* Event: dragover; Detect hover on dropable elements */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.onDragOver = /* Event: dragover; Detect hover on dropable elements */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { /** @type {?} */ var el = ((/** @type {?} */ (eventObj.target))); if (el && el.id !== this.isDragging.id) { /** @type {?} */ var 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. */ /* Event: leavedropzone; Leave drop zone for restyling items. */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.leaveDropZone = /* Event: leavedropzone; Leave drop zone for restyling items. */ /** * @param {?} eventObj * @return {?} */ function (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. */ /* Event: ondrop; Its use where draggable item drop not on allowed for drop zone: set item option currentlyDragging false. return false. */ /** * @param {?} eventObj * @return {?} */ NgxTreeService.prototype.onDropItem = /* Event: ondrop; Its use where draggable item drop not on allowed for drop zone: set item option currentlyDragging false. return false. */ /** * @param {?} eventObj * @return {?} */ function (eventObj) { if (eventObj.target) { /** @type {?} */ var 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 {?} */ var dropZoneId = parseInt(eventObj.event.target.getAttribute('data-id'), null); this.elementFinder(this.treeStorage, this.isDragging.id); /** @type {?} */ var i = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); /** @type {?} */ var 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 */ /* change position of items need set direction before use */ /** * @private * @param {?} el * @param {?} direction * @return {?} */ NgxTreeService.prototype.changeItemPosition = /* change position of items need set direction before use */ /** * @private * @param {?} el * @param {?} direction * @return {?} */ function (el, direction) { var _this = this; setTimeout(function () { var e_2, _a, e_3, _b; _this.elementFinder(_this.treeStorage, _this.isDragging.id); /** @type {?} */ var i = _this.findingResults.itemsList.indexOf(_this.findingResults.foundItem); /** @type {?} */ var copyItem = _this.findingResults.itemsList.splice(i, 1)[0]; // end test /** @type {?} */ var positionTarget = el.options.position; _this.elementFinder(_this.treeStorage, el.id); if (direction === 'up') { try { for (var _c = tslib_1.__values(_this.findingResults.itemsList), _d = _c.next(); !_d.done; _d = _c.next()) { var items = _d.value; if (items.options.position >= positionTarget) { items.options.position = items.options.position + 1; copyItem.options.position = positionTarget; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (_d && !_d.done && (_a = _c.return)) _a.call(_c); } finally { if (e_2) throw e_2.error; } } } else { try { for (var _e = tslib_1.__values(_this.findingResults.itemsList), _f = _e.next(); !_f.done; _f = _e.next()) { var items = _f.value; if (items.options.position <= positionTarget) { items.options.position = items.options.position - 1; } } } catch (e_3_1) { e_3 = { error: e_3_1 }; } finally { try { if (_f && !_f.done && (_b = _e.return)) _b.call(_e); } finally { if (e_3) throw e_3.error; } } } copyItem.options.position = positionTarget; _this.findingResults.itemsList.push(copyItem); _this.sortTree(); }); }; // get position of item // get position of item /** * @param {?} item * @return {?} */ NgxTreeService.prototype.getItemPosition = // get position of item /** * @param {?} item * @return {?} */ function (item) { this.elementFinder(this.treeStorage, item.id); /** @type {?} */ var position = this.findingResults.itemsList.indexOf(this.findingResults.foundItem); return ++position; }; // sort tree byposition // sort tree byposition /** * @return {?} */ NgxTreeService.prototype.sortTree = // sort tree byposition /** * @return {?} */ function () { this.sortElements(this.treeStorage); }; // part of sortTree() // part of sortTree() /** * @private * @param {?} tree * @return {?} */ NgxTreeService.prototype.sortElements = // part of sortTree() /** * @private * @param {?} tree * @return {?} */ function (tree) { var e_4, _a; tree.sort(this.compate); try { for (var tree_1 = tslib_1.__values(tree), tree_1_1 = tree_1.next(); !tree_1_1.done; tree_1_1 = tree_1.next()) { var item = tree_1_1.value; if (item.childrens.length > 0) { this.sortElements(item.childrens); } } } catch (e_4_1) { e_4 = { error: e_4_1 }; } finally { try { if (tree_1_1 && !tree_1_1.done && (_a = tree_1.return)) _a.call(tree_1); } finally { if (e_4) throw e_4.error; } } }; // part of sortTree() // part of sortTree() /** * @private * @param {?} a * @param {?} b * @return {?} */ NgxTreeService.prototype.compate = // part of sortTree() /** * @private * @param {?} a * @param {?} b * @return {?} */ function (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. // clear selectedElement && isDragging from element finder. /** * @return {?} */ NgxTreeService.prototype.clearAction = // clear selectedElement && isDragging from element finder. /** * @return {?} */ function () { this.findingResults = null; }; /** * @private * @param {?} data * @return {?} */ NgxTreeService.prototype.removeDestenationBorders = /** * @private * @param {?} data * @return {?} */ function (data) { var e_5, _a; try { for (var data_1 = tslib_1.__values(data), data_1_1 = data_1.next(); !data_1_1.done; data_1_1 = data_1.next()) { var item = data_1_1.value; item.options.destenationBottom = false; item.options.destenationTop = false; if (item.childrens.length > 0) { this.removeDestenationBorders(item.childrens); } } } catch (e_5_1) { e_5 = { error: e_5_1 }; } finally { try { if (data_1_1 && !data_1_1.done && (_a = data_1.return)) _a.call(data_1); } finally { if (e_5) throw e_5.error; } } }; /** * @private * @param {?} bool * @param {?} data * @return {?} */ NgxTreeService.prototype.switchDropButton = /** * @private * @param {?} bool * @param {?} data * @return {?} */ function (bool, data) { var e_6, _a; try { for (var data_2 = tslib_1.__values(data), data_2_1 = data_2.next(); !data_2_1.done; data_2_1 = data_2.next()) { var el = data_2_1.value; el.options.showActionButtons = !bool; if (el.id !== this.isDragging.id) { el.options.showDropChildZone = bool; } if (el.childrens.length > 0) { this.switchDropButton(bool, el.childrens); } } } catch (e_6_1) { e_6 = { error: e_6_1 }; } finally { try { if (data_2_1 && !data_2_1.done && (_a = data_2.return)) _a.call(data_2); } finally { if (e_6) throw e_6.error; } } }; NgxTreeService.decorators = [ { type: Injectable, args: [{ providedIn: 'root' },] }, ]; /** @nocollapse */ NgxTreeService.ctorParameters = function () { return []; }; /** @nocollapse */ NgxTreeService.ngInjectableDef = i0.defineInjectable({ factory: function NgxTreeService_Factory() { return new NgxTreeService(); }, token: NgxTreeService, providedIn: "root" }); return NgxTreeService; }()); export { NgxTreeService }; 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LXRyZWUtZG5kLnNlcnZpY2UuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9uZ3gtdHJlZS1kbmQvIiwic291cmNlcyI6WyJsaWIvbmd4LXRyZWUtZG5kLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7OztBQUtBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDM0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLE1BQU0sTUFBTSxDQUFDOztBQUc1RDtJQThCRTtRQTFCQSxnQkFBVyxHQUFnQixFQUFFLENBQUM7UUFTOUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGdCQUFXLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNqQyxnQkFBVyxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDakMsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsV0FBTSxHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDNUIsZ0JBQVcsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ2pDLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGNBQVMsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQy9CLGlCQUFZLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNsQyxzQkFBaUIsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3ZDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsc0JBQWlCLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUN2Qyx1QkFBa0IsR0FBRyxJQUFJLE9BQU8sRUFBTyxDQUFDO1FBQ3hDLHVCQUFrQixHQUFHLElBQUksT0FBTyxFQUFPLENBQUM7UUFDeEMsV0FBTSxHQUFHLElBQUksZUFBZSxDQUFNLElBQUksQ0FBQyxDQUFDO1FBSXRDLHFCQUFxQjtRQUNyQixJQUFJLENBQUMsWUFBWSxHQUFH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cmlnaHQgKEMpIDIwMTggWWFyb3NsYXYgS2lrb3RcbiBUaGlzIHByb2plY3QgaXMgbGljZW5zZWQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBNSVQgbGljZW5zZS5cbiBodHRwczovL2dpdGh1Yi5jb20vWmljcmFlbC9uZ3gtdHJlZS1kbmRcbiAqL1xuaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgU3ViamVjdCwgQmVoYXZpb3JTdWJqZWN0LCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUcmVlTW9kZWwsIFRyZWVDb25maWcsIEZpbmRpbmdSZXN1bHRzIH0gZnJvbSAnLi9tb2RlbHMvdHJlZS12aWV3Lm1vZGVsJztcblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgTmd4VHJlZVNlcnZpY2Uge1xuICB0cmVlU3RvcmFnZTogVHJlZU1vZGVsW10gPSBbXTtcbiAgcHJpdmF0ZSBmaW5kaW5nUmVzdWx0czogRmluZGluZ1Jlc3VsdHM7XG4gIC8vIGxpc3RPZlNlbGVjdGVkRWxlbWVudDogVHJlZU1vZGVsW107XG4gIC8vIHBhcmVudE9mU2VsZWN0ZWQ6IFRyZWVNb2RlbDtcbiAgLy8gcHJpdmF0ZSBzZWxlY3RlZEVsZW1lbnQ6IFRyZWVNb2RlbDtcbiAgaXNEcmFnZ2luZzogVHJlZU1vZGVsO1xuICBkcmFnRXZlbnQ6IHt9O1xuICBkaXJlY3Rpb246IHN0cmluZztcbiAgbGFzdEV4cGFuZFN0YXRlOiBib29sZWFuO1xuICBvbkRyYWdTdGFydCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25EcmFnRW50ZXIgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZ0xlYXZlID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkRyb3AgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZyA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25BbGxvd0Ryb3AgPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uRHJhZ0VuZCA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgb25BZGRJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvblJlbmFtZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uU3RhcnRSZW5hbWVJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkZpbmlzaFJlbmFtZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uU3RhcnREZWxldGVJdGVtID0gbmV3IFN1YmplY3Q8YW55PigpO1xuICBvbkZpbmlzaERlbGV0ZUl0ZW0gPSBuZXcgU3ViamVjdDxhbnk+KCk7XG4gIG9uQ2FuY2VsRGVsZXRlSXRlbSA9IG5ldyBTdWJqZWN0PGFueT4oKTtcbiAgY29uZmlnID0gbmV3IEJlaGF2aW9yU3ViamVjdDxhbnk+KG51bGwpO1xuICBkZWZhdWxDb25maWc6IFRyZWVDb25maWc7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgLy8gc2V0IGRlZmF1bHQgY29uZmlnXG4gICAgdGhpcy5kZWZhdWxDb25maWcgPSB7XG4gICAgICBzaG93QWN0aW9uQnV0dG9uczogdHJ1ZSxcbiAgICAgIHNob3dBZGRCdXR0b25zOiB0cnVlLFxuICAgICAgc2hvd1JlbmFtZUJ1dHRvbnM6IHRydWUsXG4gICAgICBzaG93RGVsZXRlQnV0dG9uczogdHJ1ZSxcbiAgICAgIHNob3dSb290QWN0aW9uQnV0dG9uczogdHJ1ZSxcbiAgICAgIGVuYWJsZUV4cGFuZEJ1dHRvbnM6IHRydWUsXG4gICAgICBlbmFibGVEcmFnZ2luZzogdHJ1ZSxcbiAgICAgIHJvb3RUaXRsZTogJ1Jvb3QnLFxuICAgICAgdmFsaWRhdGlvblRleHQ6ICdFbnRlciB2YWxpZCBuYW1lJyxcbiAgICAgIG1pbkNoYXJhY3Rlckxlbmd0aDogMSxcbiAgICAgIHNldEl0ZW1zQXNMaW5rczogZmFsc2UsXG4gICAgICBzZXRGb250U2l6ZTogMTYsXG4gICAgICBzZXRJY29uU2l6ZTogMTRcbiAgICB9O1xuICB9XG5cbiAgLypcbiAgICBnZXQgZGF0YSBhbmQgc2V0IGl0IG9uIG9ic2VydmFibGUuXG4gICAgaWYgZGF0YSA9IG51bGwgc2V0IGVtcHR5IGRhdGEgYXJyYXlcbiAgKi9cbiAgcHVibGljIGdldExvY2FsRGF0YShpdGVtKSB7XG4gICAgY29uc3QgZGF0YSA9IG5ldyBPYnNlcnZhYmxlKG9ic2VydmVyID0+IHtcbiAgICB0aGlzLnRyZWVTdG9yYWdlID0gaXRlbTtcbiAgICAgIGlmICggdGhpcy50cmVlU3RvcmFnZSAmJiB0aGlzLnRyZWVTdG9yYWdlICE9PSBudWxsICkge1xuICAgICAgICBvYnNlcnZlci5uZXh0KHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy50cmVlU3RvcmFnZSAgPSBKU09OLnBhcnNlKCdbXScpO1xuICAgICAgICBvYnNlcnZlci5uZXh0KHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBkYXRhO1xuICB9XG5cbiAgLypcbiAgIEVsZW1lbnQgZmluZGVyLCBpdGBzIGZpbmQgZWxlbWVudCBieSBpZCBpbiB0cmVlLlxuICAgUmV0dXJuczogZmluZGVkIGVsZW1lbnQsIHBhcmVudCBhcnJheS5cbiAgIFdhdGNoIG91dCwgdGhpcyBpcyByZWN1cnNpdmUgbWV0aG9kLlxuICAqL1xuICAgcHJpdmF0ZSBlbGVtZW50RmluZGVyKGxpc3QsIGlkLCBwYXJlbnQ/KSB7XG4gICAgIGZvciAoY29uc3QgaXRlbSBvZiBsaXN0KSB7XG4gICAgICAgaWYgKGl0ZW0uaWQgPT09IGlkKSB7XG4gICAgICAgICB0aGlzLmZpbmRpbmdSZXN1bHRzID0ge1xuICAgICAgICAgICBmb3VuZEl0ZW06IGl0ZW0sXG4gICAgICAgICAgIGl0ZW1zTGlzdDogbGlzdFxuICAgICAgICAgfVxuICAgICAgICAgaWYgKHBhcmVudCkge1xuICAgICAgICAgICB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gPSBwYXJlbnQ7XG4gICAgICAgICB9XG4gICAgICAgICBicmVhaztcbiAgICAgICB9IGVsc2Uge1xuICAgICAgICAgaWYgKGl0ZW0uY2hpbGRyZW5zLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgdGhpcy5lbGVtZW50RmluZGVyKGl0ZW0uY2hpbGRyZW5zLCBpZCwgaXRlbSk7XG4gICAgICAgICB9XG4gICAgICAgfVxuICAgICB9XG5cbiAgfVxuXG5cbiAgIC8qXG4gICBBZGQgbmV3IGl0ZW0gdG8gdHJlZS5cbiAgIEl0cyBhY2NlcHRzICd0eXBlJyBmb3IgZGV0ZWN0IGFkZCByb290IGVsZW1lbnQgb3IgY2hpbGRyZW4uXG4gICBFbWl0IG9uQWRkSXRlbSBTdWJqZWN0LlxuICAqL1xuICBwdWJsaWMgYWRkTmV3SXRlbShpZCwgbmFtZSwgcGFyZW50Pykge1xuICAgIGxldCBwb3MgPSAxO1xuICAgIGlmIChwYXJlbnQgJiYgcGFyZW50LmNoaWxkcmVucy5sZW5ndGggIT09IDApIHtcbiAgICAgIGNvbnN0IHBhcmVudFByZXZDaGlsZHJlbiA9IHBhcmVudC5jaGlsZHJlbnMubGVuZ3RoIC0gMTtcbiAgICAgIGNvbnN0IG5ld0l0ZW1Qb3NpdGlvbiA9IHBhcmVudC5jaGlsZHJlbnNbcGFyZW50UHJldkNoaWxkcmVuXS5vcHRpb25zLnBvc2l0aW9uICsgMTtcbiAgICAgIHBvcyA9IG5ld0l0ZW1Qb3NpdGlvbjtcbiAgICB9XG4gICAgY29uc3QgY3JlYXRlT2JqOiBUcmVlTW9kZWwgPSB7XG4gICAgICBpZCxcbiAgICAgIG5hbWUsXG4gICAgICBvcHRpb25zOiAge1xuICAgICAgICBwb3NpdGlvbjogcG9zLFxuICAgICAgICBlZGl0OiB0cnVlXG4gICAgICB9LFxuICAgICAgY2hpbGRyZW5zOiBbXVxuICAgIH07XG4gICAgXG4gICAgaWYocGFyZW50ICE9IG51bGwpIHtcbiAgICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBwYXJlbnQgPyBwYXJlbnQuaWQgOiBudWxsKTtcbiAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMgJiYgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0uY2hpbGRyZW5zLnB1c2goY3JlYXRlT2JqKTtcbiAgICB9XG4gICAgZWxzZXtcbiAgICAgIHRoaXMudHJlZVN0b3JhZ2UucHVzaChjcmVhdGVPYmopO1xuICAgIH1cbiAgICBcbiAgICBjb25zdCBldmVudEVtaXQgPSB7XG4gICAgICBlbGVtZW50OiBjcmVhdGVPYmosXG4gICAgICBwYXJlbnQ6IHBhcmVudCA/IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtIDogJ3Jvb3QnXG4gICAgfTtcblxuICAgIHRoaXMub25BZGRJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgRGVsZXRlIGVsZW1lbnQuXG4gICBJdGBzIGFjY2VwdHMgJ2lkJyBmb3IgZmluZCBpdGVtIG9uIHRyZWUuXG4gICBFbWl0IG9uU3RhcnREZWxldGVJdGVtIFN1YmplY3QgYmVmb3JlIGRlbGV0ZS5cbiAgIEVtaXQgb25GaW5pc2hEZWxldGVJdGVtIFN1YmplY3QgYWZ0ZXIgc3VibWl0IGRlbGV0ZS5cbiAgIEVtaXQgb25DYW5jZWxEZWxldGVJdGVtIFN1YmplY3QgYWZ0ZXIgb24gY2FuY2VsIGRlbGV0ZS5cbiAgKi9cbiAgcHVibGljIGRlbGV0ZUl0ZW0oaWQpIHtcbiAgICB0aGlzLmVsZW1lbnRGaW5kZXIodGhpcy50cmVlU3RvcmFnZSwgaWQpO1xuICAgIGNvbnN0IGV2ZW50RW1pdCA9IHtcbiAgICAgIGVsZW1lbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLFxuICAgICAgcGFyZW50OiB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gfHwgJ3Jvb3QnXG4gICAgfTtcbiAgICB0aGlzLm9uU3RhcnREZWxldGVJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICBsZXQgdGV4dDogc3RyaW5nO1xuICAgIGlmKCB0aGlzLmZpbmRpbmdSZXN1bHRzLmZvdW5kSXRlbS5uYW1lICkge1xuICAgICAgdGV4dCA9IGBEbyB5b3UgcmVhbGx5IHdhbnQgdG8gZGVsZXRlICcke3RoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLm5hbWV9Jz9gO1xuICAgIH0gZWxzZSB7XG4gICAgICB0ZXh0ID0gYENhbmNlbCBjcmVhdGluZyBhIG5ldyBpdGVtP2A7XG4gICAgfVxuICAgIGlmKGNvbmZpcm0odGV4dCkpIHtcbiAgICAgIHRoaXMub25GaW5pc2hEZWxldGVJdGVtLm5leHQoZXZlbnRFbWl0KTtcbiAgICAgIGNvbnN0IGkgPSB0aGlzLmZpbmRpbmdSZXN1bHRzLml0ZW1zTGlzdC5pbmRleE9mKHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtKTtcbiAgICAgIHRoaXMuZmluZGluZ1Jlc3VsdHMuaXRlbXNMaXN0LnNwbGljZShpLCAxKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5vbkNhbmNlbERlbGV0ZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICAgIH1cbiAgICB0aGlzLmNsZWFyQWN0aW9uKCk7XG4gIH1cblxuICAvKlxuICAgVHJpZ2dlciBzdGFydCByZW5hbWUgZWxlbWVudC5cbiAgIEl0YHMgYWNjZXB0cyAnbmFtZScgYW5kICdpZCcgZm9yIGZpbmQgaXRlbSBvbiB0cmVlIGFuZCBzZXQgdGhlIG5hbWUuXG4gICBFbWl0IG9uUmVuYW1lSXRlbSBTdWJqZWN0LlxuICAqL1xuIHB1YmxpYyBzdGFydFJlbmFtZUl0ZW0oZWxlbWVudCkge1xuICAgIHRoaXMuZWxlbWVudEZpbmRlcih0aGlzLnRyZWVTdG9yYWdlLCBlbGVtZW50LmlkKTtcbiAgICAvLyBldmVudCBlbWl0XG4gICAgY29uc3QgZXZlbnRFbWl0ID0ge1xuICAgICAgZWxlbWVudDogdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0sXG4gICAgICBwYXJlbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMucGFyZW50SXRlbSB8fCAncm9vdCdcbiAgICB9O1xuICAgIHRoaXMub25TdGFydFJlbmFtZUl0ZW0ubmV4dChldmVudEVtaXQpO1xuICB9XG5cbiAgLypcbiAgIFJlbmFtZSBlbGVtZW50LlxuICAgSXRgcyBhY2NlcHRzICduYW1lJyBhbmQgJ2lkJyBmb3IgZmluZCBpdGVtIG9uIHRyZWUgYW5kIHNldCB0aGUgbmFtZS5cbiAgIEVtaXQgb25SZW5hbWVJdGVtIFN1YmplY3QuXG4gICovXG4gIHB1YmxpYyBmaW5pc2hSZW5hbWVJdGVtKG5hbWUsIGlkKSB7XG4gICAgdGhpcy5lbGVtZW50RmluZGVyKHRoaXMudHJlZVN0b3JhZ2UsIGlkKTtcbiAgICAvLyBjb2RlXG4gICAgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0ubmFtZSA9IG5hbWU7XG4gICAgdGhpcy5maW5kaW5nUmVzdWx0cy5mb3VuZEl0ZW0ub3B0aW9ucy5lZGl0ID0gZmFsc2U7XG4gICAgLy8gZXZlbnQgZW1pdFxuICAgIGNvbnN0IGV2ZW50RW1pdCA9IHtcbiAgICAgIGVsZW1lbnQ6IHRoaXMuZmluZGluZ1Jlc3VsdHMuZm91bmRJdGVtLFxuICAgICAgcGFyZW50OiB0aGlzLmZpbmRpbmdSZXN1bHRzLnBhcmVudEl0ZW0gfHwgJ3Jvb3QnXG4gICAgfTtcbiAgICB0aGlzLm9uRmluaXNoUmVuYW1lSXRlbS5uZXh0KGV2ZW50RW1pdCk7XG4gICAgdGhpcy5jbGVhckFjdGlvbigpO1xuICB9XG5cbiAgLypcbiAgIEV2ZW50OiBvbmRyYWdzdGFydDtcbiAgIE9uIHN0YXJ0IGRyYWdnaW5nIGZpbmQgZWxlbWVudCBteSBpZCBhbmQgc2V0IG9wdGlvbiBjdXJyZW50bHlEcmFnZ2luZyB0cnVlLlxuICAqL1xuICBwdWJsaWMgc3RhcnREcmFnZ2luZyhldmVudE9iaikge1xuICAgIHRoaXMuc3dpdGNoRHJvcEJ1dHRvbih0cnVlLCB0aGlzLnRyZWVTdG9yYWdlKTtcbiAgICB0aGlzLm9uRHJhZ1N0YXJ0Lm5leHQoZXZlbnRPYmopO1xuICB9XG5cbiAgLypcbiAgIEV2ZW50OiBvbmRyYWc7XG4gICBUcmlnZ2VyIGRyYWdnaW5nIGVsZW1lbnRcbiAgKi9cbiAgcHVibGljIG9uRHJhZ1Byb2Nlc3MoZXZlbnRPYmopIHtcbiAgICB0aGlzLm9uRHJhZy5uZXh0KGV2ZW50T2JqKTtcbiAgfVxuXG4gIC8qXG4gICBFdmVudDogb25kcmFnZW5kO1xuICAgZGV0ZWN0IGVuZCBvZiBkcmFnIGFjdGlvblxuICAqL1xuICBwdWJsaWMgZHJhZ0VuZEFjdGlvbihldmVudE9iaikge1xuICAgIHRoaXMucmVtb3ZlRGVzdGVuYXRpb25Cb3JkZXJzKHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgIHRoaXMuc3dpdGNoRHJvcEJ1dHRvbihmYWxzZSwgdGhpcy50cmVlU3RvcmFnZSk7XG4gICAgdGhpcy5vbkRyYWdFbmQubmV4dChldmVudE9iaik7XG4gIH1cblxuICAvKlxuICAgIEV2ZW50OiBlbnRlcmRyb3B6b25lO1xuICAgIEVudGVyaW5nIGRyb3Agem9uZSBmb3Igc3R5bGluZyBpdGVtcy5cbiAgKi9cbiAgcHVibGljIGVudGVyRHJvcFpvbmUoZXZlbnRPYmopIHtcbiAgICB0aGlzLm9uRHJhZ0VudGVyLm5leHQoZXZlbnRPYmopO1xuICB9XG5cblxuICAvKlxuICAgIEV2ZW50OiBkcmFnb3ZlcjtcbiAgICBEZXRlY3QgaG92ZXIgb24gZHJvcGFibGUgZWxlbWVudHNcbiAgKi9cbiAgcHVibGljIG9uRHJhZ092ZXIoZXZlbnRPYmopIHtcbiAgICBjb25zdCBlbCA9IChldmVudE9iai50YXJnZXQgYXMgVHJlZU1vZGVsKTtcbiAgICBpZiAoZWwgJiYgZWwuaWQgIT09IHRoaXMuaXNEcmFnZ2luZy5pZCApIHtcbiAgICAgIGNvbnN0IGVsZW1lbnRIYWxmSGVpZ2h0ID0gZXZlbnRPYmouZXZlbnQudG9FbGVtZW50Lm9mZnNldEhlaWdodCAvIDI7XG4gICAgICBpZiAoZXZlbnRPYmouZXZlbnQub2Zmc2V0WSA8IGVsZW1lbnRIYWxmSGVpZ2h0KSB7XG4gICAgICAgIGVsLm9wdGlvbnMuZGVzdGVuYXRpb25Cb3R0b20gPSBmYWxzZTtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvblRvcCA9IHRydWU7XG4gICAgICB9IGVsc2UgIHtcbiAgICAgICAgZWwub3B0aW9ucy5kZXN0ZW5hdGlvbkJvdHRvbSA9IHRydWU7XG4gICAgICAgIGVsLm9wdGlvbnMuZGVzdGVuYXRpb25Ub3AgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHRoaXMub25BbGxvd0Ryb3AubmV4dChldmVudE9iaik7XG4gICAgfVxuICB9XG5cbiAgLypcbiAgICBFdmVudDogbGVhdmVkcm9wem9uZTtcbiAgICBMZWF2ZSBkcm9wIHpvbmUgZm9yIHJlc3R5bGluZyBpdGVtcy5cbiAgKi9cbiAgcHVibGljIGxlYXZlRHJvcFpvbmUoZXZlbnRPYmopIHtcbiAgICAgIHRoaXMucmVtb3ZlRGVzdGVuYXRpb25Cb3JkZXJzKHRoaXMudHJlZVN0b3JhZ2UpO1xuICAgICAgdGhpcy5vbkRyYWdMZWF2ZS5uZXh0KGV2ZW50T2JqKTtcbiAgfVxuXG4gIC