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)
513 lines (512 loc) • 54 kB
JavaScript
/* eslint-disable @typescript-eslint/no-this-alias */ /**
* Simple binary search tree
*/ "use strict";
const customUtils = require("./customUtils");
/**
* Constructor
* @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 BinarySearchTree(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;
}
// ================================
// Methods used to test the tree
// ================================
/**
* Get the descendant with max key
*/ BinarySearchTree.prototype.getMaxKeyDescendant = function() {
if (this.right) {
return this.right.getMaxKeyDescendant();
} else {
return this;
}
};
/**
* Get the maximum key
*/ BinarySearchTree.prototype.getMaxKey = function() {
return this.getMaxKeyDescendant().key;
};
/**
* Get the descendant with min key
*/ BinarySearchTree.prototype.getMinKeyDescendant = function() {
if (this.left) {
return this.left.getMinKeyDescendant();
} else {
return this;
}
};
/**
* Get the minimum key
*/ BinarySearchTree.prototype.getMinKey = function() {
return this.getMinKeyDescendant().key;
};
/**
* Check that all nodes (incl. leaves) fullfil condition given by fn
* test is a function passed every (key, data) and which throws if the condition is not met
*/ BinarySearchTree.prototype.checkAllNodesFullfillCondition = function(test) {
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return;
}
test(this.key, this.data);
if (this.left) {
this.left.checkAllNodesFullfillCondition(test);
}
if (this.right) {
this.right.checkAllNodesFullfillCondition(test);
}
};
/**
* Check that the core BST properties on node ordering are verified
* Throw if they aren't
*/ BinarySearchTree.prototype.checkNodeOrdering = function() {
let self = this;
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return;
}
if (this.left) {
this.left.checkAllNodesFullfillCondition(function(k) {
if (self.compareKeys(k, self.key) >= 0) {
throw new Error("Tree with root " + self.key + " is not a binary search tree");
}
});
this.left.checkNodeOrdering();
}
if (this.right) {
this.right.checkAllNodesFullfillCondition(function(k) {
if (self.compareKeys(k, self.key) <= 0) {
throw new Error("Tree with root " + self.key + " is not a binary search tree");
}
});
this.right.checkNodeOrdering();
}
};
/**
* Check that all pointers are coherent in this tree
*/ BinarySearchTree.prototype.checkInternalPointers = function() {
if (this.left) {
if (this.left.parent !== this) {
throw new Error("Parent pointer broken for key " + this.key);
}
this.left.checkInternalPointers();
}
if (this.right) {
if (this.right.parent !== this) {
throw new Error("Parent pointer broken for key " + this.key);
}
this.right.checkInternalPointers();
}
};
/**
* Check that a tree is a BST as defined here (node ordering and pointer references)
*/ BinarySearchTree.prototype.checkIsBST = function() {
this.checkNodeOrdering();
this.checkInternalPointers();
if (this.parent) {
throw new Error("The root shouldn't have a parent");
}
};
/**
* Get number of keys inserted
*/ BinarySearchTree.prototype.getNumberOfKeys = function() {
let res;
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return 0;
}
res = 1;
if (this.left) {
res += this.left.getNumberOfKeys();
}
if (this.right) {
res += this.right.getNumberOfKeys();
}
return res;
};
// ============================================
// Methods used to actually work on the tree
// ============================================
/**
* Create a BST similar (i.e. same options except for key and value) to the current one
* Use the same constructor (i.e. BinarySearchTree, AVLTree etc)
* @param {Object} options see constructor
*/ BinarySearchTree.prototype.createSimilar = function(options) {
options = options || {};
options.unique = this.unique;
options.compareKeys = this.compareKeys;
options.checkValueEquality = this.checkValueEquality;
return new this.constructor(options);
};
/**
* Create the left child of this BST and return it
*/ BinarySearchTree.prototype.createLeftChild = function(options) {
let leftChild = this.createSimilar(options);
leftChild.parent = this;
this.left = leftChild;
return leftChild;
};
/**
* Create the right child of this BST and return it
*/ BinarySearchTree.prototype.createRightChild = function(options) {
let rightChild = this.createSimilar(options);
rightChild.parent = this;
this.right = rightChild;
return rightChild;
};
/**
* Insert a new element
*/ BinarySearchTree.prototype.insert = function(key, value) {
// Empty tree, insert as root
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
this.key = key;
this.data.push(value);
return;
}
// Same key as root
if (this.compareKeys(this.key, key) === 0) {
if (this.unique) {
let err = new Error("Can't insert key " + key + ", it violates the unique constraint");
err.key = key;
err.errorType = "uniqueViolated";
throw err;
} else {
this.data.push(value);
}
return;
}
if (this.compareKeys(key, this.key) < 0) {
// Insert in left subtree
if (this.left) {
this.left.insert(key, value);
} else {
this.createLeftChild({
key: key,
value: value
});
}
} else {
// Insert in right subtree
if (this.right) {
this.right.insert(key, value);
} else {
this.createRightChild({
key: key,
value: value
});
}
}
};
/**
* Search for all data corresponding to a key
*/ BinarySearchTree.prototype.search = function(key) {
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return [];
}
if (this.compareKeys(this.key, key) === 0) {
return this.data;
}
if (this.compareKeys(key, this.key) < 0) {
if (this.left) {
return this.left.search(key);
} else {
return [];
}
} else {
if (this.right) {
return this.right.search(key);
} else {
return [];
}
}
};
/**
* Return a function that tells whether a given key matches a lower bound
*/ BinarySearchTree.prototype.getLowerBoundMatcher = function(query) {
let self = this;
// No lower bound
if (!Object.prototype.hasOwnProperty.call(query, "$gt") && !Object.prototype.hasOwnProperty.call(query, "$gte")) {
return function() {
return true;
};
}
if (Object.prototype.hasOwnProperty.call(query, "$gt") && Object.prototype.hasOwnProperty.call(query, "$gte")) {
if (self.compareKeys(query.$gte, query.$gt) === 0) {
return function(key) {
return self.compareKeys(key, query.$gt) > 0;
};
}
if (self.compareKeys(query.$gte, query.$gt) > 0) {
return function(key) {
return self.compareKeys(key, query.$gte) >= 0;
};
} else {
return function(key) {
return self.compareKeys(key, query.$gt) > 0;
};
}
}
if (Object.prototype.hasOwnProperty.call(query, "$gt")) {
return function(key) {
return self.compareKeys(key, query.$gt) > 0;
};
} else {
return function(key) {
return self.compareKeys(key, query.$gte) >= 0;
};
}
};
/**
* Return a function that tells whether a given key matches an upper bound
*/ BinarySearchTree.prototype.getUpperBoundMatcher = function(query) {
let self = this;
// No lower bound
if (!Object.prototype.hasOwnProperty.call(query, "$lt") && !Object.prototype.hasOwnProperty.call(query, "$lte")) {
return function() {
return true;
};
}
if (Object.prototype.hasOwnProperty.call(query, "$lt") && Object.prototype.hasOwnProperty.call(query, "$lte")) {
if (self.compareKeys(query.$lte, query.$lt) === 0) {
return function(key) {
return self.compareKeys(key, query.$lt) < 0;
};
}
if (self.compareKeys(query.$lte, query.$lt) < 0) {
return function(key) {
return self.compareKeys(key, query.$lte) <= 0;
};
} else {
return function(key) {
return self.compareKeys(key, query.$lt) < 0;
};
}
}
if (Object.prototype.hasOwnProperty.call(query, "$lt")) {
return function(key) {
return self.compareKeys(key, query.$lt) < 0;
};
} else {
return function(key) {
return self.compareKeys(key, query.$lte) <= 0;
};
}
};
// Append all elements in toAppend to array
function append(array, toAppend) {
let i;
for(i = 0; i < toAppend.length; i += 1){
array.push(toAppend[i]);
}
}
/**
* Get all data for a key between bounds
* Return it in key order
* @param {Object} query Mongo-style query where keys are $lt, $lte, $gt or $gte (other keys are not considered)
* @param {Functions} lbm/ubm matching functions calculated at the first recursive step
*/ // eslint-disable-next-line complexity
BinarySearchTree.prototype.betweenBounds = function(query, lbm, ubm) {
let res = [];
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return [];
} // Empty tree
lbm = lbm || this.getLowerBoundMatcher(query);
ubm = ubm || this.getUpperBoundMatcher(query);
if (lbm(this.key) && this.left) {
append(res, this.left.betweenBounds(query, lbm, ubm));
}
if (lbm(this.key) && ubm(this.key)) {
append(res, this.data);
}
if (ubm(this.key) && this.right) {
append(res, this.right.betweenBounds(query, lbm, ubm));
}
return res;
};
/**
* Delete the current node if it is a leaf
* Return true if it was deleted
*/ BinarySearchTree.prototype.deleteIfLeaf = function() {
if (this.left || this.right) {
return false;
}
// The leaf is itself a root
if (!this.parent) {
delete this.key;
this.data = [];
return true;
}
if (this.parent.left === this) {
this.parent.left = null;
} else {
this.parent.right = null;
}
return true;
};
/**
* Delete the current node if it has only one child
* Return true if it was deleted
*/ // eslint-disable-next-line complexity
BinarySearchTree.prototype.deleteIfOnlyOneChild = function() {
let child;
if (this.left && !this.right) {
child = this.left;
}
if (!this.left && this.right) {
child = this.right;
}
if (!child) {
return false;
}
// Root
if (!this.parent) {
this.key = child.key;
this.data = child.data;
this.left = null;
if (child.left) {
this.left = child.left;
child.left.parent = this;
}
this.right = null;
if (child.right) {
this.right = child.right;
child.right.parent = this;
}
return true;
}
if (this.parent.left === this) {
this.parent.left = child;
child.parent = this.parent;
} else {
this.parent.right = child;
child.parent = this.parent;
}
return true;
};
/**
* Delete a key or just a value
* @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
BinarySearchTree.prototype.delete = function(key, value) {
let newData = [], replaceWith, self = this;
if (!Object.prototype.hasOwnProperty.call(this, "key")) {
return;
}
if (this.compareKeys(key, this.key) < 0) {
if (this.left) {
this.left.delete(key, value);
}
return;
}
if (this.compareKeys(key, this.key) > 0) {
if (this.right) {
this.right.delete(key, value);
}
return;
}
if (!this.compareKeys(key, this.key) === 0) {
return;
}
// Delete only a value
if (this.data.length > 1 && value !== undefined) {
this.data.forEach(function(d) {
if (!self.checkValueEquality(d, value)) {
newData.push(d);
}
});
self.data = newData;
return;
}
// Delete the whole node
if (this.deleteIfLeaf()) {
return;
}
if (this.deleteIfOnlyOneChild()) {
return;
}
// We are in the case where the node to delete has two children
if (Math.random() >= 0.5) {
// Use the in-order predecessor
replaceWith = this.left.getMaxKeyDescendant();
this.key = replaceWith.key;
this.data = replaceWith.data;
if (this === replaceWith.parent) {
this.left = replaceWith.left;
if (replaceWith.left) {
replaceWith.left.parent = replaceWith.parent;
}
} else {
replaceWith.parent.right = replaceWith.left;
if (replaceWith.left) {
replaceWith.left.parent = replaceWith.parent;
}
}
} else {
// Use the in-order successor
replaceWith = this.right.getMinKeyDescendant();
this.key = replaceWith.key;
this.data = replaceWith.data;
if (this === replaceWith.parent) {
this.right = replaceWith.right;
if (replaceWith.right) {
replaceWith.right.parent = replaceWith.parent;
}
} else {
replaceWith.parent.left = replaceWith.right;
if (replaceWith.right) {
replaceWith.right.parent = replaceWith.parent;
}
}
}
};
/**
* Execute a function on every node of the tree, in key order
* @param {Function} fn Signature: node. Most useful will probably be node.key and node.data
*/ BinarySearchTree.prototype.executeOnEveryNode = function(fn) {
if (this.left) {
this.left.executeOnEveryNode(fn);
}
fn(this);
if (this.right) {
this.right.executeOnEveryNode(fn);
}
};
/**
* Pretty print a tree
* @param {Boolean} printData To print the nodes' data along with the key
*/ BinarySearchTree.prototype.prettyPrint = function(printData, spacing) {
spacing = spacing || "";
console.log(spacing + "* " + this.key);
if (printData) {
console.log(spacing + "* " + this.data);
}
if (!this.left && !this.right) {
return;
}
if (this.left) {
this.left.prettyPrint(printData, spacing + " ");
} else {
console.log(spacing + " *");
}
if (this.right) {
this.right.prettyPrint(printData, spacing + " ");
} else {
console.log(spacing + " *");
}
};
// Interface
module.exports = BinarySearchTree;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdGhpcy1hbGlhcyAqL1xuLyoqXG4gKiBTaW1wbGUgYmluYXJ5IHNlYXJjaCB0cmVlXG4gKi9cbmNvbnN0IGN1c3RvbVV0aWxzID0gcmVxdWlyZSgnLi9jdXN0b21VdGlscycpO1xuXG5cbi8qKlxuICogQ29uc3RydWN0b3JcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIE9wdGlvbmFsXG4gKiBAcGFyYW0ge0Jvb2xlYW59ICBvcHRpb25zLnVuaXF1ZSBXaGV0aGVyIHRvIGVuZm9yY2UgYSAndW5pcXVlJyBjb25zdHJhaW50IG9uIHRoZSBrZXkgb3Igbm90XG4gKiBAcGFyYW0ge0tleX0gICAgICBvcHRpb25zLmtleSBJbml0aWFsaXplIHRoaXMgQlNUJ3Mga2V5IHdpdGgga2V5XG4gKiBAcGFyYW0ge1ZhbHVlfSAgICBvcHRpb25zLnZhbHVlIEluaXRpYWxpemUgdGhpcyBCU1QncyBkYXRhIHdpdGggW3ZhbHVlXVxuICogQHBhcmFtIHtGdW5jdGlvbn0gb3B0aW9ucy5jb21wYXJlS2V5cyBJbml0aWFsaXplIHRoaXMgQlNUJ3MgY29tcGFyZUtleXNcbiAqL1xuZnVuY3Rpb24gQmluYXJ5U2VhcmNoVHJlZSAob3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblxuICB0aGlzLmxlZnQgPSBudWxsO1xuICB0aGlzLnJpZ2h0ID0gbnVsbDtcbiAgdGhpcy5wYXJlbnQgPSBvcHRpb25zLnBhcmVudCAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5wYXJlbnQgOiBudWxsO1xuICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbnMsICdrZXknKSkgeyB0aGlzLmtleSA9IG9wdGlvbnMua2V5OyB9XG4gIHRoaXMuZGF0YSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb25zLCAndmFsdWUnKSA/IFtvcHRpb25zLnZhbHVlXSA6IFtdO1xuICB0aGlzLnVuaXF1ZSA9IG9wdGlvbnMudW5pcXVlIHx8IGZhbHNlO1xuXG4gIHRoaXMuY29tcGFyZUtleXMgPSBvcHRpb25zLmNvbXBhcmVLZXlzIHx8IGN1c3RvbVV0aWxzLmRlZmF1bHRDb21wYXJlS2V5c0Z1bmN0aW9uO1xuICB0aGlzLmNoZWNrVmFsdWVFcXVhbGl0eSA9IG9wdGlvbnMuY2hlY2tWYWx1ZUVxdWFsaXR5IHx8IGN1c3RvbVV0aWxzLmRlZmF1bHRDaGVja1ZhbHVlRXF1YWxpdHk7XG59XG5cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIE1ldGhvZHMgdXNlZCB0byB0ZXN0IHRoZSB0cmVlXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5cbi8qKlxuICogR2V0IHRoZSBkZXNjZW5kYW50IHdpdGggbWF4IGtleVxuICovXG5CaW5hcnlTZWFyY2hUcmVlLnByb3RvdHlwZS5nZXRNYXhLZXlEZXNjZW5kYW50ID0gZnVuY3Rpb24gKCkge1xuICBpZiAodGhpcy5yaWdodCkge1xuICAgIHJldHVybiB0aGlzLnJpZ2h0LmdldE1heEtleURlc2NlbmRhbnQoKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufTtcblxuXG4vKipcbiAqIEdldCB0aGUgbWF4aW11bSBrZXlcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZ2V0TWF4S2V5ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5nZXRNYXhLZXlEZXNjZW5kYW50KCkua2V5O1xufTtcblxuXG4vKipcbiAqIEdldCB0aGUgZGVzY2VuZGFudCB3aXRoIG1pbiBrZXlcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZ2V0TWluS2V5RGVzY2VuZGFudCA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHRoaXMubGVmdCkge1xuICAgIHJldHVybiB0aGlzLmxlZnQuZ2V0TWluS2V5RGVzY2VuZGFudCgpXG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn07XG5cblxuLyoqXG4gKiBHZXQgdGhlIG1pbmltdW0ga2V5XG4gKi9cbkJpbmFyeVNlYXJjaFRyZWUucHJvdG90eXBlLmdldE1pbktleSA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuZ2V0TWluS2V5RGVzY2VuZGFudCgpLmtleTtcbn07XG5cblxuLyoqXG4gKiBDaGVjayB0aGF0IGFsbCBub2RlcyAoaW5jbC4gbGVhdmVzKSBmdWxsZmlsIGNvbmRpdGlvbiBnaXZlbiBieSBmblxuICogdGVzdCBpcyBhIGZ1bmN0aW9uIHBhc3NlZCBldmVyeSAoa2V5LCBkYXRhKSBhbmQgd2hpY2ggdGhyb3dzIGlmIHRoZSBjb25kaXRpb24gaXMgbm90IG1ldFxuICovXG5CaW5hcnlTZWFyY2hUcmVlLnByb3RvdHlwZS5jaGVja0FsbE5vZGVzRnVsbGZpbGxDb25kaXRpb24gPSBmdW5jdGlvbiAodGVzdCkge1xuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLCAna2V5JykpIHsgcmV0dXJuOyB9XG5cbiAgdGVzdCh0aGlzLmtleSwgdGhpcy5kYXRhKTtcbiAgaWYgKHRoaXMubGVmdCkgeyB0aGlzLmxlZnQuY2hlY2tBbGxOb2Rlc0Z1bGxmaWxsQ29uZGl0aW9uKHRlc3QpOyB9XG4gIGlmICh0aGlzLnJpZ2h0KSB7IHRoaXMucmlnaHQuY2hlY2tBbGxOb2Rlc0Z1bGxmaWxsQ29uZGl0aW9uKHRlc3QpOyB9XG59O1xuXG5cbi8qKlxuICogQ2hlY2sgdGhhdCB0aGUgY29yZSBCU1QgcHJvcGVydGllcyBvbiBub2RlIG9yZGVyaW5nIGFyZSB2ZXJpZmllZFxuICogVGhyb3cgaWYgdGhleSBhcmVuJ3RcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuY2hlY2tOb2RlT3JkZXJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gIGxldCBzZWxmID0gdGhpcztcblxuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0aGlzLCAna2V5JykpIHsgcmV0dXJuOyB9XG5cbiAgaWYgKHRoaXMubGVmdCkge1xuICAgIHRoaXMubGVmdC5jaGVja0FsbE5vZGVzRnVsbGZpbGxDb25kaXRpb24oZnVuY3Rpb24gKGspIHtcbiAgICAgIGlmIChzZWxmLmNvbXBhcmVLZXlzKGssIHNlbGYua2V5KSA+PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHJlZSB3aXRoIHJvb3QgJyArIHNlbGYua2V5ICsgJyBpcyBub3QgYSBiaW5hcnkgc2VhcmNoIHRyZWUnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLmxlZnQuY2hlY2tOb2RlT3JkZXJpbmcoKTtcbiAgfVxuXG4gIGlmICh0aGlzLnJpZ2h0KSB7XG4gICAgdGhpcy5yaWdodC5jaGVja0FsbE5vZGVzRnVsbGZpbGxDb25kaXRpb24oZnVuY3Rpb24gKGspIHtcbiAgICAgIGlmIChzZWxmLmNvbXBhcmVLZXlzKGssIHNlbGYua2V5KSA8PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHJlZSB3aXRoIHJvb3QgJyArIHNlbGYua2V5ICsgJyBpcyBub3QgYSBiaW5hcnkgc2VhcmNoIHRyZWUnKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICB0aGlzLnJpZ2h0LmNoZWNrTm9kZU9yZGVyaW5nKCk7XG4gIH1cbn07XG5cblxuLyoqXG4gKiBDaGVjayB0aGF0IGFsbCBwb2ludGVycyBhcmUgY29oZXJlbnQgaW4gdGhpcyB0cmVlXG4gKi9cbkJpbmFyeVNlYXJjaFRyZWUucHJvdG90eXBlLmNoZWNrSW50ZXJuYWxQb2ludGVycyA9IGZ1bmN0aW9uICgpIHtcbiAgaWYgKHRoaXMubGVmdCkge1xuICAgIGlmICh0aGlzLmxlZnQucGFyZW50ICE9PSB0aGlzKSB7IHRocm93IG5ldyBFcnJvcignUGFyZW50IHBvaW50ZXIgYnJva2VuIGZvciBrZXkgJyArIHRoaXMua2V5KTsgfVxuICAgIHRoaXMubGVmdC5jaGVja0ludGVybmFsUG9pbnRlcnMoKTtcbiAgfVxuXG4gIGlmICh0aGlzLnJpZ2h0KSB7XG4gICAgaWYgKHRoaXMucmlnaHQucGFyZW50ICE9PSB0aGlzKSB7IHRocm93IG5ldyBFcnJvcignUGFyZW50IHBvaW50ZXIgYnJva2VuIGZvciBrZXkgJyArIHRoaXMua2V5KTsgfVxuICAgIHRoaXMucmlnaHQuY2hlY2tJbnRlcm5hbFBvaW50ZXJzKCk7XG4gIH1cbn07XG5cblxuLyoqXG4gKiBDaGVjayB0aGF0IGEgdHJlZSBpcyBhIEJTVCBhcyBkZWZpbmVkIGhlcmUgKG5vZGUgb3JkZXJpbmcgYW5kIHBvaW50ZXIgcmVmZXJlbmNlcylcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuY2hlY2tJc0JTVCA9IGZ1bmN0aW9uICgpIHtcbiAgdGhpcy5jaGVja05vZGVPcmRlcmluZygpO1xuICB0aGlzLmNoZWNrSW50ZXJuYWxQb2ludGVycygpO1xuICBpZiAodGhpcy5wYXJlbnQpIHsgdGhyb3cgbmV3IEVycm9yKCdUaGUgcm9vdCBzaG91bGRuXFwndCBoYXZlIGEgcGFyZW50Jyk7IH1cbn07XG5cblxuLyoqXG4gKiBHZXQgbnVtYmVyIG9mIGtleXMgaW5zZXJ0ZWRcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZ2V0TnVtYmVyT2ZLZXlzID0gZnVuY3Rpb24gKCkge1xuICBsZXQgcmVzO1xuXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMsICdrZXknKSkgeyByZXR1cm4gMDsgfVxuXG5cbiAgcmVzID0gMTtcbiAgaWYgKHRoaXMubGVmdCkgeyByZXMgKz0gdGhpcy5sZWZ0LmdldE51bWJlck9mS2V5cygpOyB9XG4gIGlmICh0aGlzLnJpZ2h0KSB7IHJlcyArPSB0aGlzLnJpZ2h0LmdldE51bWJlck9mS2V5cygpOyB9XG5cbiAgcmV0dXJuIHJlcztcbn07XG5cblxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gTWV0aG9kcyB1c2VkIHRvIGFjdHVhbGx5IHdvcmsgb24gdGhlIHRyZWVcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbi8qKlxuICogQ3JlYXRlIGEgQlNUIHNpbWlsYXIgKGkuZS4gc2FtZSBvcHRpb25zIGV4Y2VwdCBmb3Iga2V5IGFuZCB2YWx1ZSkgdG8gdGhlIGN1cnJlbnQgb25lXG4gKiBVc2UgdGhlIHNhbWUgY29uc3RydWN0b3IgKGkuZS4gQmluYXJ5U2VhcmNoVHJlZSwgQVZMVHJlZSBldGMpXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBzZWUgY29uc3RydWN0b3JcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuY3JlYXRlU2ltaWxhciA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICBvcHRpb25zLnVuaXF1ZSA9IHRoaXMudW5pcXVlO1xuICBvcHRpb25zLmNvbXBhcmVLZXlzID0gdGhpcy5jb21wYXJlS2V5cztcbiAgb3B0aW9ucy5jaGVja1ZhbHVlRXF1YWxpdHkgPSB0aGlzLmNoZWNrVmFsdWVFcXVhbGl0eTtcblxuICByZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3Iob3B0aW9ucyk7XG59O1xuXG5cbi8qKlxuICogQ3JlYXRlIHRoZSBsZWZ0IGNoaWxkIG9mIHRoaXMgQlNUIGFuZCByZXR1cm4gaXRcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuY3JlYXRlTGVmdENoaWxkID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgbGV0IGxlZnRDaGlsZCA9IHRoaXMuY3JlYXRlU2ltaWxhcihvcHRpb25zKTtcbiAgbGVmdENoaWxkLnBhcmVudCA9IHRoaXM7XG4gIHRoaXMubGVmdCA9IGxlZnRDaGlsZDtcblxuICByZXR1cm4gbGVmdENoaWxkO1xufTtcblxuXG4vKipcbiAqIENyZWF0ZSB0aGUgcmlnaHQgY2hpbGQgb2YgdGhpcyBCU1QgYW5kIHJldHVybiBpdFxuICovXG5CaW5hcnlTZWFyY2hUcmVlLnByb3RvdHlwZS5jcmVhdGVSaWdodENoaWxkID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgbGV0IHJpZ2h0Q2hpbGQgPSB0aGlzLmNyZWF0ZVNpbWlsYXIob3B0aW9ucyk7XG4gIHJpZ2h0Q2hpbGQucGFyZW50ID0gdGhpcztcbiAgdGhpcy5yaWdodCA9IHJpZ2h0Q2hpbGQ7XG5cbiAgcmV0dXJuIHJpZ2h0Q2hpbGQ7XG59O1xuXG5cbi8qKlxuICogSW5zZXJ0IGEgbmV3IGVsZW1lbnRcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuaW5zZXJ0ID0gZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgLy8gRW1wdHkgdHJlZSwgaW5zZXJ0IGFzIHJvb3RcbiAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcywgJ2tleScpKSB7XG4gICAgdGhpcy5rZXkgPSBrZXk7XG4gICAgdGhpcy5kYXRhLnB1c2godmFsdWUpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIFNhbWUga2V5IGFzIHJvb3RcbiAgaWYgKHRoaXMuY29tcGFyZUtleXModGhpcy5rZXksIGtleSkgPT09IDApIHtcbiAgICBpZiAodGhpcy51bmlxdWUpIHtcbiAgICAgIGxldCBlcnIgPSBuZXcgRXJyb3IoJ0NhblxcJ3QgaW5zZXJ0IGtleSAnICsga2V5ICsgJywgaXQgdmlvbGF0ZXMgdGhlIHVuaXF1ZSBjb25zdHJhaW50Jyk7XG4gICAgICBlcnIua2V5ID0ga2V5O1xuICAgICAgZXJyLmVycm9yVHlwZSA9ICd1bmlxdWVWaW9sYXRlZCc7XG4gICAgICB0aHJvdyBlcnI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuZGF0YS5wdXNoKHZhbHVlKTtcbiAgICB9XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHRoaXMuY29tcGFyZUtleXMoa2V5LCB0aGlzLmtleSkgPCAwKSB7XG4gICAgLy8gSW5zZXJ0IGluIGxlZnQgc3VidHJlZVxuICAgIGlmICh0aGlzLmxlZnQpIHtcbiAgICAgIHRoaXMubGVmdC5pbnNlcnQoa2V5LCB2YWx1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3JlYXRlTGVmdENoaWxkKHsga2V5OiBrZXksIHZhbHVlOiB2YWx1ZSB9KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gSW5zZXJ0IGluIHJpZ2h0IHN1YnRyZWVcbiAgICBpZiAodGhpcy5yaWdodCkge1xuICAgICAgdGhpcy5yaWdodC5pbnNlcnQoa2V5LCB2YWx1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuY3JlYXRlUmlnaHRDaGlsZCh7IGtleToga2V5LCB2YWx1ZTogdmFsdWUgfSk7XG4gICAgfVxuICB9XG59O1xuXG5cbi8qKlxuICogU2VhcmNoIGZvciBhbGwgZGF0YSBjb3JyZXNwb25kaW5nIHRvIGEga2V5XG4gKi9cbkJpbmFyeVNlYXJjaFRyZWUucHJvdG90eXBlLnNlYXJjaCA9IGZ1bmN0aW9uIChrZXkpIHtcbiAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwodGhpcywgJ2tleScpKSB7IHJldHVybiBbXTsgfVxuXG4gIGlmICh0aGlzLmNvbXBhcmVLZXlzKHRoaXMua2V5LCBrZXkpID09PSAwKSB7IHJldHVybiB0aGlzLmRhdGE7IH1cblxuICBpZiAodGhpcy5jb21wYXJlS2V5cyhrZXksIHRoaXMua2V5KSA8IDApIHtcbiAgICBpZiAodGhpcy5sZWZ0KSB7XG4gICAgICByZXR1cm4gdGhpcy5sZWZ0LnNlYXJjaChrZXkpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGlmICh0aGlzLnJpZ2h0KSB7XG4gICAgICByZXR1cm4gdGhpcy5yaWdodC5zZWFyY2goa2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgfVxufTtcblxuXG4vKipcbiAqIFJldHVybiBhIGZ1bmN0aW9uIHRoYXQgdGVsbHMgd2hldGhlciBhIGdpdmVuIGtleSBtYXRjaGVzIGEgbG93ZXIgYm91bmRcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZ2V0TG93ZXJCb3VuZE1hdGNoZXIgPSBmdW5jdGlvbiAocXVlcnkpIHtcbiAgbGV0IHNlbGYgPSB0aGlzO1xuXG4gIC8vIE5vIGxvd2VyIGJvdW5kXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHF1ZXJ5LCAnJGd0JykgJiYgIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwgJyRndGUnKSkge1xuICAgIHJldHVybiBmdW5jdGlvbiAoKSB7IHJldHVybiB0cnVlOyB9O1xuICB9XG5cbiAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwgJyRndCcpICYmIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwgJyRndGUnKSkge1xuICAgIGlmIChzZWxmLmNvbXBhcmVLZXlzKHF1ZXJ5LiRndGUsIHF1ZXJ5LiRndCkgPT09IDApIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiAoa2V5KSB7IHJldHVybiBzZWxmLmNvbXBhcmVLZXlzKGtleSwgcXVlcnkuJGd0KSA+IDA7IH07XG4gICAgfVxuXG4gICAgaWYgKHNlbGYuY29tcGFyZUtleXMocXVlcnkuJGd0ZSwgcXVlcnkuJGd0KSA+IDApIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiAoa2V5KSB7IHJldHVybiBzZWxmLmNvbXBhcmVLZXlzKGtleSwgcXVlcnkuJGd0ZSkgPj0gMDsgfTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGZ1bmN0aW9uIChrZXkpIHsgcmV0dXJuIHNlbGYuY29tcGFyZUtleXMoa2V5LCBxdWVyeS4kZ3QpID4gMDsgfTtcbiAgICB9XG4gIH1cblxuICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHF1ZXJ5LCAnJGd0JykpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGtleSkgeyByZXR1cm4gc2VsZi5jb21wYXJlS2V5cyhrZXksIHF1ZXJ5LiRndCkgPiAwOyB9O1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBmdW5jdGlvbiAoa2V5KSB7IHJldHVybiBzZWxmLmNvbXBhcmVLZXlzKGtleSwgcXVlcnkuJGd0ZSkgPj0gMDsgfTtcbiAgfVxufTtcblxuXG4vKipcbiAqIFJldHVybiBhIGZ1bmN0aW9uIHRoYXQgdGVsbHMgd2hldGhlciBhIGdpdmVuIGtleSBtYXRjaGVzIGFuIHVwcGVyIGJvdW5kXG4gKi9cbkJpbmFyeVNlYXJjaFRyZWUucHJvdG90eXBlLmdldFVwcGVyQm91bmRNYXRjaGVyID0gZnVuY3Rpb24gKHF1ZXJ5KSB7XG4gIGxldCBzZWxmID0gdGhpcztcblxuICAvLyBObyBsb3dlciBib3VuZFxuICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwgJyRsdCcpICYmICFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocXVlcnksICckbHRlJykpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkgeyByZXR1cm4gdHJ1ZTsgfTtcbiAgfVxuXG4gIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocXVlcnksICckbHQnKSAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocXVlcnksICckbHRlJykpIHtcbiAgICBpZiAoc2VsZi5jb21wYXJlS2V5cyhxdWVyeS4kbHRlLCBxdWVyeS4kbHQpID09PSAwKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24gKGtleSkgeyByZXR1cm4gc2VsZi5jb21wYXJlS2V5cyhrZXksIHF1ZXJ5LiRsdCkgPCAwOyB9O1xuICAgIH1cblxuICAgIGlmIChzZWxmLmNvbXBhcmVLZXlzKHF1ZXJ5LiRsdGUsIHF1ZXJ5LiRsdCkgPCAwKSB7XG4gICAgICByZXR1cm4gZnVuY3Rpb24gKGtleSkgeyByZXR1cm4gc2VsZi5jb21wYXJlS2V5cyhrZXksIHF1ZXJ5LiRsdGUpIDw9IDA7IH07XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbiAoa2V5KSB7IHJldHVybiBzZWxmLmNvbXBhcmVLZXlzKGtleSwgcXVlcnkuJGx0KSA8IDA7IH07XG4gICAgfVxuICB9XG5cbiAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChxdWVyeSwgJyRsdCcpKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChrZXkpIHsgcmV0dXJuIHNlbGYuY29tcGFyZUtleXMoa2V5LCBxdWVyeS4kbHQpIDwgMDsgfTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGtleSkgeyByZXR1cm4gc2VsZi5jb21wYXJlS2V5cyhrZXksIHF1ZXJ5LiRsdGUpIDw9IDA7IH07XG4gIH1cbn07XG5cblxuLy8gQXBwZW5kIGFsbCBlbGVtZW50cyBpbiB0b0FwcGVuZCB0byBhcnJheVxuZnVuY3Rpb24gYXBwZW5kIChhcnJheSwgdG9BcHBlbmQpIHtcbiAgbGV0IGk7XG5cbiAgZm9yIChpID0gMDsgaSA8IHRvQXBwZW5kLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgYXJyYXkucHVzaCh0b0FwcGVuZFtpXSk7XG4gIH1cbn1cblxuXG4vKipcbiAqIEdldCBhbGwgZGF0YSBmb3IgYSBrZXkgYmV0d2VlbiBib3VuZHNcbiAqIFJldHVybiBpdCBpbiBrZXkgb3JkZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBxdWVyeSBNb25nby1zdHlsZSBxdWVyeSB3aGVyZSBrZXlzIGFyZSAkbHQsICRsdGUsICRndCBvciAkZ3RlIChvdGhlciBrZXlzIGFyZSBub3QgY29uc2lkZXJlZClcbiAqIEBwYXJhbSB7RnVuY3Rpb25zfSBsYm0vdWJtIG1hdGNoaW5nIGZ1bmN0aW9ucyBjYWxjdWxhdGVkIGF0IHRoZSBmaXJzdCByZWN1cnNpdmUgc3RlcFxuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGxleGl0eVxuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuYmV0d2VlbkJvdW5kcyA9IGZ1bmN0aW9uIChxdWVyeSwgbGJtLCB1Ym0pIHtcbiAgbGV0IHJlcyA9IFtdO1xuXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMsICdrZXknKSkgeyByZXR1cm4gW107IH0gICAvLyBFbXB0eSB0cmVlXG5cbiAgbGJtID0gbGJtIHx8IHRoaXMuZ2V0TG93ZXJCb3VuZE1hdGNoZXIocXVlcnkpO1xuICB1Ym0gPSB1Ym0gfHwgdGhpcy5nZXRVcHBlckJvdW5kTWF0Y2hlcihxdWVyeSk7XG5cbiAgaWYgKGxibSh0aGlzLmtleSkgJiYgdGhpcy5sZWZ0KSB7IGFwcGVuZChyZXMsIHRoaXMubGVmdC5iZXR3ZWVuQm91bmRzKHF1ZXJ5LCBsYm0sIHVibSkpOyB9XG4gIGlmIChsYm0odGhpcy5rZXkpICYmIHVibSh0aGlzLmtleSkpIHsgYXBwZW5kKHJlcywgdGhpcy5kYXRhKTsgfVxuICBpZiAodWJtKHRoaXMua2V5KSAmJiB0aGlzLnJpZ2h0KSB7IGFwcGVuZChyZXMsIHRoaXMucmlnaHQuYmV0d2VlbkJvdW5kcyhxdWVyeSwgbGJtLCB1Ym0pKTsgfVxuXG4gIHJldHVybiByZXM7XG59O1xuXG5cbi8qKlxuICogRGVsZXRlIHRoZSBjdXJyZW50IG5vZGUgaWYgaXQgaXMgYSBsZWFmXG4gKiBSZXR1cm4gdHJ1ZSBpZiBpdCB3YXMgZGVsZXRlZFxuICovXG5CaW5hcnlTZWFyY2hUcmVlLnByb3RvdHlwZS5kZWxldGVJZkxlYWYgPSBmdW5jdGlvbiAoKSB7XG4gIGlmICh0aGlzLmxlZnQgfHwgdGhpcy5yaWdodCkgeyByZXR1cm4gZmFsc2U7IH1cblxuICAvLyBUaGUgbGVhZiBpcyBpdHNlbGYgYSByb290XG4gIGlmICghdGhpcy5wYXJlbnQpIHtcbiAgICBkZWxldGUgdGhpcy5rZXk7XG4gICAgdGhpcy5kYXRhID0gW107XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpZiAodGhpcy5wYXJlbnQubGVmdCA9PT0gdGhpcykge1xuICAgIHRoaXMucGFyZW50LmxlZnQgPSBudWxsO1xuICB9IGVsc2Uge1xuICAgIHRoaXMucGFyZW50LnJpZ2h0ID0gbnVsbDtcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuXG4vKipcbiAqIERlbGV0ZSB0aGUgY3VycmVudCBub2RlIGlmIGl0IGhhcyBvbmx5IG9uZSBjaGlsZFxuICogUmV0dXJuIHRydWUgaWYgaXQgd2FzIGRlbGV0ZWRcbiAqL1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbkJpbmFyeVNlYXJjaFRyZWUucHJvdG90eXBlLmRlbGV0ZUlmT25seU9uZUNoaWxkID0gZnVuY3Rpb24gKCkge1xuICBsZXQgY2hpbGQ7XG5cbiAgaWYgKHRoaXMubGVmdCAmJiAhdGhpcy5yaWdodCkgeyBjaGlsZCA9IHRoaXMubGVmdDsgfVxuICBpZiAoIXRoaXMubGVmdCAmJiB0aGlzLnJpZ2h0KSB7IGNoaWxkID0gdGhpcy5yaWdodDsgfVxuICBpZiAoIWNoaWxkKSB7IHJldHVybiBmYWxzZTsgfVxuXG4gIC8vIFJvb3RcbiAgaWYgKCF0aGlzLnBhcmVudCkge1xuICAgIHRoaXMua2V5ID0gY2hpbGQua2V5O1xuICAgIHRoaXMuZGF0YSA9IGNoaWxkLmRhdGE7XG5cbiAgICB0aGlzLmxlZnQgPSBudWxsO1xuICAgIGlmIChjaGlsZC5sZWZ0KSB7XG4gICAgICB0aGlzLmxlZnQgPSBjaGlsZC5sZWZ0O1xuICAgICAgY2hpbGQubGVmdC5wYXJlbnQgPSB0aGlzO1xuICAgIH1cblxuICAgIHRoaXMucmlnaHQgPSBudWxsO1xuICAgIGlmIChjaGlsZC5yaWdodCkge1xuICAgICAgdGhpcy5yaWdodCA9IGNoaWxkLnJpZ2h0O1xuICAgICAgY2hpbGQucmlnaHQucGFyZW50ID0gdGhpcztcbiAgICB9XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGlmICh0aGlzLnBhcmVudC5sZWZ0ID09PSB0aGlzKSB7XG4gICAgdGhpcy5wYXJlbnQubGVmdCA9IGNoaWxkO1xuICAgIGNoaWxkLnBhcmVudCA9IHRoaXMucGFyZW50O1xuICB9IGVsc2Uge1xuICAgIHRoaXMucGFyZW50LnJpZ2h0ID0gY2hpbGQ7XG4gICAgY2hpbGQucGFyZW50ID0gdGhpcy5wYXJlbnQ7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cblxuLyoqXG4gKiBEZWxldGUgYSBrZXkgb3IganVzdCBhIHZhbHVlXG4gKiBAcGFyYW0ge0tleX0ga2V5XG4gKiBAcGFyYW0ge1ZhbHVlfSB2YWx1ZSBPcHRpb25hbC4gSWYgbm90IHNldCwgdGhlIHdob2xlIGtleSBpcyBkZWxldGVkLiBJZiBzZXQsIG9ubHkgdGhpcyB2YWx1ZSBpcyBkZWxldGVkXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtc3RhdGVtZW50cywgY29tcGxleGl0eVxuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZGVsZXRlID0gZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgbGV0IG5ld0RhdGEgPSBbXSwgcmVwbGFjZVdpdGhcbiAgICAsIHNlbGYgPSB0aGlzXG4gICAgO1xuXG4gIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHRoaXMsICdrZXknKSkgeyByZXR1cm47IH1cblxuICBpZiAodGhpcy5jb21wYXJlS2V5cyhrZXksIHRoaXMua2V5KSA8IDApIHtcbiAgICBpZiAodGhpcy5sZWZ0KSB7IHRoaXMubGVmdC5kZWxldGUoa2V5LCB2YWx1ZSk7IH1cbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAodGhpcy5jb21wYXJlS2V5cyhrZXksIHRoaXMua2V5KSA+IDApIHtcbiAgICBpZiAodGhpcy5yaWdodCkgeyB0aGlzLnJpZ2h0LmRlbGV0ZShrZXksIHZhbHVlKTsgfVxuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICghdGhpcy5jb21wYXJlS2V5cyhrZXksIHRoaXMua2V5KSA9PT0gMCkgeyByZXR1cm47IH1cblxuICAvLyBEZWxldGUgb25seSBhIHZhbHVlXG4gIGlmICh0aGlzLmRhdGEubGVuZ3RoID4gMSAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5kYXRhLmZvckVhY2goZnVuY3Rpb24gKGQpIHtcbiAgICAgIGlmICghc2VsZi5jaGVja1ZhbHVlRXF1YWxpdHkoZCwgdmFsdWUpKSB7IG5ld0RhdGEucHVzaChkKTsgfVxuICAgIH0pO1xuICAgIHNlbGYuZGF0YSA9IG5ld0RhdGE7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gRGVsZXRlIHRoZSB3aG9sZSBub2RlXG4gIGlmICh0aGlzLmRlbGV0ZUlmTGVhZigpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICh0aGlzLmRlbGV0ZUlmT25seU9uZUNoaWxkKCkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBXZSBhcmUgaW4gdGhlIGNhc2Ugd2hlcmUgdGhlIG5vZGUgdG8gZGVsZXRlIGhhcyB0d28gY2hpbGRyZW5cbiAgaWYgKE1hdGgucmFuZG9tKCkgPj0gMC41KSB7ICAgLy8gUmFuZG9taXplIHJlcGxhY2VtZW50IHRvIGF2b2lkIHVuYmFsYW5jaW5nIHRoZSB0cmVlIHRvbyBtdWNoXG4gICAgLy8gVXNlIHRoZSBpbi1vcmRlciBwcmVkZWNlc3NvclxuICAgIHJlcGxhY2VXaXRoID0gdGhpcy5sZWZ0LmdldE1heEtleURlc2NlbmRhbnQoKTtcblxuICAgIHRoaXMua2V5ID0gcmVwbGFjZVdpdGgua2V5O1xuICAgIHRoaXMuZGF0YSA9IHJlcGxhY2VXaXRoLmRhdGE7XG5cbiAgICBpZiAodGhpcyA9PT0gcmVwbGFjZVdpdGgucGFyZW50KSB7ICAgLy8gU3BlY2lhbCBjYXNlXG4gICAgICB0aGlzLmxlZnQgPSByZXBsYWNlV2l0aC5sZWZ0O1xuICAgICAgaWYgKHJlcGxhY2VXaXRoLmxlZnQpIHsgcmVwbGFjZVdpdGgubGVmdC5wYXJlbnQgPSByZXBsYWNlV2l0aC5wYXJlbnQ7IH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmVwbGFjZVdpdGgucGFyZW50LnJpZ2h0ID0gcmVwbGFjZVdpdGgubGVmdDtcbiAgICAgIGlmIChyZXBsYWNlV2l0aC5sZWZ0KSB7IHJlcGxhY2VXaXRoLmxlZnQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIFVzZSB0aGUgaW4tb3JkZXIgc3VjY2Vzc29yXG4gICAgcmVwbGFjZVdpdGggPSB0aGlzLnJpZ2h0LmdldE1pbktleURlc2NlbmRhbnQoKTtcblxuICAgIHRoaXMua2V5ID0gcmVwbGFjZVdpdGgua2V5O1xuICAgIHRoaXMuZGF0YSA9IHJlcGxhY2VXaXRoLmRhdGE7XG5cbiAgICBpZiAodGhpcyA9PT0gcmVwbGFjZVdpdGgucGFyZW50KSB7ICAgLy8gU3BlY2lhbCBjYXNlXG4gICAgICB0aGlzLnJpZ2h0ID0gcmVwbGFjZVdpdGgucmlnaHQ7XG4gICAgICBpZiAocmVwbGFjZVdpdGgucmlnaHQpIHsgcmVwbGFjZVdpdGgucmlnaHQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlcGxhY2VXaXRoLnBhcmVudC5sZWZ0ID0gcmVwbGFjZVdpdGgucmlnaHQ7XG4gICAgICBpZiAocmVwbGFjZVdpdGgucmlnaHQpIHsgcmVwbGFjZVdpdGgucmlnaHQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfVxuICB9XG59O1xuXG5cbi8qKlxuICogRXhlY3V0ZSBhIGZ1bmN0aW9uIG9uIGV2ZXJ5IG5vZGUgb2YgdGhlIHRyZWUsIGluIGtleSBvcmRlclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gU2lnbmF0dXJlOiBub2RlLiBNb3N0IHVzZWZ1bCB3aWxsIHByb2JhYmx5IGJlIG5vZGUua2V5IGFuZCBub2RlLmRhdGFcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZXhlY3V0ZU9uRXZlcnlOb2RlID0gZnVuY3Rpb24gKGZuKSB7XG4gIGlmICh0aGlzLmxlZnQpIHsgdGhpcy5sZWZ0LmV4ZWN1dGVPbkV2ZXJ5Tm9kZShmbik7IH1cbiAgZm4odGhpcyk7XG4gIGlmICh0aGlzLnJpZ2h0KSB7IHRoaXMucmlnaHQuZXhlY3V0ZU9uRXZlcnlOb2RlKGZuKTsgfVxufTtcblxuXG4vKipcbiAqIFByZXR0eSBwcmludCBhIHRyZWVcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcHJpbnREYXRhIFRvIHByaW50IHRoZSBub2RlcycgZGF0YSBhbG9uZyB3aXRoIHRoZSBrZXlcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUucHJldHR5UHJpbnQgPSBmdW5jdGlvbiAocHJpbnREYXRhLCBzcGFjaW5nKSB7XG4gIHNwYWNpbmcgPSBzcGFjaW5nIHx8ICcnO1xuXG4gIGNvbnNvbGUubG9nKHNwYWNpbmcgKyAnKiAnICsgdGhpcy5rZXkpO1xuICBpZiAocHJpbnREYXRhKSB7IGNvbnNvbGUubG9nKHNwYWNpbmcgKyAnKiAnICsgdGhpcy5kYXRhKTsgfVxuXG4gIGlmICghdGhpcy5sZWZ0ICYmICF0aGlzLnJpZ2h0KSB7IHJldHVybjsgfVxuXG4gIGlmICh0aGlzLmxlZnQpIHtcbiAgICB0aGlzLmxlZnQucHJldHR5UHJpbnQocHJpbnREYXRhLCBzcGFjaW5nICsgJyAgJyk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coc3BhY2luZyArICcgIConKTtcbiAgfVxuICBpZiAodGhpcy5yaWdodCkge1xuICAgIHRoaXMucmlnaHQucHJldHR5UHJpbnQocHJpbnREYXRhLCBzcGFjaW5nICsgJyAgJyk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coc3BhY2luZyArICcgIConKTtcbiAgfVxufTtcblxuXG4vLyBJbnRlcmZhY2Vcbm1vZHVsZS5leHBvcnRzID0gQmluYXJ5U2VhcmNoVHJlZTtcbiJdLCJuYW1lcyI6WyJjdXN0b21VdGlscyIsInJlcXVpcmUiLCJCaW5hcnlTZWFyY2hUcmVlIiwib3B0aW9ucyIsImxlZnQiLCJyaWdodCIsInBhcmVudCIsInVuZGVmaW5lZCIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImtleSIsImRhdGEiLCJ2YWx1ZSIsInVuaXF1ZSIsImNvbXBhcmVLZXlzIiwiZGVmYXVsdENvbXBhcmVLZXlzRnVuY3Rpb24iLCJjaGVja1ZhbHVlRXF1YWxpdHkiLCJkZWZhdWx0Q2hlY2tWYWx1ZUVxdWFsaXR5IiwiZ2V0TWF4S2V5RGVzY2VuZGFudCIsImdldE1heEtleSIsImdldE1pbktleURlc2NlbmRhbnQiLCJnZXRNaW5LZXkiLCJjaGVja0FsbE5vZGVzRnVsbGZpbGxDb25kaXRpb24iLCJ0ZXN0IiwiY2hlY2tOb2RlT3JkZXJpbmciLCJzZWxmIiwiayIsIkVycm9yIiwiY2hlY2tJbnRlcm5hbFBvaW50ZXJzIiwiY2hlY2tJc0JTVCIsImdldE51bWJlck9mS2V5cyIsInJlcyIsImNyZWF0ZVNpbWlsYXIiLCJjb25zdHJ1Y3RvciIsImNyZWF0ZUxlZnRDaGlsZCIsImxlZnRDaGlsZCIsImNyZWF0ZVJpZ2h0Q2hpbGQiLCJyaWdodENoaWxkIiwiaW5zZXJ0IiwicHVzaCIsImVyciIsImVycm9yVHlwZSIsInNlYXJjaCIsImdldExvd2VyQm91bmRNYXRjaGVyIiwicXVlcnkiLCIkZ3RlIiwiJGd0IiwiZ2V0VXBwZXJCb3VuZE1hdGNoZXIiLCIkbHRlIiwiJGx0IiwiYXBwZW5kIiwiYXJyYXkiLCJ0b0FwcGVuZCIsImkiLCJsZW5ndGgiLCJiZXR3ZWVuQm91bmRzIiwibGJtIiwidWJtIiwiZGVsZXRlSWZMZWFmIiwiZGVsZXRlSWZPbmx5T25lQ2hpbGQiLCJjaGlsZCIsImRlbGV0ZSIsIm5ld0RhdGEiLCJyZXBsYWNlV2l0aCIsImZvckVhY2giLCJkIiwiTWF0aCIsInJhbmRvbSIsImV4ZWN1dGVPbkV2ZXJ5Tm9kZSIsImZuIiwicHJldHR5UHJpbnQiLCJwcmludERhdGEiLCJzcGFjaW5nIiwiY29uc29sZSIsImxvZyIsIm1vZHVsZSIsImV4cG9ydHMiXSwibWFwcGluZ3MiOiJBQUFBLG1EQUFtRCxHQUNuRDs7Q0FFQztBQUNELE1BQU1BLGNBQWND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