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)

331 lines (330 loc) 43 kB
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _async_to_generator(fn) { return function() { var self = this, args = arguments; return new Promise(function(resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } import crypto from 'crypto-js'; import ReferenceTree from './referenceTree'; 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. */ refreshIgnoredFieldLists(region) { var _this = this; return _async_to_generator(function*() { yield _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 crypto.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(this, 'symbol', 'specifications', true, keepHashTrees); this._positionsTree = new ReferenceTree(this, 'id', 'positions', false, keepHashTrees); this._ordersTree = new ReferenceTree(this, 'id', 'orders', false, keepHashTrees); } }; /** * Responsible for handling positions, orders, and specifications hash data */ export { TerminalHashManager as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3J5cHRvIGZyb20gJ2NyeXB0by1qcyc7XG5pbXBvcnQgUmVmZXJlbmNlVHJlZSBmcm9tICcuL3JlZmVyZW5jZVRyZWUnO1xuXG4vKipcbiAqIFJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBwb3NpdGlvbnMsIG9yZGVycywgYW5kIHNwZWNpZmljYXRpb25zIGhhc2ggZGF0YVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZXJtaW5hbEhhc2hNYW5hZ2VyIHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGUgaW5zdGFuY2Ugb2YgdGVybWluYWwgaGFzaCBtYW5hZ2VyIGNsYXNzXG4gICAqIEBwYXJhbSB7Q2xpZW50QXBpQ2xpZW50fSBjbGllbnRBcGlDbGllbnQgY2xpZW50IGFwaSBjbGllbnRcbiAgICogQHBhcmFtIHtib29sZWFufSBba2VlcEhhc2hUcmVlc10gaWYgc2V0IHRvIHRydWUsIHVudXNlZCBkYXRhIHdpbGwgbm90IGJlIGNsZWFyZWQgKGZvciB1c2UgaW4gZGVidWdnaW5nKVxuICAgKi9cbiAgY29uc3RydWN0b3IoY2xpZW50QXBpQ2xpZW50LCBrZWVwSGFzaFRyZWVzID0gZmFsc2UpIHtcbiAgICB0aGlzLl9jbGllbnRBcGlDbGllbnQgPSBjbGllbnRBcGlDbGllbnQ7XG4gICAgdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlID0gbmV3IFJlZmVyZW5jZVRyZWUodGhpcywgJ3N5bWJvbCcsICdzcGVjaWZpY2F0aW9ucycsIHRydWUsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAncG9zaXRpb25zJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUgPSBuZXcgUmVmZXJlbmNlVHJlZSh0aGlzLCAnaWQnLCAnb3JkZXJzJywgZmFsc2UsIGtlZXBIYXNoVHJlZXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlZnJlc2hlcyBoYXNoaW5nIGlnbm9yZWQgZmllbGQgbGlzdHNcbiAgICogQHBhcmFtIHtTdHJpbmd9IHJlZ2lvbiBhY2NvdW50IHJlZ2lvblxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB0aGUgaGFzaGluZyBmaWVsZCBsaXN0cyBhcmUgdXBkYXRlZC5cbiAgICovXG4gIGFzeW5jIHJlZnJlc2hJZ25vcmVkRmllbGRMaXN0cyhyZWdpb24pIHtcbiAgICBhd2FpdCB0aGlzLl9jbGllbnRBcGlDbGllbnQucmVmcmVzaElnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNwZWNpZmljYXRpb25zSGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IE1ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9ufVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHNwZWNpZmljYXRpb25zSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzcGVjaWZpY2F0aW9ucyBoYXNoIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3BlY2lmaWNhdGlvbnNIYXNoIHNwZWNpZmljYXRpb25zIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfVxuICAgKi9cbiAgZ2V0U3BlY2lmaWNhdGlvbnNIYXNoZXNCeUhhc2goc3BlY2lmaWNhdGlvbnNIYXNoKXtcbiAgICByZXR1cm4gdGhpcy5fc3BlY2lmaWNhdGlvbnNUcmVlLmdldEhhc2hlc0J5SGFzaChzcGVjaWZpY2F0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gcG9zaXRpb25zSGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyUG9zaXRpb259XG4gICAqL1xuICBnZXRQb3NpdGlvbnNCeUhhc2gocG9zaXRpb25zSGFzaCkge1xuICAgIHJldHVybiB0aGlzLl9wb3NpdGlvbnNUcmVlLmdldEl0ZW1zQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcG9zaXRpb25zIGhhc2ggZGF0YSBieSBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwb3NpdGlvbnNIYXNoIHBvc2l0aW9ucyBoYXNoXG4gICAqIEByZXR1cm5zIHtbaWQ6IHN0cmluZ106IHN0cmluZ30gZGljdGlvbmFyeSBvZiBwb3NpdGlvbiBoYXNoZXNcbiAgICovXG4gIGdldFBvc2l0aW9uc0hhc2hlc0J5SGFzaChwb3NpdGlvbnNIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUuZ2V0SGFzaGVzQnlIYXNoKHBvc2l0aW9uc0hhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgb3JkZXJzIGRhdGEgYnkgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gb3JkZXJzSGFzaCBvcmRlcnMgaGFzaFxuICAgKiBAcmV0dXJucyB7W2lkOiBzdHJpbmddOiBNZXRhdHJhZGVyT3JkZXJ9IHJlbW92ZWQgcG9zaXRpb24gaWRzXG4gICAqL1xuICBnZXRPcmRlcnNCeUhhc2gob3JkZXJzSGFzaCl7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0SXRlbXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBvcmRlcnMgaGFzaCBkYXRhIGJ5IGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IG9yZGVyc0hhc2ggb3JkZXJzIGhhc2hcbiAgICogQHJldHVybnMge1tpZDogc3RyaW5nXTogc3RyaW5nfSBkaWN0aW9uYXJ5IG9mIG9yZGVyIGhhc2hlc1xuICAgKi9cbiAgZ2V0T3JkZXJzSGFzaGVzQnlIYXNoKG9yZGVyc0hhc2gpIHtcbiAgICByZXR1cm4gdGhpcy5fb3JkZXJzVHJlZS5nZXRIYXNoZXNCeUhhc2gob3JkZXJzSGFzaCk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBlbnRyeSBmb3Igc3BlY2lmaWNhdGlvbiBkYXRhIGFuZCByZXR1cm5zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcnZlck5hbWUgYnJva2VyIHNlcnZlciBuYW1lIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJTeW1ib2xTcGVjaWZpY2F0aW9uW119IHNwZWNpZmljYXRpb25zIHNwZWNpZmljYXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkU3BlY2lmaWNhdGlvbnMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICBpbnN0YW5jZUluZGV4LCBzcGVjaWZpY2F0aW9ucykge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVjb3JkSXRlbXMoc2VydmVyTmFtZSwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCxcbiAgICAgIGluc3RhbmNlSW5kZXgsIHNwZWNpZmljYXRpb25zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHNwZWNpZmljYXRpb24gZGF0YVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc2VydmVyTmFtZSBicm9rZXIgc2VydmVyIG5hbWUgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50VHlwZSBhY2NvdW50IHR5cGVcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqIEBwYXJhbSB7TWV0YXRyYWRlclN5bWJvbFNwZWNpZmljYXRpb25bXX0gc3BlY2lmaWNhdGlvbnMgc3BlY2lmaWNhdGlvbnMgYXJyYXlcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gcmVtb3ZlZFN5bWJvbHMgcmVtb3ZlZCBzcGVjaWZpY2F0aW9uIHN5bWJvbHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gIHVwZGF0ZVNwZWNpZmljYXRpb25zKHNlcnZlck5hbWUsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3NwZWNpZmljYXRpb25zVHJlZS51cGRhdGVJdGVtcyhzZXJ2ZXJOYW1lLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgc3BlY2lmaWNhdGlvbnMsIHJlbW92ZWRTeW1ib2xzLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBwb3NpdGlvbnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkUG9zaXRpb25zKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBwb3NpdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgcG9zaXRpb25zIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJQb3NpdGlvbltdfSBwb3NpdGlvbnMgcG9zaXRpb25zXG4gICAqIEBwYXJhbSB7c3RyaW5nW119IHJlbW92ZWRQb3NpdGlvbnMgcmVtb3ZlZCBwb3NpdGlvbiBpZHNcbiAgICogQHBhcmFtIHtzdHJpbmd9IHBhcmVudEhhc2ggcGFyZW50IGhhc2hcbiAgICogQHJldHVybnMge3N0cmluZ30gdXBkYXRlZCBkaWN0aW9uYXJ5IGhhc2hcbiAgICovXG4gIHVwZGF0ZVBvc2l0aW9ucyhhY2NvdW50SWQsIGFjY291bnRUeXBlLCBjb25uZWN0aW9uSWQsXG4gICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgcG9zaXRpb25zLCByZW1vdmVkUG9zaXRpb25zLCBwYXJlbnRIYXNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVudHJ5IGZvciBvcmRlcnMgZGF0YSBhbmQgcmV0dXJucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZCBcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRUeXBlIGFjY291bnQgdHlwZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICogQHBhcmFtIHtBcnJheTxNZXRhdHJhZGVyT3JkZXI+fSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IGRpY3Rpb25hcnkgaGFzaFxuICAgKi9cbiAgcmVjb3JkT3JkZXJzKGFjY291bnRJZCwgYWNjb3VudFR5cGUsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCwgb3JkZXJzKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUucmVjb3JkSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4LCBvcmRlcnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgb3JkZXJzIGRhdGFcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudFR5cGUgYWNjb3VudCB0eXBlXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJPcmRlcltdfSBvcmRlcnMgb3JkZXJzIGFycmF5XG4gICAqIEBwYXJhbSB7c3RyaW5nW119IGNvbXBsZXRlZE9yZGVycyBjb21wbGV0ZWQgb3JkZXIgaWRzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwYXJlbnRIYXNoIHBhcmVudCBoYXNoXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9IHVwZGF0ZWQgZGljdGlvbmFyeSBoYXNoXG4gICAqL1xuICB1cGRhdGVPcmRlcnMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgIGluc3RhbmNlSW5kZXgsIG9yZGVycywgY29tcGxldGVkT3JkZXJzLCBwYXJlbnRIYXNoKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUudXBkYXRlSXRlbXMoYWNjb3VudElkLCBhY2NvdW50VHlwZSwgY29ubmVjdGlvbklkLFxuICAgICAgaW5zdGFuY2VJbmRleCwgb3JkZXJzLCBjb21wbGV0ZWRPcmRlcnMsIHBhcmVudEhhc2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGxpc3Qgb2YgbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzLCB3aXRoIHNwZWNpZmllZCBzZXJ2ZXIgaGFzaGVzIHByaW9yaXRpemVkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzZXJ2ZXJOYW1lIHNlcnZlciBuYW1lXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHNwZWNpZmljYXRpb24gaGFzaGVzXG4gICAqL1xuICBnZXRMYXN0VXNlZFNwZWNpZmljYXRpb25IYXNoZXMoc2VydmVyTmFtZSkge1xuICAgIHJldHVybiB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoc2VydmVyTmFtZSk7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBsaXN0IG9mIGxhc3QgdXNlZCBwb3NpdGlvbiBoYXNoZXNcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFjY291bnRJZCBhY2NvdW50IGlkXG4gICAqIEByZXR1cm5zIHtzdHJpbmdbXX0gbGFzdCB1c2VkIHBvc2l0aW9uIGhhc2hlc1xuICAgKi9cbiAgZ2V0TGFzdFVzZWRQb3NpdGlvbkhhc2hlcyhhY2NvdW50SWQpIHtcbiAgICByZXR1cm4gdGhpcy5fcG9zaXRpb25zVHJlZS5nZXRMYXN0VXNlZEhhc2hlcyhhY2NvdW50SWQpO1xuICB9XG4gIFxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbGlzdCBvZiBsYXN0IHVzZWQgb3JkZXIgaGFzaGVzXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcmV0dXJucyB7c3RyaW5nW119IGxhc3QgdXNlZCBvcmRlciBoYXNoZXNcbiAgICovXG4gIGdldExhc3RVc2VkT3JkZXJIYXNoZXMoYWNjb3VudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuX29yZGVyc1RyZWUuZ2V0TGFzdFVzZWRIYXNoZXMoYWNjb3VudElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGFsbCByZWZlcmVuY2VzIGZvciBhIGNvbm5lY3Rpb25cbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVDb25uZWN0aW9uUmVmZXJlbmNlcyhjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLnJlbW92ZVNwZWNpZmljYXRpb25SZWZlcmVuY2UoY29ubmVjdGlvbklkLCBpbnN0YW5jZUluZGV4KTtcbiAgICB0aGlzLnJlbW92ZVBvc2l0aW9uUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gICAgdGhpcy5yZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgc3BlY2lmaWNhdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgYWRkU3BlY2lmaWNhdGlvblJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBzcGVjaWZpY2F0aW9ucyBoYXNoXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBjb25uZWN0aW9uSWQgY29ubmVjdGlvbiBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5zdGFuY2VJbmRleCBpbnN0YW5jZSBpbmRleFxuICAgKi9cbiAgcmVtb3ZlU3BlY2lmaWNhdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUucmVtb3ZlUmVmZXJlbmNlKGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gaGFzaCBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gY29ubmVjdGlvbklkIGNvbm5lY3Rpb24gaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSW5kZXggaW5zdGFuY2UgaW5kZXhcbiAgICovXG4gIGFkZFBvc2l0aW9uUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCkge1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuYWRkUmVmZXJlbmNlKGhhc2gsIGNvbm5lY3Rpb25JZCwgaW5zdGFuY2VJbmRleCk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHJlZmVyZW5jZSBmcm9tIGEgdGVybWluYWwgc3RhdGUgaW5zdGFuY2UgaW5kZXggdG8gYSBwb3NpdGlvbnMgaGFzaFxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVQb3NpdGlvblJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9wb3NpdGlvbnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGhhc2ggcG9zaXRpb25zIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICBhZGRPcmRlclJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLmFkZFJlZmVyZW5jZShoYXNoLCBjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYSByZWZlcmVuY2UgZnJvbSBhIHRlcm1pbmFsIHN0YXRlIGluc3RhbmNlIGluZGV4IHRvIGEgb3JkZXJzIGhhc2hcbiAgICogQHBhcmFtIHtzdHJpbmd9IGNvbm5lY3Rpb25JZCBjb25uZWN0aW9uIGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUluZGV4IGluc3RhbmNlIGluZGV4XG4gICAqL1xuICByZW1vdmVPcmRlclJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpIHtcbiAgICB0aGlzLl9vcmRlcnNUcmVlLnJlbW92ZVJlZmVyZW5jZShjb25uZWN0aW9uSWQsIGluc3RhbmNlSW5kZXgpO1xuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbiAgZ2V0SXRlbUhhc2goaXRlbSwgdHlwZSwgYWNjb3VudFR5cGUsIHJlZ2lvbikge1xuICAgIGNvbnN0IGhhc2hGaWVsZHMgPSB0aGlzLl9jbGllbnRBcGlDbGllbnQuZ2V0SGFzaGluZ0lnbm9yZWRGaWVsZExpc3RzKHJlZ2lvbik7XG4gICAgaXRlbSA9IE9iamVjdC5hc3NpZ24oe30sIGl0ZW0pO1xuICAgIHN3aXRjaCh0eXBlKSB7XG4gICAgY2FzZSAnc3BlY2lmaWNhdGlvbnMnOlxuICAgICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgICAgaGFzaEZpZWxkcy5nMS5zcGVjaWZpY2F0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnNwZWNpZmljYXRpb24uZm9yRWFjaChmaWVsZCA9PiBkZWxldGUgaXRlbVtmaWVsZF0pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuX2dldEhhc2goaXRlbSwgYWNjb3VudFR5cGUsIFsnZGlnaXRzJ10pO1xuICAgIGNhc2UgJ3Bvc2l0aW9ucyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLnBvc2l0aW9uLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIGNhc2UgJ29yZGVycyc6XG4gICAgICBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcxJykge1xuICAgICAgICBoYXNoRmllbGRzLmcxLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgICBoYXNoRmllbGRzLmcyLm9yZGVyLmZvckVhY2goZmllbGQgPT4gZGVsZXRlIGl0ZW1bZmllbGRdKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLl9nZXRIYXNoKGl0ZW0sIGFjY291bnRUeXBlLCBbJ21hZ2ljJ10pO1xuICAgIH1cbiAgfVxuXG4gIF9nZXRIYXNoKG9iaiwgYWNjb3VudFR5cGUsIGludGVnZXJLZXlzKSB7XG4gICAgbGV0IGpzb25JdGVtID0gJyc7XG4gICAgaWYoYWNjb3VudFR5cGUgPT09ICdjbG91ZC1nMScpIHtcbiAgICAgIGNvbnN0IHN0cmluZ2lmeSA9IChvYmpGcm9tSnNvbiwga2V5KSA9PiB7XG4gICAgICAgIGlmKHR5cGVvZiBvYmpGcm9tSnNvbiA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICBpZihpbnRlZ2VyS2V5cy5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbi50b0ZpeGVkKDgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmKEFycmF5LmlzQXJyYXkob2JqRnJvbUpzb24pKSB7XG4gICAgICAgICAgcmV0dXJuIGBbJHtvYmpGcm9tSnNvbi5tYXAoaXRlbSA9PiBzdHJpbmdpZnkoaXRlbSkpLmpvaW4oJywnKX1dYDsgXG4gICAgICAgIH0gZWxzZSBpZiAob2JqRnJvbUpzb24gPT09IG51bGwpIHtcbiAgICAgICAgICByZXR1cm4gb2JqRnJvbUpzb247XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIG9iakZyb21Kc29uICE9PSAnb2JqZWN0JyB8fCBvYmpGcm9tSnNvbi5nZXRUaW1lKXtcbiAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob2JqRnJvbUpzb24pO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGxldCBwcm9wcyA9IE9iamVjdFxuICAgICAgICAgIC5rZXlzKG9iakZyb21Kc29uKVxuICAgICAgICAgIC5tYXAoa2V5SXRlbSA9PiBgXCIke2tleUl0ZW19XCI6JHtzdHJpbmdpZnkob2JqRnJvbUpzb25ba2V5SXRlbV0sIGtleUl0ZW0pfWApXG4gICAgICAgICAgLmpvaW4oJywnKTtcbiAgICAgICAgcmV0dXJuIGB7JHtwcm9wc319YDtcbiAgICAgIH07XG4gICAgXG4gICAgICBqc29uSXRlbSA9IHN0cmluZ2lmeShvYmopO1xuICAgIH0gZWxzZSBpZihhY2NvdW50VHlwZSA9PT0gJ2Nsb3VkLWcyJykge1xuICAgICAgY29uc3Qgc3RyaW5naWZ5ID0gKG9iakZyb21Kc29uLCBrZXkpID0+IHtcbiAgICAgICAgaWYodHlwZW9mIG9iakZyb21Kc29uID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIGlmKGludGVnZXJLZXlzLmluY2x1ZGVzKGtleSkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIHBhcnNlRmxvYXQob2JqRnJvbUpzb24udG9GaXhlZCg4KSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYoQXJyYXkuaXNBcnJheShvYmpGcm9tSnNvbikpIHtcbiAgICAgICAgICByZXR1cm4gYFske29iakZyb21Kc29uLm1hcChpdGVtID0+IHN0cmluZ2lmeShpdGVtKSkuam9pbignLCcpfV1gOyBcbiAgICAgICAgfSBlbHNlIGlmIChvYmpGcm9tSnNvbiA9PT0gbnVsbCkge1xuICAgICAgICAgIHJldHVybiBvYmpGcm9tSnNvbjtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqRnJvbUpzb24gIT09ICdvYmplY3QnIHx8IG9iakZyb21Kc29uLmdldFRpbWUpe1xuICAgICAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShvYmpGcm9tSnNvbik7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgbGV0IHByb3BzID0gT2JqZWN0XG4gICAgICAgICAgLmtleXMob2JqRnJvbUpzb24pXG4gICAgICAgICAgLm1hcChrZXlJdGVtID0+IGBcIiR7a2V5SXRlbX1cIjoke3N0cmluZ2lmeShvYmpGcm9tSnNvbltrZXlJdGVtXSwga2V5SXRlbSl9YClcbiAgICAgICAgICAuam9pbignLCcpO1xuICAgICAgICByZXR1cm4gYHske3Byb3BzfX1gO1xuICAgICAgfTtcblxuICAgICAganNvbkl0ZW0gPSBzdHJpbmdpZnkob2JqKTtcbiAgICB9XG4gICAgcmV0dXJuIGNyeXB0by5NRDUoanNvbkl0ZW0pLnRvU3RyaW5nKCk7XG4gIH1cblxuICBfc3RvcCgpIHtcbiAgICB0aGlzLl9zcGVjaWZpY2F0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX3Bvc2l0aW9uc1RyZWUuc3RvcCgpO1xuICAgIHRoaXMuX29yZGVyc1RyZWUuc3RvcCgpO1xuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJjcnlwdG8iLCJSZWZlcmVuY2VUcmVlIiwiVGVybWluYWxIYXNoTWFuYWdlciIsInJlZnJlc2hJZ25vcmVkRmllbGRMaXN0cyIsInJlZ2lvbiIsIl9jbGllbnRBcGlDbGllbnQiLCJnZXRTcGVjaWZpY2F0aW9uc0J5SGFzaCIsInNwZWNpZmljYXRpb25zSGFzaCIsIl9zcGVjaWZpY2F0aW9uc1RyZWUiLCJnZXRJdGVtc0J5SGFzaCIsImdldFNwZWNpZmljYXRpb25zSGFzaGVzQnlIYXNoIiwiZ2V0SGFzaGVzQnlIYXNoIiwiZ2V0UG9zaXRpb25zQnlIYXNoIiwicG9zaXRpb25zSGFzaCIsIl9wb3NpdGlvbnNUcmVlIiwiZ2V0UG9zaXRpb25zSGFzaGVzQnlIYXNoIiwiZ2V0T3JkZXJzQnlIYXNoIiwib3JkZXJzSGFzaCIsIl9vcmRlcnNUcmVlIiwiZ2V0T3JkZXJzSGFzaGVzQnlIYXNoIiwicmVjb3JkU3BlY2lmaWNhdGlvbnMiLCJzZXJ2ZXJOYW1lIiwiYWNjb3VudFR5cGUiLCJjb25uZWN0aW9uSWQiLCJpbnN0YW5jZUluZGV4Iiwic3BlY2lmaWNhdGlvbnMiLCJyZWNvcmRJdGVtcyIsInVwZGF0ZVNwZWNpZmljYXRpb25zIiwicmVtb3ZlZFN5bWJvbHMiLCJwYXJlbnRIYXNoIiwidXBkYXRlSXRlbXMiLCJyZWNvcmRQb3NpdGlvbnMiLCJhY2NvdW50SWQiLCJwb3NpdGlvbnMiLCJ1cGRhdGVQb3NpdGlvbnMiLCJyZW1vdmVkUG9zaXRpb25zIiwicmVjb3JkT3JkZXJzIiwib3JkZXJzIiwidXBkYXRlT3JkZXJzIiwiY29tcGxldGVkT3JkZXJzIiwiZ2V0TGFzdFVzZWRTcGVjaWZpY2F0aW9uSGFzaGVzIiwiZ2V0TGFzdFVzZWRIYXNoZXMiLCJnZXRMYXN0VXNlZFBvc2l0aW9uSGFzaGVzIiwiZ2V0TGFzdFVzZWRPcmRlckhhc2hlcyIsInJlbW92ZUNvbm5lY3Rpb25SZWZlcmVuY2VzIiwicmVtb3ZlU3BlY2lmaWNhdGlvblJlZmVyZW5jZSIsInJlbW92ZVBvc2l0aW9uUmVmZXJlbmNlIiwicmVtb3ZlT3JkZXJSZWZlcmVuY2UiLCJhZGRTcGVjaWZpY2F0aW9uUmVmZXJlbmNlIiwiaGFzaCIsImFkZFJlZmVyZW5jZSIsInJlbW92ZVJlZmVyZW5jZSIsImFkZFBvc2l0aW9uUmVmZXJlbmNlIiwiYWRkT3JkZXJSZWZlcmVuY2UiLCJnZXRJdGVtSGFzaCIsIml0ZW0iLCJ0eXBlIiwiaGFzaEZpZWxkcyIsImdldEhhc2hpbmdJZ25vcmVkRmllbGRMaXN0cyIsIk9iamVjdCIsImFzc2lnbiIsImcxIiwic3BlY2lmaWNhdGlvbiIsImZvckVhY2giLCJmaWVsZCIsImcyIiwiX2dldEhhc2giLCJwb3NpdGlvbiIsIm9yZGVyIiwib2JqIiwiaW50ZWdlcktleXMiLCJqc29uSXRlbSIsInN0cmluZ2lmeSIsIm9iakZyb21Kc29uIiwia2V5IiwiaW5jbHVkZXMiLCJ0b0ZpeGVkIiwiQXJyYXkiLCJpc0FycmF5IiwibWFwIiwiam9pbiIsImdldFRpbWUiLCJKU09OIiwicHJvcHMiLCJrZXlzIiwia2V5SXRlbSIsInBhcnNlRmxvYXQiLCJNRDUiLCJ0b1N0cmluZyIsIl9zdG9wIiwic3RvcCIsImNvbnN0cnVjdG9yIiwiY2xpZW50QXBpQ2xpZW50Iiwia2VlcEhhc2hUcmVlcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxPQUFPQSxZQUFZLFlBQVk7QUFDL0IsT0FBT0MsbUJBQW1CLGtCQUFrQjtBQUs3QixJQUFBLEFBQU1DLHNCQUFOLE1BQU1BO0lBY25COzs7O0dBSUMsR0FDRCxBQUFNQyx5QkFBeUJDLE1BQU07O2VBQXJDLG9CQUFBO1lBQ0UsTUFBTSxNQUFLQyxnQkFBZ0IsQ0FBQ0Ysd0JBQXdCLENBQUNDO1FBQ3ZEOztJQUVBOzs7O0dBSUMsR0FDREUsd0JB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