UNPKG

@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
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==