UNPKG

metaapi.cloud-copyfactory-sdk

Version:

Javascript SDK for SDK for CopyFactory trade copying API. Can copy trades both between MetaTrader 5 (MT5) and MetaTrader 4 (MT4). (https://metaapi.cloud)

208 lines (207 loc) 26.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, /** * metaapi.cloud CopyFactory history API (trade copying history API) client (see * https://metaapi.cloud/docs/copyfactory/) */ "default", { enumerable: true, get: function() { return HistoryClient; } }); const _metaapiclient = /*#__PURE__*/ _interop_require_default(require("../metaapi.client")); const _transactionListenerManager = /*#__PURE__*/ _interop_require_default(require("./streaming/transactionListenerManager")); function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let HistoryClient = class HistoryClient extends _metaapiclient.default { /** * Constructs CopyFactory history API client instance * @param {DomainClient} domainClient domain client */ constructor(domainClient){ super(domainClient); this._domainClient = domainClient; this._transactionListenerManager = new _transactionListenerManager.default(domainClient); } /** * CopyFactory provider or subscriber user * @typedef {Object} CopyFactorySubscriberOrProviderUser * @property {String} id profile id * @property {String} name user name * @property {Array<CopyFactoryStrategyIdAndName>} strategies array of strategy IDs provided by provider * or subscribed to by subscriber */ /** * CopyFactory strategy id and name * @typedef {Object} CopyFactoryStrategyIdAndName * @property {String} id unique strategy id * @property {String} name human-readable strategy name */ /** * CopyFactory transaction * @typedef {Object} CopyFactoryTransaction * @property {String} id transaction id * @property {String} type transaction type (one of DEAL_TYPE_BUY, DEAL_TYPE_SELL, DEAL_TYPE_BALANCE, * DEAL_TYPE_CREDIT, DEAL_TYPE_CHARGE, DEAL_TYPE_CORRECTION, DEAL_TYPE_BONUS, DEAL_TYPE_COMMISSION, * DEAL_TYPE_COMMISSION_DAILY, DEAL_TYPE_COMMISSION_MONTHLY, DEAL_TYPE_COMMISSION_AGENT_DAILY, * DEAL_TYPE_COMMISSION_AGENT_MONTHLY, DEAL_TYPE_INTEREST, DEAL_TYPE_BUY_CANCELED, DEAL_TYPE_SELL_CANCELED, * DEAL_DIVIDEND, DEAL_DIVIDEND_FRANKED, DEAL_TAX). See * https://www.mql5.com/en/docs/constants/tradingconstants/dealproperties#enum_deal_type * @property {Date} time transaction time * @property {String} subscriberId CopyFactory subscriber id * @property {String} [symbol] symbol traded * @property {CopyFactorySubscriberOrProviderUser} subscriberUser strategy subscriber * @property {Boolean} demo demo account flag * @property {CopyFactorySubscriberOrProviderUser} providerUser strategy provider * @property {CopyFactoryStrategyIdAndName} strategy strategy * @property {String} [positionId] source position id * @property {String} [slavePositionId] subscriber position id * @property {Number} improvement high-water mark strategy balance improvement * @property {Number} providerCommission provider commission * @property {Number} platformCommission platform commission * @property {Number} [incomingProviderCommission] commission paid by provider to underlying providers * @property {Number} [incomingPlatformCommission] platform commission paid by provider to underlying providers * @property {Number} [quantity] trade volume * @property {Number} [lotPrice] trade lot price * @property {Number} [tickPrice] trade tick price * @property {Number} [amount] trade amount * @property {Number} [commission] trade commission * @property {Number} swap trade swap * @property {Number} profit trade profit * @property {CopyFactoryTransactionMetrics} [metrics] trade copying metrics such as slippage and latencies. Measured * selectively for copied trades */ /** * Trade copying metrics such as slippage and latencies * @typedef {Object} CopyFactoryTransactionMetrics * @property {Number} [tradeCopyingLatency] trade copying latency, measured in milliseconds based on transaction time * provided by broker * @property {Number} [tradeCopyingSlippageInBasisPoints] trade copying slippage, measured in basis points (0.01 * percent) based on transaction price provided by broker * @property {Number} [tradeCopyingSlippageInAccountCurrency] trade copying slippage, measured in account currency * based on transaction price provided by broker * @property {Number} [mtAndBrokerSignalLatency] trade signal latency introduced by broker and MT platform, measured * in milliseconds * @property {Number} [tradeAlgorithmLatency] trade algorithm latency introduced by CopyFactory servers, measured in * milliseconds * @property {Number} [mtAndBrokerTradeLatency] trade latency for a copied trade introduced by broker and MT platform, * measured in milliseconds */ /** * Returns list of transactions on the strategies the current user provides to other users * https://metaapi.cloud/docs/copyfactory/restApi/api/history/getProvidedTransactions/ * @param {Date} from time to load transactions from * @param {Date} till time to load transactions till * @param {Array<string>} [strategyIds] list of strategy ids to filter transactions by * @param {Array<string>} [subscriberIds] the list of CopyFactory subscriber account ids to filter by * @param {number} [offset] pagination offset. Default value is 0 * @param {number} [limit] pagination limit. Default value is 1000 * @return {Promise<Array<CopyFactoryTransaction>>} promise resolving with transactions found */ async getProvidedTransactions(from, till, strategyIds, subscriberIds, offset, limit) { if (this._isNotJwtToken()) { return this._handleNoAccessError("getProvidedTransactions"); } let params = { from, till }; if (strategyIds) { params.strategyId = strategyIds; } if (subscriberIds) { params.subscriberId = subscriberIds; } if (offset !== undefined) { params.offset = offset; } if (limit) { params.limit = limit; } const opts = { url: "/users/current/provided-transactions", method: "GET", headers: { "auth-token": this._token }, params, json: true }; let transactions = await this._domainClient.requestCopyFactory(opts, true); transactions.forEach((t)=>t.time = new Date(t.time)); return transactions; } /** * Returns list of trades on the strategies the current user subscribed to * https://metaapi.cloud/docs/copyfactory/restApi/api/history/getSubscriptionTransactions/ * @param {Date} from time to load transactions from * @param {Date} till time to load transactions till * @param {Array<String>} [strategyIds] list of strategy ids to filter transactions by * @param {Array<string>} [subscriberIds] the list of CopyFactory subscriber account ids to filter by * @param {Number} offset pagination offset. Default value is 0 * @param {Number} limit pagination limit. Default value is 1000 * @return {Promise<Array<CopyFactoryTransaction>>} promise resolving with transactions found */ async getSubscriptionTransactions(from, till, strategyIds, subscriberIds, offset, limit) { if (this._isNotJwtToken()) { return this._handleNoAccessError("getSubscriptionTransactions"); } let params = { from, till }; if (strategyIds) { params.strategyId = strategyIds; } if (subscriberIds) { params.subscriberId = subscriberIds; } if (offset !== undefined) { params.offset = offset; } if (limit) { params.limit = limit; } const opts = { url: "/users/current/subscription-transactions", method: "GET", headers: { "auth-token": this._token }, params, json: true }; let transactions = await this._domainClient.requestCopyFactory(opts, true); transactions.forEach((t)=>t.time = new Date(t.time)); return transactions; } /** * Adds a strategy transaction listener and creates a job to make requests * @param {TransactionListener} listener transaction listener * @param {String} strategyId strategy id * @param {Date} [startTime] transaction search start time * @return {String} listener id */ addStrategyTransactionListener(listener, strategyId, startTime) { return this._transactionListenerManager.addStrategyTransactionListener(listener, strategyId, startTime); } /** * Removes strategy transaction listener and cancels the event stream * @param {String} listenerId strategy transaction listener id */ removeStrategyTransactionListener(listenerId) { this._transactionListenerManager.removeStrategyTransactionListener(listenerId); } /** * Adds a subscriber transaction listener and creates a job to make requests * @param {TransactionListener} listener transaction listener * @param {String} subscriberId subscriber id * @param {Date} [startTime] transaction search start time * @return {String} listener id */ addSubscriberTransactionListener(listener, subscriberId, startTime) { return this._transactionListenerManager.addSubscriberTransactionListener(listener, subscriberId, startTime); } /** * Removes subscriber transaction listener and cancels the event stream * @param {String} listenerId subscriber transaction listener id */ removeSubscriberTransactionListener(listenerId) { this._transactionListenerManager.removeSubscriberTransactionListener(listenerId); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBNZXRhQXBpQ2xpZW50IGZyb20gJy4uL21ldGFhcGkuY2xpZW50JztcbmltcG9ydCBUcmFuc2FjdGlvbkxpc3RlbmVyTWFuYWdlciBmcm9tICcuL3N0cmVhbWluZy90cmFuc2FjdGlvbkxpc3RlbmVyTWFuYWdlcic7XG5cbi8qKlxuICogbWV0YWFwaS5jbG91ZCBDb3B5RmFjdG9yeSBoaXN0b3J5IEFQSSAodHJhZGUgY29weWluZyBoaXN0b3J5IEFQSSkgY2xpZW50IChzZWVcbiAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5LylcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgSGlzdG9yeUNsaWVudCBleHRlbmRzIE1ldGFBcGlDbGllbnQge1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIENvcHlGYWN0b3J5IGhpc3RvcnkgQVBJIGNsaWVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge0RvbWFpbkNsaWVudH0gZG9tYWluQ2xpZW50IGRvbWFpbiBjbGllbnRcbiAgICovXG4gIGNvbnN0cnVjdG9yKGRvbWFpbkNsaWVudCkge1xuICAgIHN1cGVyKGRvbWFpbkNsaWVudCk7XG4gICAgdGhpcy5fZG9tYWluQ2xpZW50ID0gZG9tYWluQ2xpZW50O1xuICAgIHRoaXMuX3RyYW5zYWN0aW9uTGlzdGVuZXJNYW5hZ2VyID0gbmV3IFRyYW5zYWN0aW9uTGlzdGVuZXJNYW5hZ2VyKGRvbWFpbkNsaWVudCk7XG4gIH1cblxuICAvKipcbiAgICogQ29weUZhY3RvcnkgcHJvdmlkZXIgb3Igc3Vic2NyaWJlciB1c2VyXG4gICAqIEB0eXBlZGVmIHtPYmplY3R9IENvcHlGYWN0b3J5U3Vic2NyaWJlck9yUHJvdmlkZXJVc2VyXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBpZCBwcm9maWxlIGlkXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBuYW1lIHVzZXIgbmFtZVxuICAgKiBAcHJvcGVydHkge0FycmF5PENvcHlGYWN0b3J5U3RyYXRlZ3lJZEFuZE5hbWU+fSBzdHJhdGVnaWVzIGFycmF5IG9mIHN0cmF0ZWd5IElEcyBwcm92aWRlZCBieSBwcm92aWRlclxuICAgKiBvciBzdWJzY3JpYmVkIHRvIGJ5IHN1YnNjcmliZXJcbiAgICovXG5cbiAgLyoqXG4gICAqIENvcHlGYWN0b3J5IHN0cmF0ZWd5IGlkIGFuZCBuYW1lXG4gICAqIEB0eXBlZGVmIHtPYmplY3R9IENvcHlGYWN0b3J5U3RyYXRlZ3lJZEFuZE5hbWVcbiAgICogQHByb3BlcnR5IHtTdHJpbmd9IGlkIHVuaXF1ZSBzdHJhdGVneSBpZFxuICAgKiBAcHJvcGVydHkge1N0cmluZ30gbmFtZSBodW1hbi1yZWFkYWJsZSBzdHJhdGVneSBuYW1lXG4gICAqL1xuXG4gIC8qKlxuICAgKiBDb3B5RmFjdG9yeSB0cmFuc2FjdGlvblxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBDb3B5RmFjdG9yeVRyYW5zYWN0aW9uXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBpZCB0cmFuc2FjdGlvbiBpZFxuICAgKiBAcHJvcGVydHkge1N0cmluZ30gdHlwZSB0cmFuc2FjdGlvbiB0eXBlIChvbmUgb2YgREVBTF9UWVBFX0JVWSwgREVBTF9UWVBFX1NFTEwsIERFQUxfVFlQRV9CQUxBTkNFLFxuICAgKiBERUFMX1RZUEVfQ1JFRElULCBERUFMX1RZUEVfQ0hBUkdFLCBERUFMX1RZUEVfQ09SUkVDVElPTiwgREVBTF9UWVBFX0JPTlVTLCBERUFMX1RZUEVfQ09NTUlTU0lPTixcbiAgICogREVBTF9UWVBFX0NPTU1JU1NJT05fREFJTFksIERFQUxfVFlQRV9DT01NSVNTSU9OX01PTlRITFksIERFQUxfVFlQRV9DT01NSVNTSU9OX0FHRU5UX0RBSUxZLFxuICAgKiBERUFMX1RZUEVfQ09NTUlTU0lPTl9BR0VOVF9NT05USExZLCBERUFMX1RZUEVfSU5URVJFU1QsIERFQUxfVFlQRV9CVVlfQ0FOQ0VMRUQsIERFQUxfVFlQRV9TRUxMX0NBTkNFTEVELFxuICAgKiBERUFMX0RJVklERU5ELCBERUFMX0RJVklERU5EX0ZSQU5LRUQsIERFQUxfVEFYKS4gU2VlXG4gICAqIGh0dHBzOi8vd3d3Lm1xbDUuY29tL2VuL2RvY3MvY29uc3RhbnRzL3RyYWRpbmdjb25zdGFudHMvZGVhbHByb3BlcnRpZXMjZW51bV9kZWFsX3R5cGVcbiAgICogQHByb3BlcnR5IHtEYXRlfSB0aW1lIHRyYW5zYWN0aW9uIHRpbWVcbiAgICogQHByb3BlcnR5IHtTdHJpbmd9IHN1YnNjcmliZXJJZCBDb3B5RmFjdG9yeSBzdWJzY3JpYmVyIGlkXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBbc3ltYm9sXSBzeW1ib2wgdHJhZGVkXG4gICAqIEBwcm9wZXJ0eSB7Q29weUZhY3RvcnlTdWJzY3JpYmVyT3JQcm92aWRlclVzZXJ9IHN1YnNjcmliZXJVc2VyIHN0cmF0ZWd5IHN1YnNjcmliZXJcbiAgICogQHByb3BlcnR5IHtCb29sZWFufSBkZW1vIGRlbW8gYWNjb3VudCBmbGFnXG4gICAqIEBwcm9wZXJ0eSB7Q29weUZhY3RvcnlTdWJzY3JpYmVyT3JQcm92aWRlclVzZXJ9IHByb3ZpZGVyVXNlciBzdHJhdGVneSBwcm92aWRlclxuICAgKiBAcHJvcGVydHkge0NvcHlGYWN0b3J5U3RyYXRlZ3lJZEFuZE5hbWV9IHN0cmF0ZWd5IHN0cmF0ZWd5XG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBbcG9zaXRpb25JZF0gc291cmNlIHBvc2l0aW9uIGlkXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBbc2xhdmVQb3NpdGlvbklkXSBzdWJzY3JpYmVyIHBvc2l0aW9uIGlkXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBpbXByb3ZlbWVudCBoaWdoLXdhdGVyIG1hcmsgc3RyYXRlZ3kgYmFsYW5jZSBpbXByb3ZlbWVudFxuICAgKiBAcHJvcGVydHkge051bWJlcn0gcHJvdmlkZXJDb21taXNzaW9uIHByb3ZpZGVyIGNvbW1pc3Npb25cbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IHBsYXRmb3JtQ29tbWlzc2lvbiBwbGF0Zm9ybSBjb21taXNzaW9uXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbaW5jb21pbmdQcm92aWRlckNvbW1pc3Npb25dIGNvbW1pc3Npb24gcGFpZCBieSBwcm92aWRlciB0byB1bmRlcmx5aW5nIHByb3ZpZGVyc1xuICAgKiBAcHJvcGVydHkge051bWJlcn0gW2luY29taW5nUGxhdGZvcm1Db21taXNzaW9uXSBwbGF0Zm9ybSBjb21taXNzaW9uIHBhaWQgYnkgcHJvdmlkZXIgdG8gdW5kZXJseWluZyBwcm92aWRlcnNcbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFtxdWFudGl0eV0gdHJhZGUgdm9sdW1lXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbbG90UHJpY2VdIHRyYWRlIGxvdCBwcmljZVxuICAgKiBAcHJvcGVydHkge051bWJlcn0gW3RpY2tQcmljZV0gdHJhZGUgdGljayBwcmljZVxuICAgKiBAcHJvcGVydHkge051bWJlcn0gW2Ftb3VudF0gdHJhZGUgYW1vdW50XG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbY29tbWlzc2lvbl0gdHJhZGUgY29tbWlzc2lvblxuICAgKiBAcHJvcGVydHkge051bWJlcn0gc3dhcCB0cmFkZSBzd2FwXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBwcm9maXQgdHJhZGUgcHJvZml0XG4gICAqIEBwcm9wZXJ0eSB7Q29weUZhY3RvcnlUcmFuc2FjdGlvbk1ldHJpY3N9IFttZXRyaWNzXSB0cmFkZSBjb3B5aW5nIG1ldHJpY3Mgc3VjaCBhcyBzbGlwcGFnZSBhbmQgbGF0ZW5jaWVzLiBNZWFzdXJlZFxuICAgKiBzZWxlY3RpdmVseSBmb3IgY29waWVkIHRyYWRlc1xuICAgKi9cblxuICAvKipcbiAgICogVHJhZGUgY29weWluZyBtZXRyaWNzIHN1Y2ggYXMgc2xpcHBhZ2UgYW5kIGxhdGVuY2llc1xuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBDb3B5RmFjdG9yeVRyYW5zYWN0aW9uTWV0cmljc1xuICAgKiBAcHJvcGVydHkge051bWJlcn0gW3RyYWRlQ29weWluZ0xhdGVuY3ldIHRyYWRlIGNvcHlpbmcgbGF0ZW5jeSwgbWVhc3VyZWQgaW4gbWlsbGlzZWNvbmRzIGJhc2VkIG9uIHRyYW5zYWN0aW9uIHRpbWVcbiAgICogcHJvdmlkZWQgYnkgYnJva2VyXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbdHJhZGVDb3B5aW5nU2xpcHBhZ2VJbkJhc2lzUG9pbnRzXSB0cmFkZSBjb3B5aW5nIHNsaXBwYWdlLCBtZWFzdXJlZCBpbiBiYXNpcyBwb2ludHMgKDAuMDFcbiAgICogcGVyY2VudCkgYmFzZWQgb24gdHJhbnNhY3Rpb24gcHJpY2UgcHJvdmlkZWQgYnkgYnJva2VyXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbdHJhZGVDb3B5aW5nU2xpcHBhZ2VJbkFjY291bnRDdXJyZW5jeV0gdHJhZGUgY29weWluZyBzbGlwcGFnZSwgbWVhc3VyZWQgaW4gYWNjb3VudCBjdXJyZW5jeVxuICAgKiBiYXNlZCBvbiB0cmFuc2FjdGlvbiBwcmljZSBwcm92aWRlZCBieSBicm9rZXJcbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFttdEFuZEJyb2tlclNpZ25hbExhdGVuY3ldIHRyYWRlIHNpZ25hbCBsYXRlbmN5IGludHJvZHVjZWQgYnkgYnJva2VyIGFuZCBNVCBwbGF0Zm9ybSwgbWVhc3VyZWRcbiAgICogaW4gbWlsbGlzZWNvbmRzXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbdHJhZGVBbGdvcml0aG1MYXRlbmN5XSB0cmFkZSBhbGdvcml0aG0gbGF0ZW5jeSBpbnRyb2R1Y2VkIGJ5IENvcHlGYWN0b3J5IHNlcnZlcnMsIG1lYXN1cmVkIGluXG4gICAqIG1pbGxpc2Vjb25kc1xuICAgKiBAcHJvcGVydHkge051bWJlcn0gW210QW5kQnJva2VyVHJhZGVMYXRlbmN5XSB0cmFkZSBsYXRlbmN5IGZvciBhIGNvcGllZCB0cmFkZSBpbnRyb2R1Y2VkIGJ5IGJyb2tlciBhbmQgTVQgcGxhdGZvcm0sXG4gICAqIG1lYXN1cmVkIGluIG1pbGxpc2Vjb25kc1xuICAgKi9cblxuICAvKipcbiAgICogUmV0dXJucyBsaXN0IG9mIHRyYW5zYWN0aW9ucyBvbiB0aGUgc3RyYXRlZ2llcyB0aGUgY3VycmVudCB1c2VyIHByb3ZpZGVzIHRvIG90aGVyIHVzZXJzXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2hpc3RvcnkvZ2V0UHJvdmlkZWRUcmFuc2FjdGlvbnMvXG4gICAqIEBwYXJhbSB7RGF0ZX0gZnJvbSB0aW1lIHRvIGxvYWQgdHJhbnNhY3Rpb25zIGZyb21cbiAgICogQHBhcmFtIHtEYXRlfSB0aWxsIHRpbWUgdG8gbG9hZCB0cmFuc2FjdGlvbnMgdGlsbFxuICAgKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFtzdHJhdGVneUlkc10gbGlzdCBvZiBzdHJhdGVneSBpZHMgdG8gZmlsdGVyIHRyYW5zYWN0aW9ucyBieVxuICAgKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFtzdWJzY3JpYmVySWRzXSB0aGUgbGlzdCBvZiBDb3B5RmFjdG9yeSBzdWJzY3JpYmVyIGFjY291bnQgaWRzIHRvIGZpbHRlciBieVxuICAgKiBAcGFyYW0ge251bWJlcn0gW29mZnNldF0gcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgdmFsdWUgaXMgMFxuICAgKiBAcGFyYW0ge251bWJlcn0gW2xpbWl0XSBwYWdpbmF0aW9uIGxpbWl0LiBEZWZhdWx0IHZhbHVlIGlzIDEwMDBcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVRyYW5zYWN0aW9uPj59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggdHJhbnNhY3Rpb25zIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRQcm92aWRlZFRyYW5zYWN0aW9ucyhmcm9tLCB0aWxsLCBzdHJhdGVneUlkcywgc3Vic2NyaWJlcklkcywgb2Zmc2V0LCBsaW1pdCkge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRQcm92aWRlZFRyYW5zYWN0aW9ucycpO1xuICAgIH1cbiAgICBsZXQgcGFyYW1zID0ge1xuICAgICAgZnJvbSxcbiAgICAgIHRpbGxcbiAgICB9O1xuICAgIGlmIChzdHJhdGVneUlkcykge1xuICAgICAgcGFyYW1zLnN0cmF0ZWd5SWQgPSBzdHJhdGVneUlkcztcbiAgICB9XG4gICAgaWYgKHN1YnNjcmliZXJJZHMpIHtcbiAgICAgIHBhcmFtcy5zdWJzY3JpYmVySWQgPSBzdWJzY3JpYmVySWRzO1xuICAgIH1cbiAgICBpZiAob2Zmc2V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHBhcmFtcy5vZmZzZXQgPSBvZmZzZXQ7XG4gICAgfVxuICAgIGlmIChsaW1pdCkge1xuICAgICAgcGFyYW1zLmxpbWl0ID0gbGltaXQ7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6ICcvdXNlcnMvY3VycmVudC9wcm92aWRlZC10cmFuc2FjdGlvbnMnLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIHBhcmFtcyxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIGxldCB0cmFuc2FjdGlvbnMgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMsIHRydWUpO1xuICAgIHRyYW5zYWN0aW9ucy5mb3JFYWNoKHQgPT4gdC50aW1lID0gbmV3IERhdGUodC50aW1lKSk7XG4gICAgcmV0dXJuIHRyYW5zYWN0aW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGxpc3Qgb2YgdHJhZGVzIG9uIHRoZSBzdHJhdGVnaWVzIHRoZSBjdXJyZW50IHVzZXIgc3Vic2NyaWJlZCB0b1xuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9oaXN0b3J5L2dldFN1YnNjcmlwdGlvblRyYW5zYWN0aW9ucy9cbiAgICogQHBhcmFtIHtEYXRlfSBmcm9tIHRpbWUgdG8gbG9hZCB0cmFuc2FjdGlvbnMgZnJvbVxuICAgKiBAcGFyYW0ge0RhdGV9IHRpbGwgdGltZSB0byBsb2FkIHRyYW5zYWN0aW9ucyB0aWxsXG4gICAqIEBwYXJhbSB7QXJyYXk8U3RyaW5nPn0gW3N0cmF0ZWd5SWRzXSBsaXN0IG9mIHN0cmF0ZWd5IGlkcyB0byBmaWx0ZXIgdHJhbnNhY3Rpb25zIGJ5XG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gW3N1YnNjcmliZXJJZHNdIHRoZSBsaXN0IG9mIENvcHlGYWN0b3J5IHN1YnNjcmliZXIgYWNjb3VudCBpZHMgdG8gZmlsdGVyIGJ5XG4gICAqIEBwYXJhbSB7TnVtYmVyfSBvZmZzZXQgcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgdmFsdWUgaXMgMFxuICAgKiBAcGFyYW0ge051bWJlcn0gbGltaXQgcGFnaW5hdGlvbiBsaW1pdC4gRGVmYXVsdCB2YWx1ZSBpcyAxMDAwXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8Q29weUZhY3RvcnlUcmFuc2FjdGlvbj4+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIHRyYW5zYWN0aW9ucyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3Vic2NyaXB0aW9uVHJhbnNhY3Rpb25zKGZyb20sIHRpbGwsIHN0cmF0ZWd5SWRzLCBzdWJzY3JpYmVySWRzLCBvZmZzZXQsIGxpbWl0KSB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2dldFN1YnNjcmlwdGlvblRyYW5zYWN0aW9ucycpO1xuICAgIH1cbiAgICBsZXQgcGFyYW1zID0ge1xuICAgICAgZnJvbSxcbiAgICAgIHRpbGxcbiAgICB9O1xuICAgIGlmIChzdHJhdGVneUlkcykge1xuICAgICAgcGFyYW1zLnN0cmF0ZWd5SWQgPSBzdHJhdGVneUlkcztcbiAgICB9XG4gICAgaWYgKHN1YnNjcmliZXJJZHMpIHtcbiAgICAgIHBhcmFtcy5zdWJzY3JpYmVySWQgPSBzdWJzY3JpYmVySWRzO1xuICAgIH1cbiAgICBpZiAob2Zmc2V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHBhcmFtcy5vZmZzZXQgPSBvZmZzZXQ7XG4gICAgfVxuICAgIGlmIChsaW1pdCkge1xuICAgICAgcGFyYW1zLmxpbWl0ID0gbGltaXQ7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6ICcvdXNlcnMvY3VycmVudC9zdWJzY3JpcHRpb24tdHJhbnNhY3Rpb25zJyxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBwYXJhbXMsXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICBsZXQgdHJhbnNhY3Rpb25zID0gYXdhaXQgdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzLCB0cnVlKTtcbiAgICB0cmFuc2FjdGlvbnMuZm9yRWFjaCh0ID0+IHQudGltZSA9IG5ldyBEYXRlKHQudGltZSkpO1xuICAgIHJldHVybiB0cmFuc2FjdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0cmF0ZWd5IHRyYW5zYWN0aW9uIGxpc3RlbmVyIGFuZCBjcmVhdGVzIGEgam9iIHRvIG1ha2UgcmVxdWVzdHNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvbkxpc3RlbmVyfSBsaXN0ZW5lciB0cmFuc2FjdGlvbiBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0RhdGV9IFtzdGFydFRpbWVdIHRyYW5zYWN0aW9uIHNlYXJjaCBzdGFydCB0aW1lXG4gICAqIEByZXR1cm4ge1N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFN0cmF0ZWd5VHJhbnNhY3Rpb25MaXN0ZW5lcihsaXN0ZW5lciwgc3RyYXRlZ3lJZCwgc3RhcnRUaW1lKSB7XG4gICAgcmV0dXJuIHRoaXMuX3RyYW5zYWN0aW9uTGlzdGVuZXJNYW5hZ2VyLmFkZFN0cmF0ZWd5VHJhbnNhY3Rpb25MaXN0ZW5lcihsaXN0ZW5lciwgc3RyYXRlZ3lJZCwgc3RhcnRUaW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN0cmF0ZWd5IHRyYW5zYWN0aW9uIGxpc3RlbmVyIGFuZCBjYW5jZWxzIHRoZSBldmVudCBzdHJlYW1cbiAgICogQHBhcmFtIHtTdHJpbmd9IGxpc3RlbmVySWQgc3RyYXRlZ3kgdHJhbnNhY3Rpb24gbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVN0cmF0ZWd5VHJhbnNhY3Rpb25MaXN0ZW5lcihsaXN0ZW5lcklkKSB7XG4gICAgdGhpcy5fdHJhbnNhY3Rpb25MaXN0ZW5lck1hbmFnZXIucmVtb3ZlU3RyYXRlZ3lUcmFuc2FjdGlvbkxpc3RlbmVyKGxpc3RlbmVySWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdWJzY3JpYmVyIHRyYW5zYWN0aW9uIGxpc3RlbmVyIGFuZCBjcmVhdGVzIGEgam9iIHRvIG1ha2UgcmVxdWVzdHNcbiAgICogQHBhcmFtIHtUcmFuc2FjdGlvbkxpc3RlbmVyfSBsaXN0ZW5lciB0cmFuc2FjdGlvbiBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtEYXRlfSBbc3RhcnRUaW1lXSB0cmFuc2FjdGlvbiBzZWFyY2ggc3RhcnQgdGltZVxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGxpc3RlbmVyIGlkXG4gICAqL1xuICBhZGRTdWJzY3JpYmVyVHJhbnNhY3Rpb25MaXN0ZW5lcihsaXN0ZW5lciwgc3Vic2NyaWJlcklkLCBzdGFydFRpbWUpIHtcbiAgICByZXR1cm4gdGhpcy5fdHJhbnNhY3Rpb25MaXN0ZW5lck1hbmFnZXIuYWRkU3Vic2NyaWJlclRyYW5zYWN0aW9uTGlzdGVuZXIobGlzdGVuZXIsIHN1YnNjcmliZXJJZCwgc3RhcnRUaW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN1YnNjcmliZXIgdHJhbnNhY3Rpb24gbGlzdGVuZXIgYW5kIGNhbmNlbHMgdGhlIGV2ZW50IHN0cmVhbVxuICAgKiBAcGFyYW0ge1N0cmluZ30gbGlzdGVuZXJJZCBzdWJzY3JpYmVyIHRyYW5zYWN0aW9uIGxpc3RlbmVyIGlkXG4gICAqL1xuICByZW1vdmVTdWJzY3JpYmVyVHJhbnNhY3Rpb25MaXN0ZW5lcihsaXN0ZW5lcklkKSB7XG4gICAgdGhpcy5fdHJhbnNhY3Rpb25MaXN0ZW5lck1hbmFnZXIucmVtb3ZlU3Vic2NyaWJlclRyYW5zYWN0aW9uTGlzdGVuZXIobGlzdGVuZXJJZCk7XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkhpc3RvcnlDbGllbnQiLCJNZXRhQXBpQ2xpZW50IiwiY29uc3RydWN0b3IiLCJkb21haW5DbGllbnQiLCJfZG9tYWluQ2xpZW50IiwiX3RyYW5zYWN0aW9uTGlzdGVuZXJNYW5hZ2VyIiwiVHJhbnNhY3Rpb25MaXN0ZW5lck1hbmFnZXIiLCJnZXRQcm92aWRlZFRyYW5zYWN0aW9ucyIsImZyb20iLCJ0aWxsIiwic3RyYXRlZ3lJZHMiLCJzdWJzY3JpYmVySWRzIiwib2Zmc2V0IiwibGltaXQiLCJfaXNOb3RKd3RUb2tlbiIsIl9oYW5kbGVOb0FjY2Vzc0Vycm9yIiwicGFyYW1zIiwic3RyYXRlZ3lJZCIsInN1YnNjcmliZXJJZCIsInVuZGVmaW5lZCIsIm9wdHMiLCJ1cmwiLCJtZXRob2QiLCJoZWFkZXJzIiwiX3Rva2VuIiwianNvbiIsInRyYW5zYWN0aW9ucyIsInJlcXVlc3RDb3B5RmFjdG9yeSIsImZvckVhY2giLCJ0IiwidGltZSIsIkRhdGUiLCJnZXRTdWJzY3JpcHRpb25UcmFuc2FjdGlvbnMiLCJhZGRTdHJhdGVneVRyYW5zYWN0aW9uTGlzdGVuZXIiLCJsaXN0ZW5lciIsInN0YXJ0VGltZSIsInJlbW92ZVN0cmF0ZWd5VHJhbnNhY3Rpb25MaXN0ZW5lciIsImxpc3RlbmVySWQiLCJhZGRTdWJzY3JpYmVyVHJhbnNhY3Rpb25MaXN0ZW5lciIsInJlbW92ZVN1YnNjcmliZXJUcmFuc2FjdGlvbkxpc3RlbmVyIl0sIm1hcHBpbmdzIjoiQUFBQTs7OzsrQkFLQTs7O0NBR0MsR0FDRDs7O2VBQXFCQTs7O3NFQVBLO21GQUNhOzs7Ozs7QUFNeEIsSUFBQSxBQUFNQSxnQkFBTixNQUFNQSxzQkFBc0JDLHNCQUFhO0lBRXREOzs7R0FHQyxHQUNEQyxZQUFZQyxZQUFZLENBQUU7UUFDeEIsS0FBSyxDQUFDQTtRQUNOLElBQUksQ0FBQ0MsYUFBYSxHQUFHRDtRQUNyQixJQUFJLENBQUNFLDJCQUEyQixHQUFHLElBQUlDLG1DQUEwQixDQUFDSDtJQUNwRTtJQUVBOzs7Ozs7O0dBT0MsR0FFRDs7Ozs7R0FLQyxHQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQ0MsR0FFRDs7Ozs7Ozs7Ozs7Ozs7O0dBZUMsR0FFRDs7Ozs7Ozs7OztHQVVDLEdBQ0QsTUFBTUksd0JBQXdCQyxJQUFJLEVBQUVDLElBQUksRUFBRUMsV0FBVyxFQUFFQyxhQUFhLEVBQUVDLE1BQU0sRUFBRUMsS0FBSyxFQUFFO1FBQ25GLElBQUksSUFBSSxDQUFDQyxjQUFjLElBQUk7WUFDekIsT0FBTyxJQUFJLENBQUNDLG9CQUFvQixDQUFDO1FBQ25DLENBQUM7UUFDRCxJQUFJQyxTQUFTO1lBQ1hSO1lBQ0FDO1FBQ0Y7UUFDQSxJQUFJQyxhQUFhO1lBQ2ZNLE9BQU9DLFVBQVUsR0FBR1A7UUFDdEIsQ0FBQztRQUNELElBQUlDLGVBQWU7WUFDakJLLE9BQU9FLFlBQVksR0FBR1A7UUFDeEIsQ0FBQztRQUNELElBQUlDLFdBQVdPLFdBQVc7WUFDeEJILE9BQU9KLE1BQU0sR0FBR0E7UUFDbEIsQ0FBQztRQUNELElBQUlDLE9BQU87WUFDVEcsT0FBT0gsS0FBSyxHQUFHQTtRQUNqQixDQUFDO1FBQ0QsTUFBTU8sT0FBTztZQUNYQyxLQUFLO1lBQ0xDLFFBQVE7WUFDUkMsU0FBUztnQkFDUCxjQUFjLElBQUksQ0FBQ0MsTUFBTTtZQUMzQjtZQUNBUjtZQUNBUyxNQUFNLElBQUk7UUFDWjtRQUNBLElBQUlDLGVBQWUsTUFBTSxJQUFJLENBQUN0QixhQUFhLENBQUN1QixrQkFBa0IsQ0FBQ1AsTUFBTSxJQUFJO1FBQ3pFTSxhQUFhRSxPQUFPLENBQUNDLENBQUFBLElBQUtBLEVBQUVDLElBQUksR0FBRyxJQUFJQyxLQUFLRixFQUFFQyxJQUFJO1FBQ2xELE9BQU9KO0lBQ1Q7SUFFQTs7Ozs7Ozs7OztHQVVDLEdBQ0QsTUFBTU0sNEJBQTRCeEIsSUFBSSxFQUFFQyxJQUFJLEVBQUVDLFdBQVcsRUFBRUMsYUFBYSxFQUFFQyxNQUFNLEVBQUVDLEtBQUssRUFBRTtRQUN2RixJQUFJLElBQUksQ0FBQ0MsY0FBYyxJQUFJO1lBQ3pCLE9BQU8sSUFBSSxDQUFDQyxvQkFBb0IsQ0FBQztRQUNuQyxDQUFDO1FBQ0QsSUFBSUMsU0FBUztZQUNYUjtZQUNBQztRQUNGO1FBQ0EsSUFBSUMsYUFBYTtZQUNmTSxPQUFPQyxVQUFVLEdBQUdQO1FBQ3RCLENBQUM7UUFDRCxJQUFJQyxlQUFlO1lBQ2pCSyxPQUFPRSxZQUFZLEdBQUdQO1FBQ3hCLENBQUM7UUFDRCxJQUFJQyxXQUFXTyxXQUFXO1lBQ3hCSCxPQUFPSixNQUFNLEdBQUdBO1FBQ2xCLENBQUM7UUFDRCxJQUFJQyxPQUFPO1lBQ1RHLE9BQU9ILEtBQUssR0FBR0E7UUFDakIsQ0FBQztRQUNELE1BQU1PLE9BQU87WUFDWEMsS0FBSztZQUNMQyxRQUFRO1lBQ1JDLFNBQVM7Z0JBQ1AsY0FBYyxJQUFJLENBQUNDLE1BQU07WUFDM0I7WUFDQVI7WUFDQVMsTUFBTSxJQUFJO1FBQ1o7UUFDQSxJQUFJQyxlQUFlLE1BQU0sSUFBSSxDQUFDdEIsYUFBYSxDQUFDdUIsa0JBQWtCLENBQUNQLE1BQU0sSUFBSTtRQUN6RU0sYUFBYUUsT0FBTyxDQUFDQyxDQUFBQSxJQUFLQSxFQUFFQyxJQUFJLEdBQUcsSUFBSUMsS0FBS0YsRUFBRUMsSUFBSTtRQUNsRCxPQUFPSjtJQUNUO0lBRUE7Ozs7OztHQU1DLEdBQ0RPLCtCQUErQkMsUUFBUSxFQUFFakIsVUFBVSxFQUFFa0IsU0FBUyxFQUFFO1FBQzlELE9BQU8sSUFBSSxDQUFDOUIsMkJBQTJCLENBQUM0Qiw4QkFBOEIsQ0FBQ0MsVUFBVWpCLFlBQVlrQjtJQUMvRjtJQUVBOzs7R0FHQyxHQUNEQyxrQ0FBa0NDLFVBQVUsRUFBRTtRQUM1QyxJQUFJLENBQUNoQywyQkFBMkIsQ0FBQytCLGlDQUFpQyxDQUFDQztJQUNyRTtJQUVBOzs7Ozs7R0FNQyxHQUNEQyxpQ0FBaUNKLFFBQVEsRUFBRWhCLFlBQVksRUFBRWlCLFNBQVMsRUFBRTtRQUNsRSxPQUFPLElBQUksQ0FBQzlCLDJCQUEyQixDQUFDaUMsZ0NBQWdDLENBQUNKLFVBQVVoQixjQUFjaUI7SUFDbkc7SUFFQTs7O0dBR0MsR0FDREksb0NBQW9DRixVQUFVLEVBQUU7UUFDOUMsSUFBSSxDQUFDaEMsMkJBQTJCLENBQUNrQyxtQ0FBbUMsQ0FBQ0Y7SUFDdkU7QUFFRiJ9