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)

205 lines (204 loc) 23.7 kB
'use strict'; 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); }); }; } function _define_property(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import LoggerManager from '../logger'; import MetaApiConnection from './metaApiConnection'; import TimeoutError from '../clients/timeoutError'; let RpcMetaApiConnection = class RpcMetaApiConnection extends MetaApiConnection { /** * Opens the connection. Can only be called the first time, next calls will be ignored. * @param {string} instanceId connection instance id * @return {Promise} promise resolving when the connection is opened */ connect(instanceId) { var _this = this; return _async_to_generator(function*() { if (!_this._openedInstances.includes(instanceId)) { _this._openedInstances.push(instanceId); } if (!_this._opened) { _this._opened = true; const accountRegions = _this._account.accountRegions; _this._websocketClient.addAccountCache(_this._account.id, accountRegions); Object.keys(accountRegions).forEach((region)=>{ if (!_this._options.region || _this._options.region === region) { _this._websocketClient.ensureSubscribe(accountRegions[region], 0); _this._websocketClient.ensureSubscribe(accountRegions[region], 1); } }); } })(); } /** * Closes the connection. The instance of the class should no longer be used after this method is invoked. * @param {string} instanceId connection instance id */ close(instanceId) { var _this = this; return _async_to_generator(function*() { if (_this._opened) { _this._openedInstances = _this._openedInstances.filter((id)=>id !== instanceId); if (!_this._openedInstances.length && !_this._closed) { yield _this._connectionRegistry.removeRpc(_this.account); _this._websocketClient.removeSynchronizationListener(_this.account.id, _this); _this._websocketClient.removeAccountCache(_this.account.id); _this._websocketClient.removeReconnectListener(_this); _this._closed = true; } } })(); } /** * Invoked when connection to MetaTrader terminal established * @param {String} instanceIndex index of an account instance connected * @param {Number} replicas number of account replicas launched * @return {Promise} promise which resolves when the asynchronous event is processed */ onConnected(instanceIndex, replicas) { var _this = this; return _async_to_generator(function*() { const state = _this._getState(instanceIndex); state.synchronized = true; const region = _this.getRegion(instanceIndex); _this.cancelRefresh(region); })(); } /** * Invoked when connection to MetaTrader terminal terminated * @param {String} instanceIndex index of an account instance connected * @return {Promise} promise which resolves when the asynchronous event is processed */ onDisconnected(instanceIndex) { var _this = this; return _async_to_generator(function*() { const state = _this._getState(instanceIndex); state.synchronized = false; _this._logger.debug(`${_this._account.id}:${instanceIndex}: disconnected from broker`); })(); } /** * Invoked when a stream for an instance index is closed * @param {String} instanceIndex index of an account instance connected */ onStreamClosed(instanceIndex) { var _this = this; return _async_to_generator(function*() { delete _this._stateByInstanceIndex[instanceIndex]; })(); } /** * Returns flag indicating status of state synchronization with MetaTrader terminal * @returns {Boolean} a flag indicating status of state synchronization with MetaTrader terminal */ isSynchronized() { return Object.values(this._stateByInstanceIndex).map((instance)=>instance.synchronized).includes(true); } /** * Waits until synchronization to RPC application is completed * @param {Number} timeoutInSeconds synchronization timeout in seconds. Defaults to 5 minutes * @return {Promise} promise which resolves when synchronization to RPC application is completed * @throws {TimeoutError} if application failed to synchronize with the teminal within timeout allowed */ waitSynchronized(timeoutInSeconds = 300) { var _this = this; return _async_to_generator(function*() { _this._checkIsConnectionActive(); const startTime = Date.now(); let synchronized = _this.isSynchronized(); while(!synchronized && startTime + timeoutInSeconds * 1000 > Date.now()){ yield new Promise((res)=>setTimeout(res, 1000)); synchronized = _this.isSynchronized(); } if (!synchronized) { throw new TimeoutError('Timed out waiting for MetaApi to synchronize to MetaTrader account ' + _this._account.id); } // eslint-disable-next-line while(true){ try { yield _this._websocketClient.waitSynchronized(_this._account.id, undefined, 'RPC', 5, 'RPC'); break; } catch (err) { if (Date.now() > startTime + timeoutInSeconds * 1000) { throw err; } } } })(); } /** * Invoked when connection to MetaApi websocket API restored after a disconnect * @param {String} region reconnected region * @param {Number} instanceNumber reconnected instance number * @return {Promise} promise which resolves when connection to MetaApi websocket API restored after a disconnect */ onReconnected(region, instanceNumber) { var _this = this; return _async_to_generator(function*() { const instanceTemplate = `${region}:${instanceNumber}`; Object.keys(_this._stateByInstanceIndex).filter((key)=>key.startsWith(`${instanceTemplate}:`)).forEach((key)=>{ delete _this._stateByInstanceIndex[key]; }); })(); } _getState(instanceIndex) { if (!this._stateByInstanceIndex[instanceIndex]) { this._stateByInstanceIndex[instanceIndex] = { instanceIndex, synchronized: false }; } return this._stateByInstanceIndex[instanceIndex]; } /** * Constructs MetaApi MetaTrader RPC Api connection * @param {MetaApiOpts} options MetaApi options * @param {MetaApiWebsocketClient} websocketClient MetaApi websocket client * @param {MetatraderAccount} account MetaTrader account id to connect to * @param {ConnectionRegistry} connectionRegistry metatrader account connection registry */ constructor(options, websocketClient, account, connectionRegistry){ super(options, websocketClient, account, 'RPC'); _define_property(this, "_openedInstances", void 0); this._connectionRegistry = connectionRegistry; this._websocketClient.addSynchronizationListener(account.id, this); this._stateByInstanceIndex = {}; this._openedInstances = []; Object.values(account.accountRegions).forEach((replicaId)=>this._websocketClient.addReconnectListener(this, replicaId)); this._logger = LoggerManager.getLogger('MetaApiConnection'); } }; /** * Exposes MetaApi MetaTrader RPC API connection to consumers */ export { RpcMetaApiConnection as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBMb2dnZXJNYW5hZ2VyIGZyb20gJy4uL2xvZ2dlcic7XG5pbXBvcnQgTWV0YUFwaUNvbm5lY3Rpb24gZnJvbSAnLi9tZXRhQXBpQ29ubmVjdGlvbic7XG5pbXBvcnQgVGltZW91dEVycm9yIGZyb20gJy4uL2NsaWVudHMvdGltZW91dEVycm9yJztcblxuLyoqXG4gKiBFeHBvc2VzIE1ldGFBcGkgTWV0YVRyYWRlciBSUEMgQVBJIGNvbm5lY3Rpb24gdG8gY29uc3VtZXJzXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJwY01ldGFBcGlDb25uZWN0aW9uIGV4dGVuZHMgTWV0YUFwaUNvbm5lY3Rpb24ge1xuICBcbiAgcHJpdmF0ZSBfb3BlbmVkSW5zdGFuY2VzOiBhbnlbXTtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBNZXRhQXBpIE1ldGFUcmFkZXIgUlBDIEFwaSBjb25uZWN0aW9uXG4gICAqIEBwYXJhbSB7TWV0YUFwaU9wdHN9IG9wdGlvbnMgTWV0YUFwaSBvcHRpb25zXG4gICAqIEBwYXJhbSB7TWV0YUFwaVdlYnNvY2tldENsaWVudH0gd2Vic29ja2V0Q2xpZW50IE1ldGFBcGkgd2Vic29ja2V0IGNsaWVudFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBhY2NvdW50IE1ldGFUcmFkZXIgYWNjb3VudCBpZCB0byBjb25uZWN0IHRvXG4gICAqIEBwYXJhbSB7Q29ubmVjdGlvblJlZ2lzdHJ5fSBjb25uZWN0aW9uUmVnaXN0cnkgbWV0YXRyYWRlciBhY2NvdW50IGNvbm5lY3Rpb24gcmVnaXN0cnlcbiAgICovXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnMsIHdlYnNvY2tldENsaWVudCwgYWNjb3VudCwgY29ubmVjdGlvblJlZ2lzdHJ5KSB7XG4gICAgc3VwZXIob3B0aW9ucywgd2Vic29ja2V0Q2xpZW50LCBhY2NvdW50LCAnUlBDJyk7XG4gICAgdGhpcy5fY29ubmVjdGlvblJlZ2lzdHJ5ID0gY29ubmVjdGlvblJlZ2lzdHJ5O1xuICAgIHRoaXMuX3dlYnNvY2tldENsaWVudC5hZGRTeW5jaHJvbml6YXRpb25MaXN0ZW5lcihhY2NvdW50LmlkLCB0aGlzKTtcbiAgICB0aGlzLl9zdGF0ZUJ5SW5zdGFuY2VJbmRleCA9IHt9O1xuICAgIHRoaXMuX29wZW5lZEluc3RhbmNlcyA9IFtdO1xuICAgIE9iamVjdC52YWx1ZXMoYWNjb3VudC5hY2NvdW50UmVnaW9ucylcbiAgICAgIC5mb3JFYWNoKHJlcGxpY2FJZCA9PiB0aGlzLl93ZWJzb2NrZXRDbGllbnQuYWRkUmVjb25uZWN0TGlzdGVuZXIodGhpcywgcmVwbGljYUlkKSk7XG4gICAgdGhpcy5fbG9nZ2VyID0gTG9nZ2VyTWFuYWdlci5nZXRMb2dnZXIoJ01ldGFBcGlDb25uZWN0aW9uJyk7XG4gIH1cblxuICAvKipcbiAgICogT3BlbnMgdGhlIGNvbm5lY3Rpb24uIENhbiBvbmx5IGJlIGNhbGxlZCB0aGUgZmlyc3QgdGltZSwgbmV4dCBjYWxscyB3aWxsIGJlIGlnbm9yZWQuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnN0YW5jZUlkIGNvbm5lY3Rpb24gaW5zdGFuY2UgaWRcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB0aGUgY29ubmVjdGlvbiBpcyBvcGVuZWRcbiAgICovXG4gIGFzeW5jIGNvbm5lY3QoaW5zdGFuY2VJZCkge1xuICAgIGlmICghdGhpcy5fb3BlbmVkSW5zdGFuY2VzLmluY2x1ZGVzKGluc3RhbmNlSWQpKSB7XG4gICAgICB0aGlzLl9vcGVuZWRJbnN0YW5jZXMucHVzaChpbnN0YW5jZUlkKTtcbiAgICB9XG4gICAgaWYgKCF0aGlzLl9vcGVuZWQpIHtcbiAgICAgIHRoaXMuX29wZW5lZCA9IHRydWU7XG4gICAgICBjb25zdCBhY2NvdW50UmVnaW9ucyA9IHRoaXMuX2FjY291bnQuYWNjb3VudFJlZ2lvbnM7XG4gICAgICB0aGlzLl93ZWJzb2NrZXRDbGllbnQuYWRkQWNjb3VudENhY2hlKHRoaXMuX2FjY291bnQuaWQsIGFjY291bnRSZWdpb25zKTtcbiAgICAgIE9iamVjdC5rZXlzKGFjY291bnRSZWdpb25zKS5mb3JFYWNoKHJlZ2lvbiA9PiB7XG4gICAgICAgIGlmICghdGhpcy5fb3B0aW9ucy5yZWdpb24gfHwgdGhpcy5fb3B0aW9ucy5yZWdpb24gPT09IHJlZ2lvbikge1xuICAgICAgICAgIHRoaXMuX3dlYnNvY2tldENsaWVudC5lbnN1cmVTdWJzY3JpYmUoYWNjb3VudFJlZ2lvbnNbcmVnaW9uXSwgMCk7XG4gICAgICAgICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LmVuc3VyZVN1YnNjcmliZShhY2NvdW50UmVnaW9uc1tyZWdpb25dLCAxKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENsb3NlcyB0aGUgY29ubmVjdGlvbi4gVGhlIGluc3RhbmNlIG9mIHRoZSBjbGFzcyBzaG91bGQgbm8gbG9uZ2VyIGJlIHVzZWQgYWZ0ZXIgdGhpcyBtZXRob2QgaXMgaW52b2tlZC5cbiAgICogQHBhcmFtIHtzdHJpbmd9IGluc3RhbmNlSWQgY29ubmVjdGlvbiBpbnN0YW5jZSBpZFxuICAgKi9cbiAgYXN5bmMgY2xvc2UoaW5zdGFuY2VJZCkge1xuICAgIGlmICh0aGlzLl9vcGVuZWQpIHtcbiAgICAgIHRoaXMuX29wZW5lZEluc3RhbmNlcyA9IHRoaXMuX29wZW5lZEluc3RhbmNlcy5maWx0ZXIoaWQgPT4gaWQgIT09IGluc3RhbmNlSWQpO1xuICAgICAgaWYgKCF0aGlzLl9vcGVuZWRJbnN0YW5jZXMubGVuZ3RoICYmICF0aGlzLl9jbG9zZWQpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5fY29ubmVjdGlvblJlZ2lzdHJ5LnJlbW92ZVJwYyh0aGlzLmFjY291bnQpO1xuICAgICAgICB0aGlzLl93ZWJzb2NrZXRDbGllbnQucmVtb3ZlU3luY2hyb25pemF0aW9uTGlzdGVuZXIodGhpcy5hY2NvdW50LmlkLCB0aGlzKTtcbiAgICAgICAgdGhpcy5fd2Vic29ja2V0Q2xpZW50LnJlbW92ZUFjY291bnRDYWNoZSh0aGlzLmFjY291bnQuaWQpO1xuICAgICAgICB0aGlzLl93ZWJzb2NrZXRDbGllbnQucmVtb3ZlUmVjb25uZWN0TGlzdGVuZXIodGhpcyk7XG4gICAgICAgIHRoaXMuX2Nsb3NlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIFxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIGNvbm5lY3Rpb24gdG8gTWV0YVRyYWRlciB0ZXJtaW5hbCBlc3RhYmxpc2hlZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaW5zdGFuY2VJbmRleCBpbmRleCBvZiBhbiBhY2NvdW50IGluc3RhbmNlIGNvbm5lY3RlZFxuICAgKiBAcGFyYW0ge051bWJlcn0gcmVwbGljYXMgbnVtYmVyIG9mIGFjY291bnQgcmVwbGljYXMgbGF1bmNoZWRcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHRoZSBhc3luY2hyb25vdXMgZXZlbnQgaXMgcHJvY2Vzc2VkXG4gICAqL1xuICBhc3luYyBvbkNvbm5lY3RlZChpbnN0YW5jZUluZGV4LCByZXBsaWNhcykge1xuICAgIGNvbnN0IHN0YXRlID0gdGhpcy5fZ2V0U3RhdGUoaW5zdGFuY2VJbmRleCk7XG4gICAgc3RhdGUuc3luY2hyb25pemVkID0gdHJ1ZTtcbiAgICBjb25zdCByZWdpb24gPSB0aGlzLmdldFJlZ2lvbihpbnN0YW5jZUluZGV4KTtcbiAgICB0aGlzLmNhbmNlbFJlZnJlc2gocmVnaW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gY29ubmVjdGlvbiB0byBNZXRhVHJhZGVyIHRlcm1pbmFsIHRlcm1pbmF0ZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlSW5kZXggaW5kZXggb2YgYW4gYWNjb3VudCBpbnN0YW5jZSBjb25uZWN0ZWRcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHRoZSBhc3luY2hyb25vdXMgZXZlbnQgaXMgcHJvY2Vzc2VkXG4gICAqL1xuICBhc3luYyBvbkRpc2Nvbm5lY3RlZChpbnN0YW5jZUluZGV4KSB7XG4gICAgY29uc3Qgc3RhdGUgPSB0aGlzLl9nZXRTdGF0ZShpbnN0YW5jZUluZGV4KTtcbiAgICBzdGF0ZS5zeW5jaHJvbml6ZWQgPSBmYWxzZTtcbiAgICB0aGlzLl9sb2dnZXIuZGVidWcoYCR7dGhpcy5fYWNjb3VudC5pZH06JHtpbnN0YW5jZUluZGV4fTogZGlzY29ubmVjdGVkIGZyb20gYnJva2VyYCk7XG4gIH1cblxuICAvKipcbiAgICogSW52b2tlZCB3aGVuIGEgc3RyZWFtIGZvciBhbiBpbnN0YW5jZSBpbmRleCBpcyBjbG9zZWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGluc3RhbmNlSW5kZXggaW5kZXggb2YgYW4gYWNjb3VudCBpbnN0YW5jZSBjb25uZWN0ZWRcbiAgICovXG4gIGFzeW5jIG9uU3RyZWFtQ2xvc2VkKGluc3RhbmNlSW5kZXgpIHtcbiAgICBkZWxldGUgdGhpcy5fc3RhdGVCeUluc3RhbmNlSW5kZXhbaW5zdGFuY2VJbmRleF07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBmbGFnIGluZGljYXRpbmcgc3RhdHVzIG9mIHN0YXRlIHN5bmNocm9uaXphdGlvbiB3aXRoIE1ldGFUcmFkZXIgdGVybWluYWxcbiAgICogQHJldHVybnMge0Jvb2xlYW59IGEgZmxhZyBpbmRpY2F0aW5nIHN0YXR1cyBvZiBzdGF0ZSBzeW5jaHJvbml6YXRpb24gd2l0aCBNZXRhVHJhZGVyIHRlcm1pbmFsXG4gICAqL1xuICBpc1N5bmNocm9uaXplZCgpIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlczxhbnk+KHRoaXMuX3N0YXRlQnlJbnN0YW5jZUluZGV4KVxuICAgICAgLm1hcChpbnN0YW5jZSA9PiBpbnN0YW5jZS5zeW5jaHJvbml6ZWQpXG4gICAgICAuaW5jbHVkZXModHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgdW50aWwgc3luY2hyb25pemF0aW9uIHRvIFJQQyBhcHBsaWNhdGlvbiBpcyBjb21wbGV0ZWRcbiAgICogQHBhcmFtIHtOdW1iZXJ9IHRpbWVvdXRJblNlY29uZHMgc3luY2hyb25pemF0aW9uIHRpbWVvdXQgaW4gc2Vjb25kcy4gRGVmYXVsdHMgdG8gNSBtaW51dGVzXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiBzeW5jaHJvbml6YXRpb24gdG8gUlBDIGFwcGxpY2F0aW9uIGlzIGNvbXBsZXRlZFxuICAgKiBAdGhyb3dzIHtUaW1lb3V0RXJyb3J9IGlmIGFwcGxpY2F0aW9uIGZhaWxlZCB0byBzeW5jaHJvbml6ZSB3aXRoIHRoZSB0ZW1pbmFsIHdpdGhpbiB0aW1lb3V0IGFsbG93ZWRcbiAgICovXG4gIGFzeW5jIHdhaXRTeW5jaHJvbml6ZWQodGltZW91dEluU2Vjb25kcz0zMDApIHtcbiAgICB0aGlzLl9jaGVja0lzQ29ubmVjdGlvbkFjdGl2ZSgpO1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgbGV0IHN5bmNocm9uaXplZCA9IHRoaXMuaXNTeW5jaHJvbml6ZWQoKTtcbiAgICB3aGlsZSAoIXN5bmNocm9uaXplZCAmJiBzdGFydFRpbWUgKyB0aW1lb3V0SW5TZWNvbmRzICogMTAwMCA+IERhdGUubm93KCkpIHtcbiAgICAgIGF3YWl0IG5ldyBQcm9taXNlKHJlcyA9PiBzZXRUaW1lb3V0KHJlcywgMTAwMCkpO1xuICAgICAgc3luY2hyb25pemVkID0gdGhpcy5pc1N5bmNocm9uaXplZCgpO1xuICAgIH1cbiAgICBpZiAoIXN5bmNocm9uaXplZCkge1xuICAgICAgdGhyb3cgbmV3IFRpbWVvdXRFcnJvcignVGltZWQgb3V0IHdhaXRpbmcgZm9yIE1ldGFBcGkgdG8gc3luY2hyb25pemUgdG8gTWV0YVRyYWRlciBhY2NvdW50ICcgK1xuICAgICAgICB0aGlzLl9hY2NvdW50LmlkKTtcbiAgICB9XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lXG4gICAgd2hpbGUgKHRydWUpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuX3dlYnNvY2tldENsaWVudC53YWl0U3luY2hyb25pemVkKHRoaXMuX2FjY291bnQuaWQsIHVuZGVmaW5lZCwgJ1JQQycsIDUsICdSUEMnKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKERhdGUubm93KCkgPiBzdGFydFRpbWUgKyB0aW1lb3V0SW5TZWNvbmRzICogMTAwMCkge1xuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VkIHdoZW4gY29ubmVjdGlvbiB0byBNZXRhQXBpIHdlYnNvY2tldCBBUEkgcmVzdG9yZWQgYWZ0ZXIgYSBkaXNjb25uZWN0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSByZWdpb24gcmVjb25uZWN0ZWQgcmVnaW9uXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBpbnN0YW5jZU51bWJlciByZWNvbm5lY3RlZCBpbnN0YW5jZSBudW1iZXJcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIGNvbm5lY3Rpb24gdG8gTWV0YUFwaSB3ZWJzb2NrZXQgQVBJIHJlc3RvcmVkIGFmdGVyIGEgZGlzY29ubmVjdFxuICAgKi9cbiAgYXN5bmMgb25SZWNvbm5lY3RlZChyZWdpb24sIGluc3RhbmNlTnVtYmVyKSB7XG4gICAgY29uc3QgaW5zdGFuY2VUZW1wbGF0ZSA9IGAke3JlZ2lvbn06JHtpbnN0YW5jZU51bWJlcn1gO1xuICAgIE9iamVjdC5rZXlzKHRoaXMuX3N0YXRlQnlJbnN0YW5jZUluZGV4KVxuICAgICAgLmZpbHRlcihrZXkgPT4ga2V5LnN0YXJ0c1dpdGgoYCR7aW5zdGFuY2VUZW1wbGF0ZX06YCkpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgICAgZGVsZXRlIHRoaXMuX3N0YXRlQnlJbnN0YW5jZUluZGV4W2tleV07XG4gICAgICB9KTtcbiAgfVxuXG4gIF9nZXRTdGF0ZShpbnN0YW5jZUluZGV4KSB7XG4gICAgaWYgKCF0aGlzLl9zdGF0ZUJ5SW5zdGFuY2VJbmRleFtpbnN0YW5jZUluZGV4XSkge1xuICAgICAgdGhpcy5fc3RhdGVCeUluc3RhbmNlSW5kZXhbaW5zdGFuY2VJbmRleF0gPSB7XG4gICAgICAgIGluc3RhbmNlSW5kZXgsXG4gICAgICAgIHN5bmNocm9uaXplZDogZmFsc2UsXG4gICAgICB9O1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fc3RhdGVCeUluc3RhbmNlSW5kZXhbaW5zdGFuY2VJbmRleF07XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkxvZ2dlck1hbmFnZXIiLCJNZXRhQXBpQ29ubmVjdGlvbiIsIlRpbWVvdXRFcnJvciIsIlJwY01ldGFBcGlDb25uZWN0aW9uIiwiY29ubmVjdCIsImluc3RhbmNlSWQiLCJfb3BlbmVkSW5zdGFuY2VzIiwiaW5jbHVkZXMiLCJwdXNoIiwiX29wZW5lZCIsImFjY291bnRSZWdpb25zIiwiX2FjY291bnQiLCJfd2Vic29ja2V0Q2xpZW50IiwiYWRkQWNjb3VudENhY2hlIiwiaWQiLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsInJlZ2lvbiIsIl9vcHRpb25zIiwiZW5zdXJlU3Vic2NyaWJlIiwiY2xvc2UiLCJmaWx0ZXIiLCJsZW5ndGgiLCJfY2xvc2VkIiwiX2Nvbm5lY3Rpb25SZWdpc3RyeSIsInJlbW92ZVJwYyIsImFjY291bnQiLCJyZW1vdmVTeW5jaHJvbml6YXRpb25MaXN0ZW5lciIsInJlbW92ZUFjY291bnRDYWNoZSIsInJlbW92ZVJlY29ubmVjdExpc3RlbmVyIiwib25Db25uZWN0ZWQiLCJpbnN0YW5jZUluZGV4IiwicmVwbGljYXMiLCJzdGF0ZSIsIl9nZXRTdGF0ZSIsInN5bmNocm9uaXplZCIsImdldFJlZ2lvbiIsImNhbmNlbFJlZnJlc2giLCJvbkRpc2Nvbm5lY3RlZCIsIl9sb2dnZXIiLCJkZWJ1ZyIsIm9uU3RyZWFtQ2xvc2VkIiwiX3N0YXRlQnlJbnN0YW5jZUluZGV4IiwiaXNTeW5jaHJvbml6ZWQiLCJ2YWx1ZXMiLCJtYXAiLCJpbnN0YW5jZSIsIndhaXRTeW5jaHJvbml6ZWQiLCJ0aW1lb3V0SW5TZWNvbmRzIiwiX2NoZWNrSXNDb25uZWN0aW9uQWN0aXZlIiwic3RhcnRUaW1lIiwiRGF0ZSIsIm5vdyIsIlByb21pc2UiLCJyZXMiLCJzZXRUaW1lb3V0IiwidW5kZWZpbmVkIiwiZXJyIiwib25SZWNvbm5lY3RlZCIsImluc3RhbmNlTnVtYmVyIiwiaW5zdGFuY2VUZW1wbGF0ZSIsImtleSIsInN0YXJ0c1dpdGgiLCJjb25zdHJ1Y3RvciIsIm9wdGlvbnMiLCJ3ZWJzb2NrZXRDbGllbnQiLCJjb25uZWN0aW9uUmVnaXN0cnkiLCJhZGRTeW5jaHJvbml6YXRpb25MaXN0ZW5lciIsInJlcGxpY2FJZCIsImFkZFJlY29ubmVjdExpc3RlbmVyIiwiZ2V0TG9nZ2VyIl0sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUVBLE9BQU9BLG1CQUFtQixZQUFZO0FBQ3RDLE9BQU9DLHVCQUF1QixzQkFBc0I7QUFDcEQsT0FBT0Msa0JBQWtCLDBCQUEwQjtBQUtwQyxJQUFBLEFBQU1DLHVCQUFOLE1BQU1BLDZCQUE2QkY7SUFzQmhEOzs7O0dBSUMsR0FDRCxBQUFNRyxRQUFRQyxVQUFVOztlQUF4QixvQkFBQTtZQUNFLElBQUksQ0FBQyxNQUFLQyxnQkFBZ0IsQ0FBQ0MsUUFBUSxDQUFDRixhQUFhO2dCQUMvQyxNQUFLQyxnQkFBZ0IsQ0FBQ0UsSUFBSSxDQUFDSDtZQUM3QjtZQUNBLElBQUksQ0FBQyxNQUFLSSxPQUFPLEVBQUU7Z0JBQ2pCLE1BQUtBLE9BQU8sR0FBRztnQkFDZixNQUFNQyxpQkFBaUIsTUFBS0MsUUFBUSxDQUFDRCxjQUFjO2dCQUNuRCxNQUFLRSxnQkFBZ0IsQ0FBQ0MsZUFB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