metaapi.cloud-sdk
Version:
SDK for MetaApi, a professional cloud forex API which includes MetaTrader REST API and MetaTrader websocket API. Supports both MetaTrader 5 (MT5) and MetaTrader 4 (MT4). CopyFactory copy trading API included. (https://metaapi.cloud)
420 lines (419 loc) • 47.6 kB
JavaScript
/* eslint-disable @typescript-eslint/no-this-alias */ /**
* Self-balancing binary search tree using the AVL implementation
*/ "use strict";
const BinarySearchTree = require("./bst"), customUtils = require("./customUtils"), util = require("util");
/**
* Constructor
* We can't use a direct pointer to the root node (as in the simple binary search tree)
* as the root will change during tree rotations
* @param {Boolean} options.unique Whether to enforce a 'unique' constraint on the key or not
* @param {Function} options.compareKeys Initialize this BST's compareKeys
*/ function AVLTree(options) {
this.tree = new _AVLTree(options);
}
/**
* Constructor of the internal AVLTree
* @param {Object} options Optional
* @param {Boolean} options.unique Whether to enforce a 'unique' constraint on the key or not
* @param {Key} options.key Initialize this BST's key with key
* @param {Value} options.value Initialize this BST's data with [value]
* @param {Function} options.compareKeys Initialize this BST's compareKeys
*/ function _AVLTree(options) {
options = options || {};
this.left = null;
this.right = null;
this.parent = options.parent !== undefined ? options.parent : null;
if (Object.prototype.hasOwnProperty.call(options, "key")) {
this.key = options.key;
}
this.data = Object.prototype.hasOwnProperty.call(options, "value") ? [
options.value
] : [];
this.unique = options.unique || false;
this.compareKeys = options.compareKeys || customUtils.defaultCompareKeysFunction;
this.checkValueEquality = options.checkValueEquality || customUtils.defaultCheckValueEquality;
}
/**
* Inherit basic functions from the basic binary search tree
*/ util.inherits(_AVLTree, BinarySearchTree);
/**
* Keep a pointer to the internal tree constructor for testing purposes
*/ AVLTree._AVLTree = _AVLTree;
/**
* Check the recorded height is correct for every node
* Throws if one height doesn't match
*/ // eslint-disable-next-line complexity
_AVLTree.prototype.checkHeightCorrect = function() {
let leftH, rightH;
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return;
} // Empty tree
if (this.left && this.left.height === undefined) {
throw new Error("Undefined height for node " + this.left.key);
}
if (this.right && this.right.height === undefined) {
throw new Error("Undefined height for node " + this.right.key);
}
if (this.height === undefined) {
throw new Error("Undefined height for node " + this.key);
}
leftH = this.left ? this.left.height : 0;
rightH = this.right ? this.right.height : 0;
if (this.height !== 1 + Math.max(leftH, rightH)) {
throw new Error("Height constraint failed for node " + this.key);
}
if (this.left) {
this.left.checkHeightCorrect();
}
if (this.right) {
this.right.checkHeightCorrect();
}
};
/**
* Return the balance factor
*/ _AVLTree.prototype.balanceFactor = function() {
let leftH = this.left ? this.left.height : 0, rightH = this.right ? this.right.height : 0;
return leftH - rightH;
};
/**
* Check that the balance factors are all between -1 and 1
*/ _AVLTree.prototype.checkBalanceFactors = function() {
if (Math.abs(this.balanceFactor()) > 1) {
throw new Error("Tree is unbalanced at node " + this.key);
}
if (this.left) {
this.left.checkBalanceFactors();
}
if (this.right) {
this.right.checkBalanceFactors();
}
};
/**
* When checking if the BST conditions are met, also check that the heights are correct
* and the tree is balanced
*/ _AVLTree.prototype.checkIsAVLT = function() {
_AVLTree.super_.prototype.checkIsBST.call(this);
this.checkHeightCorrect();
this.checkBalanceFactors();
};
AVLTree.prototype.checkIsAVLT = function() {
this.tree.checkIsAVLT();
};
/**
* Perform a right rotation of the tree if possible
* and return the root of the resulting tree
* The resulting tree's nodes' heights are also updated
*/ _AVLTree.prototype.rightRotation = function() {
let q = this, p = this.left, b, ah, bh, ch;
if (!p) {
return this;
} // No change
b = p.right;
// Alter tree structure
if (q.parent) {
p.parent = q.parent;
if (q.parent.left === q) {
q.parent.left = p;
} else {
q.parent.right = p;
}
} else {
p.parent = null;
}
p.right = q;
q.parent = p;
q.left = b;
if (b) {
b.parent = q;
}
// Update heights
ah = p.left ? p.left.height : 0;
bh = b ? b.height : 0;
ch = q.right ? q.right.height : 0;
q.height = Math.max(bh, ch) + 1;
p.height = Math.max(ah, q.height) + 1;
return p;
};
/**
* Perform a left rotation of the tree if possible
* and return the root of the resulting tree
* The resulting tree's nodes' heights are also updated
*/ _AVLTree.prototype.leftRotation = function() {
let p = this, q = this.right, b, ah, bh, ch;
if (!q) {
return this;
} // No change
b = q.left;
// Alter tree structure
if (p.parent) {
q.parent = p.parent;
if (p.parent.left === p) {
p.parent.left = q;
} else {
p.parent.right = q;
}
} else {
q.parent = null;
}
q.left = p;
p.parent = q;
p.right = b;
if (b) {
b.parent = p;
}
// Update heights
ah = p.left ? p.left.height : 0;
bh = b ? b.height : 0;
ch = q.right ? q.right.height : 0;
p.height = Math.max(ah, bh) + 1;
q.height = Math.max(ch, p.height) + 1;
return q;
};
/**
* Modify the tree if its right subtree is too small compared to the left
* Return the new root if any
*/ _AVLTree.prototype.rightTooSmall = function() {
if (this.balanceFactor() <= 1) {
return this;
} // Right is not too small, don't change
if (this.left.balanceFactor() < 0) {
this.left.leftRotation();
}
return this.rightRotation();
};
/**
* Modify the tree if its left subtree is too small compared to the right
* Return the new root if any
*/ _AVLTree.prototype.leftTooSmall = function() {
if (this.balanceFactor() >= -1) {
return this;
} // Left is not too small, don't change
if (this.right.balanceFactor() > 0) {
this.right.rightRotation();
}
return this.leftRotation();
};
/**
* Rebalance the tree along the given path. The path is given reversed (as he was calculated
* in the insert and delete functions).
* Returns the new root of the tree
* Of course, the first element of the path must be the root of the tree
*/ // eslint-disable-next-line complexity
_AVLTree.prototype.rebalanceAlongPath = function(path) {
let newRoot = this, rotated, i;
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
delete this.height;
return this;
} // Empty tree
// Rebalance the tree and update all heights
for(i = path.length - 1; i >= 0; i -= 1){
path[i].height = 1 + Math.max(path[i].left ? path[i].left.height : 0, path[i].right ? path[i].right.height : 0);
if (path[i].balanceFactor() > 1) {
rotated = path[i].rightTooSmall();
if (i === 0) {
newRoot = rotated;
}
}
if (path[i].balanceFactor() < -1) {
rotated = path[i].leftTooSmall();
if (i === 0) {
newRoot = rotated;
}
}
}
return newRoot;
};
/**
* Insert a key, value pair in the tree while maintaining the AVL tree height constraint
* Return a pointer to the root node, which may have changed
*/ _AVLTree.prototype.insert = function(key, value) {
let insertPath = [], currentNode = this;
// Empty tree, insert as root
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
this.key = key;
this.data.push(value);
this.height = 1;
return this;
}
// Insert new leaf at the right place
// eslint-disable-next-line no-constant-condition
while(true){
// Same key: no change in the tree structure
if (currentNode.compareKeys(currentNode.key, key) === 0) {
if (currentNode.unique) {
let err = new Error("Can't insert key " + key + ", it violates the unique constraint");
err.key = key;
err.errorType = "uniqueViolated";
throw err;
} else {
currentNode.data.push(value);
}
return this;
}
insertPath.push(currentNode);
if (currentNode.compareKeys(key, currentNode.key) < 0) {
if (!currentNode.left) {
insertPath.push(currentNode.createLeftChild({
key: key,
value: value
}));
break;
} else {
currentNode = currentNode.left;
}
} else {
if (!currentNode.right) {
insertPath.push(currentNode.createRightChild({
key: key,
value: value
}));
break;
} else {
currentNode = currentNode.right;
}
}
}
return this.rebalanceAlongPath(insertPath);
};
// Insert in the internal tree, update the pointer to the root if needed
AVLTree.prototype.insert = function(key, value) {
let newTree = this.tree.insert(key, value);
// If newTree is undefined, that means its structure was not modified
if (newTree) {
this.tree = newTree;
}
};
/**
* Delete a key or just a value and return the new root of the tree
* @param {Key} key
* @param {Value} value Optional. If not set, the whole key is deleted. If set, only this value is deleted
*/ // eslint-disable-next-line max-statements, complexity
_AVLTree.prototype.delete = function(key, value) {
let newData = [], replaceWith, self = this, currentNode = this, deletePath = [];
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return this;
} // Empty tree
// Either no match is found and the function will return from within the loop
// Or a match is found and deletePath will contain the path from the root to the node to delete after the loop
// eslint-disable-next-line no-constant-condition
while(true){
if (currentNode.compareKeys(key, currentNode.key) === 0) {
break;
}
deletePath.push(currentNode);
if (currentNode.compareKeys(key, currentNode.key) < 0) {
if (currentNode.left) {
currentNode = currentNode.left;
} else {
return this; // Key not found, no modification
}
} else {
// currentNode.compareKeys(key, currentNode.key) is > 0
if (currentNode.right) {
currentNode = currentNode.right;
} else {
return this; // Key not found, no modification
}
}
}
// Delete only a value (no tree modification)
if (currentNode.data.length > 1 && value !== undefined) {
currentNode.data.forEach(function(d) {
if (!currentNode.checkValueEquality(d, value)) {
newData.push(d);
}
});
currentNode.data = newData;
return this;
}
// Delete a whole node
// Leaf
if (!currentNode.left && !currentNode.right) {
if (currentNode === this) {
delete currentNode.key;
currentNode.data = [];
delete currentNode.height;
return this;
} else {
if (currentNode.parent.left === currentNode) {
currentNode.parent.left = null;
} else {
currentNode.parent.right = null;
}
return this.rebalanceAlongPath(deletePath);
}
}
// Node with only one child
if (!currentNode.left || !currentNode.right) {
replaceWith = currentNode.left ? currentNode.left : currentNode.right;
if (currentNode === this) {
replaceWith.parent = null;
return replaceWith; // height of replaceWith is necessarily 1 because the tree was balanced before deletion
} else {
if (currentNode.parent.left === currentNode) {
currentNode.parent.left = replaceWith;
replaceWith.parent = currentNode.parent;
} else {
currentNode.parent.right = replaceWith;
replaceWith.parent = currentNode.parent;
}
return this.rebalanceAlongPath(deletePath);
}
}
// Node with two children
// Use the in-order predecessor (no need to randomize since we actively rebalance)
deletePath.push(currentNode);
replaceWith = currentNode.left;
// Special case: the in-order predecessor is right below the node to delete
if (!replaceWith.right) {
currentNode.key = replaceWith.key;
currentNode.data = replaceWith.data;
currentNode.left = replaceWith.left;
if (replaceWith.left) {
replaceWith.left.parent = currentNode;
}
return this.rebalanceAlongPath(deletePath);
}
// After this loop, replaceWith is the right-most leaf in the left subtree
// and deletePath the path from the root (inclusive) to replaceWith (exclusive)
// eslint-disable-next-line no-constant-condition
while(true){
if (replaceWith.right) {
deletePath.push(replaceWith);
replaceWith = replaceWith.right;
} else {
break;
}
}
currentNode.key = replaceWith.key;
currentNode.data = replaceWith.data;
replaceWith.parent.right = replaceWith.left;
if (replaceWith.left) {
replaceWith.left.parent = replaceWith.parent;
}
return this.rebalanceAlongPath(deletePath);
};
// Delete a value
AVLTree.prototype.delete = function(key, value) {
let newTree = this.tree.delete(key, value);
// If newTree is undefined, that means its structure was not modified
if (newTree) {
this.tree = newTree;
}
};
/**
* Other functions we want to use on an AVLTree as if it were the internal _AVLTree
*/ [
"getNumberOfKeys",
"search",
"betweenBounds",
"prettyPrint",
"executeOnEveryNode"
].forEach(function(fn) {
AVLTree.prototype[fn] = function() {
return this.tree[fn].apply(this.tree, arguments);
};
});
// Interface
module.exports.AVLTree = AVLTree;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhcyAqL1xuLyoqXG4gKiBTZWxmLWJhbGFuY2luZyBiaW5hcnkgc2VhcmNoIHRyZWUgdXNpbmcgdGhlIEFWTCBpbXBsZW1lbnRhdGlvblxuICovXG5jb25zdCBCaW5hcnlTZWFyY2hUcmVlID0gcmVxdWlyZSgnLi9ic3QnKVxuICAsIGN1c3RvbVV0aWxzID0gcmVxdWlyZSgnLi9jdXN0b21VdGlscycpXG4gICwgdXRpbCA9IHJlcXVpcmUoJ3V0aWwnKVxuICA7XG5cblxuLyoqXG4gKiBDb25zdHJ1Y3RvclxuICogV2UgY2FuJ3QgdXNlIGEgZGlyZWN0IHBvaW50ZXIgdG8gdGhlIHJvb3Qgbm9kZSAoYXMgaW4gdGhlIHNpbXBsZSBiaW5hcnkgc2VhcmNoIHRyZWUpXG4gKiBhcyB0aGUgcm9vdCB3aWxsIGNoYW5nZSBkdXJpbmcgdHJlZSByb3RhdGlvbnNcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gIG9wdGlvbnMudW5pcXVlIFdoZXRoZXIgdG8gZW5mb3JjZSBhICd1bmlxdWUnIGNvbnN0cmFpbnQgb24gdGhlIGtleSBvciBub3RcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG9wdGlvbnMuY29tcGFyZUtleXMgSW5pdGlhbGl6ZSB0aGlzIEJTVCdzIGNvbXBhcmVLZXlzXG4gKi9cbmZ1bmN0aW9uIEFWTFRyZWUgKG9wdGlvbnMpIHtcbiAgdGhpcy50cmVlID0gbmV3IF9BVkxUcmVlKG9wdGlvbnMpO1xufVxuXG5cbi8qKlxuICogQ29uc3RydWN0b3Igb2YgdGhlIGludGVybmFsIEFWTFRyZWVcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE9wdGlvbmFsXG4gKiBAcGFyYW0ge0Jvb2xlYW59ICBvcHRpb25zLnVuaXF1ZSBXaGV0aGVyIHRvIGVuZm9yY2UgYSAndW5pcXVlJyBjb25zdHJhaW50IG9uIHRoZSBrZXkgb3Igbm90XG4gKiBAcGFyYW0ge0tleX0gICAgICBvcHRpb25zLmtleSBJbml0aWFsaXplIHRoaXMgQlNUJ3Mga2V5IHdpdGgga2V5XG4gKiBAcGFyYW0ge1ZhbHVlfSAgICBvcHRpb25zLnZhbHVlIEluaXRpYWxpemUgdGhpcyBCU1QncyBkYXRhIHdpdGggW3ZhbHVlXVxuICogQHBhcmFtIHtGdW5jdGlvbn0gb3B0aW9ucy5jb21wYXJlS2V5cyBJbml0aWFsaXplIHRoaXMgQlNUJ3MgY29tcGFyZUtleXNcbiAqL1xuZnVuY3Rpb24gX0FWTFRyZWUgKG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cbiAgdGhpcy5sZWZ0ID0gbnVsbDtcbiAgdGhpcy5yaWdodCA9IG51bGw7XG4gIHRoaXMucGFyZW50ID0gb3B0aW9ucy5wYXJlbnQgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMucGFyZW50IDogbnVsbDtcbiAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb25zLCAna2V5JykpIHsgdGhpcy5rZXkgPSBvcHRpb25zLmtleTsgfVxuICB0aGlzLmRhdGEgPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9ucywgJ3ZhbHVlJykgPyBbb3B0aW9ucy52YWx1ZV0gOiBbXTtcbiAgdGhpcy51bmlxdWUgPSBvcHRpb25zLnVuaXF1ZSB8fCBmYWxzZTtcblxuICB0aGlzLmNvbXBhcmVLZXlzID0gb3B0aW9ucy5jb21wYXJlS2V5cyB8fCBjdXN0b21VdGlscy5kZWZhdWx0Q29tcGFyZUtleXNGdW5jdGlvbjtcbiAgdGhpcy5jaGVja1ZhbHVlRXF1YWxpdHkgPSBvcHRpb25zLmNoZWNrVmFsdWVFcXVhbGl0eSB8fCBjdXN0b21VdGlscy5kZWZhdWx0Q2hlY2tWYWx1ZUVxdWFsaXR5O1xufVxuXG5cbi8qKlxuICogSW5oZXJpdCBiYXNpYyBmdW5jdGlvbnMgZnJvbSB0aGUgYmFzaWMgYmluYXJ5IHNlYXJjaCB0cmVlXG4gKi9cbnV0aWwuaW5oZXJpdHMoX0FWTFRyZWUsIEJpbmFyeVNlYXJjaFRyZWUpO1xuXG4vKipcbiAqIEtlZXAgYSBwb2ludGVyIHRvIHRoZSBpbnRlcm5hbCB0cmVlIGNvbnN0cnVjdG9yIGZvciB0ZXN0aW5nIHB1cnBvc2VzXG4gKi9cbkFWTFRyZWUuX0FWTFRyZWUgPSBfQVZMVHJlZTtcblxuXG4vKipcbiAqIENoZWNrIHRoZSByZWNvcmRlZCBoZWlnaHQgaXMgY29ycmVjdCBmb3IgZXZlcnkgbm9kZVxuICogVGhyb3dzIGlmIG9uZSBoZWlnaHQgZG9lc24ndCBtYXRjaFxuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGxleGl0eVxuX0FWTFRyZWUucHJvdG90eXBlLmNoZWNrSGVpZ2h0Q29ycmVjdCA9IGZ1bmN0aW9uICgpIHtcbiAgbGV0IGxlZnRILCByaWdodEg7XG5cbiAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcywgJ2tleScpKSB7IHJldHVybjsgfSAgIC8vIEVtcHR5IHRyZWVcblxuICBpZiAodGhpcy5sZWZ0ICYmIHRoaXMubGVmdC5oZWlnaHQgPT09IHVuZGVmaW5lZCkgeyB0aHJvdyBuZXcgRXJyb3IoJ1VuZGVmaW5lZCBoZWlnaHQgZm9yIG5vZGUgJyArIHRoaXMubGVmdC5rZXkpOyB9XG4gIGlmICh0aGlzLnJpZ2h0ICYmIHRoaXMucmlnaHQuaGVpZ2h0ID09PSB1bmRlZmluZWQpIHsgdGhyb3cgbmV3IEVycm9yKCdVbmRlZmluZWQgaGVpZ2h0IGZvciBub2RlICcgKyB0aGlzLnJpZ2h0LmtleSk7IH1cbiAgaWYgKHRoaXMuaGVpZ2h0ID09PSB1bmRlZmluZWQpIHsgdGhyb3cgbmV3IEVycm9yKCdVbmRlZmluZWQgaGVpZ2h0IGZvciBub2RlICcgKyB0aGlzLmtleSk7IH1cblxuICBsZWZ0SCA9IHRoaXMubGVmdCA/IHRoaXMubGVmdC5oZWlnaHQgOiAwO1xuICByaWdodEggPSB0aGlzLnJpZ2h0ID8gdGhpcy5yaWdodC5oZWlnaHQgOiAwO1xuXG4gIGlmICh0aGlzLmhlaWdodCAhPT0gMSArIE1hdGgubWF4KGxlZnRILCByaWdodEgpKSB7IHRocm93IG5ldyBFcnJvcignSGVpZ2h0IGNvbnN0cmFpbnQgZmFpbGVkIGZvciBub2RlICcgKyB0aGlzLmtleSk7IH1cbiAgaWYgKHRoaXMubGVmdCkgeyB0aGlzLmxlZnQuY2hlY2tIZWlnaHRDb3JyZWN0KCk7IH1cbiAgaWYgKHRoaXMucmlnaHQpIHsgdGhpcy5yaWdodC5jaGVja0hlaWdodENvcnJlY3QoKTsgfVxufTtcblxuXG4vKipcbiAqIFJldHVybiB0aGUgYmFsYW5jZSBmYWN0b3JcbiAqL1xuX0FWTFRyZWUucHJvdG90eXBlLmJhbGFuY2VGYWN0b3IgPSBmdW5jdGlvbiAoKSB7XG4gIGxldCBsZWZ0SCA9IHRoaXMubGVmdCA/IHRoaXMubGVmdC5oZWlnaHQgOiAwXG4gICAgLCByaWdodEggPSB0aGlzLnJpZ2h0ID8gdGhpcy5yaWdodC5oZWlnaHQgOiAwXG4gICAgO1xuICByZXR1cm4gbGVmdEggLSByaWdodEg7XG59O1xuXG5cbi8qKlxuICogQ2hlY2sgdGhhdCB0aGUgYmFsYW5jZSBmYWN0b3JzIGFyZSBhbGwgYmV0d2VlbiAtMSBhbmQgMVxuICovXG5fQVZMVHJlZS5wcm90b3R5cGUuY2hlY2tCYWxhbmNlRmFjdG9ycyA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKE1hdGguYWJzKHRoaXMuYmFsYW5jZUZhY3RvcigpKSA+IDEpIHsgdGhyb3cgbmV3IEVycm9yKCdUcmVlIGlzIHVuYmFsYW5jZWQgYXQgbm9kZSAnICsgdGhpcy5rZXkpOyB9XG5cbiAgaWYgKHRoaXMubGVmdCkgeyB0aGlzLmxlZnQuY2hlY2tCYWxhbmNlRmFjdG9ycygpOyB9XG4gIGlmICh0aGlzLnJpZ2h0KSB7IHRoaXMucmlnaHQuY2hlY2tCYWxhbmNlRmFjdG9ycygpOyB9XG59O1xuXG5cbi8qKlxuICogV2hlbiBjaGVja2luZyBpZiB0aGUgQlNUIGNvbmRpdGlvbnMgYXJlIG1ldCwgYWxzbyBjaGVjayB0aGF0IHRoZSBoZWlnaHRzIGFyZSBjb3JyZWN0XG4gKiBhbmQgdGhlIHRyZWUgaXMgYmFsYW5jZWRcbiAqL1xuX0FWTFRyZWUucHJvdG90eXBlLmNoZWNrSXNBVkxUID0gZnVuY3Rpb24gKCkge1xuICBfQVZMVHJlZS5zdXBlcl8ucHJvdG90eXBlLmNoZWNrSXNCU1QuY2FsbCh0aGlzKTtcbiAgdGhpcy5jaGVja0hlaWdodENvcnJlY3QoKTtcbiAgdGhpcy5jaGVja0JhbGFuY2VGYWN0b3JzKCk7XG59O1xuQVZMVHJlZS5wcm90b3R5cGUuY2hlY2tJc0FWTFQgPSBmdW5jdGlvbiAoKSB7IHRoaXMudHJlZS5jaGVja0lzQVZMVCgpOyB9O1xuXG5cbi8qKlxuICogUGVyZm9ybSBhIHJpZ2h0IHJvdGF0aW9uIG9mIHRoZSB0cmVlIGlmIHBvc3NpYmxlXG4gKiBhbmQgcmV0dXJuIHRoZSByb290IG9mIHRoZSByZXN1bHRpbmcgdHJlZVxuICogVGhlIHJlc3VsdGluZyB0cmVlJ3Mgbm9kZXMnIGhlaWdodHMgYXJlIGFsc28gdXBkYXRlZFxuICovXG5fQVZMVHJlZS5wcm90b3R5cGUucmlnaHRSb3RhdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgbGV0IHEgPSB0aGlzXG4gICAgLCBwID0gdGhpcy5sZWZ0XG4gICAgLCBiXG4gICAgLCBhaCwgYmgsIGNoO1xuXG4gIGlmICghcCkgeyByZXR1cm4gdGhpczsgfSAgIC8vIE5vIGNoYW5nZVxuXG4gIGIgPSBwLnJpZ2h0O1xuXG4gIC8vIEFsdGVyIHRyZWUgc3RydWN0dXJlXG4gIGlmIChxLnBhcmVudCkge1xuICAgIHAucGFyZW50ID0gcS5wYXJlbnQ7XG4gICAgaWYgKHEucGFyZW50LmxlZnQgPT09IHEpIHsgcS5wYXJlbnQubGVmdCA9IHA7IH0gZWxzZSB7IHEucGFyZW50LnJpZ2h0ID0gcDsgfVxuICB9IGVsc2Uge1xuICAgIHAucGFyZW50ID0gbnVsbDtcbiAgfVxuICBwLnJpZ2h0ID0gcTtcbiAgcS5wYXJlbnQgPSBwO1xuICBxLmxlZnQgPSBiO1xuICBpZiAoYikgeyBiLnBhcmVudCA9IHE7IH1cblxuICAvLyBVcGRhdGUgaGVpZ2h0c1xuICBhaCA9IHAubGVmdCA/IHAubGVmdC5oZWlnaHQgOiAwO1xuICBiaCA9IGIgPyBiLmhlaWdodCA6IDA7XG4gIGNoID0gcS5yaWdodCA/IHEucmlnaHQuaGVpZ2h0IDogMDtcbiAgcS5oZWlnaHQgPSBNYXRoLm1heChiaCwgY2gpICsgMTtcbiAgcC5oZWlnaHQgPSBNYXRoLm1heChhaCwgcS5oZWlnaHQpICsgMTtcblxuICByZXR1cm4gcDtcbn07XG5cblxuLyoqXG4gKiBQZXJmb3JtIGEgbGVmdCByb3RhdGlvbiBvZiB0aGUgdHJlZSBpZiBwb3NzaWJsZVxuICogYW5kIHJldHVybiB0aGUgcm9vdCBvZiB0aGUgcmVzdWx0aW5nIHRyZWVcbiAqIFRoZSByZXN1bHRpbmcgdHJlZSdzIG5vZGVzJyBoZWlnaHRzIGFyZSBhbHNvIHVwZGF0ZWRcbiAqL1xuX0FWTFRyZWUucHJvdG90eXBlLmxlZnRSb3RhdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgbGV0IHAgPSB0aGlzXG4gICAgLCBxID0gdGhpcy5yaWdodFxuICAgICwgYlxuICAgICwgYWgsIGJoLCBjaDtcblxuICBpZiAoIXEpIHsgcmV0dXJuIHRoaXM7IH0gICAvLyBObyBjaGFuZ2VcblxuICBiID0gcS5sZWZ0O1xuXG4gIC8vIEFsdGVyIHRyZWUgc3RydWN0dXJlXG4gIGlmIChwLnBhcmVudCkge1xuICAgIHEucGFyZW50ID0gcC5wYXJlbnQ7XG4gICAgaWYgKHAucGFyZW50LmxlZnQgPT09IHApIHsgcC5wYXJlbnQubGVmdCA9IHE7IH0gZWxzZSB7IHAucGFyZW50LnJpZ2h0ID0gcTsgfVxuICB9IGVsc2Uge1xuICAgIHEucGFyZW50ID0gbnVsbDtcbiAgfVxuICBxLmxlZnQgPSBwO1xuICBwLnBhcmVudCA9IHE7XG4gIHAucmlnaHQgPSBiO1xuICBpZiAoYikgeyBiLnBhcmVudCA9IHA7IH1cblxuICAvLyBVcGRhdGUgaGVpZ2h0c1xuICBhaCA9IHAubGVmdCA/IHAubGVmdC5oZWlnaHQgOiAwO1xuICBiaCA9IGIgPyBiLmhlaWdodCA6IDA7XG4gIGNoID0gcS5yaWdodCA/IHEucmlnaHQuaGVpZ2h0IDogMDtcbiAgcC5oZWlnaHQgPSBNYXRoLm1heChhaCwgYmgpICsgMTtcbiAgcS5oZWlnaHQgPSBNYXRoLm1heChjaCwgcC5oZWlnaHQpICsgMTtcblxuICByZXR1cm4gcTtcbn07XG5cblxuLyoqXG4gKiBNb2RpZnkgdGhlIHRyZWUgaWYgaXRzIHJpZ2h0IHN1YnRyZWUgaXMgdG9vIHNtYWxsIGNvbXBhcmVkIHRvIHRoZSBsZWZ0XG4gKiBSZXR1cm4gdGhlIG5ldyByb290IGlmIGFueVxuICovXG5fQVZMVHJlZS5wcm90b3R5cGUucmlnaHRUb29TbWFsbCA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHRoaXMuYmFsYW5jZUZhY3RvcigpIDw9IDEpIHsgcmV0dXJuIHRoaXM7IH0gICAvLyBSaWdodCBpcyBub3QgdG9vIHNtYWxsLCBkb24ndCBjaGFuZ2VcblxuICBpZiAodGhpcy5sZWZ0LmJhbGFuY2VGYWN0b3IoKSA8IDApIHtcbiAgICB0aGlzLmxlZnQubGVmdFJvdGF0aW9uKCk7XG4gIH1cblxuICByZXR1cm4gdGhpcy5yaWdodFJvdGF0aW9uKCk7XG59O1xuXG5cbi8qKlxuICogTW9kaWZ5IHRoZSB0cmVlIGlmIGl0cyBsZWZ0IHN1YnRyZWUgaXMgdG9vIHNtYWxsIGNvbXBhcmVkIHRvIHRoZSByaWdodFxuICogUmV0dXJuIHRoZSBuZXcgcm9vdCBpZiBhbnlcbiAqL1xuX0FWTFRyZWUucHJvdG90eXBlLmxlZnRUb29TbWFsbCA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHRoaXMuYmFsYW5jZUZhY3RvcigpID49IC0xKSB7IHJldHVybiB0aGlzOyB9ICAgLy8gTGVmdCBpcyBub3QgdG9vIHNtYWxsLCBkb24ndCBjaGFuZ2VcblxuICBpZiAodGhpcy5yaWdodC5iYWxhbmNlRmFjdG9yKCkgPiAwKSB7XG4gICAgdGhpcy5yaWdodC5yaWdodFJvdGF0aW9uKCk7XG4gIH1cblxuICByZXR1cm4gdGhpcy5sZWZ0Um90YXRpb24oKTtcbn07XG5cblxuLyoqXG4gKiBSZWJhbGFuY2UgdGhlIHRyZWUgYWxvbmcgdGhlIGdpdmVuIHBhdGguIFRoZSBwYXRoIGlzIGdpdmVuIHJldmVyc2VkIChhcyBoZSB3YXMgY2FsY3VsYXRlZFxuICogaW4gdGhlIGluc2VydCBhbmQgZGVsZXRlIGZ1bmN0aW9ucykuXG4gKiBSZXR1cm5zIHRoZSBuZXcgcm9vdCBvZiB0aGUgdHJlZVxuICogT2YgY291cnNlLCB0aGUgZmlyc3QgZWxlbWVudCBvZiB0aGUgcGF0aCBtdXN0IGJlIHRoZSByb290IG9mIHRoZSB0cmVlXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG5fQVZMVHJlZS5wcm90b3R5cGUucmViYWxhbmNlQWxvbmdQYXRoID0gZnVuY3Rpb24gKHBhdGgpIHtcbiAgbGV0IG5ld1Jvb3QgPSB0aGlzXG4gICAgLCByb3RhdGVkXG4gICAgLCBpO1xuXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMsICdrZXknKSkgeyBkZWxldGUgdGhpcy5oZWlnaHQ7IHJldHVybiB0aGlzOyB9ICAgLy8gRW1wdHkgdHJlZVxuXG4gIC8vIFJlYmFsYW5jZSB0aGUgdHJlZSBhbmQgdXBkYXRlIGFsbCBoZWlnaHRzXG4gIGZvciAoaSA9IHBhdGgubGVuZ3RoIC0gMTsgaSA+PSAwOyBpIC09IDEpIHtcbiAgICBwYXRoW2ldLmhlaWdodCA9IDEgKyBNYXRoLm1heChwYXRoW2ldLmxlZnQgPyBwYXRoW2ldLmxlZnQuaGVpZ2h0IDogMCwgcGF0aFtpXS5yaWdodCA/IHBhdGhbaV0ucmlnaHQuaGVpZ2h0IDogMCk7XG5cbiAgICBpZiAocGF0aFtpXS5iYWxhbmNlRmFjdG9yKCkgPiAxKSB7XG4gICAgICByb3RhdGVkID0gcGF0aFtpXS5yaWdodFRvb1NtYWxsKCk7XG4gICAgICBpZiAoaSA9PT0gMCkgeyBuZXdSb290ID0gcm90YXRlZDsgfVxuICAgIH1cblxuICAgIGlmIChwYXRoW2ldLmJhbGFuY2VGYWN0b3IoKSA8IC0xKSB7XG4gICAgICByb3RhdGVkID0gcGF0aFtpXS5sZWZ0VG9vU21hbGwoKTtcbiAgICAgIGlmIChpID09PSAwKSB7IG5ld1Jvb3QgPSByb3RhdGVkOyB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG5ld1Jvb3Q7XG59O1xuXG5cbi8qKlxuICogSW5zZXJ0IGEga2V5LCB2YWx1ZSBwYWlyIGluIHRoZSB0cmVlIHdoaWxlIG1haW50YWluaW5nIHRoZSBBVkwgdHJlZSBoZWlnaHQgY29uc3RyYWludFxuICogUmV0dXJuIGEgcG9pbnRlciB0byB0aGUgcm9vdCBub2RlLCB3aGljaCBtYXkgaGF2ZSBjaGFuZ2VkXG4gKi9cbl9BVkxUcmVlLnByb3RvdHlwZS5pbnNlcnQgPSBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICBsZXQgaW5zZXJ0UGF0aCA9IFtdXG4gICAgLCBjdXJyZW50Tm9kZSA9IHRoaXNcbiAgICA7XG5cbiAgLy8gRW1wdHkgdHJlZSwgaW5zZXJ0IGFzIHJvb3RcbiAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcywgJ2tleScpKSB7XG4gICAgdGhpcy5rZXkgPSBrZXk7XG4gICAgdGhpcy5kYXRhLnB1c2godmFsdWUpO1xuICAgIHRoaXMuaGVpZ2h0ID0gMTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIEluc2VydCBuZXcgbGVhZiBhdCB0aGUgcmlnaHQgcGxhY2VcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnN0YW50LWNvbmRpdGlvblxuICB3aGlsZSAodHJ1ZSkge1xuICAgIC8vIFNhbWUga2V5OiBubyBjaGFuZ2UgaW4gdGhlIHRyZWUgc3RydWN0dXJlXG4gICAgaWYgKGN1cnJlbnROb2RlLmNvbXBhcmVLZXlzKGN1cnJlbnROb2RlLmtleSwga2V5KSA9PT0gMCkge1xuICAgICAgaWYgKGN1cnJlbnROb2RlLnVuaXF1ZSkge1xuICAgICAgICBsZXQgZXJyID0gbmV3IEVycm9yKCdDYW5cXCd0IGluc2VydCBrZXkgJyArIGtleSArICcsIGl0IHZpb2xhdGVzIHRoZSB1bmlxdWUgY29uc3RyYWludCcpO1xuICAgICAgICBlcnIua2V5ID0ga2V5O1xuICAgICAgICBlcnIuZXJyb3JUeXBlID0gJ3VuaXF1ZVZpb2xhdGVkJztcbiAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3VycmVudE5vZGUuZGF0YS5wdXNoKHZhbHVlKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGluc2VydFBhdGgucHVzaChjdXJyZW50Tm9kZSk7XG5cbiAgICBpZiAoY3VycmVudE5vZGUuY29tcGFyZUtleXMoa2V5LCBjdXJyZW50Tm9kZS5rZXkpIDwgMCkge1xuICAgICAgaWYgKCFjdXJyZW50Tm9kZS5sZWZ0KSB7XG4gICAgICAgIGluc2VydFBhdGgucHVzaChjdXJyZW50Tm9kZS5jcmVhdGVMZWZ0Q2hpbGQoeyBrZXk6IGtleSwgdmFsdWU6IHZhbHVlIH0pKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlLmxlZnQ7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmICghY3VycmVudE5vZGUucmlnaHQpIHtcbiAgICAgICAgaW5zZXJ0UGF0aC5wdXNoKGN1cnJlbnROb2RlLmNyZWF0ZVJpZ2h0Q2hpbGQoeyBrZXk6IGtleSwgdmFsdWU6IHZhbHVlIH0pKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlLnJpZ2h0O1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0aGlzLnJlYmFsYW5jZUFsb25nUGF0aChpbnNlcnRQYXRoKTtcbn07XG5cbi8vIEluc2VydCBpbiB0aGUgaW50ZXJuYWwgdHJlZSwgdXBkYXRlIHRoZSBwb2ludGVyIHRvIHRoZSByb290IGlmIG5lZWRlZFxuQVZMVHJlZS5wcm90b3R5cGUuaW5zZXJ0ID0gZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgbGV0IG5ld1RyZWUgPSB0aGlzLnRyZWUuaW5zZXJ0KGtleSwgdmFsdWUpO1xuXG4gIC8vIElmIG5ld1RyZWUgaXMgdW5kZWZpbmVkLCB0aGF0IG1lYW5zIGl0cyBzdHJ1Y3R1cmUgd2FzIG5vdCBtb2RpZmllZFxuICBpZiAobmV3VHJlZSkgeyB0aGlzLnRyZWUgPSBuZXdUcmVlOyB9XG59O1xuXG5cbi8qKlxuICogRGVsZXRlIGEga2V5IG9yIGp1c3QgYSB2YWx1ZSBhbmQgcmV0dXJuIHRoZSBuZXcgcm9vdCBvZiB0aGUgdHJlZVxuICogQHBhcmFtIHtLZXl9IGtleVxuICogQHBhcmFtIHtWYWx1ZX0gdmFsdWUgT3B0aW9uYWwuIElmIG5vdCBzZXQsIHRoZSB3aG9sZSBrZXkgaXMgZGVsZXRlZC4gSWYgc2V0LCBvbmx5IHRoaXMgdmFsdWUgaXMgZGVsZXRlZFxuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LXN0YXRlbWVudHMsIGNvbXBsZXhpdHlcbl9BVkxUcmVlLnByb3RvdHlwZS5kZWxldGUgPSBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICBsZXQgbmV3RGF0YSA9IFtdLCByZXBsYWNlV2l0aFxuICAgICwgc2VsZiA9IHRoaXNcbiAgICAsIGN1cnJlbnROb2RlID0gdGhpc1xuICAgICwgZGVsZXRlUGF0aCA9IFtdXG4gICAgO1xuXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMsICdrZXknKSkgeyByZXR1cm4gdGhpczsgfSAgIC8vIEVtcHR5IHRyZWVcblxuICAvLyBFaXRoZXIgbm8gbWF0Y2ggaXMgZm91bmQgYW5kIHRoZSBmdW5jdGlvbiB3aWxsIHJldHVybiBmcm9tIHdpdGhpbiB0aGUgbG9vcFxuICAvLyBPciBhIG1hdGNoIGlzIGZvdW5kIGFuZCBkZWxldGVQYXRoIHdpbGwgY29udGFpbiB0aGUgcGF0aCBmcm9tIHRoZSByb290IHRvIHRoZSBub2RlIHRvIGRlbGV0ZSBhZnRlciB0aGUgbG9vcFxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RhbnQtY29uZGl0aW9uXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgaWYgKGN1cnJlbnROb2RlLmNvbXBhcmVLZXlzKGtleSwgY3VycmVudE5vZGUua2V5KSA9PT0gMCkgeyBicmVhazsgfVxuXG4gICAgZGVsZXRlUGF0aC5wdXNoKGN1cnJlbnROb2RlKTtcblxuICAgIGlmIChjdXJyZW50Tm9kZS5jb21wYXJlS2V5cyhrZXksIGN1cnJlbnROb2RlLmtleSkgPCAwKSB7XG4gICAgICBpZiAoY3VycmVudE5vZGUubGVmdCkge1xuICAgICAgICBjdXJyZW50Tm9kZSA9IGN1cnJlbnROb2RlLmxlZnQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpczsgICAvLyBLZXkgbm90IGZvdW5kLCBubyBtb2RpZmljYXRpb25cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY3VycmVudE5vZGUuY29tcGFyZUtleXMoa2V5LCBjdXJyZW50Tm9kZS5rZXkpIGlzID4gMFxuICAgICAgaWYgKGN1cnJlbnROb2RlLnJpZ2h0KSB7XG4gICAgICAgIGN1cnJlbnROb2RlID0gY3VycmVudE5vZGUucmlnaHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gdGhpczsgICAvLyBLZXkgbm90IGZvdW5kLCBubyBtb2RpZmljYXRpb25cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBEZWxldGUgb25seSBhIHZhbHVlIChubyB0cmVlIG1vZGlmaWNhdGlvbilcbiAgaWYgKGN1cnJlbnROb2RlLmRhdGEubGVuZ3RoID4gMSAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgY3VycmVudE5vZGUuZGF0YS5mb3JFYWNoKGZ1bmN0aW9uIChkKSB7XG4gICAgICBpZiAoIWN1cnJlbnROb2RlLmNoZWNrVmFsdWVFcXVhbGl0eShkLCB2YWx1ZSkpIHsgbmV3RGF0YS5wdXNoKGQpOyB9XG4gICAgfSk7XG4gICAgY3VycmVudE5vZGUuZGF0YSA9IG5ld0RhdGE7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBEZWxldGUgYSB3aG9sZSBub2RlXG5cbiAgLy8gTGVhZlxuICBpZiAoIWN1cnJlbnROb2RlLmxlZnQgJiYgIWN1cnJlbnROb2RlLnJpZ2h0KSB7XG4gICAgaWYgKGN1cnJlbnROb2RlID09PSB0aGlzKSB7ICAgLy8gVGhpcyBsZWFmIGlzIGFsc28gdGhlIHJvb3RcbiAgICAgIGRlbGV0ZSBjdXJyZW50Tm9kZS5rZXk7XG4gICAgICBjdXJyZW50Tm9kZS5kYXRhID0gW107XG4gICAgICBkZWxldGUgY3VycmVudE5vZGUuaGVpZ2h0O1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChjdXJyZW50Tm9kZS5wYXJlbnQubGVmdCA9PT0gY3VycmVudE5vZGUpIHtcbiAgICAgICAgY3VycmVudE5vZGUucGFyZW50LmxlZnQgPSBudWxsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3VycmVudE5vZGUucGFyZW50LnJpZ2h0ID0gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLnJlYmFsYW5jZUFsb25nUGF0aChkZWxldGVQYXRoKTtcbiAgICB9XG4gIH1cblxuXG4gIC8vIE5vZGUgd2l0aCBvbmx5IG9uZSBjaGlsZFxuICBpZiAoIWN1cnJlbnROb2RlLmxlZnQgfHwgIWN1cnJlbnROb2RlLnJpZ2h0KSB7XG4gICAgcmVwbGFjZVdpdGggPSBjdXJyZW50Tm9kZS5sZWZ0ID8gY3VycmVudE5vZGUubGVmdCA6IGN1cnJlbnROb2RlLnJpZ2h0O1xuXG4gICAgaWYgKGN1cnJlbnROb2RlID09PSB0aGlzKSB7ICAgLy8gVGhpcyBub2RlIGlzIGFsc28gdGhlIHJvb3RcbiAgICAgIHJlcGxhY2VXaXRoLnBhcmVudCA9IG51bGw7XG4gICAgICByZXR1cm4gcmVwbGFjZVdpdGg7ICAgLy8gaGVpZ2h0IG9mIHJlcGxhY2VXaXRoIGlzIG5lY2Vzc2FyaWx5IDEgYmVjYXVzZSB0aGUgdHJlZSB3YXMgYmFsYW5jZWQgYmVmb3JlIGRlbGV0aW9uXG4gICAgfSBlbHNlIHtcbiAgICAgIGlmIChjdXJyZW50Tm9kZS5wYXJlbnQubGVmdCA9PT0gY3VycmVudE5vZGUpIHtcbiAgICAgICAgY3VycmVudE5vZGUucGFyZW50LmxlZnQgPSByZXBsYWNlV2l0aDtcbiAgICAgICAgcmVwbGFjZVdpdGgucGFyZW50ID0gY3VycmVudE5vZGUucGFyZW50O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY3VycmVudE5vZGUucGFyZW50LnJpZ2h0ID0gcmVwbGFjZVdpdGg7XG4gICAgICAgIHJlcGxhY2VXaXRoLnBhcmVudCA9IGN1cnJlbnROb2RlLnBhcmVudDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRoaXMucmViYWxhbmNlQWxvbmdQYXRoKGRlbGV0ZVBhdGgpO1xuICAgIH1cbiAgfVxuXG5cbiAgLy8gTm9kZSB3aXRoIHR3byBjaGlsZHJlblxuICAvLyBVc2UgdGhlIGluLW9yZGVyIHByZWRlY2Vzc29yIChubyBuZWVkIHRvIHJhbmRvbWl6ZSBzaW5jZSB3ZSBhY3RpdmVseSByZWJhbGFuY2UpXG4gIGRlbGV0ZVBhdGgucHVzaChjdXJyZW50Tm9kZSk7XG4gIHJlcGxhY2VXaXRoID0gY3VycmVudE5vZGUubGVmdDtcblxuICAvLyBTcGVjaWFsIGNhc2U6IHRoZSBpbi1vcmRlciBwcmVkZWNlc3NvciBpcyByaWdodCBiZWxvdyB0aGUgbm9kZSB0byBkZWxldGVcbiAgaWYgKCFyZXBsYWNlV2l0aC5yaWdodCkge1xuICAgIGN1cnJlbnROb2RlLmtleSA9IHJlcGxhY2VXaXRoLmtleTtcbiAgICBjdXJyZW50Tm9kZS5kYXRhID0gcmVwbGFjZVdpdGguZGF0YTtcbiAgICBjdXJyZW50Tm9kZS5sZWZ0ID0gcmVwbGFjZVdpdGgubGVmdDtcbiAgICBpZiAocmVwbGFjZVdpdGgubGVmdCkgeyByZXBsYWNlV2l0aC5sZWZ0LnBhcmVudCA9IGN1cnJlbnROb2RlOyB9XG4gICAgcmV0dXJuIHRoaXMucmViYWxhbmNlQWxvbmdQYXRoKGRlbGV0ZVBhdGgpO1xuICB9XG5cbiAgLy8gQWZ0ZXIgdGhpcyBsb29wLCByZXBsYWNlV2l0aCBpcyB0aGUgcmlnaHQtbW9zdCBsZWFmIGluIHRoZSBsZWZ0IHN1YnRyZWVcbiAgLy8gYW5kIGRlbGV0ZVBhdGggdGhlIHBhdGggZnJvbSB0aGUgcm9vdCAoaW5jbHVzaXZlKSB0byByZXBsYWNlV2l0aCAoZXhjbHVzaXZlKVxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc3RhbnQtY29uZGl0aW9uXG4gIHdoaWxlICh0cnVlKSB7XG4gICAgaWYgKHJlcGxhY2VXaXRoLnJpZ2h0KSB7XG4gICAgICBkZWxldGVQYXRoLnB1c2gocmVwbGFjZVdpdGgpO1xuICAgICAgcmVwbGFjZVdpdGggPSByZXBsYWNlV2l0aC5yaWdodDtcbiAgICB9IGVsc2Uge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgY3VycmVudE5vZGUua2V5ID0gcmVwbGFjZVdpdGgua2V5O1xuICBjdXJyZW50Tm9kZS5kYXRhID0gcmVwbGFjZVdpdGguZGF0YTtcblxuICByZXBsYWNlV2l0aC5wYXJlbnQucmlnaHQgPSByZXBsYWNlV2l0aC5sZWZ0O1xuICBpZiAocmVwbGFjZVdpdGgubGVmdCkgeyByZXBsYWNlV2l0aC5sZWZ0LnBhcmVudCA9IHJlcGxhY2VXaXRoLnBhcmVudDsgfVxuXG4gIHJldHVybiB0aGlzLnJlYmFsYW5jZUFsb25nUGF0aChkZWxldGVQYXRoKTtcbn07XG5cbi8vIERlbGV0ZSBhIHZhbHVlXG5BVkxUcmVlLnByb3RvdHlwZS5kZWxldGUgPSBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xuICBsZXQgbmV3VHJlZSA9IHRoaXMudHJlZS5kZWxldGUoa2V5LCB2YWx1ZSk7XG5cbiAgLy8gSWYgbmV3VHJlZSBpcyB1bmRlZmluZWQsIHRoYXQgbWVhbnMgaXRzIHN0cnVjdHVyZSB3YXMgbm90IG1vZGlmaWVkXG4gIGlmIChuZXdUcmVlKSB7IHRoaXMudHJlZSA9IG5ld1RyZWU7IH1cbn07XG5cblxuLyoqXG4gKiBPdGhlciBmdW5jdGlvbnMgd2Ugd2FudCB0byB1c2Ugb24gYW4gQVZMVHJlZSBhcyBpZiBpdCB3ZXJlIHRoZSBpbnRlcm5hbCBfQVZMVHJlZVxuICovXG5bJ2dldE51bWJlck9mS2V5cycsICdzZWFyY2gnLCAnYmV0d2VlbkJvdW5kcycsICdwcmV0dHlQcmludCcsICdleGVjdXRlT25FdmVyeU5vZGUnXS5mb3JFYWNoKGZ1bmN0aW9uIChmbikge1xuICBBVkxUcmVlLnByb3RvdHlwZVtmbl0gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMudHJlZVtmbl0uYXBwbHkodGhpcy50cmVlLCBhcmd1bWVudHMpO1xuICB9O1xufSk7XG5cblxuLy8gSW50ZXJmYWNlXG5tb2R1bGUuZXhwb3J0cy5BVkxUcmVlID0gQVZMVHJlZTtcbiJdLCJuYW1lcyI6WyJCaW5hcnlTZWFyY2hUcmVlIiwicmVxdWlyZSIsImN1c3RvbVV0aWxzIiwidXRpbCIsIkFWTFRyZWUiLCJvcHRpb25zIiwidHJlZSIsIl9BVkxUcmVlIiwibGVmdCIsInJpZ2h0IiwicGFyZW50IiwidW5kZWZpbmVkIiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwia2V5IiwiZGF0YSIsInZhbHVlIiwidW5pcXVlIiwiY29tcGFyZUtleXMiLCJkZWZhdWx0Q29tcGFyZUtleXNGdW5jdGlvbiIsImNoZWNrVmFsdWVFcXVhbGl0eSIsImRlZmF1bHRDaGVja1ZhbHVlRXF1YWxpdHkiLCJpbmhlcml0cyIsImNoZWNrSGVpZ2h0Q29ycmVjdCIsImxlZnRIIiwicmlnaHRIIiwiaGVpZ2h0IiwiRXJyb3IiLCJNYXRoIiwibWF4IiwiYmFsYW5jZUZhY3RvciIsImNoZWNrQmFsYW5jZUZhY3RvcnMiLCJhYnMiLCJjaGVja0lzQVZMVCIsInN1cGVyXyIsImNoZWNrSXNCU1QiLCJyaWdodFJvdGF0aW9uIiwicSIsInAiLCJiIiwiYWgiLCJiaCIsImNoIiwibGVmdFJvdGF0aW9uIiwicmlnaHRUb29TbWFsbCIsImxlZnRUb29TbWFsbCIsInJlYmFsYW5jZUFsb25nUGF0aCIsInBhdGgiLCJuZXdSb290Iiwicm90YXRlZCIsImkiLCJsZW5ndGgiLCJpbnNlcnQiLCJpbnNlcnRQYXRoIiwiY3VycmVudE5vZGUiLCJwdXNoIiwiZXJyIiwiZXJyb3JUeXBlIiwiY3JlYXRlTGVmdENoaWxkIiwiY3JlYXRlUmlnaHRDaGlsZCIsIm5ld1RyZWUiLCJkZWxldGUiLCJuZXdEYXRhIiwicmVwbGFjZVdpdGgiLCJzZWxmIiwiZGVsZXRlUGF0aCIsImZvckVhY2giLCJkIiwiZm4iLCJhcHBseSIsImFyZ3VtZW50cyIsIm1vZHVsZSIsImV4cG9ydHMiXSwibWFwcGluZ3MiOiJBQUFBLG1EQUFtRCxHQUNuRDs7Q0FFQztBQUNELE1BQU1BLG1CQUFtQkMsUUFBUSxVQUM3QkMsY0FBY0QsUUFBUSxrQkFDdEJFLE9BQU9GLFFBQVE7QUFJbkI7Ozs7OztDQU1DLEdBQ0QsU0FBU0csUUFBU0MsT0FBTztJQUN2QixJQUFJLENBQUNDLElBQUksR0FBRyxJQUFJQyxTQUFTRjtBQUMzQjtBQUdBOzs7Ozs7O0NBT0MsR0FDRCxTQUFTRSxTQUFVRixPQUFPO0lBQ3hCQSxVQUFVQSxXQUFXLENBQUM7SUFFdEIsSUFBSSxDQUFDRyxJQUFJLEdBQUc7SUFDWixJQUFJLENBQUNDLEtBQUssR0FBRztJQUNiLElBQUksQ0FBQ0MsTUFBTSxHQUFHTCxRQUFRSyxNQUFNLEtBQUtDLFlBQVlOLFFBQVFLLE1BQU0sR0FBRztJQUM5RCxJQUFJRSxPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDVixTQUFTLFFBQVE7UUFBRSxJQUFJLENBQUNXLEdBQUcsR0FBR1gsUUFBUVcsR0FBRztJQUFFO0lBQ3BGLElBQUksQ0FBQ0MsSUFBSSxHQUFHTCxPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDVixTQUFT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