UNPKG

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
/* 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+IDApIHtcbiAgICBpZiAodGhpcy5yaWdodCkgeyB0aGlzLnJpZ2h0LmRlbGV0ZShrZXksIHZhbHVlKTsgfVxuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICghdGhpcy5jb21wYXJlS2V5cyhrZXksIHRoaXMua2V5KSA9PT0gMCkgeyByZXR1cm47IH1cblxuICAvLyBEZWxldGUgb25seSBhIHZhbHVlXG4gIGlmICh0aGlzLmRhdGEubGVuZ3RoID4gMSAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5kYXRhLmZvckVhY2goZnVuY3Rpb24gKGQpIHtcbiAgICAgIGlmICghc2VsZi5jaGVja1ZhbHVlRXF1YWxpdHkoZCwgdmFsdWUpKSB7IG5ld0RhdGEucHVzaChkKTsgfVxuICAgIH0pO1xuICAgIHNlbGYuZGF0YSA9IG5ld0RhdGE7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gRGVsZXRlIHRoZSB3aG9sZSBub2RlXG4gIGlmICh0aGlzLmRlbGV0ZUlmTGVhZigpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICh0aGlzLmRlbGV0ZUlmT25seU9uZUNoaWxkKCkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBXZSBhcmUgaW4gdGhlIGNhc2Ugd2hlcmUgdGhlIG5vZGUgdG8gZGVsZXRlIGhhcyB0d28gY2hpbGRyZW5cbiAgaWYgKE1hdGgucmFuZG9tKCkgPj0gMC41KSB7ICAgLy8gUmFuZG9taXplIHJlcGxhY2VtZW50IHRvIGF2b2lkIHVuYmFsYW5jaW5nIHRoZSB0cmVlIHRvbyBtdWNoXG4gICAgLy8gVXNlIHRoZSBpbi1vcmRlciBwcmVkZWNlc3NvclxuICAgIHJlcGxhY2VXaXRoID0gdGhpcy5sZWZ0LmdldE1heEtleURlc2NlbmRhbnQoKTtcblxuICAgIHRoaXMua2V5ID0gcmVwbGFjZVdpdGgua2V5O1xuICAgIHRoaXMuZGF0YSA9IHJlcGxhY2VXaXRoLmRhdGE7XG5cbiAgICBpZiAodGhpcyA9PT0gcmVwbGFjZVdpdGgucGFyZW50KSB7ICAgLy8gU3BlY2lhbCBjYXNlXG4gICAgICB0aGlzLmxlZnQgPSByZXBsYWNlV2l0aC5sZWZ0O1xuICAgICAgaWYgKHJlcGxhY2VXaXRoLmxlZnQpIHsgcmVwbGFjZVdpdGgubGVmdC5wYXJlbnQgPSByZXBsYWNlV2l0aC5wYXJlbnQ7IH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmVwbGFjZVdpdGgucGFyZW50LnJpZ2h0ID0gcmVwbGFjZVdpdGgubGVmdDtcbiAgICAgIGlmIChyZXBsYWNlV2l0aC5sZWZ0KSB7IHJlcGxhY2VXaXRoLmxlZnQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIFVzZSB0aGUgaW4tb3JkZXIgc3VjY2Vzc29yXG4gICAgcmVwbGFjZVdpdGggPSB0aGlzLnJpZ2h0LmdldE1pbktleURlc2NlbmRhbnQoKTtcblxuICAgIHRoaXMua2V5ID0gcmVwbGFjZVdpdGgua2V5O1xuICAgIHRoaXMuZGF0YSA9IHJlcGxhY2VXaXRoLmRhdGE7XG5cbiAgICBpZiAodGhpcyA9PT0gcmVwbGFjZVdpdGgucGFyZW50KSB7ICAgLy8gU3BlY2lhbCBjYXNlXG4gICAgICB0aGlzLnJpZ2h0ID0gcmVwbGFjZVdpdGgucmlnaHQ7XG4gICAgICBpZiAocmVwbGFjZVdpdGgucmlnaHQpIHsgcmVwbGFjZVdpdGgucmlnaHQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHJlcGxhY2VXaXRoLnBhcmVudC5sZWZ0ID0gcmVwbGFjZVdpdGgucmlnaHQ7XG4gICAgICBpZiAocmVwbGFjZVdpdGgucmlnaHQpIHsgcmVwbGFjZVdpdGgucmlnaHQucGFyZW50ID0gcmVwbGFjZVdpdGgucGFyZW50OyB9XG4gICAgfVxuICB9XG59O1xuXG5cbi8qKlxuICogRXhlY3V0ZSBhIGZ1bmN0aW9uIG9uIGV2ZXJ5IG5vZGUgb2YgdGhlIHRyZWUsIGluIGtleSBvcmRlclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gU2lnbmF0dXJlOiBub2RlLiBNb3N0IHVzZWZ1bCB3aWxsIHByb2JhYmx5IGJlIG5vZGUua2V5IGFuZCBub2RlLmRhdGFcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUuZXhlY3V0ZU9uRXZlcnlOb2RlID0gZnVuY3Rpb24gKGZuKSB7XG4gIGlmICh0aGlzLmxlZnQpIHsgdGhpcy5sZWZ0LmV4ZWN1dGVPbkV2ZXJ5Tm9kZShmbik7IH1cbiAgZm4odGhpcyk7XG4gIGlmICh0aGlzLnJpZ2h0KSB7IHRoaXMucmlnaHQuZXhlY3V0ZU9uRXZlcnlOb2RlKGZuKTsgfVxufTtcblxuXG4vKipcbiAqIFByZXR0eSBwcmludCBhIHRyZWVcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gcHJpbnREYXRhIFRvIHByaW50IHRoZSBub2RlcycgZGF0YSBhbG9uZyB3aXRoIHRoZSBrZXlcbiAqL1xuQmluYXJ5U2VhcmNoVHJlZS5wcm90b3R5cGUucHJldHR5UHJpbnQgPSBmdW5jdGlvbiAocHJpbnREYXRhLCBzcGFjaW5nKSB7XG4gIHNwYWNpbmcgPSBzcGFjaW5nIHx8ICcnO1xuXG4gIGNvbnNvbGUubG9nKHNwYWNpbmcgKyAnKiAnICsgdGhpcy5rZXkpO1xuICBpZiAocHJpbnREYXRhKSB7IGNvbnNvbGUubG9nKHNwYWNpbmcgKyAnKiAnICsgdGhpcy5kYXRhKTsgfVxuXG4gIGlmICghdGhpcy5sZWZ0ICYmICF0aGlzLnJpZ2h0KSB7IHJldHVybjsgfVxuXG4gIGlmICh0aGlzLmxlZnQpIHtcbiAgICB0aGlzLmxlZnQucHJldHR5UHJpbnQocHJpbnREYXRhLCBzcGFjaW5nICsgJyAgJyk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coc3BhY2luZyArICcgIConKTtcbiAgfVxuICBpZiAodGhpcy5yaWdodCkge1xuICAgIHRoaXMucmlnaHQucHJldHR5UHJpbnQocHJpbnREYXRhLCBzcGFjaW5nICsgJyAgJyk7XG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coc3BhY2luZyArICcgIConKTtcbiAgfVxufTtcblxuXG4vLyBJbnRlcmZhY2Vcbm1vZHVsZS5leHBvcnRzID0gQmluYXJ5U2VhcmNoVHJlZTtcbiJdLCJuYW1lcyI6WyJjdXN0b21VdGlscyIsInJlcXVpcmUiLCJCaW5hcnlTZWFyY2hUcmVlIiwib3B0aW9ucyIsImxlZnQiLCJyaWdodCIsInBhcmVudCIsInVuZGVmaW5lZCIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImtleSIsImRhdGEiLCJ2YWx1ZSIsInVuaXF1ZSIsImNvbXBhcmVLZXlzIiwiZGVmYXVsdENvbXBhcmVLZXlzRnVuY3Rpb24iLCJjaGVja1ZhbHVlRXF1YWxpdHkiLCJkZWZhdWx0Q2hlY2tWYWx1ZUVxdWFsaXR5IiwiZ2V0TWF4S2V5RGVzY2VuZGFudCIsImdldE1heEtleSIsImdldE1pbktleURlc2NlbmRhbnQiLCJnZXRNaW5LZXkiLCJjaGVja0FsbE5vZGVzRnVsbGZpbGxDb25kaXRpb24iLCJ0ZXN0IiwiY2hlY2tOb2RlT3JkZXJpbmciLCJzZWxmIiwiayIsIkVycm9yIiwiY2hlY2tJbnRlcm5hbFBvaW50ZXJzIiwiY2hlY2tJc0JTVCIsImdldE51bWJlck9mS2V5cyIsInJlcyIsImNyZWF0ZVNpbWlsYXIiLCJjb25zdHJ1Y3RvciIsImNyZWF0ZUxlZnRDaGlsZCIsImxlZnRDaGlsZCIsImNyZWF0ZVJpZ2h0Q2hpbGQiLCJyaWdodENoaWxkIiwiaW5zZXJ0IiwicHVzaCIsImVyciIsImVycm9yVHlwZSIsInNlYXJjaCIsImdldExvd2VyQm91bmRNYXRjaGVyIiwicXVlcnkiLCIkZ3RlIiwiJGd0IiwiZ2V0VXBwZXJCb3VuZE1hdGNoZXIiLCIkbHRlIiwiJGx0IiwiYXBwZW5kIiwiYXJyYXkiLCJ0b0FwcGVuZCIsImkiLCJsZW5ndGgiLCJiZXR3ZWVuQm91bmRzIiwibGJtIiwidWJtIiwiZGVsZXRlSWZMZWFmIiwiZGVsZXRlSWZPbmx5T25lQ2hpbGQiLCJjaGlsZCIsImRlbGV0ZSIsIm5ld0RhdGEiLCJyZXBsYWNlV2l0aCIsImZvckVhY2giLCJkIiwiTWF0aCIsInJhbmRvbSIsImV4ZWN1dGVPbkV2ZXJ5Tm9kZSIsImZuIiwicHJldHR5UHJpbnQiLCJwcmludERhdGEiLCJzcGFjaW5nIiwiY29uc29sZSIsImxvZyIsIm1vZHVsZSIsImV4cG9ydHMiXSwibWFwcGluZ3MiOiJBQUFBLG1EQUFtRCxHQUNuRDs7Q0FFQztBQUNELE1BQU1BLGNBQWNDLFFBQVE7QUFHNUI7Ozs7Ozs7Q0FPQyxHQUNELFNBQVNDLGlCQUFrQkMsT0FBTztJQUNoQ0EsVUFBVUEsV0FBVyxDQUFDO0lBRXRCLElBQUksQ0FBQ0MsSUFBSSxHQUFHO0lBQ1osSUFBSSxDQUFDQyxLQUFLLEdBQUc7SUFDYixJQUFJLENBQUNDLE1BQU0sR0FBR0gsUUFBUUcsTUFBTSxLQUFLQyxZQUFZSixRQUFRRyxNQUFNLEdBQUc7SUFDOUQsSUFBSUUsT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQ1IsU0FBUyxRQUFRO1FBQUUsSUFBSSxDQUFDUyxHQUFHLEdBQUdULFFBQVFTLEdBQUc7SUFBRTtJQUNwRixJQUFJLENBQUNDLElBQUksR0FBR0wsT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQ1IsU0FBUyxXQUFXO1FBQUNBLFFBQVFXLEtBQUs7S0FBQyxHQUFHLEVBQUU7SUFDekYsSUFBSSxDQUFDQyxNQUFNLEdBQUdaLFFBQVFZLE1BQU0sSUFBSTtJQUVoQyxJQUFJLENBQUNDLFdBQVcsR0FBR2IsUUFBUWEsV0FBVyxJQUFJaEIsWUFBWWlCLDBCQUEwQjtJQUNoRixJQUFJLENBQUNDLGtCQUFrQixHQUFHZixRQUFRZSxrQkFBa0IsSUFBSWxCLFlBQVltQix5QkFBeUI7QUFDL0Y7QUFHQSxtQ0FBbUM7QUFDbkMsZ0NBQWdDO0FBQ2hDLG1DQUFtQztBQUduQzs7Q0FFQyxHQUNEakIsaUJBQWlCTyxTQUFTLENBQUNXLG1CQUFtQixHQUFHO0lBQy9DLElBQUksSUFBSSxDQUFDZixLQUFLLEVBQUU7UUFDZCxPQUFPLElBQUksQ0FBQ0EsS0FBSyxDQUFDZSxtQkFBbUI7SUFDdkMsT0FBTztRQUNMLE9BQU8sSUFBSTtJQUNiO0FBQ0Y7QUFHQTs7Q0FFQyxHQUNEbEIsaUJBQWlCTyxTQUFTLENBQUNZLFNBQVMsR0FBRztJQUNyQyxPQUFPLElBQUksQ0FBQ0QsbUJBQW1CLEdBQUdSLEdBQUc7QUFDdkM7QUFHQTs7Q0FFQyxHQUNEVixpQkFBaUJPLFNBQVMsQ0FBQ2EsbUJBQW1CLEdBQUc7SUFDL0MsSUFBSSxJQUFJLENBQUNsQixJQUFJLEVBQUU7UUFDYixPQUFPLElBQUksQ0FBQ0EsSUFBSSxDQUFDa0IsbUJBQW1CO0lBQ3RDLE9BQU87UUFDTCxPQUFPLElBQUk7SUFDYjtBQUNGO0FBR0E7O0NBRUMsR0FDRHBCLGlCQUFpQk8sU0FBUyxDQUFDYyxTQUFTLEdBQUc7SUFDckMsT0FBTyxJQUFJLENBQUNELG1CQUFtQixHQUFHVixHQUFHO0FBQ3ZDO0FBR0E7OztDQUdDLEdBQ0RWLGlCQUFpQk8sU0FBUyxDQUFDZSw4QkFBOEIsR0FBRyxTQUFVQyxJQUFJO0lBQ3hFLElBQUksQ0FBQ2pCLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVE7UUFBRTtJQUFRO0lBRWxFYyxLQUFLLElBQUksQ0FBQ2IsR0FBRyxFQUFFLElBQUksQ0FBQ0MsSUFBSTtJQUN4QixJQUFJLElBQUksQ0FBQ1QsSUFBSSxFQUFFO1FBQUUsSUFBSSxDQUFDQSxJQUFJLENBQUNvQiw4QkFBOEIsQ0FBQ0M7SUFBTztJQUNqRSxJQUFJLElBQUksQ0FBQ3BCLEtBQUssRUFBRTtRQUFFLElBQUksQ0FBQ0EsS0FBSyxDQUFDbUIsOEJBQThCLENBQUNDO0lBQU87QUFDckU7QUFHQTs7O0NBR0MsR0FDRHZCLGlCQUFpQk8sU0FBUyxDQUFDaUIsaUJBQWlCLEdBQUc7SUFDN0MsSUFBSUMsT0FBTyxJQUFJO0lBRWYsSUFBSSxDQUFDbkIsT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUTtRQUFFO0lBQVE7SUFFbEUsSUFBSSxJQUFJLENBQUNQLElBQUksRUFBRTtRQUNiLElBQUksQ0FBQ0EsSUFBSSxDQUFDb0IsOEJBQThCLENBQUMsU0FBVUksQ0FBQztZQUNsRCxJQUFJRCxLQUFLWCxXQUFXLENBQUNZLEdBQUdELEtBQUtmLEdBQUcsS0FBSyxHQUFHO2dCQUN0QyxNQUFNLElBQUlpQixNQUFNLG9CQUFvQkYsS0FBS2YsR0FBRyxHQUFHO1lBQ2pEO1FBQ0Y7UUFDQSxJQUFJLENBQUNSLElBQUksQ0FBQ3NCLGlCQUFpQjtJQUM3QjtJQUVBLElBQUksSUFBSSxDQUFDckIsS0FBSyxFQUFFO1FBQ2QsSUFBSSxDQUFDQSxLQUFLLENBQUNtQiw4QkFBOEIsQ0FBQyxTQUFVSSxDQUFDO1lBQ25ELElBQUlELEtBQUtYLFdBQVcsQ0FBQ1ksR0FBR0QsS0FBS2YsR0FBRyxLQUFLLEdBQUc7Z0JBQ3RDLE1BQU0sSUFBSWlCLE1BQU0sb0JBQW9CRixLQUFLZixHQUFHLEdBQUc7WUFDakQ7UUFDRjtRQUNBLElBQUksQ0FBQ1AsS0FBSyxDQUFDcUIsaUJBQWlCO0lBQzlCO0FBQ0Y7QUFHQTs7Q0FFQyxHQUNEeEIsaUJBQWlCTyxTQUFTLENBQUNxQixxQkFBcUIsR0FBRztJQUNqRCxJQUFJLElBQUksQ0FBQzFCLElBQUksRUFBRTtRQUNiLElBQUksSUFBSSxDQUFDQSxJQUFJLENBQUNFLE1BQU0sS0FBSyxJQUFJLEVBQUU7WUFBRSxNQUFNLElBQUl1QixNQUFNLG1DQUFtQyxJQUFJLENBQUNqQixHQUFHO1FBQUc7UUFDL0YsSUFBSSxDQUFDUixJQUFJLENBQUMwQixxQkFBcUI7SUFDakM7SUFFQSxJQUFJLElBQUksQ0FBQ3pCLEtBQUssRUFBRTtRQUNkLElBQUksSUFBSSxDQUFDQSxLQUFLLENBQUNDLE1BQU0sS0FBSyxJQUFJLEVBQUU7WUFBRSxNQUFNLElBQUl1QixNQUFNLG1DQUFtQyxJQUFJLENBQUNqQixHQUFHO1FBQUc7UUFDaEcsSUFBSSxDQUFDUCxLQUFLLENBQUN5QixxQkFBcUI7SUFDbEM7QUFDRjtBQUdBOztDQUVDLEdBQ0Q1QixpQkFBaUJPLFNBQVMsQ0FBQ3NCLFVBQVUsR0FBRztJQUN0QyxJQUFJLENBQUNMLGlCQUFpQjtJQUN0QixJQUFJLENBQUNJLHFCQUFxQjtJQUMxQixJQUFJLElBQUksQ0FBQ3hCLE1BQU0sRUFBRTtRQUFFLE1BQU0sSUFBSXVCLE1BQU07SUFBc0M7QUFDM0U7QUFHQTs7Q0FFQyxHQUNEM0IsaUJBQWlCTyxTQUFTLENBQUN1QixlQUFlLEdBQUc7SUFDM0MsSUFBSUM7SUFFSixJQUFJLENBQUN6QixPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDLElBQUksRUFBRSxRQUFRO1FBQUUsT0FBTztJQUFHO0lBR3BFc0IsTUFBTTtJQUNOLElBQUksSUFBSSxDQUFDN0IsSUFBSSxFQUFFO1FBQUU2QixPQUFPLElBQUksQ0FBQzdCLElBQUksQ0FBQzRCLGVBQWU7SUFBSTtJQUNyRCxJQUFJLElBQUksQ0FBQzNCLEtBQUssRUFBRTtRQUFFNEIsT0FBTyxJQUFJLENBQUM1QixLQUFLLENBQUMyQixlQUFlO0lBQUk7SUFFdkQsT0FBT0M7QUFDVDtBQUlBLCtDQUErQztBQUMvQyw0Q0FBNEM7QUFDNUMsK0NBQStDO0FBRS9DOzs7O0NBSUMsR0FDRC9CLGlCQUFpQk8sU0FBUyxDQUFDeUIsYUFBYSxHQUFHLFNBQVUvQixPQUFPO0lBQzFEQSxVQUFVQSxXQUFXLENBQUM7SUFDdEJBLFFBQVFZLE1BQU0sR0FBRyxJQUFJLENBQUNBLE1BQU07SUFDNUJaLFFBQVFhLFdBQVcsR0FBRyxJQUFJLENBQUNBLFdBQVc7SUFDdENiLFFBQVFlLGtCQUFrQixHQUFHLElBQUksQ0FBQ0Esa0JBQWtCO0lBRXBELE9BQU8sSUFBSSxJQUFJLENBQUNpQixXQUFXLENBQUNoQztBQUM5QjtBQUdBOztDQUVDLEdBQ0RELGlCQUFpQk8sU0FBUyxDQUFDMkIsZUFBZSxHQUFHLFNBQVVqQyxPQUFPO0lBQzVELElBQUlrQyxZQUFZLElBQUksQ0FBQ0gsYUFBYSxDQUFDL0I7SUFDbkNrQyxVQUFVL0IsTUFBTSxHQUFHLElBQUk7SUFDdkIsSUFBSSxDQUFDRixJQUFJLEdBQUdpQztJQUVaLE9BQU9BO0FBQ1Q7QUFHQTs7Q0FFQyxHQUNEbkMsaUJBQWlCTyxTQUFTLENBQUM2QixnQkFBZ0IsR0FBRyxTQUFVbkMsT0FBTztJQUM3RCxJQUFJb0MsYUFBYSxJQUFJLENBQUNMLGFBQWEsQ0FBQy9CO0lBQ3BDb0MsV0FBV2pDLE1BQU0sR0FBRyxJQUFJO0lBQ3hCLElBQUksQ0FBQ0QsS0FBSyxHQUFHa0M7SUFFYixPQUFPQTtBQUNUO0FBR0E7O0NBRUMsR0FDRHJDLGlCQUFpQk8sU0FBUyxDQUFDK0IsTUFBTSxHQUFHLFNBQVU1QixHQUFHLEVBQUVFLEtBQUs7SUFDdEQsNkJBQTZCO0lBQzdCLElBQUksQ0FBQ04sT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUTtRQUN0RCxJQUFJLENBQUNDLEdBQUcsR0FBR0E7UUFDWCxJQUFJLENBQUNDLElBQUksQ0FBQzRCLElBQUksQ0FBQzNCO1FBQ2Y7SUFDRjtJQUVBLG1CQUFtQjtJQUNuQixJQUFJLElBQUksQ0FBQ0UsV0FBVyxDQUFDLElBQUksQ0FBQ0osR0FBRyxFQUFFQSxTQUFTLEdBQUc7UUFDekMsSUFBSSxJQUFJLENBQUNHLE1BQU0sRUFBRTtZQUNmLElBQUkyQixNQUFNLElBQUliLE1BQU0sc0JBQXVCakIsTUFBTTtZQUNqRDhCLElBQUk5QixHQUFHLEdBQUdBO1lBQ1Y4QixJQUFJQyxTQUFTLEdBQUc7WUFDaEIsTUFBTUQ7UUFDUixPQUFPO1lBQ0wsSUFBSSxDQUFDN0IsSUFBSSxDQUFDNEIsSUFBSSxDQUFDM0I7UUFDakI7UUFDQTtJQUNGO0lBRUEsSUFBSSxJQUFJLENBQUNFLFdBQVcsQ0FBQ0osS0FBSyxJQUFJLENBQUNBLEdBQUcsSUFBSSxHQUFHO1FBQ3ZDLHlCQUF5QjtRQUN6QixJQUFJLElBQUksQ0FBQ1IsSUFBSSxFQUFFO1lBQ2IsSUFBSSxDQUFDQSxJQUFJLENBQUNvQyxNQUFNLENBQUM1QixLQUFLRTtRQUN4QixPQUFPO1lBQ0wsSUFBSSxDQUFDc0IsZUFBZSxDQUFDO2dCQUFFeEIsS0FBS0E7Z0JBQUtFLE9BQU9BO1lBQU07UUFDaEQ7SUFDRixPQUFPO1FBQ0wsMEJBQTBCO1FBQzFCLElBQUksSUFBSSxDQUFDVCxLQUFLLEVBQUU7WUFDZCxJQUFJLENBQUNBLEtBQUssQ0FBQ21DLE1BQU0sQ0FBQzVCLEtBQUtFO1FBQ3pCLE9BQU87WUFDTCxJQUFJLENBQUN3QixnQkFBZ0IsQ0FBQztnQkFBRTFCLEtBQUtBO2dCQUFLRSxPQUFPQTtZQUFNO1FBQ2pEO0lBQ0Y7QUFDRjtBQUdBOztDQUVDLEdBQ0RaLGlCQUFpQk8sU0FBUyxDQUFDbUMsTUFBTSxHQUFHLFNBQVVoQyxHQUFHO0lBQy9DLElBQUksQ0FBQ0osT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUTtRQUFFLE9BQU8sRUFBRTtJQUFFO0lBRXJFLElBQUksSUFBSSxDQUFDSyxXQUFXLENBQUMsSUFBSSxDQUFDSixHQUFHLEVBQUVBLFNBQVMsR0FBRztRQUFFLE9BQU8sSUFBSSxDQUFDQyxJQUFJO0lBQUU7SUFFL0QsSUFBSSxJQUFJLENBQUNHLFdBQVcsQ0FBQ0osS0FBSyxJQUFJLENBQUNBLEdBQUcsSUFBSSxHQUFHO1FBQ3ZDLElBQUksSUFBSSxDQUFDUixJQUFJLEVBQUU7WUFDYixPQUFPLElBQUksQ0FBQ0EsSUFBSSxDQUFDd0MsTUFBTSxDQUFDaEM7UUFDMUIsT0FBTztZQUNMLE9BQU8sRUFBRTtRQUNYO0lBQ0YsT0FBTztRQUNMLElBQUksSUFBSSxDQUFDUCxLQUFLLEVBQUU7WUFDZCxPQUFPLElBQUksQ0FBQ0EsS0FBSyxDQUFDdUMsTUFBTSxDQUFDaEM7UUFDM0IsT0FBTztZQUNMLE9BQU8sRUFBRTtRQUNYO0lBQ0Y7QUFDRjtBQUdBOztDQUVDLEdBQ0RWLGlCQUFpQk8sU0FBUyxDQUFDb0Msb0JBQW9CLEdBQUcsU0FBVUMsS0FBSztJQUMvRCxJQUFJbkIsT0FBTyxJQUFJO0lBRWYsaUJBQWlCO0lBQ2pCLElBQUksQ0FBQ25CLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUNtQyxPQUFPLFVBQVUsQ0FBQ3RDLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUNtQyxPQUFPLFNBQVM7UUFDL0csT0FBTztZQUFjLE9BQU87UUFBTTtJQUNwQztJQUVBLElBQUl0QyxPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDbUMsT0FBTyxVQUFVdEMsT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQ21DLE9BQU8sU0FBUztRQUM3RyxJQUFJbkIsS0FBS1gsV0FBVyxDQUFDOEIsTUFBTUMsSUFBSSxFQUFFRCxNQUFNRSxHQUFHLE1BQU0sR0FBRztZQUNqRCxPQUFPLFNBQVVwQyxHQUFHO2dCQUFJLE9BQU9lLEtBQUtYLFdBQVcsQ0FBQ0osS0FBS2tDLE1BQU1FLEdBQUcsSUFBSTtZQUFHO1FBQ3ZFO1FBRUEsSUFBSXJCLEtBQUtYLFdBQVcsQ0FBQzhCLE1BQU1DLElBQUksRUFBRUQsTUFBTUUsR0FBRyxJQUFJLEdBQUc7WUFDL0MsT0FBTyxTQUFVcEMsR0FBRztnQkFBSSxPQUFPZSxLQUFLWCxXQUFXLENBQUNKLEtBQUtrQyxNQUFNQyxJQUFJLEtBQUs7WUFBRztRQUN6RSxPQUFPO1lBQ0wsT0FBTyxTQUFVbkMsR0FBRztnQkFBSSxPQUFPZSxLQUFLWCxXQUFXLENBQUNKLEtBQUtrQyxNQUFNRSxHQUFHLElBQUk7WUFBRztRQUN2RTtJQUNGO0lBRUEsSUFBSXhDLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUNtQyxPQUFPLFFBQVE7UUFDdEQsT0FBTyxTQUFVbEMsR0FBRztZQUFJLE9BQU9lLEtBQUtYLFdBQVcsQ0FBQ0osS0FBS2tDLE1BQU1FLEdBQUcsSUFBSTtRQUFHO0lBQ3ZFLE9BQU87UUFDTCxPQUFPLFNBQVVwQyxHQUFHO1lBQUksT0FBT2UsS0FBS1gsV0FBVyxDQUFDSixLQUFLa0MsTUFBTUMsSUFBSSxLQUFLO1FBQUc7SUFDekU7QUFDRjtBQUdBOztDQUVDLEdBQ0Q3QyxpQkFBaUJPLFNBQVMsQ0FBQ3dDLG9CQUFvQixHQUFHLFNBQVVILEtBQUs7SUFDL0QsSUFBSW5CLE9BQU8sSUFBSTtJQUVmLGlCQUFpQjtJQUNqQixJQUFJLENBQUNuQixPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDbUMsT0FBTyxVQUFVLENBQUN0QyxPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDbUMsT0FBTyxTQUFTO1FBQy9HLE9BQU87WUFBYyxPQUFPO1FBQU07SUFDcEM7SUFFQSxJQUFJdEMsT0FBT0MsU0FBUyxDQUFDQyxjQUFjLENBQUNDLElBQUksQ0FBQ21DLE9BQU8sVUFBVXRDLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUNtQyxPQUFPLFNBQVM7UUFDN0csSUFBSW5CLEtBQUtYLFdBQVcsQ0FBQzhCLE1BQU1JLElBQUksRUFBRUosTUFBTUssR0FBRyxNQUFNLEdBQUc7WUFDakQsT0FBTyxTQUFVdkMsR0FBRztnQkFBSSxPQUFPZSxLQUFLWCxXQUFXLENBQUNKLEtBQUtrQyxNQUFNSyxHQUFHLElBQUk7WUFBRztRQUN2RTtRQUVBLElBQUl4QixLQUFLWCxXQUFXLENBQUM4QixNQUFNSSxJQUFJLEVBQUVKLE1BQU1LLEdBQUcsSUFBSSxHQUFHO1lBQy9DLE9BQU8sU0FBVXZDLEdBQUc7Z0JBQUksT0FBT2UsS0FBS1gsV0FBVyxDQUFDSixLQUFLa0MsTUFBTUksSUFBSSxLQUFLO1lBQUc7UUFDekUsT0FBTztZQUNMLE9BQU8sU0FBVXRDLEdBQUc7Z0JBQUksT0FBT2UsS0FBS1gsV0FBVyxDQUFDSixLQUFLa0MsTUFBTUssR0FBRyxJQUFJO1lBQUc7UUFDdkU7SUFDRjtJQUVBLElBQUkzQyxPQUFPQyxTQUFTLENBQUNDLGNBQWMsQ0FBQ0MsSUFBSSxDQUFDbUMsT0FBTyxRQUFRO1FBQ3RELE9BQU8sU0FBVWxDLEdBQUc7WUFBSSxPQUFPZSxLQUFLWCxXQUFXLENBQUNKLEtBQUtrQyxNQUFNSyxHQUFHLElBQUk7UUFBRztJQUN2RSxPQUFPO1FBQ0wsT0FBTyxTQUFVdkMsR0FBRztZQUFJLE9BQU9lLEtBQUtYLFdBQVcsQ0FBQ0osS0FBS2tDLE1BQU1JLElBQUksS0FBSztRQUFHO0lBQ3pFO0FBQ0Y7QUFHQSwyQ0FBMkM7QUFDM0MsU0FBU0UsT0FBUUMsS0FBSyxFQUFFQyxRQUFRO0lBQzlCLElBQUlDO0lBRUosSUFBS0EsSUFBSSxHQUFHQSxJQUFJRCxTQUFTRSxNQUFNLEVBQUVELEtBQUssRUFBRztRQUN2Q0YsTUFBTVosSUFBSSxDQUFDYSxRQUFRLENBQUNDLEVBQUU7SUFDeEI7QUFDRjtBQUdBOzs7OztDQUtDLEdBQ0Qsc0NBQXNDO0FBQ3RDckQsaUJBQWlCTyxTQUFTLENBQUNnRCxhQUFhLEdBQUcsU0FBVVgsS0FBSyxFQUFFWSxHQUFHLEVBQUVDLEdBQUc7SUFDbEUsSUFBSTFCLE1BQU0sRUFBRTtJQUVaLElBQUksQ0FBQ3pCLE9BQU9DLFNBQVMsQ0FBQ0MsY0FBYyxDQUFDQyxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVE7UUFBRSxPQUFPLEVBQUU7SUFBRSxFQUFJLGFBQWE7SUFFdEYrQyxNQUFNQSxPQUFPLElBQUksQ0FBQ2Isb0JBQW9CLENBQUNDO0lBQ3ZDYSxNQUFNQSxPQUFPLElBQUksQ0FBQ1Ysb0JBQW9CLENBQUNIO0lBRXZDLElBQUlZLElBQUksSUFBSSxDQUFDOUMsR0FBRyxLQUFLLElBQUksQ0FBQ1IsSUFBSSxFQUFFO1FBQUVnRCxPQUFPbkIsS0FBSyxJQUFJLENBQUM3QixJQUFJLENBQUNxRCxhQUFhLENBQUNYLE9BQU9ZLEtBQUtDO0lBQU87SUFDekYsSUFBSUQsSUFBSSxJQUFJLENBQUM5QyxHQUFHLEtBQUsrQyxJQUFJLElBQUksQ0FBQy9DLEdBQUcsR0FBRztRQUFFd0MsT0FBT25CLEtBQUssSUFBSSxDQUFDcEIsSUFBSTtJQUFHO0lBQzlELElBQUk4QyxJQUFJLElBQUksQ0FBQy9DLEdBQUcsS0FBSyxJQUFJLENBQUNQLEtBQUssRUFBRTtRQUFFK0MsT0FBT25CLEtBQUssSUFBSSxDQUFDNUIsS0FBSyxDQUFDb0QsYUFBYSxDQUFDWCxPQUFPWSxLQUFLQztJQUFPO0lBRTNGLE9BQU8xQjtBQUNUO0FBR0E7OztDQUdDLEdBQ0QvQixpQkFBaUJPLFNBQVMsQ0FBQ21ELFlBQVksR0FBRztJQUN4QyxJQUFJLElBQUksQ0FBQ3hELElBQUksSUFBSSxJQUFJLENBQUNDLEtBQUssRUFBRTtRQUFFLE9BQU87SUFBTztJQUU3Qyw0QkFBNEI7SUFDNUIsSUFBSSxDQUFDLElBQUksQ0FBQ0MsTUFBTSxFQUFFO1FBQ2hCLE9BQU8sSUFBSSxDQUFDTSxHQUFHO1FBQ2YsSUFBSSxDQUFDQyxJQUFJLEdBQUcsRUFBRTtRQUNkLE9BQU87SUFDVDtJQUVBLElBQUksSUFBSSxDQUFDUCxNQUFNLENBQUNGLElBQUksS0FBSyxJQUFJLEVBQUU7UUFDN0IsSUFBSSxDQUFDRSxNQUFNLENBQUNGLElBQUksR0FBRztJQUNyQixPQUFPO1FBQ0wsSUFBSSxDQUFDRSxNQUFNLENBQUNELEtBQUssR0FBRztJQUN0QjtJQUVBLE9BQU87QUFDVDtBQUdBOzs7Q0FHQyxHQUNELHNDQUFzQztBQUN0Q0gsaUJBQWlCTyxTQUFTLENBQUNvRCxvQkFBb0IsR0FBRztJQUNoRCxJQUFJQztJQUVKLElBQUksSUFBSSxDQUFDMUQsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDQyxLQUFLLEVBQUU7UUFBRXlELFFBQVEsSUFBSSxDQUFDMUQsSUFBSTtJQUFFO0lBQ25ELElBQUksQ0FBQyxJQUFJLENBQUNBLElBQUksSUFBSSxJQUFJLENBQUNDLEtBQUssRUFBRTtRQUFFeUQsUUFBUSxJQUFJLENBQUN6RCxLQUFLO0lBQUU7SUFDcEQsSUFBSSxDQUFDeUQsT0FBTztRQUFFLE9BQU87SUFBTztJQUU1QixPQUFPO0lBQ1AsSUFBSSxDQUFDLElBQUksQ0FBQ3hELE1BQU0sRUFBRTtRQUNoQixJQUFJLENBQUNNLEdBQUcsR0FBR2tELE1BQU1sRCxHQUFHO1FBQ3BCLElBQUksQ0FBQ0MsSUFBSSxHQUFHaUQsTUFBTWpELElBQUk7UUFFdEIsSUFBSSxDQUFDVCxJQUFJLEdBQUc7UUFDWixJQUFJMEQsTUFBTTFELElBQUksRUFBRTtZQUNkLElBQUksQ0FBQ0EsSUFBSSxHQUFHMEQsTUFBTTFELElBQUk7WUFDdEIwRCxNQUFNMUQsSUFBSSxDQUFDRSxNQUFNLEdBQUcsSUFBSTtRQUMxQjtRQUVBLElBQUksQ0FBQ0QsS0FBSyxHQUFHO1FBQ2IsSUFBSXlELE1BQU16RCxLQUFLLEVBQUU7WUFDZixJQUFJLENBQUNBLEtBQUssR0FBR3lELE1BQU16RCxLQUFLO1lBQ3hCeUQsTUFBTXpELEtBQUssQ0FBQ0MsTUFBTSxHQUFHLElBQUk7UUFDM0I7UUFFQSxPQUFPO0lBQ1Q7SUFFQSxJQUFJLElB