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)

154 lines (153 loc) 19.2 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 StreamingMetaApiConnection from './streamingMetaApiConnection'; import RpcMetaApiConnection from './rpcMetaApiConnection'; import StreamingMetaApiConnectionInstance from './streamingMetaApiConnectionInstance'; import RpcMetaApiConnectionInstance from './rpcMetaApiConnectionInstance'; let ConnectionRegistry = class ConnectionRegistry { /** * Creates and returns a new account streaming connection if doesnt exist, otherwise returns old * @param {MetatraderAccount} account MetaTrader account id to connect to * @param {HistoryStorage} historyStorage terminal history storage * @param {Date} [historyStartTime] history start time * @return {StreamingMetaApiConnection} streaming metaapi connection */ connectStreaming(account, historyStorage, historyStartTime) { if (!this._streamingConnections[account.id]) { this._streamingConnections[account.id] = new StreamingMetaApiConnection(this._options, this._metaApiWebsocketClient, this._terminalHashManager, account, historyStorage, this, historyStartTime, this._refreshSubscriptionsOpts); } const instance = new StreamingMetaApiConnectionInstance(this._metaApiWebsocketClient, this._streamingConnections[account.id]); this._streamingConnectionInstances[account.id] = this._streamingConnectionInstances[account.id] || []; this._streamingConnectionInstances[account.id].push(instance); return instance; } /** * Removes a streaming connection from registry * @param {MetatraderAccount} account MetaTrader account to remove from registry */ removeStreaming(account) { var _this = this; return _async_to_generator(function*() { if (_this._streamingConnections[account.id]) { delete _this._streamingConnections[account.id]; delete _this._streamingConnectionInstances[account.id]; } if (!_this._rpcConnections[account.id]) { yield _this._closeLastConnection(account); } })(); } /** * Creates and returns a new account rpc connection if doesnt exist, otherwise returns old * @param {MetatraderAccount} account MetaTrader account id to connect to * @returns {RpcMetaApiConnection} rpc metaapi connection */ connectRpc(account) { if (!this._rpcConnections[account.id]) { this._rpcConnections[account.id] = new RpcMetaApiConnection(this._options, this._metaApiWebsocketClient, account, this); } const instance = new RpcMetaApiConnectionInstance(this._metaApiWebsocketClient, this._rpcConnections[account.id]); this._rpcConnectionInstances[account.id] = this._rpcConnectionInstances[account.id] || []; this._rpcConnectionInstances[account.id].push(instance); return instance; } /** * Removes an RPC connection from registry * @param {MetatraderAccount} account MetaTrader account to remove from registry */ removeRpc(account) { var _this = this; return _async_to_generator(function*() { if (_this._rpcConnections[account.id]) { delete _this._rpcConnections[account.id]; delete _this._rpcConnectionInstances[account.id]; } if (!_this._streamingConnections[account.id]) { yield _this._closeLastConnection(account); } })(); } /** * Returns application type * @return {String} application type */ get application() { return this._application; } _closeLastConnection(account) { var _this = this; return _async_to_generator(function*() { const accountRegions = account.accountRegions; yield Promise.all(Object.values(accountRegions).map((replicaId)=>_this._metaApiWebsocketClient.unsubscribe(replicaId))); })(); } /** * Returns the dictionary of streaming connections * @returns {{[id: string]: StreamingMetaApiConnection}} */ get streamingConnections() { return this._streamingConnections; } /** * Returns the dictionary of rpc connections * @returns {{[id: string]: RpcMetaApiConnection}} */ get rpcConnections() { return this._rpcConnections; } /** * Closes all connection instances for an account * @param {string} accountId */ closeAllInstances(accountId) { if (this._rpcConnectionInstances[accountId]) { this._rpcConnectionInstances[accountId].forEach((instance)=>instance.close()); } if (this._streamingConnectionInstances[accountId]) { this._streamingConnectionInstances[accountId].forEach((instance)=>instance.close()); } } /** * Constructs a MetaTrader connection registry instance * @param {MetaApiOpts} options metaapi options * @param {MetaApiWebsocketClient} metaApiWebsocketClient MetaApi websocket client * @param {ClientApiClient} clientApiClient client API client * @param {String} application application id * @param {String} refreshSubscriptionsOpts subscriptions refresh options */ constructor(options, metaApiWebsocketClient, terminalHashManager, application = 'MetaApi', refreshSubscriptionsOpts){ refreshSubscriptionsOpts = refreshSubscriptionsOpts || {}; this._metaApiWebsocketClient = metaApiWebsocketClient; this._terminalHashManager = terminalHashManager; this._application = application; this._refreshSubscriptionsOpts = refreshSubscriptionsOpts; this._rpcConnections = {}; this._rpcConnectionInstances = {}; this._streamingConnections = {}; this._streamingConnectionInstances = {}; this._connectionLocks = {}; this._options = options; } }; /** * Manages account connections */ export { ConnectionRegistry as default }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb24gZnJvbSAnLi9zdHJlYW1pbmdNZXRhQXBpQ29ubmVjdGlvbic7XG5pbXBvcnQgUnBjTWV0YUFwaUNvbm5lY3Rpb24gZnJvbSAnLi9ycGNNZXRhQXBpQ29ubmVjdGlvbic7XG5pbXBvcnQgU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSBmcm9tICcuL3N0cmVhbWluZ01ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UnO1xuaW1wb3J0IFJwY01ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UgZnJvbSAnLi9ycGNNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlJztcblxuLyoqXG4gKiBNYW5hZ2VzIGFjY291bnQgY29ubmVjdGlvbnNcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQ29ubmVjdGlvblJlZ2lzdHJ5IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBhIE1ldGFUcmFkZXIgY29ubmVjdGlvbiByZWdpc3RyeSBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge01ldGFBcGlPcHRzfSBvcHRpb25zIG1ldGFhcGkgb3B0aW9uc1xuICAgKiBAcGFyYW0ge01ldGFBcGlXZWJzb2NrZXRDbGllbnR9IG1ldGFBcGlXZWJzb2NrZXRDbGllbnQgTWV0YUFwaSB3ZWJzb2NrZXQgY2xpZW50XG4gICAqIEBwYXJhbSB7Q2xpZW50QXBpQ2xpZW50fSBjbGllbnRBcGlDbGllbnQgY2xpZW50IEFQSSBjbGllbnRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGFwcGxpY2F0aW9uIGFwcGxpY2F0aW9uIGlkXG4gICAqIEBwYXJhbSB7U3RyaW5nfSByZWZyZXNoU3Vic2NyaXB0aW9uc09wdHMgc3Vic2NyaXB0aW9ucyByZWZyZXNoIG9wdGlvbnNcbiAgICovXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnMsIG1ldGFBcGlXZWJzb2NrZXRDbGllbnQsIHRlcm1pbmFsSGFzaE1hbmFnZXIsXG4gICAgYXBwbGljYXRpb24gPSAnTWV0YUFwaScsIHJlZnJlc2hTdWJzY3JpcHRpb25zT3B0cykge1xuICAgIHJlZnJlc2hTdWJzY3JpcHRpb25zT3B0cyA9IHJlZnJlc2hTdWJzY3JpcHRpb25zT3B0cyB8fCB7fTtcbiAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50ID0gbWV0YUFwaVdlYnNvY2tldENsaWVudDtcbiAgICB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyID0gdGVybWluYWxIYXNoTWFuYWdlcjtcbiAgICB0aGlzLl9hcHBsaWNhdGlvbiA9IGFwcGxpY2F0aW9uO1xuICAgIHRoaXMuX3JlZnJlc2hTdWJzY3JpcHRpb25zT3B0cyA9IHJlZnJlc2hTdWJzY3JpcHRpb25zT3B0cztcbiAgICB0aGlzLl9ycGNDb25uZWN0aW9ucyA9IHt9O1xuICAgIHRoaXMuX3JwY0Nvbm5lY3Rpb25JbnN0YW5jZXMgPSB7fTtcbiAgICB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9ucyA9IHt9O1xuICAgIHRoaXMuX3N0cmVhbWluZ0Nvbm5lY3Rpb25JbnN0YW5jZXMgPSB7fTtcbiAgICB0aGlzLl9jb25uZWN0aW9uTG9ja3MgPSB7fTtcbiAgICB0aGlzLl9vcHRpb25zID0gb3B0aW9ucztcbiAgfVxuICBcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW5kIHJldHVybnMgYSBuZXcgYWNjb3VudCBzdHJlYW1pbmcgY29ubmVjdGlvbiBpZiBkb2VzbnQgZXhpc3QsIG90aGVyd2lzZSByZXR1cm5zIG9sZFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBhY2NvdW50IE1ldGFUcmFkZXIgYWNjb3VudCBpZCB0byBjb25uZWN0IHRvXG4gICAqIEBwYXJhbSB7SGlzdG9yeVN0b3JhZ2V9IGhpc3RvcnlTdG9yYWdlIHRlcm1pbmFsIGhpc3Rvcnkgc3RvcmFnZVxuICAgKiBAcGFyYW0ge0RhdGV9IFtoaXN0b3J5U3RhcnRUaW1lXSBoaXN0b3J5IHN0YXJ0IHRpbWVcbiAgICogQHJldHVybiB7U3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb259IHN0cmVhbWluZyBtZXRhYXBpIGNvbm5lY3Rpb25cbiAgICovXG4gIGNvbm5lY3RTdHJlYW1pbmcoYWNjb3VudCwgaGlzdG9yeVN0b3JhZ2UsIGhpc3RvcnlTdGFydFRpbWUpIHtcbiAgICBpZiAoIXRoaXMuX3N0cmVhbWluZ0Nvbm5lY3Rpb25zW2FjY291bnQuaWRdKSB7XG4gICAgICB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9uc1thY2NvdW50LmlkXSA9IG5ldyBTdHJlYW1pbmdNZXRhQXBpQ29ubmVjdGlvbih0aGlzLl9vcHRpb25zLFxuICAgICAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LCB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyLCBhY2NvdW50LCBoaXN0b3J5U3RvcmFnZSwgdGhpcywgaGlzdG9yeVN0YXJ0VGltZSxcbiAgICAgICAgdGhpcy5fcmVmcmVzaFN1YnNjcmlwdGlvbnNPcHRzKTtcbiAgICB9XG4gICAgY29uc3QgaW5zdGFuY2UgPSBuZXcgU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSh0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LCBcbiAgICAgIHRoaXMuX3N0cmVhbWluZ0Nvbm5lY3Rpb25zW2FjY291bnQuaWRdKTtcbiAgICB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnQuaWRdID0gdGhpcy5fc3RyZWFtaW5nQ29ubmVjdGlvbkluc3RhbmNlc1thY2NvdW50LmlkXSB8fCBbXTtcbiAgICB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnQuaWRdLnB1c2goaW5zdGFuY2UpO1xuICAgIHJldHVybiBpbnN0YW5jZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGEgc3RyZWFtaW5nIGNvbm5lY3Rpb24gZnJvbSByZWdpc3RyeVxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBhY2NvdW50IE1ldGFUcmFkZXIgYWNjb3VudCB0byByZW1vdmUgZnJvbSByZWdpc3RyeVxuICAgKi9cbiAgYXN5bmMgcmVtb3ZlU3RyZWFtaW5nKGFjY291bnQpIHtcbiAgICBpZiAodGhpcy5fc3RyZWFtaW5nQ29ubmVjdGlvbnNbYWNjb3VudC5pZF0pIHtcbiAgICAgIGRlbGV0ZSB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9uc1thY2NvdW50LmlkXTtcbiAgICAgIGRlbGV0ZSB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnQuaWRdO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuX3JwY0Nvbm5lY3Rpb25zW2FjY291bnQuaWRdKSB7XG4gICAgICBhd2FpdCB0aGlzLl9jbG9zZUxhc3RDb25uZWN0aW9uKGFjY291bnQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgbmV3IGFjY291bnQgcnBjIGNvbm5lY3Rpb24gaWYgZG9lc250IGV4aXN0LCBvdGhlcndpc2UgcmV0dXJucyBvbGRcbiAgICogQHBhcmFtIHtNZXRhdHJhZGVyQWNjb3VudH0gYWNjb3VudCBNZXRhVHJhZGVyIGFjY291bnQgaWQgdG8gY29ubmVjdCB0b1xuICAgKiBAcmV0dXJucyB7UnBjTWV0YUFwaUNvbm5lY3Rpb259IHJwYyBtZXRhYXBpIGNvbm5lY3Rpb25cbiAgICovXG4gIGNvbm5lY3RScGMoYWNjb3VudCkge1xuICAgIGlmICghdGhpcy5fcnBjQ29ubmVjdGlvbnNbYWNjb3VudC5pZF0pIHtcbiAgICAgIHRoaXMuX3JwY0Nvbm5lY3Rpb25zW2FjY291bnQuaWRdID0gbmV3IFJwY01ldGFBcGlDb25uZWN0aW9uKHRoaXMuX29wdGlvbnMsIHRoaXMuX21ldGFBcGlXZWJzb2NrZXRDbGllbnQsIGFjY291bnQsXG4gICAgICAgIHRoaXMpO1xuICAgIH1cbiAgICBjb25zdCBpbnN0YW5jZSA9IG5ldyBScGNNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlKHRoaXMuX21ldGFBcGlXZWJzb2NrZXRDbGllbnQsIFxuICAgICAgdGhpcy5fcnBjQ29ubmVjdGlvbnNbYWNjb3VudC5pZF0pO1xuICAgIHRoaXMuX3JwY0Nvbm5lY3Rpb25JbnN0YW5jZXNbYWNjb3VudC5pZF0gPSB0aGlzLl9ycGNDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnQuaWRdIHx8IFtdO1xuICAgIHRoaXMuX3JwY0Nvbm5lY3Rpb25JbnN0YW5jZXNbYWNjb3VudC5pZF0ucHVzaChpbnN0YW5jZSk7XG4gICAgcmV0dXJuIGluc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgYW4gUlBDIGNvbm5lY3Rpb24gZnJvbSByZWdpc3RyeVxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBhY2NvdW50IE1ldGFUcmFkZXIgYWNjb3VudCB0byByZW1vdmUgZnJvbSByZWdpc3RyeVxuICAgKi9cbiAgYXN5bmMgcmVtb3ZlUnBjKGFjY291bnQpIHtcbiAgICBpZiAodGhpcy5fcnBjQ29ubmVjdGlvbnNbYWNjb3VudC5pZF0pIHtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ycGNDb25uZWN0aW9uc1thY2NvdW50LmlkXTtcbiAgICAgIGRlbGV0ZSB0aGlzLl9ycGNDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnQuaWRdO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuX3N0cmVhbWluZ0Nvbm5lY3Rpb25zW2FjY291bnQuaWRdKSB7XG4gICAgICBhd2FpdCB0aGlzLl9jbG9zZUxhc3RDb25uZWN0aW9uKGFjY291bnQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFwcGxpY2F0aW9uIHR5cGVcbiAgICogQHJldHVybiB7U3RyaW5nfSBhcHBsaWNhdGlvbiB0eXBlXG4gICAqL1xuICBnZXQgYXBwbGljYXRpb24oKSB7XG4gICAgcmV0dXJuIHRoaXMuX2FwcGxpY2F0aW9uO1xuICB9XG5cbiAgYXN5bmMgX2Nsb3NlTGFzdENvbm5lY3Rpb24oYWNjb3VudCkge1xuICAgIGNvbnN0IGFjY291bnRSZWdpb25zID0gYWNjb3VudC5hY2NvdW50UmVnaW9ucztcbiAgICBhd2FpdCBQcm9taXNlLmFsbChPYmplY3QudmFsdWVzKGFjY291bnRSZWdpb25zKS5tYXAocmVwbGljYUlkID0+XG4gICAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LnVuc3Vic2NyaWJlKHJlcGxpY2FJZCkpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBkaWN0aW9uYXJ5IG9mIHN0cmVhbWluZyBjb25uZWN0aW9uc1xuICAgKiBAcmV0dXJucyB7e1tpZDogc3RyaW5nXTogU3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb259fVxuICAgKi9cbiAgZ2V0IHN0cmVhbWluZ0Nvbm5lY3Rpb25zKCkge1xuICAgIHJldHVybiB0aGlzLl9zdHJlYW1pbmdDb25uZWN0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBkaWN0aW9uYXJ5IG9mIHJwYyBjb25uZWN0aW9uc1xuICAgKiBAcmV0dXJucyB7e1tpZDogc3RyaW5nXTogUnBjTWV0YUFwaUNvbm5lY3Rpb259fVxuICAgKi9cbiAgZ2V0IHJwY0Nvbm5lY3Rpb25zKCkge1xuICAgIHJldHVybiB0aGlzLl9ycGNDb25uZWN0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZXMgYWxsIGNvbm5lY3Rpb24gaW5zdGFuY2VzIGZvciBhbiBhY2NvdW50XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgXG4gICAqL1xuICBjbG9zZUFsbEluc3RhbmNlcyhhY2NvdW50SWQpIHtcbiAgICBpZiAodGhpcy5fcnBjQ29ubmVjdGlvbkluc3RhbmNlc1thY2NvdW50SWRdKSB7XG4gICAgICB0aGlzLl9ycGNDb25uZWN0aW9uSW5zdGFuY2VzW2FjY291bnRJZF0uZm9yRWFjaChpbnN0YW5jZSA9PiBpbnN0YW5jZS5jbG9zZSgpKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuX3N0cmVhbWluZ0Nvbm5lY3Rpb25JbnN0YW5jZXNbYWNjb3VudElkXSkge1xuICAgICAgdGhpcy5fc3RyZWFtaW5nQ29ubmVjdGlvbkluc3RhbmNlc1thY2NvdW50SWRdLmZvckVhY2goaW5zdGFuY2UgPT4gaW5zdGFuY2UuY2xvc2UoKSk7XG4gICAgfVxuICB9XG4gIFxufVxuIl0sIm5hbWVzIjpbIlN0cmVhbWluZ01ldGFBcGlDb25uZWN0aW9uIiwiUnBjTWV0YUFwaUNvbm5lY3Rpb24iLCJTdHJlYW1pbmdNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlIiwiUnBjTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSIsIkNvbm5lY3Rpb25SZWdpc3RyeSIsImNvbm5lY3RTdHJlYW1pbmciLCJhY2NvdW50IiwiaGlzdG9yeVN0b3JhZ2UiLCJoaXN0b3J5U3RhcnRUaW1lIiwiX3N0cmVhbWluZ0Nvbm5lY3Rpb25zIiwiaWQiLCJfb3B0aW9ucyIsIl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50IiwiX3Rlcm1pbmFsSGFzaE1hbmFnZXIiLCJfcmVmcmVzaFN1YnNjcmlwdGlvbnNPcHRzIiwiaW5zdGFuY2UiLCJfc3RyZWFtaW5nQ29ubmVjdGlvbkluc3RhbmNlcyIsInB1c2giLCJyZW1vdmVTdHJlYW1pbmciLCJfcnBjQ29ubmVjdGlvbnMiLCJfY2xvc2VMYXN0Q29ubmVjdGlvbiIsImNvbm5lY3RScGMiLCJfcnBjQ29ubmVjdGlvbkluc3RhbmNlcyIsInJlbW92ZVJwYyIsImFwcGxpY2F0aW9uIiwiX2FwcGxpY2F0aW9uIiwiYWNjb3VudFJlZ2lvbnMiLCJQcm9taXNlIiwiYWxsIiwiT2JqZWN0IiwidmFsdWVzIiwibWFwIiwicmVwbGljYUlkIiwidW5zdWJzY3JpYmUiLCJzdHJlYW1pbmdDb25uZWN0aW9ucyIsInJwY0Nvbm5lY3Rpb25zIiwiY2xvc2VBbGxJbnN0YW5jZXMiLCJhY2NvdW50SWQiLCJmb3JFYWNoIiwiY2xvc2UiLCJjb25zdHJ1Y3RvciIsIm9wdGlvbnMiLCJtZXRhQXBpV2Vic29ja2V0Q2xpZW50IiwidGVybWluYWxIYXNoTWFuYWdlciIsInJlZnJlc2hTdWJzY3JpcHRpb25zT3B0cyIsIl9jb25uZWN0aW9uTG9j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