@cute-dw/core
Version:
This TypeScript library is the main part of a more powerfull package designed for the fast WEB software development. The cornerstone of the library is the **DataStore** class, which might be useful when you need a full control of the data, but do not need
389 lines • 42.2 kB
JavaScript
import { Comparator } from "../../util/Comparator";
export class BinaryTreeNode {
constructor(key, value, comparator) {
this.left = null;
this.right = null;
this.parent = null;
this.value = null;
this.data = new Map();
this.nodeCompare = Comparator.compare;
this.value = value === undefined ? null : value;
this.key = key;
this.keyComparator = comparator ?? Comparator.getInstance();
}
/**
* @param {BinaryTreeNode} sourceNode
* @param {BinaryTreeNode} targetNode
* @static
*/
static copyNode(sourceNode, targetNode) {
targetNode.key = sourceNode.key;
targetNode.setValue(sourceNode.value);
targetNode.setLeft(sourceNode.left);
targetNode.setRight(sourceNode.right);
}
get height() {
return Math.max(this.leftHeight, this.rightHeight);
}
get leftHeight() {
if (!this.left)
return 0;
return this.left.height + 1;
}
get rightHeight() {
if (!this.right)
return 0;
return this.right.height + 1;
}
get balanceFactor() {
return this.leftHeight - this.rightHeight;
}
/**
* Get current node's sibling node if exists
* @returns {BinaryTreeNode}
*/
get sibling() {
// Check if current node has parent.
if (!this.parent) {
return undefined;
}
// So for now we know that current node has a parent and this
// parent has at least one children. Let's find out who is the brother.
if (this.nodeCompare(this, this.parent.left) == 0) {
// Right one is a sibling (if exists)
return this.parent.right ?? undefined;
}
// Left one is a sibling (if exists)
return this.parent.left ?? undefined;
}
/**
* Get parent's sibling if it exists.
* @returns {BinaryTreeNode}
*/
get uncle() {
// Check if current node has parent.
if (!this.parent) {
return undefined;
}
// Check if current node has grand-parent.
if (!this.parent.parent) {
return undefined;
}
// Check if grand-parent has two children.
if (!this.parent.parent.left || !this.parent.parent.right) {
return undefined;
}
// So for now we know that current node has grand-parent and this
// grand-parent has two children. Let's find out who is the uncle.
if (this.nodeCompare(this.parent, this.parent.parent.left) == 0) {
// Right one is an uncle.
return this.parent.parent.right;
}
// Left one is an uncle.
return this.parent.parent.left;
}
/**
* Gets the child direction of the current node relative to the parent node
* @returns `0` - if the node is the _left_ child, `1` - if the node is the _right_ child, `NaN` - node hasn't the parent node
*/
get direction() {
if (this.parent) {
if (this.parent.left == this) {
return 0;
}
return 1;
}
return NaN;
}
/**
* @param {*} value
* @returns {boolean}
*/
setValue(value) {
if (value === undefined)
return false;
this.value = value;
return true;
}
/**
* Sets a node as a left child node
* @param {BinaryTreeNode} node A new node to attach
* @returns {this} `this`
*/
setLeft(node) {
// Reset parent for left node since it is going to be detached.
if (this.left) {
this.left.parent = null;
}
// Attach new node to the left.
this.left = node;
// Make current node to be a parent for new left one.
if (this.left) {
this.left.parent = this;
}
return this;
}
/**
* Sets a node as a right child node
* @param {BinaryTreeNode} node A new node to attach
* @returns `this`
*/
setRight(node) {
// Reset parent for right node since it is going to be detached.
if (this.right) {
this.right.parent = null;
}
// Attach new node to the right.
this.right = node;
// Make current node to be a parent for new right one.
if (this.right) {
this.right.parent = this;
}
return this;
}
/**
* Removes a specified node if it was attached to this node as a child
* @param {BinaryTreeNode} nodeToRemove A node to remove if it is a child node
* @returns {boolean} _true_ if a node is a child node and it was removed successfully, else _false_
*/
removeChild(nodeToRemove) {
if (this.left && this.nodeCompare(this.left, nodeToRemove) == 0) {
this.left = null;
return true;
}
if (this.right && this.nodeCompare(this.right, nodeToRemove) == 0) {
this.right = null;
return true;
}
return false;
}
/**
* Replaces a child node
* @param {BinaryTreeNode} nodeToReplace
* @param {BinaryTreeNode} replacementNode
* @returns {boolean}
*/
replaceChild(nodeToReplace, replacementNode) {
if (!nodeToReplace || !replacementNode) {
return false;
}
if (this.left && this.nodeCompare(this.left, nodeToReplace) == 0) {
this.left = replacementNode;
return true;
}
if (this.right && this.nodeCompare(this.right, nodeToReplace) == 0) {
this.right = replacementNode;
return true;
}
return false;
}
/**
* @param {*} key
* @returns {boolean}
*/
contains(key) {
return !!this.findNode(key);
}
/**
* Finds right most child node
* @returns {BinaryTreeNode} The node with the maximum key value
* @readonly
*/
findMax() {
if (!this.right) {
return this;
}
return this.right.findMax();
}
/**
* Finds left most child node
* @returns {BinaryTreeNode} The node with the minimum key value
* @readonly
*/
findMin() {
if (!this.left) {
return this;
}
return this.left.findMin();
}
/**
* Finds a node by its `key` value
* @param {K} key Key of the searching node
* @returns {BinaryTreeNode|null} Node object or _null_ if the node was not found
*/
findNode(key) {
// Check this
if (this.keyComparator.equal(this.key, key)) {
return this;
}
if (this.keyComparator.lessThan(key, this.key) && this.left) {
// Check left nodes
return this.left.findNode(key);
}
if (this.keyComparator.greaterThan(key, this.key) && this.right) {
// Check right nodes
return this.right.findNode(key);
}
return null;
}
/**
* Traverses tree nodes up starting from the current node
* @returns {BinaryTreeNode[]} Readonly array of nodes
* @readonly
*/
*traverseUpIterator() {
let parentNode = this.parent;
while (parentNode) {
yield parentNode;
parentNode = parentNode.parent;
}
}
/**
* Traverses tree nodes and generate a stream of the node objects
* @param orderType
*/
*traverseDownIterator(orderType = "InOrder!") {
if (orderType == "PreOrder!") {
// Add root
yield this;
}
// Add left nodes
if (this.left) {
yield* this.left.traverseDownIterator(orderType);
}
if (orderType == "InOrder!") {
// Add root
yield this;
}
// Add right nodes
if (this.right) {
yield* this.right.traverseDownIterator(orderType);
}
if (orderType == "PostOrder!") {
// Add root
yield this;
}
}
/**
* Traverses tree nodes down starting from the current node
* @returns {BinaryTreeNode[]} Readonly array of nodes
* @readonly
*/
traverse(orderType = "InOrder!") {
return [...this.traverseDownIterator(orderType)];
}
/**
* Iterator
*/
*[Symbol.iterator]() {
yield* this.traverseDownIterator();
}
/**
* Adds a new node to this node
* @param node New node object
* @returns New node reference or `this` node if its `key` is identical to the key of `node`
*/
addNode(node) {
if (node) {
if (this.keyComparator.lessThan(node.key, this.key)) {
// Insert to the left.
if (this.left) {
return this.left.addNode(node);
}
this.setLeft(node);
return node;
}
if (this.keyComparator.greaterThan(node.key, this.key)) {
// Insert to the right.
if (this.right) {
return this.right.addNode(node);
}
this.setRight(node);
return node;
}
this.setValue(node.value);
}
return this;
}
/**
* Adds a new node to the current node
* @param key Key of the node
* @param value Node's value
* @returns {BinaryTreeNode}
*/
add(key, value) {
const newNode = new BinaryTreeNode(key, value, this.keyComparator);
return this.addNode(newNode);
}
/**
* Removes the node with the key `key` from the current node
* @param {K} key A key of the node to remove
* @returns {BinaryTreeNode|null} Removed node or `null` if the node was not found
*/
remove(key) {
const nodeToRemove = this.findNode(key);
if (!nodeToRemove) {
//throw new Error('Item not found in the tree');
return null;
}
const { parent } = nodeToRemove;
if (!nodeToRemove.left && !nodeToRemove.right) {
// Node is a leaf and thus has no children.
if (parent) {
// Node has a parent. Just remove the pointer to this node from the parent.
parent.removeChild(nodeToRemove);
}
else {
// Node has no parent. Just erase current node value.
nodeToRemove.setValue(null);
nodeToRemove.setLeft(null);
nodeToRemove.setRight(null);
}
}
else if (nodeToRemove.left && nodeToRemove.right) {
// Node has two children.
// Find the next biggest value (minimum value in the right branch)
// and replace current value node with that next biggest value.
const nextBiggerNode = nodeToRemove.right.findMin();
if (!(this.nodeCompare(nextBiggerNode, nodeToRemove.right) == 0)) {
this.remove(nextBiggerNode.key);
nodeToRemove.key = nextBiggerNode.key;
nodeToRemove.value = nextBiggerNode.value;
}
else {
// In case if next right value is the next bigger one and it doesn't have left child
// then just replace node that is going to be deleted with the right node.
nodeToRemove.key = nodeToRemove.right.key;
nodeToRemove.value = nodeToRemove.right.value;
nodeToRemove.setRight(nodeToRemove.right.right);
}
}
else {
// Node has only one child.
// Make this child to be a direct child of current node's parent.
const childNode = nodeToRemove.left || nodeToRemove.right;
if (childNode) {
if (parent) {
parent.replaceChild(nodeToRemove, childNode);
nodeToRemove.setLeft(null);
nodeToRemove.setRight(null);
nodeToRemove.setValue(null);
}
else {
BinaryTreeNode.copyNode(childNode, nodeToRemove);
}
}
}
// Clear the parent of removed node.
nodeToRemove.parent = null;
return nodeToRemove;
}
/**
* Returns the comma delimited string of tree keys
* @returns {string} String
*/
toString() {
return this.traverse().map(node => node.key).toString();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQmluYXJ5VHJlZU5vZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jdXRlLWNvcmUvc3JjL2xpYi9jb2xsZWN0aW9ucy90cmVlL0JpbmFyeVRyZWVOb2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUluRCxNQUFNLE9BQU8sY0FBYztJQVV6QixZQUFZLEdBQU0sRUFBRSxLQUFrQixFQUFFLFVBQTBCO1FBVGxFLFNBQUksR0FBZ0MsSUFBSSxDQUFDO1FBQ3pDLFVBQUssR0FBZ0MsSUFBSSxDQUFDO1FBQzFDLFdBQU0sR0FBZ0MsSUFBSSxDQUFDO1FBRTNDLFVBQUssR0FBZSxJQUFJLENBQUM7UUFDaEIsU0FBSSxHQUFrQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQy9CLGdCQUFXLEdBQTRDLFVBQVUsQ0FBQyxPQUFPLENBQUM7UUFJbEYsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQztRQUNoRCxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztRQUNmLElBQUksQ0FBQyxhQUFhLEdBQUcsVUFBVSxJQUFJLFVBQVUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztJQUM5RCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILE1BQU0sQ0FBQyxRQUFRLENBQUMsVUFBMEIsRUFBRSxVQUEwQjtRQUNwRSxVQUFVLENBQUMsR0FBRyxHQUFHLFVBQVUsQ0FBQyxHQUFHLENBQUM7UUFDaEMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDdEMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDcEMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENB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Q0FBQyxDQUFDO2lCQUM3QjtxQkFBTTtvQkFDTCxjQUFjLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxZQUFZLENBQUMsQ0FBQztpQkFDbEQ7YUFDRjtTQUNGO1FBRUQsb0NBQW9DO1FBQ3BDLFlBQVksQ0FBQyxNQUFNLEdBQUcsSUFBSSxDQUFDO1FBRTNCLE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7SUFDRDs7O09BR0c7SUFDRixRQUFRO1FBQ1AsT0FBTyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQzFELENBQUM7Q0FFRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBhcmF0b3IgfSBmcm9tIFwiLi4vLi4vdXRpbC9Db21wYXJhdG9yXCI7XHJcbmltcG9ydCB7IENvbXBhcmUgfSBmcm9tIFwiLi4vLi4vdXRpbC9mdW5jdGlvbi9Db21wYXJlXCI7XHJcbmltcG9ydCB7IEVsZW1lbnQgfSBmcm9tIFwiLi4vQ29sbGVjdGlvblwiO1xyXG5cclxuZXhwb3J0IGNsYXNzIEJpbmFyeVRyZWVOb2RlPEsgPSBhbnksIFYgPSBhbnk+IHtcclxuICBsZWZ0OiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB8IG51bGwgPSBudWxsO1xyXG4gIHJpZ2h0OiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB8IG51bGwgPSBudWxsO1xyXG4gIHBhcmVudDogQmluYXJ5VHJlZU5vZGU8SywgVj4gfCBudWxsID0gbnVsbDtcclxuICBrZXk6IEs7XHJcbiAgdmFsdWU6IEVsZW1lbnQ8Vj4gPSBudWxsO1xyXG4gIHJlYWRvbmx5IGRhdGE6IE1hcDxhbnksIGFueT4gPSBuZXcgTWFwKCk7XHJcbiAgcHJvdGVjdGVkIG5vZGVDb21wYXJlOiBDb21wYXJlPFJlYWRvbmx5PEJpbmFyeVRyZWVOb2RlPEssIFY+Pj4gPSBDb21wYXJhdG9yLmNvbXBhcmU7XHJcbiAgcHJvdGVjdGVkIGtleUNvbXBhcmF0b3I6IENvbXBhcmF0b3I8Sz47XHJcblxyXG4gIGNvbnN0cnVjdG9yKGtleTogSywgdmFsdWU/OiBFbGVtZW50PFY+LCBjb21wYXJhdG9yPzogQ29tcGFyYXRvcjxLPikge1xyXG4gICAgdGhpcy52YWx1ZSA9IHZhbHVlID09PSB1bmRlZmluZWQgPyBudWxsIDogdmFsdWU7XHJcbiAgICB0aGlzLmtleSA9IGtleTtcclxuICAgIHRoaXMua2V5Q29tcGFyYXRvciA9IGNvbXBhcmF0b3IgPz8gQ29tcGFyYXRvci5nZXRJbnN0YW5jZSgpO1xyXG4gIH1cclxuXHJcbiAgLyoqXHJcbiAgICogQHBhcmFtIHtCaW5hcnlUcmVlTm9kZX0gc291cmNlTm9kZVxyXG4gICAqIEBwYXJhbSB7QmluYXJ5VHJlZU5vZGV9IHRhcmdldE5vZGVcclxuICAgKiBAc3RhdGljXHJcbiAgICovXHJcbiAgc3RhdGljIGNvcHlOb2RlKHNvdXJjZU5vZGU6IEJpbmFyeVRyZWVOb2RlLCB0YXJnZXROb2RlOiBCaW5hcnlUcmVlTm9kZSk6IHZvaWQge1xyXG4gICAgdGFyZ2V0Tm9kZS5rZXkgPSBzb3VyY2VOb2RlLmtleTtcclxuICAgIHRhcmdldE5vZGUuc2V0VmFsdWUoc291cmNlTm9kZS52YWx1ZSk7XHJcbiAgICB0YXJnZXROb2RlLnNldExlZnQoc291cmNlTm9kZS5sZWZ0KTtcclxuICAgIHRhcmdldE5vZGUuc2V0UmlnaHQoc291cmNlTm9kZS5yaWdodCk7XHJcbiAgfVxyXG5cclxuICBnZXQgaGVpZ2h0KCk6IG51bWJlciB7XHJcbiAgICByZXR1cm4gTWF0aC5tYXgodGhpcy5sZWZ0SGVpZ2h0LCB0aGlzLnJpZ2h0SGVpZ2h0KTtcclxuICB9XHJcblxyXG4gIGdldCBsZWZ0SGVpZ2h0KCk6IG51bWJlciB7XHJcbiAgICBpZiAoIXRoaXMubGVmdCkgcmV0dXJuIDA7XHJcbiAgICByZXR1cm4gdGhpcy5sZWZ0LmhlaWdodCArIDE7XHJcbiAgfVxyXG5cclxuICBnZXQgcmlnaHRIZWlnaHQoKTogbnVtYmVyIHtcclxuICAgIGlmICghdGhpcy5yaWdodCkgcmV0dXJuIDA7XHJcbiAgICByZXR1cm4gdGhpcy5yaWdodC5oZWlnaHQgKyAxO1xyXG4gIH1cclxuXHJcbiAgZ2V0IGJhbGFuY2VGYWN0b3IoKTogbnVtYmVyIHtcclxuICAgIHJldHVybiB0aGlzLmxlZnRIZWlnaHQgLSB0aGlzLnJpZ2h0SGVpZ2h0O1xyXG4gIH1cclxuICAvKipcclxuICAgKiBHZXQgY3VycmVudCBub2RlJ3Mgc2libGluZyBub2RlIGlmIGV4aXN0c1xyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZX1cclxuICAgKi9cclxuICBnZXQgc2libGluZygpOiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB8IHVuZGVmaW5lZCB7XHJcbiAgICAvLyBDaGVjayBpZiBjdXJyZW50IG5vZGUgaGFzIHBhcmVudC5cclxuICAgIGlmICghdGhpcy5wYXJlbnQpIHtcclxuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcclxuICAgIH1cclxuICAgIC8vIFNvIGZvciBub3cgd2Uga25vdyB0aGF0IGN1cnJlbnQgbm9kZSBoYXMgYSBwYXJlbnQgYW5kIHRoaXNcclxuICAgIC8vIHBhcmVudCBoYXMgYXQgbGVhc3Qgb25lIGNoaWxkcmVuLiBMZXQncyBmaW5kIG91dCB3aG8gaXMgdGhlIGJyb3RoZXIuXHJcbiAgICBpZiAodGhpcy5ub2RlQ29tcGFyZSh0aGlzLCB0aGlzLnBhcmVudC5sZWZ0KSA9PSAwKSB7XHJcbiAgICAgIC8vIFJpZ2h0IG9uZSBpcyBhIHNpYmxpbmcgKGlmIGV4aXN0cylcclxuICAgICAgcmV0dXJuIHRoaXMucGFyZW50LnJpZ2h0ID8/IHVuZGVmaW5lZDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMZWZ0IG9uZSBpcyBhIHNpYmxpbmcgKGlmIGV4aXN0cylcclxuICAgIHJldHVybiB0aGlzLnBhcmVudC5sZWZ0ID8/IHVuZGVmaW5lZDtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogR2V0IHBhcmVudCdzIHNpYmxpbmcgaWYgaXQgZXhpc3RzLlxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZX1cclxuICAgKi9cclxuICBnZXQgdW5jbGUoKTogQmluYXJ5VHJlZU5vZGU8SywgVj4gfCB1bmRlZmluZWQge1xyXG4gICAgLy8gQ2hlY2sgaWYgY3VycmVudCBub2RlIGhhcyBwYXJlbnQuXHJcbiAgICBpZiAoIXRoaXMucGFyZW50KSB7XHJcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgY3VycmVudCBub2RlIGhhcyBncmFuZC1wYXJlbnQuXHJcbiAgICBpZiAoIXRoaXMucGFyZW50LnBhcmVudCkge1xyXG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIGlmIGdyYW5kLXBhcmVudCBoYXMgdHdvIGNoaWxkcmVuLlxyXG4gICAgaWYgKCF0aGlzLnBhcmVudC5wYXJlbnQubGVmdCB8fCAhdGhpcy5wYXJlbnQucGFyZW50LnJpZ2h0KSB7XHJcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU28gZm9yIG5vdyB3ZSBrbm93IHRoYXQgY3VycmVudCBub2RlIGhhcyBncmFuZC1wYXJlbnQgYW5kIHRoaXNcclxuICAgIC8vIGdyYW5kLXBhcmVudCBoYXMgdHdvIGNoaWxkcmVuLiBMZXQncyBmaW5kIG91dCB3aG8gaXMgdGhlIHVuY2xlLlxyXG4gICAgaWYgKHRoaXMubm9kZUNvbXBhcmUodGhpcy5wYXJlbnQsIHRoaXMucGFyZW50LnBhcmVudC5sZWZ0KSA9PSAwKSB7XHJcbiAgICAgIC8vIFJpZ2h0IG9uZSBpcyBhbiB1bmNsZS5cclxuICAgICAgcmV0dXJuIHRoaXMucGFyZW50LnBhcmVudC5yaWdodDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMZWZ0IG9uZSBpcyBhbiB1bmNsZS5cclxuICAgIHJldHVybiB0aGlzLnBhcmVudC5wYXJlbnQubGVmdDtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogR2V0cyB0aGUgY2hpbGQgZGlyZWN0aW9uIG9mIHRoZSBjdXJyZW50IG5vZGUgcmVsYXRpdmUgdG8gdGhlIHBhcmVudCBub2RlXHJcbiAgICogQHJldHVybnMgYDBgIC0gaWYgdGhlIG5vZGUgaXMgdGhlIF9sZWZ0XyBjaGlsZCwgYDFgIC0gaWYgdGhlIG5vZGUgaXMgdGhlIF9yaWdodF8gY2hpbGQsIGBOYU5gIC0gbm9kZSBoYXNuJ3QgdGhlIHBhcmVudCBub2RlXHJcbiAgICovXHJcbiAgZ2V0IGRpcmVjdGlvbigpOiBudW1iZXIge1xyXG4gICAgaWYgKHRoaXMucGFyZW50KSB7XHJcbiAgICAgIGlmICh0aGlzLnBhcmVudC5sZWZ0ID09IHRoaXMpIHtcclxuICAgICAgICByZXR1cm4gMDtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gMTtcclxuICAgIH1cclxuICAgIHJldHVybiBOYU47XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEBwYXJhbSB7Kn0gdmFsdWVcclxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuICAgKi9cclxuICBzZXRWYWx1ZSh2YWx1ZTogRWxlbWVudDxWPik6IGJvb2xlYW4ge1xyXG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQpIHJldHVybiBmYWxzZTtcclxuICAgIHRoaXMudmFsdWUgPSB2YWx1ZTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBTZXRzIGEgbm9kZSBhcyBhIGxlZnQgY2hpbGQgbm9kZVxyXG4gICAqIEBwYXJhbSB7QmluYXJ5VHJlZU5vZGV9IG5vZGUgQSBuZXcgbm9kZSB0byBhdHRhY2hcclxuICAgKiBAcmV0dXJucyB7dGhpc30gYHRoaXNgXHJcbiAgICovXHJcbiAgc2V0TGVmdChub2RlOiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB8IG51bGwpOiB0aGlzIHtcclxuICAgIC8vIFJlc2V0IHBhcmVudCBmb3IgbGVmdCBub2RlIHNpbmNlIGl0IGlzIGdvaW5nIHRvIGJlIGRldGFjaGVkLlxyXG4gICAgaWYgKHRoaXMubGVmdCkge1xyXG4gICAgICB0aGlzLmxlZnQucGFyZW50ID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBdHRhY2ggbmV3IG5vZGUgdG8gdGhlIGxlZnQuXHJcbiAgICB0aGlzLmxlZnQgPSBub2RlO1xyXG5cclxuICAgIC8vIE1ha2UgY3VycmVudCBub2RlIHRvIGJlIGEgcGFyZW50IGZvciBuZXcgbGVmdCBvbmUuXHJcbiAgICBpZiAodGhpcy5sZWZ0KSB7XHJcbiAgICAgIHRoaXMubGVmdC5wYXJlbnQgPSB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBTZXRzIGEgbm9kZSBhcyBhIHJpZ2h0IGNoaWxkIG5vZGVcclxuICAgKiBAcGFyYW0ge0JpbmFyeVRyZWVOb2RlfSBub2RlIEEgbmV3IG5vZGUgdG8gYXR0YWNoXHJcbiAgICogQHJldHVybnMgYHRoaXNgXHJcbiAgICovXHJcbiAgc2V0UmlnaHQobm9kZTogQmluYXJ5VHJlZU5vZGU8SywgVj4gfCBudWxsKTogdGhpcyB7XHJcbiAgICAvLyBSZXNldCBwYXJlbnQgZm9yIHJpZ2h0IG5vZGUgc2luY2UgaXQgaXMgZ29pbmcgdG8gYmUgZGV0YWNoZWQuXHJcbiAgICBpZiAodGhpcy5yaWdodCkge1xyXG4gICAgICB0aGlzLnJpZ2h0LnBhcmVudCA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQXR0YWNoIG5ldyBub2RlIHRvIHRoZSByaWdodC5cclxuICAgIHRoaXMucmlnaHQgPSBub2RlO1xyXG5cclxuICAgIC8vIE1ha2UgY3VycmVudCBub2RlIHRvIGJlIGEgcGFyZW50IGZvciBuZXcgcmlnaHQgb25lLlxyXG4gICAgaWYgKHRoaXMucmlnaHQpIHtcclxuICAgICAgdGhpcy5yaWdodC5wYXJlbnQgPSB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZW1vdmVzIGEgc3BlY2lmaWVkIG5vZGUgaWYgaXQgd2FzIGF0dGFjaGVkIHRvIHRoaXMgbm9kZSBhcyBhIGNoaWxkXHJcbiAgICogQHBhcmFtIHtCaW5hcnlUcmVlTm9kZX0gbm9kZVRvUmVtb3ZlIEEgbm9kZSB0byByZW1vdmUgaWYgaXQgaXMgYSBjaGlsZCBub2RlXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IF90cnVlXyBpZiBhIG5vZGUgaXMgYSBjaGlsZCBub2RlIGFuZCBpdCB3YXMgcmVtb3ZlZCBzdWNjZXNzZnVsbHksIGVsc2UgX2ZhbHNlX1xyXG4gICAqL1xyXG4gIHJlbW92ZUNoaWxkKG5vZGVUb1JlbW92ZTogQmluYXJ5VHJlZU5vZGU8SywgVj4pOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLmxlZnQgJiYgdGhpcy5ub2RlQ29tcGFyZSh0aGlzLmxlZnQsIG5vZGVUb1JlbW92ZSkgPT0gMCkge1xyXG4gICAgICB0aGlzLmxlZnQgPSBudWxsO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5yaWdodCAmJiB0aGlzLm5vZGVDb21wYXJlKHRoaXMucmlnaHQsIG5vZGVUb1JlbW92ZSkgPT0gMCkge1xyXG4gICAgICB0aGlzLnJpZ2h0ID0gbnVsbDtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZXBsYWNlcyBhIGNoaWxkIG5vZGVcclxuICAgKiBAcGFyYW0ge0JpbmFyeVRyZWVOb2RlfSBub2RlVG9SZXBsYWNlXHJcbiAgICogQHBhcmFtIHtCaW5hcnlUcmVlTm9kZX0gcmVwbGFjZW1lbnROb2RlXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAgICovXHJcbiAgcmVwbGFjZUNoaWxkKG5vZGVUb1JlcGxhY2U6IEJpbmFyeVRyZWVOb2RlPEssIFY+LCByZXBsYWNlbWVudE5vZGU6IEJpbmFyeVRyZWVOb2RlPEssIFY+KTogYm9vbGVhbiB7XHJcbiAgICBpZiAoIW5vZGVUb1JlcGxhY2UgfHwgIXJlcGxhY2VtZW50Tm9kZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMubGVmdCAmJiB0aGlzLm5vZGVDb21wYXJlKHRoaXMubGVmdCwgbm9kZVRvUmVwbGFjZSkgPT0gMCkge1xyXG4gICAgICB0aGlzLmxlZnQgPSByZXBsYWNlbWVudE5vZGU7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLnJpZ2h0ICYmIHRoaXMubm9kZUNvbXBhcmUodGhpcy5yaWdodCwgbm9kZVRvUmVwbGFjZSkgPT0gMCkge1xyXG4gICAgICB0aGlzLnJpZ2h0ID0gcmVwbGFjZW1lbnROb2RlO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEBwYXJhbSB7Kn0ga2V5XHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59XHJcbiAgICovXHJcbiAgY29udGFpbnMoa2V5OiBLKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gISF0aGlzLmZpbmROb2RlKGtleSk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEZpbmRzIHJpZ2h0IG1vc3QgY2hpbGQgbm9kZVxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZX0gIFRoZSBub2RlIHdpdGggdGhlIG1heGltdW0ga2V5IHZhbHVlXHJcbiAgICogQHJlYWRvbmx5XHJcbiAgICovXHJcbiAgZmluZE1heCgpOiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB7XHJcbiAgICBpZiAoIXRoaXMucmlnaHQpIHtcclxuICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5yaWdodC5maW5kTWF4KCk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEZpbmRzIGxlZnQgbW9zdCBjaGlsZCBub2RlXHJcbiAgICogQHJldHVybnMge0JpbmFyeVRyZWVOb2RlfSBUaGUgbm9kZSB3aXRoIHRoZSBtaW5pbXVtIGtleSB2YWx1ZVxyXG4gICAqIEByZWFkb25seVxyXG4gICAqL1xyXG4gIGZpbmRNaW4oKTogQmluYXJ5VHJlZU5vZGU8SywgVj4ge1xyXG4gICAgaWYgKCF0aGlzLmxlZnQpIHtcclxuICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcy5sZWZ0LmZpbmRNaW4oKTtcclxuICB9XHJcbiAgLyoqXHJcbiAgICogRmluZHMgYSBub2RlIGJ5IGl0cyBga2V5YCB2YWx1ZVxyXG4gICAqIEBwYXJhbSB7S30ga2V5ICAgS2V5IG9mIHRoZSBzZWFyY2hpbmcgbm9kZVxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZXxudWxsfSAgIE5vZGUgb2JqZWN0IG9yIF9udWxsXyBpZiB0aGUgbm9kZSB3YXMgbm90IGZvdW5kXHJcbiAgICovXHJcbiAgZmluZE5vZGUoa2V5OiBLKTogQmluYXJ5VHJlZU5vZGU8SywgVj4gfCBudWxsIHtcclxuICAgIC8vIENoZWNrIHRoaXNcclxuICAgIGlmICh0aGlzLmtleUNvbXBhcmF0b3IuZXF1YWwodGhpcy5rZXksIGtleSkpIHtcclxuICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMua2V5Q29tcGFyYXRvci5sZXNzVGhhbihrZXksIHRoaXMua2V5KSAmJiB0aGlzLmxlZnQpIHtcclxuICAgICAgLy8gQ2hlY2sgbGVmdCBub2Rlc1xyXG4gICAgICByZXR1cm4gdGhpcy5sZWZ0LmZpbmROb2RlKGtleSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMua2V5Q29tcGFyYXRvci5ncmVhdGVyVGhhbihrZXksIHRoaXMua2V5KSAmJiB0aGlzLnJpZ2h0KSB7XHJcbiAgICAgIC8vIENoZWNrIHJpZ2h0IG5vZGVzXHJcbiAgICAgIHJldHVybiB0aGlzLnJpZ2h0LmZpbmROb2RlKGtleSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIFRyYXZlcnNlcyB0cmVlIG5vZGVzIHVwIHN0YXJ0aW5nIGZyb20gdGhlIGN1cnJlbnQgbm9kZVxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZVtdfSBSZWFkb25seSBhcnJheSBvZiBub2Rlc1xyXG4gICAqIEByZWFkb25seVxyXG4gICAqL1xyXG4gICp0cmF2ZXJzZVVwSXRlcmF0b3IoKTogSXRlcmFibGVJdGVyYXRvcjxCaW5hcnlUcmVlTm9kZTxLLCBWPj4ge1xyXG4gICAgbGV0IHBhcmVudE5vZGUgPSB0aGlzLnBhcmVudDtcclxuICAgIHdoaWxlIChwYXJlbnROb2RlKSB7XHJcbiAgICAgIHlpZWxkIHBhcmVudE5vZGU7XHJcbiAgICAgIHBhcmVudE5vZGUgPSBwYXJlbnROb2RlLnBhcmVudDtcclxuICAgIH1cclxuICB9XHJcbiAgLyoqXHJcbiAgICogVHJhdmVyc2VzIHRyZWUgbm9kZXMgYW5kIGdlbmVyYXRlIGEgc3RyZWFtIG9mIHRoZSBub2RlIG9iamVjdHNcclxuICAgKiBAcGFyYW0gb3JkZXJUeXBlXHJcbiAgICovXHJcbiAgKnRyYXZlcnNlRG93bkl0ZXJhdG9yKG9yZGVyVHlwZTogXCJQcmVPcmRlciFcIiB8IFwiSW5PcmRlciFcIiB8IFwiUG9zdE9yZGVyIVwiID0gXCJJbk9yZGVyIVwiKTogSXRlcmFibGVJdGVyYXRvcjxCaW5hcnlUcmVlTm9kZTxLLCBWPj4ge1xyXG5cclxuICAgIGlmIChvcmRlclR5cGUgPT0gXCJQcmVPcmRlciFcIikge1xyXG4gICAgICAvLyBBZGQgcm9vdFxyXG4gICAgICB5aWVsZCB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCBsZWZ0IG5vZGVzXHJcbiAgICBpZiAodGhpcy5sZWZ0KSB7XHJcbiAgICAgIHlpZWxkKiB0aGlzLmxlZnQudHJhdmVyc2VEb3duSXRlcmF0b3Iob3JkZXJUeXBlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAob3JkZXJUeXBlID09IFwiSW5PcmRlciFcIikge1xyXG4gICAgICAvLyBBZGQgcm9vdFxyXG4gICAgICB5aWVsZCB0aGlzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkZCByaWdodCBub2Rlc1xyXG4gICAgaWYgKHRoaXMucmlnaHQpIHtcclxuICAgICAgeWllbGQqIHRoaXMucmlnaHQudHJhdmVyc2VEb3duSXRlcmF0b3Iob3JkZXJUeXBlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAob3JkZXJUeXBlID09IFwiUG9zdE9yZGVyIVwiKSB7XHJcbiAgICAgIC8vIEFkZCByb290XHJcbiAgICAgIHlpZWxkIHRoaXM7XHJcbiAgICB9XHJcblxyXG4gIH1cclxuICAvKipcclxuICAgKiBUcmF2ZXJzZXMgdHJlZSBub2RlcyBkb3duIHN0YXJ0aW5nIGZyb20gdGhlIGN1cnJlbnQgbm9kZVxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZVtdfSBSZWFkb25seSBhcnJheSBvZiBub2Rlc1xyXG4gICAqIEByZWFkb25seVxyXG4gICAqL1xyXG4gIHRyYXZlcnNlKG9yZGVyVHlwZTogXCJQcmVPcmRlciFcIiB8IFwiSW5PcmRlciFcIiB8IFwiUG9zdE9yZGVyIVwiID0gXCJJbk9yZGVyIVwiKTogUmVhZG9ubHlBcnJheTxCaW5hcnlUcmVlTm9kZTxLLCBWPj4ge1xyXG4gICAgcmV0dXJuIFsuLi50aGlzLnRyYXZlcnNlRG93bkl0ZXJhdG9yKG9yZGVyVHlwZSldO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBJdGVyYXRvclxyXG4gICAqL1xyXG4gICpbU3ltYm9sLml0ZXJhdG9yXSgpOiBJdGVyYWJsZUl0ZXJhdG9yPEJpbmFyeVRyZWVOb2RlPEssVj4+IHtcclxuICAgIHlpZWxkKiB0aGlzLnRyYXZlcnNlRG93bkl0ZXJhdG9yKCk7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEFkZHMgYSBuZXcgbm9kZSB0byB0aGlzIG5vZGVcclxuICAgKiBAcGFyYW0gbm9kZSBOZXcgbm9kZSBvYmplY3RcclxuICAgKiBAcmV0dXJucyBOZXcgbm9kZSByZWZlcmVuY2Ugb3IgYHRoaXNgIG5vZGUgaWYgaXRzIGBrZXlgIGlzIGlkZW50aWNhbCB0byB0aGUga2V5IG9mIGBub2RlYFxyXG4gICAqL1xyXG4gIGFkZE5vZGUobm9kZTogQmluYXJ5VHJlZU5vZGU8SywgVj4pOiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB7XHJcbiAgICBpZiAobm9kZSkge1xyXG4gICAgICBpZiAodGhpcy5rZXlDb21wYXJhdG9yLmxlc3NUaGFuKG5vZGUua2V5LCB0aGlzLmtleSkpIHtcclxuICAgICAgICAvLyBJbnNlcnQgdG8gdGhlIGxlZnQuXHJcbiAgICAgICAgaWYgKHRoaXMubGVmdCkge1xyXG4gICAgICAgICAgcmV0dXJuIHRoaXMubGVmdC5hZGROb2RlKG5vZGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnNldExlZnQobm9kZSk7XHJcbiAgICAgICAgcmV0dXJuIG5vZGU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmICh0aGlzLmtleUNvbXBhcmF0b3IuZ3JlYXRlclRoYW4obm9kZS5rZXksIHRoaXMua2V5KSkge1xyXG4gICAgICAgIC8vIEluc2VydCB0byB0aGUgcmlnaHQuXHJcbiAgICAgICAgaWYgKHRoaXMucmlnaHQpIHtcclxuICAgICAgICAgIHJldHVybiB0aGlzLnJpZ2h0LmFkZE5vZGUobm9kZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHRoaXMuc2V0UmlnaHQobm9kZSk7XHJcbiAgICAgICAgcmV0dXJuIG5vZGU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMuc2V0VmFsdWUobm9kZS52YWx1ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG4gIC8qKlxyXG4gICAqIEFkZHMgYSBuZXcgbm9kZSB0byB0aGUgY3VycmVudCBub2RlXHJcbiAgICogQHBhcmFtIGtleSAgIEtleSBvZiB0aGUgbm9kZVxyXG4gICAqIEBwYXJhbSB2YWx1ZSBOb2RlJ3MgdmFsdWVcclxuICAgKiBAcmV0dXJucyB7QmluYXJ5VHJlZU5vZGV9XHJcbiAgICovXHJcbiAgYWRkKGtleTogSywgdmFsdWU6IEVsZW1lbnQ8Vj4pOiBCaW5hcnlUcmVlTm9kZTxLLCBWPiB7XHJcbiAgICBjb25zdCBuZXdOb2RlID0gbmV3IEJpbmFyeVRyZWVOb2RlKGtleSwgdmFsdWUsIHRoaXMua2V5Q29tcGFyYXRvcik7XHJcbiAgICByZXR1cm4gdGhpcy5hZGROb2RlKG5ld05vZGUpO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZW1vdmVzIHRoZSBub2RlIHdpdGggdGhlIGtleSBga2V5YCBmcm9tIHRoZSBjdXJyZW50IG5vZGVcclxuICAgKiBAcGFyYW0ge0t9IGtleSAgIEEga2V5IG9mIHRoZSBub2RlIHRvIHJlbW92ZVxyXG4gICAqIEByZXR1cm5zIHtCaW5hcnlUcmVlTm9kZXxudWxsfSBSZW1vdmVkIG5vZGUgb3IgYG51bGxgIGlmIHRoZSBub2RlIHdhcyBub3QgZm91bmRcclxuICAgKi9cclxuICByZW1vdmUoa2V5OiBLKTogUmVhZG9ubHk8QmluYXJ5VHJlZU5vZGU8SywgVj4+IHwgbnVsbCB7XHJcbiAgICBjb25zdCBub2RlVG9SZW1vdmUgPSB0aGlzLmZpbmROb2RlKGtleSkgYXMgQmluYXJ5VHJlZU5vZGU8SywgVj47XHJcblxyXG4gICAgaWYgKCFub2RlVG9SZW1vdmUpIHtcclxuICAgICAgLy90aHJvdyBuZXcgRXJyb3IoJ0l0ZW0gbm90IGZvdW5kIGluIHRoZSB0cmVlJyk7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IHsgcGFyZW50IH0gPSBub2RlVG9SZW1vdmU7XHJcblxyXG4gICAgaWYgKCFub2RlVG9SZW1vdmUubGVmdCAmJiAhbm9kZVRvUmVtb3ZlLnJpZ2h0KSB7XHJcbiAgICAgIC8vIE5vZGUgaXMgYSBsZWFmIGFuZCB0aHVzIGhhcyBubyBjaGlsZHJlbi5cclxuICAgICAgaWYgKHBhcmVudCkge1xyXG4gICAgICAgIC8vIE5vZGUgaGFzIGEgcGFyZW50LiBKdXN0IHJlbW92ZSB0aGUgcG9pbnRlciB0byB0aGlzIG5vZGUgZnJvbSB0aGUgcGFyZW50LlxyXG4gICAgICAgIHBhcmVudC5yZW1vdmVDaGlsZChub2RlVG9SZW1vdmUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vZGUgaGFzIG5vIHBhcmVudC4gSnVzdCBlcmFzZSBjdXJyZW50IG5vZGUgdmFsdWUuXHJcbiAgICAgICAgbm9kZVRvUmVtb3ZlLnNldFZhbHVlKG51bGwpO1xyXG4gICAgICAgIG5vZGVUb1JlbW92ZS5zZXRMZWZ0KG51bGwpO1xyXG4gICAgICAgIG5vZGVUb1JlbW92ZS5zZXRSaWdodChudWxsKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChub2RlVG9SZW1vdmUubGVmdCAmJiBub2RlVG9SZW1vdmUucmlnaHQpIHtcclxuICAgICAgLy8gTm9kZSBoYXMgdHdvIGNoaWxkcmVuLlxyXG4gICAgICAvLyBGaW5kIHRoZSBuZXh0IGJpZ2dlc3QgdmFsdWUgKG1pbmltdW0gdmFsdWUgaW4gdGhlIHJpZ2h0IGJyYW5jaClcclxuICAgICAgLy8gYW5kIHJlcGxhY2UgY3VycmVudCB2YWx1ZSBub2RlIHdpdGggdGhhdCBuZXh0IGJpZ2dlc3QgdmFsdWUuXHJcbiAgICAgIGNvbnN0IG5leHRCaWdnZXJOb2RlID0gbm9kZVRvUmVtb3ZlLnJpZ2h0LmZpbmRNaW4oKTtcclxuICAgICAgaWYgKCEodGhpcy5ub2RlQ29tcGFyZShuZXh0QmlnZ2VyTm9kZSwgbm9kZVRvUmVtb3ZlLnJpZ2h0KSA9PSAwKSkge1xyXG4gICAgICAgIHRoaXMucmVtb3ZlKG5leHRCaWdnZXJOb2RlLmtleSk7XHJcbiAgICAgICAgbm9kZVRvUmVtb3ZlLmtleSA9IG5leHRCaWdnZXJOb2RlLmtleTtcclxuICAgICAgICBub2RlVG9SZW1vdmUudmFsdWUgPSBuZXh0QmlnZ2VyTm9kZS52YWx1ZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBJbiBjYXNlIGlmIG5leHQgcmlnaHQgdmFsdWUgaXMgdGhlIG5leHQgYmlnZ2VyIG9uZSBhbmQgaXQgZG9lc24ndCBoYXZlIGxlZnQgY2hpbGRcclxuICAgICAgICAvLyB0aGVuIGp1c3QgcmVwbGFjZSBub2RlIHRoYXQgaXMgZ29pbmcgdG8gYmUgZGVsZXRlZCB3aXRoIHRoZSByaWdodCBub2RlLlxyXG4gICAgICAgIG5vZGVUb1JlbW92ZS5rZXkgPSBub2RlVG9SZW1vdmUucmlnaHQua2V5O1xyXG4gICAgICAgIG5vZGVUb1JlbW92ZS52YWx1ZSA9IG5vZGVUb1JlbW92ZS5yaWdodC52YWx1ZTtcclxuICAgICAgICBub2RlVG9SZW1vdmUuc2V0UmlnaHQobm9kZVRvUmVtb3ZlLnJpZ2h0LnJpZ2h0KTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gTm9kZSBoYXMgb25seSBvbmUgY2hpbGQuXHJcbiAgICAgIC8vIE1ha2UgdGhpcyBjaGlsZCB0byBiZSBhIGRpcmVjdCBjaGlsZCBvZiBjdXJyZW50IG5vZGUncyBwYXJlbnQuXHJcbiAgICAgIGNvbnN0IGNoaWxkTm9kZSA9IG5vZGVUb1JlbW92ZS5sZWZ0IHx8IG5vZGVUb1JlbW92ZS5yaWdodDtcclxuXHJcbiAgICAgIGlmIChjaGlsZE5vZGUpIHtcclxuICAgICAgICBpZiAocGFyZW50KSB7XHJcbiAgICAgICAgICBwYXJlbnQucmVwbGFjZUNoaWxkKG5vZGVUb1JlbW92ZSwgY2hpbGROb2RlKTtcclxuICAgICAgICAgIG5vZGVUb1JlbW92ZS5zZXRMZWZ0KG51bGwpO1xyXG4gICAgICAgICAgbm9kZVRvUmVtb3ZlLnNldFJpZ2h0KG51bGwpO1xyXG4gICAgICAgICAgbm9kZVRvUmVtb3ZlLnNldFZhbHVlKG51bGwpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBCaW5hcnlUcmVlTm9kZS5jb3B5Tm9kZShjaGlsZE5vZGUsIG5vZGVUb1JlbW92ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgdGhlIHBhcmVudCBvZiByZW1vdmVkIG5vZGUuXHJcbiAgICBub2RlVG9SZW1vdmUucGFyZW50ID0gbnVsbDtcclxuXHJcbiAgICByZXR1cm4gbm9kZVRvUmVtb3ZlO1xyXG4gIH1cclxuICAvKipcclxuICAgKiBSZXR1cm5zIHRoZSBjb21tYSBkZWxpbWl0ZWQgc3RyaW5nIG9mIHRyZWUga2V5c1xyXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IFN0cmluZ1xyXG4gICAqL1xyXG4gICB0b1N0cmluZygpOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIHRoaXMudHJhdmVyc2UoKS5tYXAobm9kZSA9PiBub2RlLmtleSkudG9TdHJpbmcoKTtcclxuICB9XHJcblxyXG59XHJcbiJdfQ==