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)

311 lines (310 loc) 42.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "default", { enumerable: true, get: function() { return TerminalHashManager; } }); const _cryptojs = /*#__PURE__*/ _interop_require_default(require("crypto-js")); const _referenceTree = /*#__PURE__*/ _interop_require_default(require("./referenceTree")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let TerminalHashManager = class TerminalHashManager { /** * Refreshes hashing ignored field lists * @param {String} region account region * @returns {Promise} promise resolving when the hashing field lists are updated. */ async refreshIgnoredFieldLists(region) { await this._clientApiClient.refreshIgnoredFieldLists(region); } /** * Returns specifications data by hash * @param {string} specificationsHash specifications hash * @returns {[id: string]: MetatraderSymbolSpecification} */ getSpecificationsByHash(specificationsHash) { return this._specificationsTree.getItemsByHash(specificationsHash); } /** * Returns specifications hash data by hash * @param {string} specificationsHash specifications hash * @returns {[id: string]: string} */ getSpecificationsHashesByHash(specificationsHash) { return this._specificationsTree.getHashesByHash(specificationsHash); } /** * Returns positions data by hash * @param {string} positionsHash positions hash * @returns {[id: string]: MetatraderPosition} */ getPositionsByHash(positionsHash) { return this._positionsTree.getItemsByHash(positionsHash); } /** * Returns positions hash data by hash * @param {string} positionsHash positions hash * @returns {[id: string]: string} dictionary of position hashes */ getPositionsHashesByHash(positionsHash) { return this._positionsTree.getHashesByHash(positionsHash); } /** * Returns orders data by hash * @param {string} ordersHash orders hash * @returns {[id: string]: MetatraderOrder} removed position ids */ getOrdersByHash(ordersHash) { return this._ordersTree.getItemsByHash(ordersHash); } /** * Returns orders hash data by hash * @param {string} ordersHash orders hash * @returns {[id: string]: string} dictionary of order hashes */ getOrdersHashesByHash(ordersHash) { return this._ordersTree.getHashesByHash(ordersHash); } /** * Creates an entry for specification data and returns hash * @param {string} serverName broker server name * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {MetatraderSymbolSpecification[]} specifications specifications array * @returns {string} dictionary hash */ recordSpecifications(serverName, accountType, connectionId, instanceIndex, specifications) { return this._specificationsTree.recordItems(serverName, accountType, connectionId, instanceIndex, specifications); } /** * Updates specification data * @param {string} serverName broker server name * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {MetatraderSymbolSpecification[]} specifications specifications array * @param {string[]} removedSymbols removed specification symbols * @param {string} parentHash parent hash * @returns {string} updated dictionary hash */ // eslint-disable-next-line complexity updateSpecifications(serverName, accountType, connectionId, instanceIndex, specifications, removedSymbols, parentHash) { return this._specificationsTree.updateItems(serverName, accountType, connectionId, instanceIndex, specifications, removedSymbols, parentHash); } /** * Creates an entry for positions data and returns hash * @param {string} accountId account id * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {MetatraderPosition[]} positions positions array * @returns {string} dictionary hash */ recordPositions(accountId, accountType, connectionId, instanceIndex, positions) { return this._positionsTree.recordItems(accountId, accountType, connectionId, instanceIndex, positions); } /** * Updates positions data * @param {string} accountId account id * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {MetatraderPosition[]} positions positions * @param {string[]} removedPositions removed position ids * @param {string} parentHash parent hash * @returns {string} updated dictionary hash */ updatePositions(accountId, accountType, connectionId, instanceIndex, positions, removedPositions, parentHash) { return this._positionsTree.updateItems(accountId, accountType, connectionId, instanceIndex, positions, removedPositions, parentHash); } /** * Creates an entry for orders data and returns hash * @param {string} accountId account id * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {Array<MetatraderOrder>} orders orders array * @returns {string} dictionary hash */ recordOrders(accountId, accountType, connectionId, instanceIndex, orders) { return this._ordersTree.recordItems(accountId, accountType, connectionId, instanceIndex, orders); } /** * Updates orders data * @param {string} accountId account id * @param {string} accountType account type * @param {string} connectionId connection id * @param {string} instanceIndex instance index * @param {MetatraderOrder[]} orders orders array * @param {string[]} completedOrders completed order ids * @param {string} parentHash parent hash * @returns {string} updated dictionary hash */ updateOrders(accountId, accountType, connectionId, instanceIndex, orders, completedOrders, parentHash) { return this._ordersTree.updateItems(accountId, accountType, connectionId, instanceIndex, orders, completedOrders, parentHash); } /** * Returns the list of last used specification hashes, with specified server hashes prioritized * @param {string} serverName server name * @returns {string[]} last used specification hashes */ getLastUsedSpecificationHashes(serverName) { return this._specificationsTree.getLastUsedHashes(serverName); } /** * Returns the list of last used position hashes * @param {string} accountId account id * @returns {string[]} last used position hashes */ getLastUsedPositionHashes(accountId) { return this._positionsTree.getLastUsedHashes(accountId); } /** * Returns the list of last used order hashes * @param {string} accountId account id * @returns {string[]} last used order hashes */ getLastUsedOrderHashes(accountId) { return this._ordersTree.getLastUsedHashes(accountId); } /** * Removes all references for a connection * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ removeConnectionReferences(connectionId, instanceIndex) { this.removeSpecificationReference(connectionId, instanceIndex); this.removePositionReference(connectionId, instanceIndex); this.removeOrderReference(connectionId, instanceIndex); } /** * Adds a reference from a terminal state instance index to a specifications hash * @param {string} hash specifications hash * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ addSpecificationReference(hash, connectionId, instanceIndex) { this._specificationsTree.addReference(hash, connectionId, instanceIndex); } /** * Removes a reference from a terminal state instance index to a specifications hash * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ removeSpecificationReference(connectionId, instanceIndex) { this._specificationsTree.removeReference(connectionId, instanceIndex); } /** * Adds a reference from a terminal state instance index to a positions hash * @param {string} hash positions hash * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ addPositionReference(hash, connectionId, instanceIndex) { this._positionsTree.addReference(hash, connectionId, instanceIndex); } /** * Removes a reference from a terminal state instance index to a positions hash * @param {string} accountId account id * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ removePositionReference(connectionId, instanceIndex) { this._positionsTree.removeReference(connectionId, instanceIndex); } /** * Adds a reference from a terminal state instance index to a orders hash * @param {string} hash positions hash * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ addOrderReference(hash, connectionId, instanceIndex) { this._ordersTree.addReference(hash, connectionId, instanceIndex); } /** * Removes a reference from a terminal state instance index to a orders hash * @param {string} connectionId connection id * @param {string} instanceIndex instance index */ removeOrderReference(connectionId, instanceIndex) { this._ordersTree.removeReference(connectionId, instanceIndex); } // eslint-disable-next-line complexity getItemHash(item, type, accountType, region) { const hashFields = this._clientApiClient.getHashingIgnoredFieldLists(region); item = Object.assign({}, item); switch(type){ case "specifications": if (accountType === "cloud-g1") { hashFields.g1.specification.forEach((field)=>delete item[field]); } else if (accountType === "cloud-g2") { hashFields.g2.specification.forEach((field)=>delete item[field]); } return this._getHash(item, accountType, [ "digits" ]); case "positions": if (accountType === "cloud-g1") { hashFields.g1.position.forEach((field)=>delete item[field]); } else if (accountType === "cloud-g2") { hashFields.g2.position.forEach((field)=>delete item[field]); } return this._getHash(item, accountType, [ "magic" ]); case "orders": if (accountType === "cloud-g1") { hashFields.g1.order.forEach((field)=>delete item[field]); } else if (accountType === "cloud-g2") { hashFields.g2.order.forEach((field)=>delete item[field]); } return this._getHash(item, accountType, [ "magic" ]); } } _getHash(obj, accountType, integerKeys) { let jsonItem = ""; if (accountType === "cloud-g1") { const stringify = (objFromJson, key)=>{ if (typeof objFromJson === "number") { if (integerKeys.includes(key)) { return objFromJson; } else { return objFromJson.toFixed(8); } } else if (Array.isArray(objFromJson)) { return `[${objFromJson.map((item)=>stringify(item)).join(",")}]`; } else if (objFromJson === null) { return objFromJson; } else if (typeof objFromJson !== "object" || objFromJson.getTime) { return JSON.stringify(objFromJson); } let props = Object.keys(objFromJson).map((keyItem)=>`"${keyItem}":${stringify(objFromJson[keyItem], keyItem)}`).join(","); return `{${props}}`; }; jsonItem = stringify(obj); } else if (accountType === "cloud-g2") { const stringify = (objFromJson, key)=>{ if (typeof objFromJson === "number") { if (integerKeys.includes(key)) { return objFromJson; } else { return parseFloat(objFromJson.toFixed(8)); } } else if (Array.isArray(objFromJson)) { return `[${objFromJson.map((item)=>stringify(item)).join(",")}]`; } else if (objFromJson === null) { return objFromJson; } else if (typeof objFromJson !== "object" || objFromJson.getTime) { return JSON.stringify(objFromJson); } let props = Object.keys(objFromJson).map((keyItem)=>`"${keyItem}":${stringify(objFromJson[keyItem], keyItem)}`).join(","); return `{${props}}`; }; jsonItem = stringify(obj); } return _cryptojs.default.MD5(jsonItem).toString(); } _stop() { this._specificationsTree.stop(); this._positionsTree.stop(); this._ordersTree.stop(); } /** * Constructs the instance of terminal hash manager class * @param {ClientApiClient} clientApiClient client api client * @param {boolean} [keepHashTrees] if set to true, unused data will not be cleared (for use in debugging) */ constructor(clientApiClient, keepHashTrees = false){ this._clientApiClient = clientApiClient; this._specificationsTree = new _referenceTree.default(this, "symbol", "specifications", true, keepHashTrees); this._positionsTree = new _referenceTree.default(this, "id", "positions", false, keepHashTrees); this._ordersTree = new _referenceTree.default(this, "id", "orders", false, keepHashTrees); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3J5cHRvIGZyb20gJ2NyeXB0by1qcyc7XG5pbXBvcnQgUmVmZXJlbmNlVHJlZSBmcm9tICcuL3JlZmVyZW5jZVRyZWUnO1xuXG4vKipcbiAqIFJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBwb3NpdGlvbnMsIG9yZGVycywgYW5kIHNwZWNpZmljYXRpb25zIGhhc2ggZGF0YVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZXJtaW5hbEhhc2hNYW5hZ2VyIHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGUgaW5zdGFuY2Ugb2YgdGVybWluYWwgaGFzaCBtYW5hZ2VyIGNsYXNzXG4gICAqIEBwYXJhbSB7Q2xpZW50QXBpQ2xpZW50fSBjbGllbnRBcGlDbGllbnQgY2xpZW50IGFwaSBjbGllbnRcbiAgICogQHBhcmFtIHtib29sZWFufSBba2VlcEhhc2hUcmVlc10gaWYgc2V0IHRvIHRydWUsIHVudXNlZCBkYXRhIHdpbGwgbm90IGJlIGNsZWFyZWQgKGZvciB1c2UgaW4gZGVidWdnaW5nKVxuICAgKi9cbiAgY29uc3RydWN0b3IoY2xpZW50QXBpQ2xpZW50LCBrZWVwSGFzaFRyZWVzID0gZmFsc2UpIHtcbiAgICB0aGlzLl9jbGllbnRBcGlDbGllbnQgPSBjbGllbnRBcGlDbGllbnQ7XG4gICAgdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlID0gbmV3IFJlZmVyZW5jZVRyZWUodGhpcywgJ3N5bWJvbCcsICdzcGVjaWZpY2F0aW9ucycsIHRydWUsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAncG9zaXRpb25zJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAnb3JkZXJzJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZnJlc2hlcyBoYXNoaW5nIGlnbm9yZWQgZmllbGQgbGlzdHNcbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlZ2lvbiBhY2NvdW50IHJlZ2lvblxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB0aGUgaGFzaGluZyBmaWVsZCBsaXN0cyBhcmUgdXBkYXRlZC5cbiAgICovXG4gIGFzeW5jIHJlZnJlc2hJZ25vcmVkRmllbGRMaXN0cyhyZWdpb24pIHtcbiAgICBhd2FpdCB0aGlzLl9jbGllbnRBcGlDbGllbnQucmVmcmVzaElnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNwZWNpZmljYXRpb25zSGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IE1ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9ufVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHNwZWNpZmljYXRpb25zSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBoYXNoIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3BlY2lmaWNhdGlvbnNIYXNoIHNwZWNpZmljYXRpb25zIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNIYXNoZXNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEhhc2hlc0J5SGFzaChzcGVjaWZpY2F0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcG9zaXRpb25zSGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyUG9zaXRpb259XG4gICAqL1xuICBnZXRQb3NpdGlvbnNCeUhhc2gocG9zaXRpb25zSGFzaCkge1xuICAgIHJldHVybiB0aGlzLl9wb3NpdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGhhc2ggZGF0YSBieSBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwb3NpdGlvbnNIYXNoIHBvc2l0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IHN0cmluZ30gZGljdGlvbmFyeSBvZiBwb3NpdGlvbiBoYXNoZXNcbiAgICovXG4gIGdldFBvc2l0aW9uc0hhc2hlc0J5SGFzaChwb3NpdGlvbnNIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUuZ2V0SGFzaGVzQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgb3JkZXJzIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3JkZXJzSGFzaCBvcmRlcnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyT3JkZXJ9IHJlbW92ZWQgcG9zaXRpb24gaWRzXG4gICAqL1xuICBnZXRPcmRlcnNCeUhhc2gob3JkZXJzSGFzaCl7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0SXRlbXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBvcmRlcnMgaGFzaCBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9yZGVyc0hhc2ggb3JkZXJzIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfSBkaWN0aW9uYXJ5IG9mIG9yZGVyIGhhc2hlc1xuICAgKi9cbiAgZ2V0T3JkZXJzSGFzaGVzQnlIYXNoKG9yZGVyc0hhc2gpIHtcbiAgICByZXR1cm4gdGhpcy5fb3JkZXJzVHJlZS5nZXRIYXNoZXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBlbnRyeSBmb3Igc3BlY2lmaWNhdGlvbiBkYXRhIGFuZCByZXR1cm5zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcnZlck5hbWUgYnJva2VyIHNlcnZlciBuYW1lIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9uW119IHNwZWNpZmljYXRpb25zIHNwZWNpZmljYXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkU3BlY2lmaWNhdGlvbnMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICBpbnN0YW5jZUluZGV4LCBzcGVjaWZpY2F0aW9ucykge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVjb3JkSXRlbXMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICAgIGluc3RhbmNlSW5kZXgsIHNwZWNpZmljYXRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHNwZWNpZmljYXRpb24gZGF0YVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VydmVyTmFtZSBicm9rZXIgc2VydmVyIG5hbWUgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50VHlwZSBhY2NvdW50IHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqIEBwYXJhbSB7TWV0YXRyYWRlclN5bWJvbFNwZWNpZmljYXRpb25bXX0gc3BlY2lmaWNhdGlvbnMgc3BlY2lmaWNhdGlvbnMgYXJyYXlcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gcmVtb3ZlZFN5bWJvbHMgcmVtb3ZlZCBzcGVjaWZpY2F0aW9uIHN5bWJvbHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gIHVwZGF0ZVNwZWNpZmljYXRpb25zKHNlcnZlck5hbWUsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3NwZWNpZmljYXRpb25zVHJlZS51cGRhdGVJdGVtcyhzZXJ2ZXJOYW1lLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBwb3NpdGlvbnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkUG9zaXRpb25zKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBwb3NpdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgcG9zaXRpb25zIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHJlbW92ZWRQb3NpdGlvbnMgcmVtb3ZlZCBwb3NpdGlvbiBpZHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIHVwZGF0ZVBvc2l0aW9ucyhhY2NvdW50SWQsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBvcmRlcnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZCBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRUeXBlIGFjY291bnQgdHlwZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICogQHBhcmFtIHtBcnJheTxNZXRhdHJhZGVyT3JkZXI+fSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkT3JkZXJzKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgb3JkZXJzKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBvcmRlcnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgb3JkZXJzIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJPcmRlcltdfSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGNvbXBsZXRlZE9yZGVycyBjb21wbGV0ZWQgb3JkZXIgaWRzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRIYXNoIHBhcmVudCBoYXNoXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHVwZGF0ZWQgZGljdGlvbmFyeSBoYXNoXG4gICAqL1xuICB1cGRhdGVPcmRlcnMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgIGluc3RhbmNlSW5kZXgsIG9yZGVycywgY29tcGxldGVkT3JkZXJzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgb3JkZXJzLCBjb21wbGV0ZWRPcmRlcnMsIHBhcmVudEhhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxpc3Qgb2YgbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzLCB3aXRoIHNwZWNpZmllZCBzZXJ2ZXIgaGFzaGVzIHByaW9yaXRpemVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZXJ2ZXJOYW1lIHNlcnZlciBuYW1lXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzXG4gICAqL1xuICBnZXRMYXN0VXNlZFNwZWNpZmljYXRpb25IYXNoZXMoc2VydmVyTmFtZSkge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoc2VydmVyTmFtZSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBsaXN0IG9mIGxhc3QgdXNlZCBwb3NpdGlvbiBoYXNoZXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHBvc2l0aW9uIGhhc2hlc1xuICAgKi9cbiAgZ2V0TGFzdFVzZWRQb3NpdGlvbkhhc2hlcyhhY2NvdW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5fcG9zaXRpb25zVHJlZS5nZXRMYXN0VXNlZEhhc2hlcyhhY2NvdW50SWQpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGlzdCBvZiBsYXN0IHVzZWQgb3JkZXIgaGFzaGVzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcmV0dXJucyB7c3RyaW5nW119IGxhc3QgdXNlZCBvcmRlciBoYXNoZXNcbiAgICovXG4gIGdldExhc3RVc2VkT3JkZXJIYXNoZXMoYWNjb3VudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoYWNjb3VudElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGFsbCByZWZlcmVuY2VzIGZvciBhIGNvbm5lY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVDb25uZWN0aW9uUmVmZXJlbmNlcyhjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLnJlbW92ZVNwZWNpZmljYXRpb25SZWZlcmVuY2UoY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KTtcbiAgICB0aGlzLnJlbW92ZVBvc2l0aW9uUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gICAgdGhpcy5yZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgc3BlY2lmaWNhdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgYWRkU3BlY2lmaWNhdGlvblJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgcmVtb3ZlU3BlY2lmaWNhdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVtb3ZlUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICovXG4gIGFkZFBvc2l0aW9uUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCkge1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVQb3NpdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9wb3NpdGlvbnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggcG9zaXRpb25zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICBhZGRPcmRlclJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLmFkZFJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgZ2V0SXRlbUhhc2goaXRlbSwgdHlwZSwgYWNjb3VudFR5cGUsIHJlZ2lvbikge1xuICAgIGNvbnN0IGhhc2hGaWVsZHMgPSB0aGlzLl9jbGllbnRBcGlDbGllbnQuZ2V0SGFzaGluZ0lnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gICAgaXRlbSA9IE9iamVjdC5hc3NpZ24oe30sIGl0ZW0pO1xuICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgY2FzZSAnc3BlY2lmaWNhdGlvbnMnOlxuICAgICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgICAgaGFzaEZpZWxkcy5nMS5zcGVjaWZpY2F0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnNwZWNpZmljYXRpb24uZm9yRWFjaChmaWVsZCA9PiBkZWxldGUgaXRlbVtmaWVsZF0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuX2dldEhhc2goaXRlbSwgYWNjb3VudFR5cGUsIFsnZGlnaXRzJ10pO1xuICAgIGNhc2UgJ3Bvc2l0aW9ucyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIGNhc2UgJ29yZGVycyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIH1cbiAgfVxuXG4gIF9nZXRIYXNoKG9iaiwgYWNjb3VudFR5cGUsIGludGVnZXJLZXlzKSB7XG4gICAgbGV0IGpzb25JdGVtID0gJyc7XG4gICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgIGNvbnN0IHN0cmluZ2lmeSA9IChvYmpGcm9tSnNvbiwga2V5KSA9PiB7XG4gICAgICAgIGlmKHR5cGVvZiBvYmpGcm9tSnNvbiA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICBpZihpbnRlZ2VyS2V5cy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbi50b0ZpeGVkKDgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmKEFycmF5LmlzQXJyYXkob2JqRnJvbUpzb24pKSB7XG4gICAgICAgICAgcmV0dXJuIGBbJHtvYmpGcm9tSnNvbi5tYXAoaXRlbSA9PiBzdHJpbmdpZnkoaXRlbSkpLmpvaW4oJywnKX1dYDsgXG4gICAgICAgIH0gZWxzZSBpZiAob2JqRnJvbUpzb24gPT09IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG9iakZyb21Kc29uICE9PSAnb2JqZWN0JyB8fCBvYmpGcm9tSnNvbi5nZXRUaW1lKXtcbiAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqRnJvbUpzb24pO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGxldCBwcm9wcyA9IE9iamVjdFxuICAgICAgICAgIC5rZXlzKG9iakZyb21Kc29uKVxuICAgICAgICAgIC5tYXAoa2V5SXRlbSA9PiBgXCIke2tleUl0ZW19XCI6JHtzdHJpbmdpZnkob2JqRnJvbUpzb25ba2V5SXRlbV0sIGtleUl0ZW0pfWApXG4gICAgICAgICAgLmpvaW4oJywnKTtcbiAgICAgICAgcmV0dXJuIGB7JHtwcm9wc319YDtcbiAgICAgIH07XG4gICAgXG4gICAgICBqc29uSXRlbSA9IHN0cmluZ2lmeShvYmopO1xuICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgY29uc3Qgc3RyaW5naWZ5ID0gKG9iakZyb21Kc29uLCBrZXkpID0+IHtcbiAgICAgICAgaWYodHlwZW9mIG9iakZyb21Kc29uID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIGlmKGludGVnZXJLZXlzLmluY2x1ZGVzKGtleSkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQob2JqRnJvbUpzb24udG9GaXhlZCg4KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYoQXJyYXkuaXNBcnJheShvYmpGcm9tSnNvbikpIHtcbiAgICAgICAgICByZXR1cm4gYFske29iakZyb21Kc29uLm1hcChpdGVtID0+IHN0cmluZ2lmeShpdGVtKSkuam9pbignLCcpfV1gOyBcbiAgICAgICAgfSBlbHNlIGlmIChvYmpGcm9tSnNvbiA9PT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqRnJvbUpzb24gIT09ICdvYmplY3QnIHx8IG9iakZyb21Kc29uLmdldFRpbWUpe1xuICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShvYmpGcm9tSnNvbik7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgbGV0IHByb3BzID0gT2JqZWN0XG4gICAgICAgICAgLmtleXMob2JqRnJvbUpzb24pXG4gICAgICAgICAgLm1hcChrZXlJdGVtID0+IGBcIiR7a2V5SXRlbX1cIjoke3N0cmluZ2lmeShvYmpGcm9tSnNvbltrZXlJdGVtXSwga2V5SXRlbSl9YClcbiAgICAgICAgICAuam9pbignLCcpO1xuICAgICAgICByZXR1cm4gYHske3Byb3BzfX1gO1xuICAgICAgfTtcblxuICAgICAganNvbkl0ZW0gPSBzdHJpbmdpZnkob2JqKTtcbiAgICB9XG4gICAgcmV0dXJuIGNyeXB0by5NRDUoanNvbkl0ZW0pLnRvU3RyaW5nKCk7XG4gIH1cblxuICBfc3RvcCgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUuc3RvcCgpO1xuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJUZXJtaW5hbEhhc2hNYW5hZ2VyIiwicmVmcmVzaElnbm9yZWRGaWVsZExpc3RzIiwicmVnaW9uIiwiX2NsaWVudEFwaUNsaWVudCIsImdldFNwZWNpZmljYXRpb25zQnlIYXNoIiwic3BlY2lmaWNhdGlvbnNIYXNoIiwiX3NwZWNpZmljYXRpb25zVHJlZSIsImdldEl0ZW1zQnlIYXNoIiwiZ2V0U3BlY2lmaWNhdGlvbnNIYXNoZXNCeUhhc2giLCJnZXRIYXNoZXNCeUhhc2giLCJnZXRQb3NpdGlvbnNCeUhhc2giLCJwb3NpdGlvbnNIYXNoIiwiX3Bvc2l0aW9uc1RyZWUiLCJnZXRQb3NpdGlvbnNIYXNoZXNCeUhhc2giLCJnZXRPcmRlcnNCeUhhc2giLCJvcmRlcnNIYXNoIiwiX29yZGVyc1RyZWUiLCJnZXRPcmRlcnNIYXNoZXNCeUhhc2giLCJyZWNvcmRTcGVjaWZpY2F0aW9ucyIsInNlcnZlck5hbWUiLCJhY2NvdW50VHlwZSIsImNvbm5lY3Rpb25JZCIsImluc3RhbmNlSW5kZXgiLCJzcGVjaWZpY2F0aW9ucyIsInJlY29yZEl0ZW1zIiwidXBkYXRlU3BlY2lmaWNhdGlvbnMiLCJyZW1vdmVkU3ltYm9scyIsInBhcmVudEhhc2giLCJ1cGRhdGVJdGVtcyIsInJlY29yZFBvc2l0aW9ucyIsImFjY291bnRJZCIsInBvc2l0aW9ucyIsInVwZGF0ZVBvc2l0aW9ucyIsInJlbW92ZWRQb3NpdGlvbnMiLCJyZWNvcmRPcmRlcnMiLCJvcmRlcnMiLCJ1cGRhdGVPcmRlcnMiLCJjb21wbGV0ZWRPcmRlcnMiLCJnZXRMYXN0VXNlZFNwZWNpZmljYXRpb25IYXNoZXMiLCJnZXRMYXN0VXNlZEhhc2hlcyIsImdldExhc3RVc2VkUG9zaXRpb25IYXNoZXMiLCJnZXRMYXN0VXNlZE9yZGVySGFzaGVzIiwicmVtb3ZlQ29ubmVjdGlvblJlZmVyZW5jZXMiLCJyZW1vdmVTcGVjaWZpY2F0aW9uUmVmZXJlbmNlIiwicmVtb3ZlUG9zaXRpb25SZWZlcmVuY2UiLCJyZW1vdmVPcmRlclJlZmVyZW5jZSIsImFkZFNwZWNpZmljYXRpb25SZWZlcmVuY2UiLCJoYXNoIiwiYWRkUmVmZXJlbmNlIiwicmVtb3ZlUmVmZXJlbmNlIiwiYWRkUG9zaXRpb25SZWZlcmVuY2UiLCJhZGRPcmRlclJlZmVyZW5jZSIsImdldEl0ZW1IYXNoIiwiaXRlbSIsInR5cGUiLCJoYXNoRmllbGRzIiwiZ2V0SGFzaGluZ0lnbm9yZWRGaWVsZExpc3RzIiwiT2JqZWN0IiwiYXNzaWduIiwiZzEiLCJzcGVjaWZpY2F0aW9uIiwiZm9yRWFjaCIsImZpZWxkIiwiZzIiLCJfZ2V0SGFzaCIsInBvc2l0aW9uIiwib3JkZXIiLCJvYmoiLCJpbnRlZ2VyS2V5cyIsImpzb25JdGVtIiwic3RyaW5naWZ5Iiwib2JqRnJvbUpzb24iLCJrZXkiLCJpbmNsdWRlcyIsInRvRml4ZWQiLCJBcnJheSIsImlzQXJyYXkiLCJtYXAiLCJqb2luIiwiZ2V0VGltZSIsIkpTT04iLCJwcm9wcyIsImtleXMiLCJrZXlJdGVtIiwicGFyc2VGbG9hdCIsImNyeXB0byIsIk1ENSIsInRvU3RyaW5nIiwiX3N0b3AiLCJzdG9wIiwiY29uc3RydWN0b3IiLCJjbGllbnRBcGlDbGllbnQiLCJrZWVwSGFzaFRyZWVzIiwiUmVmZXJlbmNlVHJlZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztlQU1xQkE7OztpRUFORjtzRUFDTzs7Ozs7O0FBS1gsSUFBQSxBQUFNQSxzQkFBTixNQUFNQTtJQWNuQjs7OztHQUlDLEdBQ0QsTUFBTUMseUJBQXlCQyxNQUFNLEVBQUU7UUFDckMsTUFBTSxJQUFJLENBQUNDLGdCQUFnQixDQUFDRix3QkFBd0IsQ0FBQ0M7SUFDdkQ7SUFFQTs7OztHQUlDLEdBQ0RFLHdCQUF3QkMsa0JBQWtCLEVBQUM7UUFDekMsT0FBTyxJQUFJLENBQUNDLG1CQUFtQixD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