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)
285 lines (284 loc) • 37 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return EquityTrackingClient;
}
});
const _trackerEventListenerManager = /*#__PURE__*/ _interop_require_default(require("./trackerEventListenerManager"));
const _periodStatisticsStreamManager = /*#__PURE__*/ _interop_require_default(require("./periodStatisticsStreamManager"));
const _equityChartStreamManager = /*#__PURE__*/ _interop_require_default(require("./equityChartStreamManager"));
const _equityBalanceStreamManager = /*#__PURE__*/ _interop_require_default(require("./equityBalanceStreamManager"));
const _moment = /*#__PURE__*/ _interop_require_default(require("moment"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let EquityTrackingClient = class EquityTrackingClient {
/**
* Creates a profit/drawdown tracker. See
* https://metaapi.cloud/docs/risk-management/restApi/api/createTracker/
* @param {String} accountId id of the MetaApi account
* @param {NewTracker} tracker profit/drawdown tracker
* @return {Promise<TrackerId>} promise resolving with profit/drawdown tracker id
*/ createTracker(accountId, tracker) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
method: "POST",
data: tracker
});
}
/**
* Returns trackers defined for an account. See
* https://metaapi.cloud/docs/risk-management/restApi/api/getTrackers/
* @param {String} accountId id of the MetaApi account
* @return {Promise<Tracker[]>} promise resolving with trackers
*/ getTrackers(accountId) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
method: "GET"
});
}
/**
* Returns profit/drawdown tracker by account and id. See
* https://metaapi.cloud/docs/risk-management/restApi/api/getTracker/
* @param {string} accountId id of the MetaApi account
* @param {string} id tracker id
* @returns {Promise<Tracker>} promise resolving with profit/drawdown tracker found
*/ getTracker(accountId, id) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers/${id}`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
method: "GET"
});
}
/**
* Returns profit/drawdown tracker by account and name
* @param {string} accountId id of the MetaApi account
* @param {string} name tracker name
* @returns {Promise<Tracker>} promise resolving with profit/drawdown tracker found
*/ getTrackerByName(accountId, name) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers/name/${encodeURIComponent(name)}`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
method: "GET"
});
}
/**
* Updates profit/drawdown tracker. See
* https://metaapi.cloud/docs/risk-management/restApi/api/updateTracker/
* @param {String} accountId id of the MetaApi account
* @param {String} id id of the tracker
* @param {TrackerUpdate} update tracker update
* @return {Promise} promise resolving when profit/drawdown tracker updated
*/ updateTracker(accountId, id, update) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers/${id}`,
method: "PUT",
data: update
});
}
/**
* Removes profit/drawdown tracker. See
* https://metaapi.cloud/docs/risk-management/restApi/api/removeTracker/
* @param {String} accountId id of the MetaApi account
* @param {String} id id of the tracker
* @return {Promise} promise resolving when profit/drawdown tracker removed
*/ deleteTracker(accountId, id) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers/${id}`,
method: "DELETE"
});
}
/**
* Returns tracker events by broker time range. See
* https://metaapi.cloud/docs/risk-management/restApi/api/getTrackerEvents/
* @param {String} [startBrokerTime] value of the event time in broker timezone to start loading data from, inclusive,
* in 'YYYY-MM-DD HH:mm:ss.SSS format
* @param {String} [endBrokerTime] value of the event time in broker timezone to end loading data at, inclusive,
* in 'YYYY-MM-DD HH:mm:ss.SSS format
* @param {String} [accountId] id of the MetaApi account
* @param {String} [trackerId] id of the tracker
* @param {Number} [limit] pagination limit, default is 1000
* @return {Promise<TrackerEvent[]>} promise resolving with tracker events
*/ getTrackerEvents(startBrokerTime, endBrokerTime, accountId, trackerId, limit) {
return this._domainClient.requestApi({
url: "/users/current/tracker-events/by-broker-time",
params: {
startBrokerTime,
endBrokerTime,
accountId,
trackerId,
limit
},
method: "GET"
});
}
/**
* Adds a tracker event listener and creates a job to make requests
* @param {TrackerEventListener} listener tracker event listener
* @param {String} [accountId] account id
* @param {String} [trackerId] tracker id
* @param {Number} [sequenceNumber] sequence number
* @return {String} listener id
*/ addTrackerEventListener(listener, accountId, trackerId, sequenceNumber) {
return this._trackerEventListenerManager.addTrackerEventListener(listener, accountId, trackerId, sequenceNumber);
}
/**
* Removes tracker event listener and cancels the event stream
* @param {String} listenerId tracker event listener id
*/ removeTrackerEventListener(listenerId) {
this._trackerEventListenerManager.removeTrackerEventListener(listenerId);
}
/**
* Returns account profit and drawdown tracking statistics by tracker id. See
* https://metaapi.cloud/docs/risk-management/restApi/api/getTrackingStats/
* @param {String} accountId id of MetaAPI account
* @param {String} trackerId id of the tracker
* @param {String} [startTime] time to start loading stats from, default is current time. Note that stats is loaded in
* backwards direction
* @param {Number} [limit] number of records to load, default is 1
* @param {Boolean} [realTime] if true, real-time data will be requested
* @return {Promise<PeriodStatistics[]>} promise resolving with profit and drawdown statistics
*/ getTrackingStatistics(accountId, trackerId, startTime, limit, realTime = false) {
return this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/trackers/${trackerId}/statistics`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
params: {
startTime,
limit,
realTime
},
method: "GET"
});
}
/**
* Adds a period statistics event listener
* @param {PeriodStatisticsListener} listener period statistics event listener
* @param {String} accountId account id
* @param {String} trackerId tracker id
* @returns {Promise<String>} listener id
*/ addPeriodStatisticsListener(listener, accountId, trackerId) {
return this._periodStatisticsStreamManager.addPeriodStatisticsListener(listener, accountId, trackerId);
}
/**
* Removes period statistics event listener by id
* @param {String} listenerId listener id
*/ removePeriodStatisticsListener(listenerId) {
this._periodStatisticsStreamManager.removePeriodStatisticsListener(listenerId);
}
/**
* Returns equity chart by account id. See
* https://metaapi.cloud/docs/risk-management/restApi/api/getEquityChart/
* @param {String} accountId metaApi account id
* @param {String} [startTime] starting broker time in YYYY-MM-DD HH:mm:ss format
* @param {String} [endTime] ending broker time in YYYY-MM-DD HH:mm:ss format
* @param {Boolean} [realTime] if true, real-time data will be requested
* @param {Boolean} [fillSkips] if true, skipped records will be automatically filled based on existing ones
* @return {Promise<EquityChartItem[]>} promise resolving with equity chart
*/ async getEquityChart(accountId, startTime, endTime, realTime = false, fillSkips = false) {
const records = await this._domainClient.requestApi({
url: `/users/current/accounts/${accountId}/equity-chart`,
headers: {
"auth-token": this._domainClient.token,
"api-version": "1"
},
params: {
startTime,
endTime,
realTime
},
method: "GET"
});
if (fillSkips) {
let i = 0;
while(i < records.length - 1){
const timeDiff = new Date(records[i + 1].startBrokerTime).getTime() - new Date(records[i].startBrokerTime).getTime();
if (timeDiff > 60 * 60 * 1000 && records[i].lastBalance !== undefined) {
const recordCopy = JSON.parse(JSON.stringify(records[i]));
recordCopy.minEquity = recordCopy.lastEquity;
recordCopy.maxEquity = recordCopy.lastEquity;
recordCopy.averageEquity = recordCopy.lastEquity;
recordCopy.minBalance = recordCopy.lastBalance;
recordCopy.maxBalance = recordCopy.lastBalance;
recordCopy.averageBalance = recordCopy.lastBalance;
const startBrokerTime = new Date(recordCopy.startBrokerTime);
startBrokerTime.setUTCHours(startBrokerTime.getUTCHours() + 1);
startBrokerTime.setUTCMinutes(0);
startBrokerTime.setUTCSeconds(0);
startBrokerTime.setUTCMilliseconds(0);
recordCopy.startBrokerTime = (0, _moment.default)(startBrokerTime).format("YYYY-MM-DD HH:mm:ss.SSS");
startBrokerTime.setUTCHours(startBrokerTime.getUTCHours() + 1);
startBrokerTime.setUTCMilliseconds(-1);
recordCopy.endBrokerTime = (0, _moment.default)(startBrokerTime).format("YYYY-MM-DD HH:mm:ss.SSS");
recordCopy.brokerTime = recordCopy.endBrokerTime;
records.splice(i + 1, 0, recordCopy);
}
i++;
}
}
return records;
}
/**
* Adds an equity chart event listener
* @param {EquityChartListener} listener equity chart event listener
* @param {String} accountId account id
* @param {Date} [startTime] date to start tracking from
* @returns {Promise<string>} listener id
*/ addEquityChartListener(listener, accountId, startTime) {
return this._equityChartStreamManager.addEquityChartListener(listener, accountId, startTime);
}
/**
* Removes equity chart event listener by id
* @param {String} listenerId equity chart listener id
*/ removeEquityChartListener(listenerId) {
this._equityChartStreamManager.removeEquityChartListener(listenerId);
}
/**
* Adds an equity balance event listener
* @param {EquityBalanceListener} listener equity balance event listener
* @param {string} accountId account id
* @returns {Promise<string>} listener id
*/ addEquityBalanceListener(listener, accountId) {
return this._equityBalanceStreamManager.addEquityBalanceListener(listener, accountId);
}
/**
* Removes equity balance event listener by id
* @param {string} listenerId equity balance listener id
*/ removeEquityBalanceListener(listenerId) {
this._equityBalanceStreamManager.removeEquityBalanceListener(listenerId);
}
/**
* Constructs RiskManagement equity tracking API client instance
* @param {DomainClient} domainClient domain client
* @param {MetaApi} metaApi metaApi SDK instance
*/ constructor(domainClient, metaApi){
this._domainClient = domainClient;
this._trackerEventListenerManager = new _trackerEventListenerManager.default(domainClient);
this._equityBalanceStreamManager = new _equityBalanceStreamManager.default(domainClient, metaApi);
this._periodStatisticsStreamManager = new _periodStatisticsStreamManager.default(domainClient, this, metaApi);
this._equityChartStreamManager = new _equityChartStreamManager.default(domainClient, this, metaApi);
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBUcmFja2VyRXZlbnRMaXN0ZW5lck1hbmFnZXIgZnJvbSAnLi90cmFja2VyRXZlbnRMaXN0ZW5lck1hbmFnZXInO1xuaW1wb3J0IFBlcmlvZFN0YXRpc3RpY3NTdHJlYW1NYW5hZ2VyIGZyb20gJy4vcGVyaW9kU3RhdGlzdGljc1N0cmVhbU1hbmFnZXInO1xuaW1wb3J0IEVxdWl0eUNoYXJ0U3RyZWFtTWFuYWdlciBmcm9tICcuL2VxdWl0eUNoYXJ0U3RyZWFtTWFuYWdlcic7XG5pbXBvcnQgRXF1aXR5QmFsYW5jZVN0cmVhbU1hbmFnZXIgZnJvbSAnLi9lcXVpdHlCYWxhbmNlU3RyZWFtTWFuYWdlcic7XG5pbXBvcnQgbW9tZW50IGZyb20gJ21vbWVudCc7XG5cbi8qKlxuICogbWV0YWFwaS5jbG91ZCBSaXNrTWFuYWdlbWVudCBlcXVpdHkgdHJhY2tpbmcgQVBJIGNsaWVudCAoc2VlIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL3Jpc2stbWFuYWdlbWVudC8pXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIEVxdWl0eVRyYWNraW5nQ2xpZW50IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBSaXNrTWFuYWdlbWVudCBlcXVpdHkgdHJhY2tpbmcgQVBJIGNsaWVudCBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge0RvbWFpbkNsaWVudH0gZG9tYWluQ2xpZW50IGRvbWFpbiBjbGllbnRcbiAgICogQHBhcmFtIHtNZXRhQXBpfSBtZXRhQXBpIG1ldGFBcGkgU0RLIGluc3RhbmNlXG4gICAqL1xuICBjb25zdHJ1Y3Rvcihkb21haW5DbGllbnQsIG1ldGFBcGkpIHtcbiAgICB0aGlzLl9kb21haW5DbGllbnQgPSBkb21haW5DbGllbnQ7XG4gICAgdGhpcy5fdHJhY2tlckV2ZW50TGlzdGVuZXJNYW5hZ2VyID0gbmV3IFRyYWNrZXJFdmVudExpc3RlbmVyTWFuYWdlcihkb21haW5DbGllbnQpO1xuICAgIHRoaXMuX2VxdWl0eUJhbGFuY2VTdHJlYW1NYW5hZ2VyID0gbmV3IEVxdWl0eUJhbGFuY2VTdHJlYW1NYW5hZ2VyKGRvbWFpbkNsaWVudCwgbWV0YUFwaSk7XG4gICAgdGhpcy5fcGVyaW9kU3RhdGlzdGljc1N0cmVhbU1hbmFnZXIgPSBuZXcgUGVyaW9kU3RhdGlzdGljc1N0cmVhbU1hbmFnZXIoZG9tYWluQ2xpZW50LCB0aGlzLCBtZXRhQXBpKTtcbiAgICB0aGlzLl9lcXVpdHlDaGFydFN0cmVhbU1hbmFnZXIgPSBuZXcgRXF1aXR5Q2hhcnRTdHJlYW1NYW5hZ2VyKGRvbWFpbkNsaWVudCwgdGhpcywgbWV0YUFwaSk7IFxuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBwcm9maXQvZHJhd2Rvd24gdHJhY2tlci4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL3Jpc2stbWFuYWdlbWVudC9yZXN0QXBpL2FwaS9jcmVhdGVUcmFja2VyL1xuICAgKiBAcGFyYW0ge1N0cmluZ30gYWNjb3VudElkIGlkIG9mIHRoZSBNZXRhQXBpIGFjY291bnRcbiAgICogQHBhcmFtIHtOZXdUcmFja2VyfSB0cmFja2VyIHByb2ZpdC9kcmF3ZG93biB0cmFja2VyXG4gICAqIEByZXR1cm4ge1Byb21pc2U8VHJhY2tlcklkPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciBpZFxuICAgKi9cbiAgY3JlYXRlVHJhY2tlcihhY2NvdW50SWQsIHRyYWNrZXIpIHtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RBcGkoe1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvYWNjb3VudHMvJHthY2NvdW50SWR9L3RyYWNrZXJzYCxcbiAgICAgIGhlYWRlcnM6IHsnYXV0aC10b2tlbic6IHRoaXMuX2RvbWFpbkNsaWVudC50b2tlbiwgJ2FwaS12ZXJzaW9uJzogJzEnfSxcbiAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgZGF0YTogdHJhY2tlclxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJhY2tlcnMgZGVmaW5lZCBmb3IgYW4gYWNjb3VudC4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL3Jpc2stbWFuYWdlbWVudC9yZXN0QXBpL2FwaS9nZXRUcmFja2Vycy9cbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBpZCBvZiB0aGUgTWV0YUFwaSBhY2NvdW50XG4gICAqIEByZXR1cm4ge1Byb21pc2U8VHJhY2tlcltdPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCB0cmFja2Vyc1xuICAgKi9cbiAgZ2V0VHJhY2tlcnMoYWNjb3VudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0QXBpKHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2FjY291bnRzLyR7YWNjb3VudElkfS90cmFja2Vyc2AsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl9kb21haW5DbGllbnQudG9rZW4sICdhcGktdmVyc2lvbic6ICcxJ30sXG4gICAgICBtZXRob2Q6ICdHRVQnXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciBieSBhY2NvdW50IGFuZCBpZC4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL3Jpc2stbWFuYWdlbWVudC9yZXN0QXBpL2FwaS9nZXRUcmFja2VyL1xuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGlkIG9mIHRoZSBNZXRhQXBpIGFjY291bnQgXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpZCB0cmFja2VyIGlkIFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUcmFja2VyPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciBmb3VuZFxuICAgKi9cbiAgZ2V0VHJhY2tlcihhY2NvdW50SWQsIGlkKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0QXBpKHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2FjY291bnRzLyR7YWNjb3VudElkfS90cmFja2Vycy8ke2lkfWAsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl9kb21haW5DbGllbnQudG9rZW4sICdhcGktdmVyc2lvbic6ICcxJ30sXG4gICAgICBtZXRob2Q6ICdHRVQnXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciBieSBhY2NvdW50IGFuZCBuYW1lXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBhY2NvdW50SWQgaWQgb2YgdGhlIE1ldGFBcGkgYWNjb3VudCBcbiAgICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgdHJhY2tlciBuYW1lIFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxUcmFja2VyPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciBmb3VuZFxuICAgKi9cbiAgZ2V0VHJhY2tlckJ5TmFtZShhY2NvdW50SWQsIG5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RBcGkoe1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvYWNjb3VudHMvJHthY2NvdW50SWR9L3RyYWNrZXJzL25hbWUvJHtlbmNvZGVVUklDb21wb25lbnQobmFtZSl9YCxcbiAgICAgIGhlYWRlcnM6IHsnYXV0aC10b2tlbic6IHRoaXMuX2RvbWFpbkNsaWVudC50b2tlbiwgJ2FwaS12ZXJzaW9uJzogJzEnfSxcbiAgICAgIG1ldGhvZDogJ0dFVCdcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIHByb2ZpdC9kcmF3ZG93biB0cmFja2VyLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3Mvcmlzay1tYW5hZ2VtZW50L3Jlc3RBcGkvYXBpL3VwZGF0ZVRyYWNrZXIvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBhY2NvdW50SWQgaWQgb2YgdGhlIE1ldGFBcGkgYWNjb3VudFxuICAgKiBAcGFyYW0ge1N0cmluZ30gaWQgaWQgb2YgdGhlIHRyYWNrZXJcbiAgICogQHBhcmFtIHtUcmFja2VyVXBkYXRlfSB1cGRhdGUgdHJhY2tlciB1cGRhdGVcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBwcm9maXQvZHJhd2Rvd24gdHJhY2tlciB1cGRhdGVkXG4gICAqL1xuICB1cGRhdGVUcmFja2VyKGFjY291bnRJZCwgaWQsIHVwZGF0ZSkge1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdEFwaSh7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9hY2NvdW50cy8ke2FjY291bnRJZH0vdHJhY2tlcnMvJHtpZH1gLFxuICAgICAgbWV0aG9kOiAnUFVUJyxcbiAgICAgIGRhdGE6IHVwZGF0ZVxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgcHJvZml0L2RyYXdkb3duIHRyYWNrZXIuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9yaXNrLW1hbmFnZW1lbnQvcmVzdEFwaS9hcGkvcmVtb3ZlVHJhY2tlci9cbiAgICogQHBhcmFtIHtTdHJpbmd9IGFjY291bnRJZCBpZCBvZiB0aGUgTWV0YUFwaSBhY2NvdW50XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBpZCBpZCBvZiB0aGUgdHJhY2tlclxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHByb2ZpdC9kcmF3ZG93biB0cmFja2VyIHJlbW92ZWRcbiAgICovXG4gIGRlbGV0ZVRyYWNrZXIoYWNjb3VudElkLCBpZCkge1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdEFwaSh7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9hY2NvdW50cy8ke2FjY291bnRJZH0vdHJhY2tlcnMvJHtpZH1gLFxuICAgICAgbWV0aG9kOiAnREVMRVRFJ1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJhY2tlciBldmVudHMgYnkgYnJva2VyIHRpbWUgcmFuZ2UuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9yaXNrLW1hbmFnZW1lbnQvcmVzdEFwaS9hcGkvZ2V0VHJhY2tlckV2ZW50cy9cbiAgICogQHBhcmFtIHtTdHJpbmd9IFtzdGFydEJyb2tlclRpbWVdIHZhbHVlIG9mIHRoZSBldmVudCB0aW1lIGluIGJyb2tlciB0aW1lem9uZSB0byBzdGFydCBsb2FkaW5nIGRhdGEgZnJvbSwgaW5jbHVzaXZlLFxuICAgKiBpbiAnWVlZWS1NTS1ERCBISDptbTpzcy5TU1MgZm9ybWF0XG4gICAqIEBwYXJhbSB7U3RyaW5nfSBbZW5kQnJva2VyVGltZV0gdmFsdWUgb2YgdGhlIGV2ZW50IHRpbWUgaW4gYnJva2VyIHRpbWV6b25lIHRvIGVuZCBsb2FkaW5nIGRhdGEgYXQsIGluY2x1c2l2ZSxcbiAgICogaW4gJ1lZWVktTU0tREQgSEg6bW06c3MuU1NTIGZvcm1hdFxuICAgKiBAcGFyYW0ge1N0cmluZ30gW2FjY291bnRJZF0gaWQgb2YgdGhlIE1ldGFBcGkgYWNjb3VudFxuICAgKiBAcGFyYW0ge1N0cmluZ30gW3RyYWNrZXJJZF0gaWQgb2YgdGhlIHRyYWNrZXJcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtsaW1pdF0gcGFnaW5hdGlvbiBsaW1pdCwgZGVmYXVsdCBpcyAxMDAwXG4gICAqIEByZXR1cm4ge1Byb21pc2U8VHJhY2tlckV2ZW50W10+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIHRyYWNrZXIgZXZlbnRzXG4gICAqL1xuICBnZXRUcmFja2VyRXZlbnRzKHN0YXJ0QnJva2VyVGltZSwgZW5kQnJva2VyVGltZSwgYWNjb3VudElkLCB0cmFja2VySWQsIGxpbWl0KSB7XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0QXBpKHtcbiAgICAgIHVybDogJy91c2Vycy9jdXJyZW50L3RyYWNrZXItZXZlbnRzL2J5LWJyb2tlci10aW1lJyxcbiAgICAgIHBhcmFtczoge3N0YXJ0QnJva2VyVGltZSwgZW5kQnJva2VyVGltZSwgYWNjb3VudElkLCB0cmFja2VySWQsIGxpbWl0fSxcbiAgICAgIG1ldGhvZDogJ0dFVCdcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgdHJhY2tlciBldmVudCBsaXN0ZW5lciBhbmQgY3JlYXRlcyBhIGpvYiB0byBtYWtlIHJlcXVlc3RzXG4gICAqIEBwYXJhbSB7VHJhY2tlckV2ZW50TGlzdGVuZXJ9IGxpc3RlbmVyIHRyYWNrZXIgZXZlbnQgbGlzdGVuZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IFthY2NvdW50SWRdIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IFt0cmFja2VySWRdIHRyYWNrZXIgaWRcbiAgICogQHBhcmFtIHtOdW1iZXJ9IFtzZXF1ZW5jZU51bWJlcl0gc2VxdWVuY2UgbnVtYmVyXG4gICAqIEByZXR1cm4ge1N0cmluZ30gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZFRyYWNrZXJFdmVudExpc3RlbmVyKGxpc3RlbmVyLCBhY2NvdW50SWQsIHRyYWNrZXJJZCwgc2VxdWVuY2VOdW1iZXIpIHtcbiAgICByZXR1cm4gdGhpcy5fdHJhY2tlckV2ZW50TGlzdGVuZXJNYW5hZ2VyLmFkZFRyYWNrZXJFdmVudExpc3RlbmVyKGxpc3RlbmVyLCBhY2NvdW50SWQsIHRyYWNrZXJJZCwgc2VxdWVuY2VOdW1iZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgdHJhY2tlciBldmVudCBsaXN0ZW5lciBhbmQgY2FuY2VscyB0aGUgZXZlbnQgc3RyZWFtXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBsaXN0ZW5lcklkIHRyYWNrZXIgZXZlbnQgbGlzdGVuZXIgaWRcbiAgICovXG4gIHJlbW92ZVRyYWNrZXJFdmVudExpc3RlbmVyKGxpc3RlbmVySWQpIHtcbiAgICB0aGlzLl90cmFja2VyRXZlbnRMaXN0ZW5lck1hbmFnZXIucmVtb3ZlVHJhY2tlckV2ZW50TGlzdGVuZXIobGlzdGVuZXJJZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhY2NvdW50IHByb2ZpdCBhbmQgZHJhd2Rvd24gdHJhY2tpbmcgc3RhdGlzdGljcyBieSB0cmFja2VyIGlkLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3Mvcmlzay1tYW5hZ2VtZW50L3Jlc3RBcGkvYXBpL2dldFRyYWNraW5nU3RhdHMvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBhY2NvdW50SWQgaWQgb2YgTWV0YUFQSSBhY2NvdW50XG4gICAqIEBwYXJhbSB7U3RyaW5nfSB0cmFja2VySWQgaWQgb2YgdGhlIHRyYWNrZXJcbiAgICogQHBhcmFtIHtTdHJpbmd9IFtzdGFydFRpbWVdIHRpbWUgdG8gc3RhcnQgbG9hZGluZyBzdGF0cyBmcm9tLCBkZWZhdWx0IGlzIGN1cnJlbnQgdGltZS4gTm90ZSB0aGF0IHN0YXRzIGlzIGxvYWRlZCBpblxuICAgKiBiYWNrd2FyZHMgZGlyZWN0aW9uXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBbbGltaXRdIG51bWJlciBvZiByZWNvcmRzIHRvIGxvYWQsIGRlZmF1bHQgaXMgMVxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IFtyZWFsVGltZV0gaWYgdHJ1ZSwgcmVhbC10aW1lIGRhdGEgd2lsbCBiZSByZXF1ZXN0ZWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxQZXJpb2RTdGF0aXN0aWNzW10+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIHByb2ZpdCBhbmQgZHJhd2Rvd24gc3RhdGlzdGljc1xuICAgKi9cbiAgZ2V0VHJhY2tpbmdTdGF0aXN0aWNzKGFjY291bnRJZCwgdHJhY2tlcklkLCBzdGFydFRpbWUsIGxpbWl0LCByZWFsVGltZSA9IGZhbHNlKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0QXBpKHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2FjY291bnRzLyR7YWNjb3VudElkfS90cmFja2Vycy8ke3RyYWNrZXJJZH0vc3RhdGlzdGljc2AsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl9kb21haW5DbGllbnQudG9rZW4sICdhcGktdmVyc2lvbic6ICcxJ30sXG4gICAgICBwYXJhbXM6IHtzdGFydFRpbWUsIGxpbWl0LCByZWFsVGltZX0sXG4gICAgICBtZXRob2Q6ICdHRVQnXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhIHBlcmlvZCBzdGF0aXN0aWNzIGV2ZW50IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7UGVyaW9kU3RhdGlzdGljc0xpc3RlbmVyfSBsaXN0ZW5lciBwZXJpb2Qgc3RhdGlzdGljcyBldmVudCBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge1N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHRyYWNrZXJJZCB0cmFja2VyIGlkXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFN0cmluZz59IGxpc3RlbmVyIGlkXG4gICAqL1xuICBhZGRQZXJpb2RTdGF0aXN0aWNzTGlzdGVuZXIobGlzdGVuZXIsIGFjY291bnRJZCwgdHJhY2tlcklkKSB7XG4gICAgcmV0dXJuIHRoaXMuX3BlcmlvZFN0YXRpc3RpY3NTdHJlYW1NYW5hZ2VyLmFkZFBlcmlvZFN0YXRpc3RpY3NMaXN0ZW5lcihsaXN0ZW5lciwgYWNjb3VudElkLCB0cmFja2VySWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZXMgcGVyaW9kIHN0YXRpc3RpY3MgZXZlbnQgbGlzdGVuZXIgYnkgaWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IGxpc3RlbmVySWQgbGlzdGVuZXIgaWQgXG4gICAqL1xuICByZW1vdmVQZXJpb2RTdGF0aXN0aWNzTGlzdGVuZXIobGlzdGVuZXJJZCkge1xuICAgIHRoaXMuX3BlcmlvZFN0YXRpc3RpY3NTdHJlYW1NYW5hZ2VyLnJlbW92ZVBlcmlvZFN0YXRpc3RpY3NMaXN0ZW5lcihsaXN0ZW5lcklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGVxdWl0eSBjaGFydCBieSBhY2NvdW50IGlkLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3Mvcmlzay1tYW5hZ2VtZW50L3Jlc3RBcGkvYXBpL2dldEVxdWl0eUNoYXJ0L1xuICAgKiBAcGFyYW0ge1N0cmluZ30gYWNjb3VudElkIG1ldGFBcGkgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gW3N0YXJ0VGltZV0gc3RhcnRpbmcgYnJva2VyIHRpbWUgaW4gWVlZWS1NTS1ERCBISDptbTpzcyBmb3JtYXRcbiAgICogQHBhcmFtIHtTdHJpbmd9IFtlbmRUaW1lXSBlbmRpbmcgYnJva2VyIHRpbWUgaW4gWVlZWS1NTS1ERCBISDptbTpzcyBmb3JtYXRcbiAgICogQHBhcmFtIHtCb29sZWFufSBbcmVhbFRpbWVdIGlmIHRydWUsIHJlYWwtdGltZSBkYXRhIHdpbGwgYmUgcmVxdWVzdGVkXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gW2ZpbGxTa2lwc10gaWYgdHJ1ZSwgc2tpcHBlZCByZWNvcmRzIHdpbGwgYmUgYXV0b21hdGljYWxseSBmaWxsZWQgYmFzZWQgb24gZXhpc3Rpbmcgb25lc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPEVxdWl0eUNoYXJ0SXRlbVtdPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBlcXVpdHkgY2hhcnRcbiAgICovXG4gIGFzeW5jIGdldEVxdWl0eUNoYXJ0KGFjY291bnRJZCwgc3RhcnRUaW1lLCBlbmRUaW1lLCByZWFsVGltZSA9IGZhbHNlLCBmaWxsU2tpcHMgPSBmYWxzZSkge1xuICAgIGNvbnN0IHJlY29yZHMgPSBhd2FpdCB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdEFwaSh7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9hY2NvdW50cy8ke2FjY291bnRJZH0vZXF1aXR5LWNoYXJ0YCxcbiAgICAgIGhlYWRlcnM6IHsnYXV0aC10b2tlbic6IHRoaXMuX2RvbWFpbkNsaWVudC50b2tlbiwgJ2FwaS12ZXJzaW9uJzogJzEnfSxcbiAgICAgIHBhcmFtczoge3N0YXJ0VGltZSwgZW5kVGltZSwgcmVhbFRpbWV9LFxuICAgICAgbWV0aG9kOiAnR0VUJ1xuICAgIH0pO1xuICAgIGlmKGZpbGxTa2lwcyl7XG4gICAgICBsZXQgaSA9IDA7XG4gICAgICB3aGlsZShpIDwgcmVjb3Jkcy5sZW5ndGggLSAxKSB7XG4gICAgICAgIGNvbnN0IHRpbWVEaWZmID0gbmV3IERhdGUocmVjb3Jkc1tpICsgMV0uc3RhcnRCcm9rZXJUaW1lKS5nZXRUaW1lKCkgLSBcbiAgICAgICAgbmV3IERhdGUocmVjb3Jkc1tpXS5zdGFydEJyb2tlclRpbWUpLmdldFRpbWUoKTtcbiAgICAgICAgXG4gICAgICAgIGlmKHRpbWVEaWZmID4gNjAgKiA2MCAqIDEwMDAgJiYgcmVjb3Jkc1tpXS5sYXN0QmFsYW5jZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgY29uc3QgcmVjb3JkQ29weSA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkocmVjb3Jkc1tpXSkpO1xuICAgICAgICAgIHJlY29yZENvcHkubWluRXF1aXR5ID0gcmVjb3JkQ29weS5sYXN0RXF1aXR5O1xuICAgICAgICAgIHJlY29yZENvcHkubWF4RXF1aXR5ID0gcmVjb3JkQ29weS5sYXN0RXF1aXR5O1xuICAgICAgICAgIHJlY29yZENvcHkuYXZlcmFnZUVxdWl0eSA9IHJlY29yZENvcHkubGFzdEVxdWl0eTtcbiAgICAgICAgICByZWNvcmRDb3B5Lm1pbkJhbGFuY2UgPSByZWNvcmRDb3B5Lmxhc3RCYWxhbmNlO1xuICAgICAgICAgIHJlY29yZENvcHkubWF4QmFsYW5jZSA9IHJlY29yZENvcHkubGFzdEJhbGFuY2U7XG4gICAgICAgICAgcmVjb3JkQ29weS5hdmVyYWdlQmFsYW5jZSA9IHJlY29yZENvcHkubGFzdEJhbGFuY2U7XG4gICAgICAgICAgY29uc3Qgc3RhcnRCcm9rZXJUaW1lID0gbmV3IERhdGUocmVjb3JkQ29weS5zdGFydEJyb2tlclRpbWUpO1xuICAgICAgICAgIHN0YXJ0QnJva2VyVGltZS5zZXRVVENIb3VycyhzdGFydEJyb2tlclRpbWUuZ2V0VVRDSG91cnMoKSArIDEpO1xuICAgICAgICAgIHN0YXJ0QnJva2VyVGltZS5zZXRVVENNaW51dGVzKDApO1xuICAgICAgICAgIHN0YXJ0QnJva2VyVGltZS5zZXRVVENTZWNvbmRzKDApO1xuICAgICAgICAgIHN0YXJ0QnJva2VyVGltZS5zZXRVVENNaWxsaXNlY29uZHMoMCk7XG4gICAgICAgICAgcmVjb3JkQ29weS5zdGFydEJyb2tlclRpbWUgPSBtb21lbnQoc3RhcnRCcm9rZXJUaW1lKS5mb3JtYXQoJ1lZWVktTU0tREQgSEg6bW06c3MuU1NTJyk7XG4gICAgICAgICAgc3RhcnRCcm9rZXJUaW1lLnNldFVUQ0hvdXJzKHN0YXJ0QnJva2VyVGltZS5nZXRVVENIb3VycygpICsgMSk7XG4gICAgICAgICAgc3RhcnRCcm9rZXJUaW1lLnNldFVUQ01pbGxpc2Vjb25kcygtMSk7XG4gICAgICAgICAgcmVjb3JkQ29weS5lbmRCcm9rZXJUaW1lID0gbW9tZW50KHN0YXJ0QnJva2VyVGltZSkuZm9ybWF0KCdZWVlZLU1NLUREIEhIOm1tOnNzLlNTUycpO1xuICAgICAgICAgIHJlY29yZENvcHkuYnJva2VyVGltZSA9IHJlY29yZENvcHkuZW5kQnJva2VyVGltZTtcbiAgICAgICAgICByZWNvcmRzLnNwbGljZShpICsgMSwgMCwgcmVjb3JkQ29weSk7XG4gICAgICAgIH1cbiAgICAgICAgaSsrO1xuICAgICAgfSAgXG4gICAgfVxuICAgIHJldHVybiByZWNvcmRzO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gZXF1aXR5IGNoYXJ0IGV2ZW50IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7RXF1aXR5Q2hhcnRMaXN0ZW5lcn0gbGlzdGVuZXIgZXF1aXR5IGNoYXJ0IGV2ZW50IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBhY2NvdW50SWQgYWNjb3VudCBpZFxuICAgKiBAcGFyYW0ge0RhdGV9IFtzdGFydFRpbWVdIGRhdGUgdG8gc3RhcnQgdHJhY2tpbmcgZnJvbVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBsaXN0ZW5lciBpZFxuICAgKi9cbiAgYWRkRXF1aXR5Q2hhcnRMaXN0ZW5lcihsaXN0ZW5lciwgYWNjb3VudElkLCBzdGFydFRpbWUpIHtcbiAgICByZXR1cm4gdGhpcy5fZXF1aXR5Q2hhcnRTdHJlYW1NYW5hZ2VyLmFkZEVxdWl0eUNoYXJ0TGlzdGVuZXIobGlzdGVuZXIsIGFjY291bnRJZCwgc3RhcnRUaW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGVxdWl0eSBjaGFydCBldmVudCBsaXN0ZW5lciBieSBpZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gbGlzdGVuZXJJZCBlcXVpdHkgY2hhcnQgbGlzdGVuZXIgaWQgXG4gICAqL1xuICByZW1vdmVFcXVpdHlDaGFydExpc3RlbmVyKGxpc3RlbmVySWQpIHtcbiAgICB0aGlzLl9lcXVpdHlDaGFydFN0cmVhbU1hbmFnZXIucmVtb3ZlRXF1aXR5Q2hhcnRMaXN0ZW5lcihsaXN0ZW5lcklkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIGVxdWl0eSBiYWxhbmNlIGV2ZW50IGxpc3RlbmVyXG4gICAqIEBwYXJhbSB7RXF1aXR5QmFsYW5jZUxpc3RlbmVyfSBsaXN0ZW5lciBlcXVpdHkgYmFsYW5jZSBldmVudCBsaXN0ZW5lclxuICAgKiBAcGFyYW0ge3N0cmluZ30gYWNjb3VudElkIGFjY291bnQgaWRcbiAgICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gbGlzdGVuZXIgaWRcbiAgICovXG4gIGFkZEVxdWl0eUJhbGFuY2VMaXN0ZW5lcihsaXN0ZW5lciwgYWNjb3VudElkKSB7XG4gICAgcmV0dXJuIHRoaXMuX2VxdWl0eUJhbGFuY2VTdHJlYW1NYW5hZ2VyLmFkZEVxdWl0eUJhbGFuY2VMaXN0ZW5lcihsaXN0ZW5lciwgYWNjb3VudElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmVzIGVxdWl0eSBiYWxhbmNlIGV2ZW50IGxpc3RlbmVyIGJ5IGlkXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBsaXN0ZW5lcklkIGVxdWl0eSBiYWxhbmNlIGxpc3RlbmVyIGlkIFxuICAgKi9cbiAgcmVtb3ZlRXF1aXR5QmFsYW5jZUxpc3RlbmVyKGxpc3RlbmVySWQpIHtcbiAgICB0aGlzLl9lcXVpdHlCYWxhbmNlU3RyZWFtTWFuYWdlci5yZW1vdmVFcXVpdHlCYWxhbmNlTGlzdGVuZXIobGlzdGVuZXJJZCk7XG4gIH1cblxufVxuIl0sIm5hbWVzIjpbIkVxdWl0eVRyYWNraW5nQ2xpZW50IiwiY3JlYXRlVHJhY2tlciIsImFjY291bnRJZCIsInRyYWNrZXIiLCJfZG9tYWluQ2xpZW50IiwicmVxdWVzdEFwaSIsInVybCIsImhlYWRlcnMiLCJ0b2tlbiIsIm1ldGhvZCIsImRhdGEiLCJnZXRUcmFja2VycyIsImdldFRyYWNrZXIiLCJpZCIsImdldFRyYWNrZXJCeU5hbWUiLCJuYW1lIiwiZW5jb2RlVVJJQ29tcG9uZW50IiwidXBkYXRlVHJhY2tlciIsInVwZGF0ZSIsImRlbGV0ZVRyYWNrZXIiLCJnZXRUcmFja2VyRXZlbnRzIiwic3RhcnRCcm9rZXJUaW1lIiwiZW5kQnJva2VyVGltZSIsInRyYWNrZXJJZCIsImxpbWl0IiwicGFyYW1zIiwiYWRkVHJhY2tlckV2ZW50TGlzdGVuZXIiLCJsaXN0ZW5lciIsInNlcXVlbmNlTnVtYmVyIiwiX3RyYWNrZXJFdmVudExpc3RlbmVyTWFuYWdlciIsInJlbW92ZVRyYWNrZXJFdmVudExpc3RlbmVyIiwibGlzdGVuZXJJZCIsImdldFRyYWNraW5nU3RhdGlzdGljcyIsInN0YXJ0VGltZSIsInJlYWxUaW1lIiwiYWRkUGVyaW9kU3RhdGlzdGljc0xpc3RlbmVyIiwiX3BlcmlvZFN0YXRpc3RpY3NTdHJlYW1NYW5hZ2VyIiwicmVtb3ZlUGVyaW9kU3RhdGlzdGljc0xpc3RlbmVyIiwiZ2V0RXF1aXR5Q2hhcnQiLCJlbmRUaW1lIiwiZmlsbFNraXBzIiwicmVjb3JkcyIsImkiLCJsZW5ndGgiLCJ0aW1lRGlmZiIsIkRhdGUiLCJnZXRUaW1lIiwibGFzdEJhbGFuY2UiLCJ1bmRlZmluZWQiLCJyZWNvcmRDb3B5IiwiSlNPTiIsInBhcnNlIiwic3RyaW5naWZ5IiwibWluRXF1aXR5IiwibGFzdEVxdWl0eSIsIm1heEVxdWl0eSIsImF2ZXJhZ2VFcXVpdHkiLCJtaW5CYWxhbmNlIiwibWF4QmFsYW5jZSIsImF2ZXJhZ2VCYWxhbmNlIiwic2V0VVRDSG91cnMiLCJnZXRVVENIb3VycyIsInNldFVUQ01pbnV0ZXMiLCJzZXRVVENTZWNvbmRzIiwic2V0VVRDTWlsbGlzZWNvbmRzIiwibW9tZW50IiwiZm9ybWF0IiwiYnJva2VyVGltZSIsInNwbGljZSIsImFkZEVxdWl0eUNoYXJ0TGlzdGVuZXIiLCJfZXF1aXR5Q2hhcnRTdHJlYW1NYW5hZ2VyIiwicmVtb3ZlRXF1aXR5Q2hhcnRMaXN0ZW5lciIsImFkZEVxdWl0eUJhbGFuY2VMaXN0ZW5lciIsIl9lcXVpdHlCYWxhbmNlU3RyZWFtTWFuYWdlciIsInJlbW92ZUVxdWl0eUJhbGFuY2VMaXN0ZW5lciIsImNvbnN0cnVjdG9yIiwiZG9tYWluQ2xpZW50IiwibWV0YUFwaSIsIlRyYWNrZXJFdmVudExpc3RlbmVyTWFuYWdlciIsIkVxdWl0eUJhbGFuY2VTdHJlYW1NYW5hZ2VyIiwiUGVyaW9kU3RhdGlzdGljc1N0cmVhbU1hbmFnZXIiLCJFcXVpdHlDaGFydFN0cmVhbU1hbmFnZXIiXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7O2VBV3FCQTs7O29GQVRtQjtzRkFDRTtpRkFDTDttRkFDRTsrREFDcEI7Ozs7OztBQUtKLElBQUEsQUFBTUEsdUJBQU4sTUFBTUE7SUFlbkI7Ozs7OztHQU1DLEdBQ0RDLGNBQWNDLFNBQVMsRUFBRUMsT0FBTyxFQUFFO1FBQ2hDLE9BQU8sSUFBSSxDQUFDQyxhQUFhLENBQUNDLFVBQVUsQ0FBQztZQUNuQ0MsS0FBSyxDQUFD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