ngx-tree-dnd
Version:
Angular 7 support tree with drag-and-drop sortable data tree. It`s fast and smart.
537 lines • 45 kB
JavaScript
/**
* @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