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)
296 lines (295 loc) • 38 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, /**
* metaapi.cloud CopyFactory trading API (trade copying trading API) client (see
* https://metaapi.cloud/docs/copyfactory/)
*/ "default", {
enumerable: true,
get: function() {
return TradingClient;
}
});
const _metaapiclient = /*#__PURE__*/ _interop_require_default(require("../metaapi.client"));
const _subscriberSignalclient = /*#__PURE__*/ _interop_require_default(require("./subscriberSignal.client"));
const _strategySignalclient = /*#__PURE__*/ _interop_require_default(require("./strategySignal.client"));
const _stopoutListenerManager = /*#__PURE__*/ _interop_require_default(require("./streaming/stopoutListenerManager"));
const _userLogListenerManager = /*#__PURE__*/ _interop_require_default(require("./streaming/userLogListenerManager"));
_export_star(require("./trading.client.schemas"), exports);
function _export_star(from, to) {
Object.keys(from).forEach(function(k) {
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
Object.defineProperty(to, k, {
enumerable: true,
get: function() {
return from[k];
}
});
}
});
return from;
}
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let TradingClient = class TradingClient extends _metaapiclient.default {
_configurationClient;
_stopoutListenerManager;
_userLogListenerManager;
/**
* Constructs CopyFactory trading API client instance
* @param {DomainClient} domainClient domain client
* @param {ConfigurationClient} configurationClient configuration client
*/ constructor(domainClient, configurationClient){
super(domainClient);
this._domainClient = domainClient;
this._configurationClient = configurationClient;
this._stopoutListenerManager = new _stopoutListenerManager.default(domainClient);
this._userLogListenerManager = new _userLogListenerManager.default(domainClient);
}
/**
* Resynchronizes the account. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resynchronize/
* @param {string} accountId account id
* @param {Array<string>} [strategyIds] array of strategy ids to recynchronize. Default is to synchronize all
* strategies
* @param {Array<string>} [positionIds] array of position ids to resynchronize. Default is to synchronize all
* positions
* @return {Promise} promise which resolves when resynchronization is scheduled
*/ async resynchronize(accountId, strategyIds, positionIds) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("resynchronize");
}
const opts = {
url: `/users/current/subscribers/${accountId}/resynchronize`,
method: "POST",
headers: {
"auth-token": this._token
},
params: {
strategyId: strategyIds,
positionId: positionIds
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Generates an instance of signal client for a subscriber
* @param {string} subscriberId subscriber account id
*/ async getSubscriberSignalClient(subscriberId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("getSubscriberSignalClient");
}
let accountData = await this._domainClient.getAccountInfo(subscriberId);
const host = await this._domainClient.getSignalClientHost(accountData.regions);
return new _subscriberSignalclient.default(accountData.id, host, this._domainClient);
}
/**
* Generates an instance of signal client for a strategy
* @param {string} strategyId strategy id
*/ async getStrategySignalClient(strategyId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("getStrategySignalClient");
}
const strategy = await this._configurationClient.getStrategy(strategyId);
const accountData = await this._domainClient.getAccountInfo(strategy.accountId);
const host = await this._domainClient.getSignalClientHost(accountData.regions);
return new _strategySignalclient.default(accountData.id, strategyId, host, this._domainClient);
}
/**
* Returns subscriber account stopouts. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getStopOuts/
* @param {string} subscriberId subscriber id
* @return {Promise<Array<CopyFactoryStrategyStopout>>} promise which resolves with stopouts found
*/ async getStopouts(subscriberId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("getStopouts");
}
const opts = {
url: `/users/current/subscribers/${subscriberId}/stopouts`,
method: "GET",
headers: {
"auth-token": this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Resets subscription stopouts. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resetSubscriptionStopOuts/
* @param {string} subscriberId subscriber id
* @param {string} strategyId strategy id
* @param {CopyFactoryStrategyStopoutReason} reason stopout reason to reset
* yearly-equity, monthly-equity, daily-equity
* @return {Promise} promise which resolves when the stopouts are reset
*/ resetSubscriptionStopouts(subscriberId, strategyId, reason) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("resetSubscriptionStopouts");
}
const opts = {
url: `/users/current/subscribers/${subscriberId}/subscription-strategies/` + `${strategyId}/stopouts/${reason}/reset`,
method: "POST",
headers: {
"auth-token": this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Resets subscriber stopouts. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/resetSubscriberStopOuts/
* @param {string} subscriberId subscriber id
* @param {CopyFactoryStrategyStopoutReason} reason stopout reason to reset
* yearly-equity, monthly-equity, daily-equity
* @return {Promise} promise which resolves when the stopouts are reset
*/ resetSubscriberStopouts(subscriberId, reason) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("resetSubscriberStopouts");
}
const opts = {
url: `/users/current/subscribers/${subscriberId}/stopouts/${reason}/reset`,
method: "POST",
headers: {
"auth-token": this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Returns copy trading user log for an account and time range. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getUserLog/
* @param {string} subscriberId subscriber id
* @param {Date} [startTime] time to start loading data from
* @param {Date} [endTime] time to stop loading data at
* @param {string} [strategyId] strategy id filter
* @param {string} [positionId] position id filter
* @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level
* @param {Number} [offset] pagination offset. Default is 0
* @param {Number} [limit] pagination limit. Default is 1000
* @return {Promise<Array<CopyFactoryUserLogMessage>>} promise which resolves with log records found
*/ async getUserLog(subscriberId, startTime, endTime, strategyId, positionId, level, offset = 0, limit = 1000) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("getUserLog");
}
const opts = {
url: `/users/current/subscribers/${subscriberId}/user-log`,
method: "GET",
params: {
startTime,
endTime,
strategyId,
positionId,
level,
offset,
limit
},
headers: {
"auth-token": this._token
},
json: true
};
let result = await this._domainClient.requestCopyFactory(opts, true);
if (result) {
result.map((r)=>r.time = new Date(r.time));
}
return result;
}
/**
* Returns event log for CopyFactory strategy, sorted in reverse chronological order. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/trading/getStrategyLog/
* @param {string} strategyId strategy id to retrieve log for
* @param {Date} [startTime] time to start loading data from
* @param {Date} [endTime] time to stop loading data at
* @param {string} [positionId] position id filter
* @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level
* @param {Number} [offset] pagination offset. Default is 0
* @param {Number} [limit] pagination limit. Default is 1000
* @return {Promise<Array<CopyFactoryUserLogMessage>>} promise which resolves with log records found
*/ async getStrategyLog(strategyId, startTime, endTime, positionId, level, offset = 0, limit = 1000) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError("getStrategyLog");
}
const opts = {
url: `/users/current/strategies/${strategyId}/user-log`,
method: "GET",
params: {
startTime,
endTime,
positionId,
level,
offset,
limit
},
headers: {
"auth-token": this._token
},
json: true
};
let result = await this._domainClient.requestCopyFactory(opts, true);
if (result) {
result.map((r)=>r.time = new Date(r.time));
}
return result;
}
/**
* Adds a stopout listener and creates a job to make requests
* @param {StopoutListener} listener stopout listener
* @param {string} [accountId] account id
* @param {string} [strategyId] strategy id
* @param {Number} [sequenceNumber] sequence number
* @return {string} listener id
*/ addStopoutListener(listener, accountId, strategyId, sequenceNumber) {
return this._stopoutListenerManager.addStopoutListener(listener, accountId, strategyId, sequenceNumber);
}
/**
* Removes stopout listener and cancels the event stream
* @param {string} listenerId stopout listener id
*/ removeStopoutListener(listenerId) {
this._stopoutListenerManager.removeStopoutListener(listenerId);
}
/**
* Adds a strategy log listener and creates a job to make requests
* @param {UserLogListener} listener user log listener
* @param {string} strategyId strategy id
* @param {Date} [startTime] log search start time
* @param {string} [positionId] position id filter
* @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level
* @param {Number} [limit] log pagination limit
* @return {string} listener id
*/ addStrategyLogListener(listener, strategyId, startTime, positionId, level, limit) {
return this._userLogListenerManager.addStrategyLogListener(listener, strategyId, startTime, positionId, level, limit);
}
/**
* Removes strategy log listener and cancels the event stream
* @param {string} listenerId strategy log listener id
*/ removeStrategyLogListener(listenerId) {
this._userLogListenerManager.removeStrategyLogListener(listenerId);
}
/**
* Adds a subscriber log listener and creates a job to make requests
* @param {UserLogListener} listener user log listener
* @param {string} subscriberId subscriber id
* @param {Date} [startTime] log search start time
* @param {string} [strategyId] strategy id filter
* @param {string} [positionId] position id filter
* @param {'DEBUG'|'INFO'|'WARN'|'ERROR'} [level] minimum severity level
* @param {Number} [limit] log pagination limit
* @return {string} listener id
*/ addSubscriberLogListener(listener, subscriberId, startTime, strategyId, positionId, level, limit) {
return this._userLogListenerManager.addSubscriberLogListener(listener, subscriberId, startTime, strategyId, positionId, level, limit);
}
/**
* Removes subscriber log listener and cancels the event stream
* @param {string} listenerId subscriber log listener id
*/ removeSubscriberLogListener(listenerId) {
this._userLogListenerManager.removeSubscriberLogListener(listenerId);
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBNZXRhQXBpQ2xpZW50IGZyb20gJy4uL21ldGFhcGkuY2xpZW50JztcbmltcG9ydCBTdWJzY3JpYmVyU2lnbmFsQ2xpZW50IGZyb20gJy4vc3Vic2NyaWJlclNpZ25hbC5jbGllbnQnO1xuaW1wb3J0IFN0cmF0ZWd5U2lnbmFsQ2xpZW50IGZyb20gJy4vc3RyYXRlZ3lTaWduYWwuY2xpZW50JztcbmltcG9ydCBTdG9wb3V0TGlzdGVuZXJNYW5hZ2VyIGZyb20gJy4vc3RyZWFtaW5nL3N0b3BvdXRMaXN0ZW5lck1hbmFnZXInO1xuaW1wb3J0IFVzZXJMb2dMaXN0ZW5lck1hbmFnZXIgZnJvbSAnLi9zdHJlYW1pbmcvdXNlckxvZ0xpc3RlbmVyTWFuYWdlcic7XG5pbXBvcnQgQ29uZmlndXJhdGlvbkNsaWVudCBmcm9tICcuL2NvbmZpZ3VyYXRpb24uY2xpZW50JztcbmltcG9ydCBEb21haW5DbGllbnQgZnJvbSAnLi4vZG9tYWluLmNsaWVudCc7XG5pbXBvcnQgU3RvcG91dExpc3RlbmVyIGZyb20gJy4vc3RyZWFtaW5nL3N0b3BvdXRMaXN0ZW5lcic7XG5pbXBvcnQgVXNlckxvZ0xpc3RlbmVyIGZyb20gJy4vc3RyZWFtaW5nL3VzZXJMb2dMaXN0ZW5lcic7XG5pbXBvcnQge1xuICBDb3B5RmFjdG9yeVN0cmF0ZWd5U3RvcG91dCwgQ29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXRSZWFzb24sIENvcHlGYWN0b3J5VXNlckxvZ01lc3NhZ2Vcbn0gZnJvbSAnLi90cmFkaW5nLmNsaWVudC5zY2hlbWFzJztcblxuZXhwb3J0ICogZnJvbSAnLi90cmFkaW5nLmNsaWVudC5zY2hlbWFzJztcblxuLyoqXG4gKiBtZXRhYXBpLmNsb3VkIENvcHlGYWN0b3J5IHRyYWRpbmcgQVBJICh0cmFkZSBjb3B5aW5nIHRyYWRpbmcgQVBJKSBjbGllbnQgKHNlZVxuICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvKVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUcmFkaW5nQ2xpZW50IGV4dGVuZHMgTWV0YUFwaUNsaWVudCB7XG4gIFxuICBwcml2YXRlIF9jb25maWd1cmF0aW9uQ2xpZW50OiBDb25maWd1cmF0aW9uQ2xpZW50O1xuICBwcml2YXRlIF9zdG9wb3V0TGlzdGVuZXJNYW5hZ2VyOiBTdG9wb3V0TGlzdGVuZXJNYW5hZ2VyO1xuICBwcml2YXRlIF91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyOiBVc2VyTG9nTGlzdGVuZXJNYW5hZ2VyO1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIENvcHlGYWN0b3J5IHRyYWRpbmcgQVBJIGNsaWVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge0RvbWFpbkNsaWVudH0gZG9tYWluQ2xpZW50IGRvbWFpbiBjbGllbnRcbiAgICogQHBhcmFtIHtDb25maWd1cmF0aW9uQ2xpZW50fSBjb25maWd1cmF0aW9uQ2xpZW50IGNvbmZpZ3VyYXRpb24gY2xpZW50XG4gICAqL1xuICBjb25zdHJ1Y3Rvcihkb21haW5DbGllbnQ6IERvbWFpbkNsaWVudCwgY29uZmlndXJhdGlvbkNsaWVudDogQ29uZmlndXJhdGlvbkNsaWVudCkge1xuICAgIHN1cGVyKGRvbWFpbkNsaWVudCk7XG4gICAgdGhpcy5fZG9tYWluQ2xpZW50ID0gZG9tYWluQ2xpZW50O1xuICAgIHRoaXMuX2NvbmZpZ3VyYXRpb25DbGllbnQgPSBjb25maWd1cmF0aW9uQ2xpZW50O1xuICAgIHRoaXMuX3N0b3BvdXRMaXN0ZW5lck1hbmFnZXIgPSBuZXcgU3RvcG91dExpc3RlbmVyTWFuYWdlcihkb21haW5DbGllbnQpO1xuICAgIHRoaXMuX3VzZXJMb2dMaXN0ZW5lck1hbmFnZXIgPSBuZXcgVXNlckxvZ0xpc3RlbmVyTWFuYWdlcihkb21haW5DbGllbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc3luY2hyb25pemVzIHRoZSBhY2NvdW50LiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvdHJhZGluZy9yZXN5bmNocm9uaXplL1xuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBbc3RyYXRlZ3lJZHNdIGFycmF5IG9mIHN0cmF0ZWd5IGlkcyB0byByZWN5bmNocm9uaXplLiBEZWZhdWx0IGlzIHRvIHN5bmNocm9uaXplIGFsbFxuICAgKiBzdHJhdGVnaWVzXG4gICAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gW3Bvc2l0aW9uSWRzXSBhcnJheSBvZiBwb3NpdGlvbiBpZHMgdG8gcmVzeW5jaHJvbml6ZS4gRGVmYXVsdCBpcyB0byBzeW5jaHJvbml6ZSBhbGxcbiAgICogcG9zaXRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiByZXN5bmNocm9uaXphdGlvbiBpcyBzY2hlZHVsZWRcbiAgICovXG4gIGFzeW5jIHJlc3luY2hyb25pemUoYWNjb3VudElkOiBzdHJpbmcsIHN0cmF0ZWd5SWRzPzogQXJyYXk8c3RyaW5nPiwgcG9zaXRpb25JZHM/OiBBcnJheTxzdHJpbmc+KTogUHJvbWlzZTxhbnk+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcigncmVzeW5jaHJvbml6ZScpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3Vic2NyaWJlcnMvJHthY2NvdW50SWR9L3Jlc3luY2hyb25pemVgLFxuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RyYXRlZ3lJZDogc3RyYXRlZ3lJZHMsXG4gICAgICAgIHBvc2l0aW9uSWQ6IHBvc2l0aW9uSWRzXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogR2VuZXJhdGVzIGFuIGluc3RhbmNlIG9mIHNpZ25hbCBjbGllbnQgZm9yIGEgc3Vic2NyaWJlclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgYWNjb3VudCBpZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3Vic2NyaWJlclNpZ25hbENsaWVudChzdWJzY3JpYmVySWQ6IHN0cmluZyk6IFByb21pc2U8U3Vic2NyaWJlclNpZ25hbENsaWVudD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdWJzY3JpYmVyU2lnbmFsQ2xpZW50Jyk7XG4gICAgfVxuXG4gICAgbGV0IGFjY291bnREYXRhID0gYXdhaXQgdGhpcy5fZG9tYWluQ2xpZW50LmdldEFjY291bnRJbmZvKHN1YnNjcmliZXJJZCk7XG4gICAgY29uc3QgaG9zdCA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5nZXRTaWduYWxDbGllbnRIb3N0KGFjY291bnREYXRhLnJlZ2lvbnMpO1xuICAgIHJldHVybiBuZXcgU3Vic2NyaWJlclNpZ25hbENsaWVudChhY2NvdW50RGF0YS5pZCwgaG9zdCwgdGhpcy5fZG9tYWluQ2xpZW50KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmF0ZXMgYW4gaW5zdGFuY2Ugb2Ygc2lnbmFsIGNsaWVudCBmb3IgYSBzdHJhdGVneVxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3RyYXRlZ3lTaWduYWxDbGllbnQoc3RyYXRlZ3lJZDogc3RyaW5nKTogUHJvbWlzZTxTdHJhdGVneVNpZ25hbENsaWVudD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdHJhdGVneVNpZ25hbENsaWVudCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHN0cmF0ZWd5ID0gYXdhaXQgdGhpcy5fY29uZmlndXJhdGlvbkNsaWVudC5nZXRTdHJhdGVneShzdHJhdGVneUlkKTtcbiAgICBjb25zdCBhY2NvdW50RGF0YSA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5nZXRBY2NvdW50SW5mbyhzdHJhdGVneS5hY2NvdW50SWQpO1xuICAgIGNvbnN0IGhvc3QgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQuZ2V0U2lnbmFsQ2xpZW50SG9zdChhY2NvdW50RGF0YS5yZWdpb25zKTtcbiAgICByZXR1cm4gbmV3IFN0cmF0ZWd5U2lnbmFsQ2xpZW50KGFjY291bnREYXRhLmlkLCBzdHJhdGVneUlkLCBob3N0LCB0aGlzLl9kb21haW5DbGllbnQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgc3Vic2NyaWJlciBhY2NvdW50IHN0b3BvdXRzLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvdHJhZGluZy9nZXRTdG9wT3V0cy9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHN1YnNjcmliZXJJZCBzdWJzY3JpYmVyIGlkXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXQ+Pn0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aXRoIHN0b3BvdXRzIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRTdG9wb3V0cyhzdWJzY3JpYmVySWQ6IHN0cmluZyk6IFByb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneVN0b3BvdXQ+PiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2dldFN0b3BvdXRzJyk7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9zdWJzY3JpYmVycy8ke3N1YnNjcmliZXJJZH0vc3RvcG91dHNgLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlc2V0cyBzdWJzY3JpcHRpb24gc3RvcG91dHMuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS90cmFkaW5nL3Jlc2V0U3Vic2NyaXB0aW9uU3RvcE91dHMvXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBzdWJzY3JpYmVySWQgc3Vic2NyaWJlciBpZFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29ufSByZWFzb24gc3RvcG91dCByZWFzb24gdG8gcmVzZXRcbiAgICogeWVhcmx5LWVxdWl0eSwgbW9udGhseS1lcXVpdHksIGRhaWx5LWVxdWl0eVxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHdoaWNoIHJlc29sdmVzIHdoZW4gdGhlIHN0b3BvdXRzIGFyZSByZXNldFxuICAgKi9cbiAgcmVzZXRTdWJzY3JpcHRpb25TdG9wb3V0cyhcbiAgICBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RyYXRlZ3lJZDogc3RyaW5nLCByZWFzb246IENvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29uXG4gICk6IFByb21pc2U8YW55PiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ3Jlc2V0U3Vic2NyaXB0aW9uU3RvcG91dHMnKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L3N1YnNjcmliZXJzLyR7c3Vic2NyaWJlcklkfS9zdWJzY3JpcHRpb24tc3RyYXRlZ2llcy9gICtcbiAgICAgICAgYCR7c3RyYXRlZ3lJZH0vc3RvcG91dHMvJHtyZWFzb259L3Jlc2V0YCxcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogUmVzZXRzIHN1YnNjcmliZXIgc3RvcG91dHMuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS90cmFkaW5nL3Jlc2V0U3Vic2NyaWJlclN0b3BPdXRzL1xuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtDb3B5RmFjdG9yeVN0cmF0ZWd5U3RvcG91dFJlYXNvbn0gcmVhc29uIHN0b3BvdXQgcmVhc29uIHRvIHJlc2V0XG4gICAqIHllYXJseS1lcXVpdHksIG1vbnRobHktZXF1aXR5LCBkYWlseS1lcXVpdHlcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIHRoZSBzdG9wb3V0cyBhcmUgcmVzZXRcbiAgICovXG4gIHJlc2V0U3Vic2NyaWJlclN0b3BvdXRzKHN1YnNjcmliZXJJZDogc3RyaW5nLCByZWFzb246IENvcHlGYWN0b3J5U3RyYXRlZ3lTdG9wb3V0UmVhc29uKTogUHJvbWlzZTxhbnk+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcigncmVzZXRTdWJzY3JpYmVyU3RvcG91dHMnKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L3N1YnNjcmliZXJzLyR7c3Vic2NyaWJlcklkfS9zdG9wb3V0cy8ke3JlYXNvbn0vcmVzZXRgLFxuICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGNvcHkgdHJhZGluZyB1c2VyIGxvZyBmb3IgYW4gYWNjb3VudCBhbmQgdGltZSByYW5nZS4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL3RyYWRpbmcvZ2V0VXNlckxvZy9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHN1YnNjcmliZXJJZCBzdWJzY3JpYmVyIGlkXG4gICAqIEBwYXJhbSB7RGF0ZX0gW3N0YXJ0VGltZV0gdGltZSB0byBzdGFydCBsb2FkaW5nIGRhdGEgZnJvbVxuICAgKiBAcGFyYW0ge0RhdGV9IFtlbmRUaW1lXSB0aW1lIHRvIHN0b3AgbG9hZGluZyBkYXRhIGF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbc3RyYXRlZ3lJZF0gc3RyYXRlZ3kgaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcG9zaXRpb25JZF0gcG9zaXRpb24gaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7J0RFQlVHJ3wnSU5GTyd8J1dBUk4nfCdFUlJPUid9IFtsZXZlbF0gbWluaW11bSBzZXZlcml0eSBsZXZlbFxuICAgKiBAcGFyYW0ge051bWJlcn0gW29mZnNldF0gcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgaXMgMFxuICAgKiBAcGFyYW0ge051bWJlcn0gW2xpbWl0XSBwYWdpbmF0aW9uIGxpbWl0LiBEZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2l0aCBsb2cgcmVjb3JkcyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0VXNlckxvZyhcbiAgICBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RhcnRUaW1lPzogRGF0ZSwgZW5kVGltZT86IERhdGUsIHN0cmF0ZWd5SWQ/OiBzdHJpbmcsIHBvc2l0aW9uSWQ/OiBzdHJpbmcsXG4gICAgbGV2ZWw/OiAnREVCVUcnIHwgJ0lORk8nIHwgJ1dBUk4nIHwgJ0VSUk9SJywgb2Zmc2V0ID0gMCwgbGltaXQgPSAxMDAwXG4gICk6IFByb21pc2U8QXJyYXk8Q29weUZhY3RvcnlVc2VyTG9nTWVzc2FnZT4+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0VXNlckxvZycpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3Vic2NyaWJlcnMvJHtzdWJzY3JpYmVySWR9L3VzZXItbG9nYCxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICBlbmRUaW1lLFxuICAgICAgICBzdHJhdGVneUlkLCBcbiAgICAgICAgcG9zaXRpb25JZCwgXG4gICAgICAgIGxldmVsLFxuICAgICAgICBvZmZzZXQsXG4gICAgICAgIGxpbWl0XG4gICAgICB9LFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgbGV0IHJlc3VsdCA9IGF3YWl0IHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cywgdHJ1ZSk7XG4gICAgaWYgKHJlc3VsdCkge1xuICAgICAgcmVzdWx0Lm1hcChyID0+IHIudGltZSA9IG5ldyBEYXRlKHIudGltZSkpO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZXZlbnQgbG9nIGZvciBDb3B5RmFjdG9yeSBzdHJhdGVneSwgc29ydGVkIGluIHJldmVyc2UgY2hyb25vbG9naWNhbCBvcmRlci4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL3RyYWRpbmcvZ2V0U3RyYXRlZ3lMb2cvIFxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZCB0byByZXRyaWV2ZSBsb2cgZm9yXG4gICAqIEBwYXJhbSB7RGF0ZX0gW3N0YXJ0VGltZV0gdGltZSB0byBzdGFydCBsb2FkaW5nIGRhdGEgZnJvbVxuICAgKiBAcGFyYW0ge0RhdGV9IFtlbmRUaW1lXSB0aW1lIHRvIHN0b3AgbG9hZGluZyBkYXRhIGF0XG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbcG9zaXRpb25JZF0gcG9zaXRpb24gaWQgZmlsdGVyXG4gICAqIEBwYXJhbSB7J0RFQlVHJ3wnSU5GTyd8J1dBUk4nfCdFUlJPUid9IFtsZXZlbF0gbWluaW11bSBzZXZlcml0eSBsZXZlbFxuICAgKiBAcGFyYW0ge051bWJlcn0gW29mZnNldF0gcGFnaW5hdGlvbiBvZmZzZXQuIERlZmF1bHQgaXMgMFxuICAgKiBAcGFyYW0ge051bWJlcn0gW2xpbWl0XSBwYWdpbmF0aW9uIGxpbWl0LiBEZWZhdWx0IGlzIDEwMDBcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj59IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2l0aCBsb2cgcmVjb3JkcyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3RyYXRlZ3lMb2coXG4gICAgc3RyYXRlZ3lJZDogc3RyaW5nLCBzdGFydFRpbWU/OiBEYXRlLCBlbmRUaW1lPzogRGF0ZSwgcG9zaXRpb25JZD86IHN0cmluZyxcbiAgICBsZXZlbD86ICdERUJVRycgfCAnSU5GTycgfCAnV0FSTicgfCAnRVJST1InLCBvZmZzZXQgPSAwLCBsaW1pdCA9IDEwMDBcbiAgKTogUHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVVzZXJMb2dNZXNzYWdlPj4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdHJhdGVneUxvZycpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvc3RyYXRlZ2llcy8ke3N0cmF0ZWd5SWR9L3VzZXItbG9nYCxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBwYXJhbXM6IHtcbiAgICAgICAgc3RhcnRUaW1lLFxuICAgICAgICBlbmRUaW1lLFxuICAgICAgICBwb3NpdGlvbklkLFxuICAgICAgICBsZXZlbCxcbiAgICAgICAgb2Zmc2V0LFxuICAgICAgICBsaW1pdFxuICAgICAgfSxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIGxldCByZXN1bHQgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMsIHRydWUpO1xuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIHJlc3VsdC5tYXAociA9PiByLnRpbWUgPSBuZXcgRGF0ZShyLnRpbWUpKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgc3RvcG91dCBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7U3RvcG91dExpc3RlbmVyfSBsaXN0ZW5lciBzdG9wb3V0IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYWNjb3VudElkXSBhY2NvdW50IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbc3RyYXRlZ3lJZF0gc3RyYXRlZ3kgaWRcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtzZXF1ZW5jZU51bWJlcl0gc2VxdWVuY2UgbnVtYmVyXG4gICAqIEByZXR1cm4ge3N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFN0b3BvdXRMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogU3RvcG91dExpc3RlbmVyLCBhY2NvdW50SWQ/OiBzdHJpbmcsIHN0cmF0ZWd5SWQ/OiBzdHJpbmcsIHNlcXVlbmNlTnVtYmVyPzogbnVtYmVyXG4gICk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX3N0b3BvdXRMaXN0ZW5lck1hbmFnZXIuYWRkU3RvcG91dExpc3RlbmVyKGxpc3RlbmVyLCBhY2NvdW50SWQsIHN0cmF0ZWd5SWQsIHNlcXVlbmNlTnVtYmVyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN0b3BvdXQgbGlzdGVuZXIgYW5kIGNhbmNlbHMgdGhlIGV2ZW50IHN0cmVhbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGlzdGVuZXJJZCBzdG9wb3V0IGxpc3RlbmVyIGlkXG4gICAqL1xuICByZW1vdmVTdG9wb3V0TGlzdGVuZXIobGlzdGVuZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5fc3RvcG91dExpc3RlbmVyTWFuYWdlci5yZW1vdmVTdG9wb3V0TGlzdGVuZXIobGlzdGVuZXJJZCk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHN0cmF0ZWd5IGxvZyBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7VXNlckxvZ0xpc3RlbmVyfSBsaXN0ZW5lciB1c2VyIGxvZyBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0RhdGV9IFtzdGFydFRpbWVdIGxvZyBzZWFyY2ggc3RhcnQgdGltZVxuICAgKiBAcGFyYW0ge3N0cmluZ30gW3Bvc2l0aW9uSWRdIHBvc2l0aW9uIGlkIGZpbHRlclxuICAgKiBAcGFyYW0geydERUJVRyd8J0lORk8nfCdXQVJOJ3wnRVJST1InfSBbbGV2ZWxdIG1pbmltdW0gc2V2ZXJpdHkgbGV2ZWxcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtsaW1pdF0gbG9nIHBhZ2luYXRpb24gbGltaXRcbiAgICogQHJldHVybiB7c3RyaW5nfSBsaXN0ZW5lciBpZFxuICAgKi9cbiAgYWRkU3RyYXRlZ3lMb2dMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogVXNlckxvZ0xpc3RlbmVyLCBzdHJhdGVneUlkOiBzdHJpbmcsIHN0YXJ0VGltZT86IERhdGUsIHBvc2l0aW9uSWQ/OiBzdHJpbmcsXG4gICAgbGV2ZWw/OiAnREVCVUcnIHwgJ0lORk8nIHwgJ1dBUk4nIHwgJ0VSUk9SJywgbGltaXQ/OiBudW1iZXJcbiAgKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fdXNlckxvZ0xpc3RlbmVyTWFuYWdlci5hZGRTdHJhdGVneUxvZ0xpc3RlbmVyKFxuICAgICAgbGlzdGVuZXIsIFxuICAgICAgc3RyYXRlZ3lJZCwgXG4gICAgICBzdGFydFRpbWUsIFxuICAgICAgcG9zaXRpb25JZCwgXG4gICAgICBsZXZlbCwgXG4gICAgICBsaW1pdFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBzdHJhdGVneSBsb2cgbGlzdGVuZXIgYW5kIGNhbmNlbHMgdGhlIGV2ZW50IHN0cmVhbVxuICAgKiBAcGFyYW0ge3N0cmluZ30gbGlzdGVuZXJJZCBzdHJhdGVneSBsb2cgbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVN0cmF0ZWd5TG9nTGlzdGVuZXIobGlzdGVuZXJJZDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5fdXNlckxvZ0xpc3RlbmVyTWFuYWdlci5yZW1vdmVTdHJhdGVneUxvZ0xpc3RlbmVyKGxpc3RlbmVySWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBzdWJzY3JpYmVyIGxvZyBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7VXNlckxvZ0xpc3RlbmVyfSBsaXN0ZW5lciB1c2VyIGxvZyBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge3N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtEYXRlfSBbc3RhcnRUaW1lXSBsb2cgc2VhcmNoIHN0YXJ0IHRpbWVcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtzdHJhdGVneUlkXSBzdHJhdGVneSBpZCBmaWx0ZXJcbiAgICogQHBhcmFtIHtzdHJpbmd9IFtwb3NpdGlvbklkXSBwb3NpdGlvbiBpZCBmaWx0ZXJcbiAgICogQHBhcmFtIHsnREVCVUcnfCdJTkZPJ3wnV0FSTid8J0VSUk9SJ30gW2xldmVsXSBtaW5pbXVtIHNldmVyaXR5IGxldmVsXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBbbGltaXRdIGxvZyBwYWdpbmF0aW9uIGxpbWl0XG4gICAqIEByZXR1cm4ge3N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFN1YnNjcmliZXJMb2dMaXN0ZW5lcihcbiAgICBsaXN0ZW5lcjogVXNlckxvZ0xpc3RlbmVyLCBzdWJzY3JpYmVySWQ6IHN0cmluZywgc3RhcnRUaW1lPzogRGF0ZSwgc3RyYXRlZ3lJZD86IHN0cmluZywgcG9zaXRpb25JZD86IHN0cmluZyxcbiAgICBsZXZlbD86ICdERUJVRycgfCAnSU5GTycgfCAnV0FSTicgfCAnRVJST1InLCBsaW1pdD86IG51bWJlclxuICApOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyLmFkZFN1YnNjcmliZXJMb2dMaXN0ZW5lcihcbiAgICAgIGxpc3RlbmVyLCBcbiAgICAgIHN1YnNjcmliZXJJZCwgXG4gICAgICBzdGFydFRpbWUsIFxuICAgICAgc3RyYXRlZ3lJZCwgXG4gICAgICBwb3NpdGlvbklkLCBcbiAgICAgIGxldmVsLCBcbiAgICAgIGxpbWl0XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIHN1YnNjcmliZXIgbG9nIGxpc3RlbmVyIGFuZCBjYW5jZWxzIHRoZSBldmVudCBzdHJlYW1cbiAgICogQHBhcmFtIHtzdHJpbmd9IGxpc3RlbmVySWQgc3Vic2NyaWJlciBsb2cgbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVN1YnNjcmliZXJMb2dMaXN0ZW5lcihsaXN0ZW5lcklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLl91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyLnJlbW92ZVN1YnNjcmliZXJMb2dMaXN0ZW5lcihsaXN0ZW5lcklkKTtcbiAgfVxufVxuIl0sIm5hbWVzIjpbIlRyYWRpbmdDbGllbnQiLCJNZXRhQXBpQ2xpZW50IiwiX2NvbmZpZ3VyYXRpb25DbGllbnQiLCJfc3RvcG91dExpc3RlbmVyTWFuYWdlciIsIl91c2VyTG9nTGlzdGVuZXJNYW5hZ2VyIiwiY29uc3RydWN0b3IiLCJkb21haW5DbGllbnQiLCJjb25maWd1cmF0aW9uQ2xpZW50IiwiX2RvbWFpbkNsaWVudCIsIlN0b3BvdXRMaXN0ZW5lck1hbmFnZXIiLCJVc2VyTG9nTGlzdGVuZXJNYW5hZ2VyIiwicmVzeW5jaHJvbml6ZSIsImFjY291bnRJZCIsInN0cmF0ZWd5SWRzIiwicG9zaXRpb25JZHMiLCJfaXNOb3RKd3RUb2tlbiIsIl9oYW5kbGVOb0FjY2Vzc0Vycm9yIiwib3B0cyIsInVybCIsIm1ldGhvZCIsImhlYWRlcnMiLCJfdG9rZW4iLCJwYXJhbXMiLCJzdHJhdGVneUlkIiwicG9zaXRpb25JZCIsImpzb24iLCJyZXF1ZXN0Q29weUZhY3RvcnkiLCJnZXRTdWJzY3JpYmVyU2lnbmFsQ2xpZW50Iiwic3Vic2NyaWJlcklkIiwiYWNjb3VudERhdGEiLCJnZXRBY2NvdW50SW5mbyIsImhvc3QiLCJnZXRTaWduYWxDbGllbnRIb3N0IiwicmVnaW9ucyIsIlN1YnNjcmliZXJTaWduYWxDbGllbnQiLCJpZCIsImdldFN0cmF0ZWd5U2lnbmFsQ2xpZW50Iiwic3RyYXRlZ3kiLCJnZXRTdHJhdGVneSIsIlN0cmF0ZWd5U2lnbmFsQ2xpZW50IiwiZ2V0U3RvcG91dHMiLCJyZXNldFN1YnNjcmlwdGlvblN0b3BvdXRzIiwicmVhc29uIiwicmVzZXRTdWJzY3JpYmVyU3RvcG91dHMiLCJnZXRVc2VyTG9nIiwic3RhcnRUaW1lIiwiZW5kVGltZSIsImxldmVsIiwib2Zmc2V0IiwibGltaXQiLCJyZXN1bHQiLCJtYXAiLCJyIiwidGltZSIsIkRhdGUiLCJnZXRTdHJhdGVneUxvZyIsImFkZFN0b3BvdXRMaXN0ZW5lciIsImxpc3RlbmVyIiwic2VxdWVuY2VOdW1iZXIiLCJyZW1vdmVTdG9wb3V0TGlzdGVuZXIiLCJsaXN0ZW5lcklkIiwiYWRkU3RyYXRlZ3lMb2dMaXN0ZW5lciIsInJlbW92ZVN0cmF0ZWd5TG9nTGlzdGVuZXIiLCJhZGRTdWJzY3JpYmVyTG9nTGlzdGVuZXIiLCJyZW1vdmVTdWJzY3JpYmVyTG9nTGlzdGVuZXIiXSwibWFwcGluZ3MiOiJBQUFBOzs7OytCQWlCQTs7O0NBR0MsR0FDRDs7O2VBQXFCQTs7O3NFQW5CSzsrRUFDUzs2RUFDRjsrRUFDRTsrRUFDQTtxQkFTckI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFNQyxJQUFBLEFBQU1BLGdCQUFOLE1BQU1BLHNCQUFzQkMsc0JBQWE7SUFFOUNDLHFCQUEwQztJQUMxQ0Msd0JBQWdEO0lBQ2hEQyx3QkFBZ0Q7SUFFeEQ7Ozs7R0FJQyxHQUNEQyxZQUFZQyxZQUEwQixFQUFFQyxtQkFBd0MsQ0FB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