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)
260 lines (259 loc) • 35.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "default", {
enumerable: true,
get: function() {
return MetatraderAccountReplica;
}
});
const _timeoutError = /*#__PURE__*/ _interop_require_default(require("../clients/timeoutError"));
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
let MetatraderAccountReplica = class MetatraderAccountReplica {
/**
* Returns account replica id
* @return {string} unique account replica id
*/ get id() {
return this._data._id;
}
/**
* Returns current account replica state. One of CREATED, DEPLOYING, DEPLOYED, DEPLOY_FAILED, UNDEPLOYING,
* UNDEPLOYED, UNDEPLOY_FAILED, DELETING, DELETE_FAILED, REDEPLOY_FAILED, DRAFT
* @return {State} current account replica state
*/ get state() {
return this._data.state;
}
/**
* Returns MetaTrader magic to place trades using
* @return {number} MetaTrader magic to place trades using
*/ get magic() {
return this._data.magic;
}
/**
* Returns terminal & broker connection status, one of CONNECTED, DISCONNECTED, DISCONNECTED_FROM_BROKER
* @return {ConnectionStatus} terminal & broker connection status
*/ get connectionStatus() {
return this._data.connectionStatus;
}
/**
* Returns quote streaming interval in seconds
* @return {number} quote streaming interval in seconds
*/ get quoteStreamingIntervalInSeconds() {
return this._data.quoteStreamingIntervalInSeconds;
}
/**
* Returns symbol provided by broker
* @return {string} any symbol provided by broker
*/ get symbol() {
return this._data.symbol;
}
/**
* Returns reliability value. Possible values are regular and high
* @return {Reliability} account replica reliability value
*/ get reliability() {
return this._data.reliability;
}
/**
* Returns user-defined account replica tags
* @return {Array<string>} user-defined account replica tags
*/ get tags() {
return this._data.tags;
}
/**
* Returns extra information which can be stored together with your account replica
* @return {Object} extra information which can be stored together with your account replica
*/ get metadata() {
return this._data.metadata;
}
/**
* Returns number of resource slots to allocate to account replica. Allocating extra resource slots
* results in better account performance under load which is useful for some applications. E.g. if you have many
* accounts copying the same strategy via CopyFactory API, then you can increase resourceSlots to get a lower trade
* copying latency. Please note that allocating extra resource slots is a paid option. Please note that high
* reliability accounts use redundant infrastructure, so that each resource slot for a high reliability account
* is billed as 2 standard resource slots.
* @return {number} number of resource slots to allocate to account replica
*/ get resourceSlots() {
return this._data.resourceSlots;
}
/**
* Returns the number of CopyFactory 2 resource slots to allocate to account replica.
* Allocating extra resource slots results in lower trade copying latency. Please note that allocating extra resource
* slots is a paid option. Please also note that CopyFactory 2 uses redundant infrastructure so that
* each CopyFactory resource slot is billed as 2 standard resource slots. You will be billed for CopyFactory 2
* resource slots only if you have added your account replica to CopyFactory 2 by specifying copyFactoryRoles field.
* @return {number} number of CopyFactory 2 resource slots to allocate to account replica
*/ get copyFactoryResourceSlots() {
return this._data.copyFactoryResourceSlots;
}
/**
* Returns account replica region
* @return {string} account replica region value
*/ get region() {
return this._data.region;
}
/**
* Returns the time account replica was created at, in ISO format
* @returns {string} the time account replica was created at, in ISO format
*/ get createdAt() {
return new Date(this._data.createdAt);
}
/**
* Returns primary MetaTrader account of the replica from DTO
* @return {MetatraderAccount} primary MetaTrader account of the replica from DTO
*/ get primaryAccountFromDto() {
return this._data.primaryAccount;
}
/**
* Returns primary MetaTrader account of the replica
* @return {MetatraderAccount} primary MetaTrader account of the replica
*/ get primaryAccount() {
return this._primaryAccount;
}
/**
* Updates account replica data
* @param {MetatraderAccountReplicaDto} data MetaTrader account replica data
*/ updateData(data) {
this._data = data;
}
/**
* Removes a trading account replica and stops the API server serving the replica
* @return {Promise} promise resolving when account replica is scheduled for deletion
*/ async remove() {
await this._metatraderAccountClient.deleteAccountReplica(this.primaryAccount.id, this.id);
try {
await this._primaryAccount.reload();
} catch (err) {
if (err.name !== "NotFoundError") {
throw err;
}
}
}
/**
* Starts API server and trading terminal for trading account replica.
* This request will be ignored if the replica is already deployed
* @returns {Promise} promise resolving when account replica is scheduled for deployment
*/ async deploy() {
await this._metatraderAccountClient.deployAccountReplica(this.primaryAccount.id, this.id);
await this._primaryAccount.reload();
}
/**
* Stops API server and trading terminal for trading account replica.
* The request will be ignored if trading account replica is already undeployed
* @returns {Promise} promise resolving when account replica is scheduled for undeployment
*/ async undeploy() {
await this._metatraderAccountClient.undeployAccountReplica(this.primaryAccount.id, this.id);
await this._primaryAccount.reload();
}
/**
* Redeploys trading account replica. This is equivalent to undeploy immediately followed by deploy.
* @returns {Promise} promise resolving when account replica is scheduled for redeployment
*/ async redeploy() {
await this._metatraderAccountClient.redeployAccountReplica(this.primaryAccount.id, this.id);
await this._primaryAccount.reload();
}
/**
* Increases trading account reliability in order to increase the expected account uptime.
* The account will be temporary stopped to perform this action.
* Note that increasing reliability is a paid option
* @returns {Promise} promise resolving when account replica reliability is increased
*/ async increaseReliability() {
await this._metatraderAccountClient.increaseReliability(this.id);
await this._primaryAccount.reload();
}
/**
* Waits until API server has finished deployment and account replica reached the DEPLOYED state
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account replica reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account replica is deployed
* @throws {TimeoutError} if account replica has not reached the DEPLOYED state within timeout allowed
*/ async waitDeployed(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
let startTime = Date.now();
await this._primaryAccount.reload();
while(this.state !== "DEPLOYED" && startTime + timeoutInSeconds * 1000 > Date.now()){
await this._delay(intervalInMilliseconds);
await this._primaryAccount.reload();
}
if (this.state !== "DEPLOYED") {
throw new _timeoutError.default("Timed out waiting for account replica " + this.id + " to be deployed");
}
}
/**
* Waits until API server has finished undeployment and account replica reached the UNDEPLOYED state
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account replica reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account replica is deployed
* @throws {TimeoutError} if account replica has not reached the UNDEPLOYED state within timeout allowed
*/ async waitUndeployed(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
let startTime = Date.now();
await this._primaryAccount.reload();
while(this.state !== "UNDEPLOYED" && startTime + timeoutInSeconds * 1000 > Date.now()){
await this._delay(intervalInMilliseconds);
await this._primaryAccount.reload();
}
if (this.state !== "UNDEPLOYED") {
throw new _timeoutError.default("Timed out waiting for account replica " + this.id + " to be undeployed");
}
}
/**
* Waits until account replica has been deleted
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account replica reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account replica is deleted
* @throws {TimeoutError} if account replica was not deleted within timeout allowed
*/ async waitRemoved(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
let startTime = Date.now();
await this._primaryAccount.reload();
while(startTime + timeoutInSeconds * 1000 > Date.now() && this._primaryAccount.accountRegions[this.region] === this.id){
await this._delay(intervalInMilliseconds);
await this._primaryAccount.reload();
}
if (this._primaryAccount.accountRegions[this.region] === this.id) {
throw new _timeoutError.default("Timed out waiting for account " + this.id + " to be deleted");
}
}
/**
* Waits until API server has connected to the terminal and terminal has connected to the broker
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account replica reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when API server is connected to the broker
* @throws {TimeoutError} if account replica has not connected to the broker within timeout allowed
*/ async waitConnected(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
let startTime = Date.now();
await this._primaryAccount.reload();
while(this.connectionStatus !== "CONNECTED" && startTime + timeoutInSeconds * 1000 > Date.now()){
await this._delay(intervalInMilliseconds);
await this._primaryAccount.reload();
}
if (this.connectionStatus !== "CONNECTED") {
throw new _timeoutError.default("Timed out waiting for account " + this.id + " to connect to the broker");
}
}
/**
* Updates trading account replica
* @param {UpdatedMetatraderAccountReplicaDto} metatraderAccount updated account replica information
* @return {Promise} promise resolving when account replica is updated
*/ async update(metatraderAccount) {
await this._metatraderAccountClient.updateAccountReplica(this._primaryAccount.id, this.id, metatraderAccount);
await this._primaryAccount.reload();
}
_delay(timeoutInMilliseconds) {
return new Promise((res)=>setTimeout(res, timeoutInMilliseconds));
}
/**
* Constructs a MetaTrader account replica entity
* @param {MetatraderAccountReplicaDto} data MetaTrader account replica data
* @param {MetatraderAccount} primaryAccount primary MetaTrader account
* @param {MetatraderAccountClient} metatraderAccountClient MetaTrader account REST API client
*/ constructor(data, primaryAccount, metatraderAccountClient){
this._data = data;
this._primaryAccount = primaryAccount;
this._metatraderAccountClient = metatraderAccountClient;
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgVGltZW91dEVycm9yIGZyb20gJy4uL2NsaWVudHMvdGltZW91dEVycm9yJztcbi8vIGltcG9ydCB7UmVsaWFiaWxpdHksIFN0YXRlLCBDb25uZWN0aW9uU3RhdHVzfSBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvbWV0YXRyYWRlckFjY291bnQuY2xpZW50JztcblxuLyoqXG4gKiBJbXBsZW1lbnRzIGEgTWV0YVRyYWRlciBhY2NvdW50IHJlcGxpY2EgZW50aXR5XG4gKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1ldGF0cmFkZXJBY2NvdW50UmVwbGljYSB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgYSBNZXRhVHJhZGVyIGFjY291bnQgcmVwbGljYSBlbnRpdHlcbiAgICogQHBhcmFtIHtNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2FEdG99IGRhdGEgTWV0YVRyYWRlciBhY2NvdW50IHJlcGxpY2EgZGF0YVxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50fSBwcmltYXJ5QWNjb3VudCBwcmltYXJ5IE1ldGFUcmFkZXIgYWNjb3VudFxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50Q2xpZW50fSBtZXRhdHJhZGVyQWNjb3VudENsaWVudCBNZXRhVHJhZGVyIGFjY291bnQgUkVTVCBBUEkgY2xpZW50XG4gICAqL1xuICBjb25zdHJ1Y3RvcihkYXRhLCBwcmltYXJ5QWNjb3VudCwgbWV0YXRyYWRlckFjY291bnRDbGllbnQpIHtcbiAgICB0aGlzLl9kYXRhID0gZGF0YTtcbiAgICB0aGlzLl9wcmltYXJ5QWNjb3VudCA9IHByaW1hcnlBY2NvdW50O1xuICAgIHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50ID0gbWV0YXRyYWRlckFjY291bnRDbGllbnQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhY2NvdW50IHJlcGxpY2EgaWRcbiAgICogQHJldHVybiB7c3RyaW5nfSB1bmlxdWUgYWNjb3VudCByZXBsaWNhIGlkXG4gICAqL1xuICBnZXQgaWQoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuX2lkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY3VycmVudCBhY2NvdW50IHJlcGxpY2Egc3RhdGUuIE9uZSBvZiBDUkVBVEVELCBERVBMT1lJTkcsIERFUExPWUVELCBERVBMT1lfRkFJTEVELCBVTkRFUExPWUlORyxcbiAgICogVU5ERVBMT1lFRCwgVU5ERVBMT1lfRkFJTEVELCBERUxFVElORywgREVMRVRFX0ZBSUxFRCwgUkVERVBMT1lfRkFJTEVELCBEUkFGVFxuICAgKiBAcmV0dXJuIHtTdGF0ZX0gY3VycmVudCBhY2NvdW50IHJlcGxpY2Egc3RhdGVcbiAgICovXG4gIGdldCBzdGF0ZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5zdGF0ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIE1ldGFUcmFkZXIgbWFnaWMgdG8gcGxhY2UgdHJhZGVzIHVzaW5nXG4gICAqIEByZXR1cm4ge251bWJlcn0gTWV0YVRyYWRlciBtYWdpYyB0byBwbGFjZSB0cmFkZXMgdXNpbmdcbiAgICovXG4gIGdldCBtYWdpYygpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5tYWdpYztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgdGVybWluYWwgJiBicm9rZXIgY29ubmVjdGlvbiBzdGF0dXMsIG9uZSBvZiBDT05ORUNURUQsIERJU0NPTk5FQ1RFRCwgRElTQ09OTkVDVEVEX0ZST01fQlJPS0VSXG4gICAqIEByZXR1cm4ge0Nvbm5lY3Rpb25TdGF0dXN9IHRlcm1pbmFsICYgYnJva2VyIGNvbm5lY3Rpb24gc3RhdHVzXG4gICAqL1xuICBnZXQgY29ubmVjdGlvblN0YXR1cygpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5jb25uZWN0aW9uU3RhdHVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcXVvdGUgc3RyZWFtaW5nIGludGVydmFsIGluIHNlY29uZHMgXG4gICAqIEByZXR1cm4ge251bWJlcn0gcXVvdGUgc3RyZWFtaW5nIGludGVydmFsIGluIHNlY29uZHNcbiAgICovXG4gIGdldCBxdW90ZVN0cmVhbWluZ0ludGVydmFsSW5TZWNvbmRzKCkge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnF1b3RlU3RyZWFtaW5nSW50ZXJ2YWxJblNlY29uZHM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBzeW1ib2wgcHJvdmlkZWQgYnkgYnJva2VyIFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IGFueSBzeW1ib2wgcHJvdmlkZWQgYnkgYnJva2VyXG4gICAqL1xuICBnZXQgc3ltYm9sKCkge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnN5bWJvbDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHJlbGlhYmlsaXR5IHZhbHVlLiBQb3NzaWJsZSB2YWx1ZXMgYXJlIHJlZ3VsYXIgYW5kIGhpZ2hcbiAgICogQHJldHVybiB7UmVsaWFiaWxpdHl9IGFjY291bnQgcmVwbGljYSByZWxpYWJpbGl0eSB2YWx1ZVxuICAgKi9cbiAgZ2V0IHJlbGlhYmlsaXR5KCkge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnJlbGlhYmlsaXR5O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdXNlci1kZWZpbmVkIGFjY291bnQgcmVwbGljYSB0YWdzXG4gICAqIEByZXR1cm4ge0FycmF5PHN0cmluZz59IHVzZXItZGVmaW5lZCBhY2NvdW50IHJlcGxpY2EgdGFnc1xuICAgKi9cbiAgZ2V0IHRhZ3MoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEudGFncztcbiAgfSAgXG5cbiAgLyoqXG4gICAqIFJldHVybnMgZXh0cmEgaW5mb3JtYXRpb24gd2hpY2ggY2FuIGJlIHN0b3JlZCB0b2dldGhlciB3aXRoIHlvdXIgYWNjb3VudCByZXBsaWNhXG4gICAqIEByZXR1cm4ge09iamVjdH0gZXh0cmEgaW5mb3JtYXRpb24gd2hpY2ggY2FuIGJlIHN0b3JlZCB0b2dldGhlciB3aXRoIHlvdXIgYWNjb3VudCByZXBsaWNhXG4gICAqL1xuICBnZXQgbWV0YWRhdGEoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEubWV0YWRhdGE7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBudW1iZXIgb2YgcmVzb3VyY2Ugc2xvdHMgdG8gYWxsb2NhdGUgdG8gYWNjb3VudCByZXBsaWNhLiBBbGxvY2F0aW5nIGV4dHJhIHJlc291cmNlIHNsb3RzXG4gICAqIHJlc3VsdHMgaW4gYmV0dGVyIGFjY291bnQgcGVyZm9ybWFuY2UgdW5kZXIgbG9hZCB3aGljaCBpcyB1c2VmdWwgZm9yIHNvbWUgYXBwbGljYXRpb25zLiBFLmcuIGlmIHlvdSBoYXZlIG1hbnlcbiAgICogYWNjb3VudHMgY29weWluZyB0aGUgc2FtZSBzdHJhdGVneSB2aWEgQ29weUZhY3RvcnkgQVBJLCB0aGVuIHlvdSBjYW4gaW5jcmVhc2UgcmVzb3VyY2VTbG90cyB0byBnZXQgYSBsb3dlciB0cmFkZVxuICAgKiBjb3B5aW5nIGxhdGVuY3kuIFBsZWFzZSBub3RlIHRoYXQgYWxsb2NhdGluZyBleHRyYSByZXNvdXJjZSBzbG90cyBpcyBhIHBhaWQgb3B0aW9uLiBQbGVhc2Ugbm90ZSB0aGF0IGhpZ2hcbiAgICogcmVsaWFiaWxpdHkgYWNjb3VudHMgdXNlIHJlZHVuZGFudCBpbmZyYXN0cnVjdHVyZSwgc28gdGhhdCBlYWNoIHJlc291cmNlIHNsb3QgZm9yIGEgaGlnaCByZWxpYWJpbGl0eSBhY2NvdW50XG4gICAqIGlzIGJpbGxlZCBhcyAyIHN0YW5kYXJkIHJlc291cmNlIHNsb3RzLlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IG51bWJlciBvZiByZXNvdXJjZSBzbG90cyB0byBhbGxvY2F0ZSB0byBhY2NvdW50IHJlcGxpY2FcbiAgICovXG4gIGdldCByZXNvdXJjZVNsb3RzKCkge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnJlc291cmNlU2xvdHM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgbnVtYmVyIG9mIENvcHlGYWN0b3J5IDIgcmVzb3VyY2Ugc2xvdHMgdG8gYWxsb2NhdGUgdG8gYWNjb3VudCByZXBsaWNhLlxuICAgKiBBbGxvY2F0aW5nIGV4dHJhIHJlc291cmNlIHNsb3RzIHJlc3VsdHMgaW4gbG93ZXIgdHJhZGUgY29weWluZyBsYXRlbmN5LiBQbGVhc2Ugbm90ZSB0aGF0IGFsbG9jYXRpbmcgZXh0cmEgcmVzb3VyY2VcbiAgICogc2xvdHMgaXMgYSBwYWlkIG9wdGlvbi4gUGxlYXNlIGFsc28gbm90ZSB0aGF0IENvcHlGYWN0b3J5IDIgdXNlcyByZWR1bmRhbnQgaW5mcmFzdHJ1Y3R1cmUgc28gdGhhdFxuICAgKiBlYWNoIENvcHlGYWN0b3J5IHJlc291cmNlIHNsb3QgaXMgYmlsbGVkIGFzIDIgc3RhbmRhcmQgcmVzb3VyY2Ugc2xvdHMuIFlvdSB3aWxsIGJlIGJpbGxlZCBmb3IgQ29weUZhY3RvcnkgMlxuICAgKiByZXNvdXJjZSBzbG90cyBvbmx5IGlmIHlvdSBoYXZlIGFkZGVkIHlvdXIgYWNjb3VudCByZXBsaWNhIHRvIENvcHlGYWN0b3J5IDIgYnkgc3BlY2lmeWluZyBjb3B5RmFjdG9yeVJvbGVzIGZpZWxkLlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IG51bWJlciBvZiBDb3B5RmFjdG9yeSAyIHJlc291cmNlIHNsb3RzIHRvIGFsbG9jYXRlIHRvIGFjY291bnQgcmVwbGljYVxuICAgKi9cbiAgZ2V0IGNvcHlGYWN0b3J5UmVzb3VyY2VTbG90cygpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5jb3B5RmFjdG9yeVJlc291cmNlU2xvdHM7XG4gIH1cblxuICAvKipcbiAgICAgKiBSZXR1cm5zIGFjY291bnQgcmVwbGljYSByZWdpb25cbiAgICAgKiBAcmV0dXJuIHtzdHJpbmd9IGFjY291bnQgcmVwbGljYSByZWdpb24gdmFsdWVcbiAgICAgKi9cbiAgZ2V0IHJlZ2lvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5yZWdpb247XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgdGltZSBhY2NvdW50IHJlcGxpY2Egd2FzIGNyZWF0ZWQgYXQsIGluIElTTyBmb3JtYXRcbiAgICogQHJldHVybnMge3N0cmluZ30gdGhlIHRpbWUgYWNjb3VudCByZXBsaWNhIHdhcyBjcmVhdGVkIGF0LCBpbiBJU08gZm9ybWF0XG4gICAqL1xuICBnZXQgY3JlYXRlZEF0KCkge1xuICAgIHJldHVybiBuZXcgRGF0ZSh0aGlzLl9kYXRhLmNyZWF0ZWRBdCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwcmltYXJ5IE1ldGFUcmFkZXIgYWNjb3VudCBvZiB0aGUgcmVwbGljYSBmcm9tIERUT1xuICAgKiBAcmV0dXJuIHtNZXRhdHJhZGVyQWNjb3VudH0gcHJpbWFyeSBNZXRhVHJhZGVyIGFjY291bnQgb2YgdGhlIHJlcGxpY2EgZnJvbSBEVE9cbiAgICovXG4gIGdldCBwcmltYXJ5QWNjb3VudEZyb21EdG8oKSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEucHJpbWFyeUFjY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBwcmltYXJ5IE1ldGFUcmFkZXIgYWNjb3VudCBvZiB0aGUgcmVwbGljYVxuICAgKiBAcmV0dXJuIHtNZXRhdHJhZGVyQWNjb3VudH0gcHJpbWFyeSBNZXRhVHJhZGVyIGFjY291bnQgb2YgdGhlIHJlcGxpY2FcbiAgICovXG4gIGdldCBwcmltYXJ5QWNjb3VudCgpIHtcbiAgICByZXR1cm4gdGhpcy5fcHJpbWFyeUFjY291bnQ7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBhY2NvdW50IHJlcGxpY2EgZGF0YVxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50UmVwbGljYUR0b30gZGF0YSBNZXRhVHJhZGVyIGFjY291bnQgcmVwbGljYSBkYXRhIFxuICAgKi9cbiAgdXBkYXRlRGF0YShkYXRhKSB7XG4gICAgdGhpcy5fZGF0YSA9IGRhdGE7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHRyYWRpbmcgYWNjb3VudCByZXBsaWNhIGFuZCBzdG9wcyB0aGUgQVBJIHNlcnZlciBzZXJ2aW5nIHRoZSByZXBsaWNhXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gYWNjb3VudCByZXBsaWNhIGlzIHNjaGVkdWxlZCBmb3IgZGVsZXRpb25cbiAgICovXG4gIGFzeW5jIHJlbW92ZSgpIHtcbiAgICBhd2FpdCB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudENsaWVudC5kZWxldGVBY2NvdW50UmVwbGljYSh0aGlzLnByaW1hcnlBY2NvdW50LmlkLCB0aGlzLmlkKTtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBpZiAoZXJyLm5hbWUgIT09ICdOb3RGb3VuZEVycm9yJykge1xuICAgICAgICB0aHJvdyBlcnI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0cyBBUEkgc2VydmVyIGFuZCB0cmFkaW5nIHRlcm1pbmFsIGZvciB0cmFkaW5nIGFjY291bnQgcmVwbGljYS5cbiAgICogVGhpcyByZXF1ZXN0IHdpbGwgYmUgaWdub3JlZCBpZiB0aGUgcmVwbGljYSBpcyBhbHJlYWR5IGRlcGxveWVkXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIGFjY291bnQgcmVwbGljYSBpcyBzY2hlZHVsZWQgZm9yIGRlcGxveW1lbnRcbiAgICovXG4gIGFzeW5jIGRlcGxveSgpIHtcbiAgICBhd2FpdCB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudENsaWVudC5kZXBsb3lBY2NvdW50UmVwbGljYSh0aGlzLnByaW1hcnlBY2NvdW50LmlkLCB0aGlzLmlkKTtcbiAgICBhd2FpdCB0aGlzLl9wcmltYXJ5QWNjb3VudC5yZWxvYWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyBBUEkgc2VydmVyIGFuZCB0cmFkaW5nIHRlcm1pbmFsIGZvciB0cmFkaW5nIGFjY291bnQgcmVwbGljYS5cbiAgICogVGhlIHJlcXVlc3Qgd2lsbCBiZSBpZ25vcmVkIGlmIHRyYWRpbmcgYWNjb3VudCByZXBsaWNhIGlzIGFscmVhZHkgdW5kZXBsb3llZFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IHJlcGxpY2EgaXMgc2NoZWR1bGVkIGZvciB1bmRlcGxveW1lbnRcbiAgICovXG4gIGFzeW5jIHVuZGVwbG95KCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LnVuZGVwbG95QWNjb3VudFJlcGxpY2EodGhpcy5wcmltYXJ5QWNjb3VudC5pZCwgdGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVkZXBsb3lzIHRyYWRpbmcgYWNjb3VudCByZXBsaWNhLiBUaGlzIGlzIGVxdWl2YWxlbnQgdG8gdW5kZXBsb3kgaW1tZWRpYXRlbHkgZm9sbG93ZWQgYnkgZGVwbG95LlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IHJlcGxpY2EgaXMgc2NoZWR1bGVkIGZvciByZWRlcGxveW1lbnRcbiAgICovXG4gIGFzeW5jIHJlZGVwbG95KCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LnJlZGVwbG95QWNjb3VudFJlcGxpY2EodGhpcy5wcmltYXJ5QWNjb3VudC5pZCwgdGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogSW5jcmVhc2VzIHRyYWRpbmcgYWNjb3VudCByZWxpYWJpbGl0eSBpbiBvcmRlciB0byBpbmNyZWFzZSB0aGUgZXhwZWN0ZWQgYWNjb3VudCB1cHRpbWUuXG4gICAqIFRoZSBhY2NvdW50IHdpbGwgYmUgdGVtcG9yYXJ5IHN0b3BwZWQgdG8gcGVyZm9ybSB0aGlzIGFjdGlvbi5cbiAgICogTm90ZSB0aGF0IGluY3JlYXNpbmcgcmVsaWFiaWxpdHkgaXMgYSBwYWlkIG9wdGlvblxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IHJlcGxpY2EgcmVsaWFiaWxpdHkgaXMgaW5jcmVhc2VkXG4gICAqL1xuICBhc3luYyBpbmNyZWFzZVJlbGlhYmlsaXR5KCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LmluY3JlYXNlUmVsaWFiaWxpdHkodGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgdW50aWwgQVBJIHNlcnZlciBoYXMgZmluaXNoZWQgZGVwbG95bWVudCBhbmQgYWNjb3VudCByZXBsaWNhIHJlYWNoZWQgdGhlIERFUExPWUVEIHN0YXRlXG4gICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lb3V0SW5TZWNvbmRzIHdhaXQgdGltZW91dCBpbiBzZWNvbmRzLCBkZWZhdWx0IGlzIDVtXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbnRlcnZhbEluTWlsbGlzZWNvbmRzIGludGVydmFsIGJldHdlZW4gYWNjb3VudCByZXBsaWNhIHJlbG9hZHMgd2hpbGUgd2FpdGluZyBmb3IgYSBjaGFuZ2UsIGRlZmF1bHQgaXMgMXNcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIGFjY291bnQgcmVwbGljYSBpcyBkZXBsb3llZFxuICAgKiBAdGhyb3dzIHtUaW1lb3V0RXJyb3J9IGlmIGFjY291bnQgcmVwbGljYSBoYXMgbm90IHJlYWNoZWQgdGhlIERFUExPWUVEIHN0YXRlIHdpdGhpbiB0aW1lb3V0IGFsbG93ZWRcbiAgICovXG4gIGFzeW5jIHdhaXREZXBsb3llZCh0aW1lb3V0SW5TZWNvbmRzID0gMzAwLCBpbnRlcnZhbEluTWlsbGlzZWNvbmRzID0gMTAwMCkge1xuICAgIGxldCBzdGFydFRpbWUgPSBEYXRlLm5vdygpO1xuICAgIGF3YWl0IHRoaXMuX3ByaW1hcnlBY2NvdW50LnJlbG9hZCgpO1xuICAgIHdoaWxlICh0aGlzLnN0YXRlICE9PSAnREVQTE9ZRUQnICYmIChzdGFydFRpbWUgKyB0aW1lb3V0SW5TZWNvbmRzICogMTAwMCkgPiBEYXRlLm5vdygpKSB7XG4gICAgICBhd2FpdCB0aGlzLl9kZWxheShpbnRlcnZhbEluTWlsbGlzZWNvbmRzKTtcbiAgICAgIGF3YWl0IHRoaXMuX3ByaW1hcnlBY2NvdW50LnJlbG9hZCgpO1xuICAgIH1cbiAgICBpZiAodGhpcy5zdGF0ZSAhPT0gJ0RFUExPWUVEJykge1xuICAgICAgdGhyb3cgbmV3IFRpbWVvdXRFcnJvcignVGltZWQgb3V0IHdhaXRpbmcgZm9yIGFjY291bnQgcmVwbGljYSAnICsgdGhpcy5pZCArICcgdG8gYmUgZGVwbG95ZWQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgdW50aWwgQVBJIHNlcnZlciBoYXMgZmluaXNoZWQgdW5kZXBsb3ltZW50IGFuZCBhY2NvdW50IHJlcGxpY2EgcmVhY2hlZCB0aGUgVU5ERVBMT1lFRCBzdGF0ZVxuICAgKiBAcGFyYW0ge251bWJlcn0gdGltZW91dEluU2Vjb25kcyB3YWl0IHRpbWVvdXQgaW4gc2Vjb25kcywgZGVmYXVsdCBpcyA1bVxuICAgKiBAcGFyYW0ge251bWJlcn0gaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyBpbnRlcnZhbCBiZXR3ZWVuIGFjY291bnQgcmVwbGljYSByZWxvYWRzIHdoaWxlIHdhaXRpbmcgZm9yIGEgY2hhbmdlLCBkZWZhdWx0IGlzIDFzXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiBhY2NvdW50IHJlcGxpY2EgaXMgZGVwbG95ZWRcbiAgICogQHRocm93cyB7VGltZW91dEVycm9yfSBpZiBhY2NvdW50IHJlcGxpY2EgaGFzIG5vdCByZWFjaGVkIHRoZSBVTkRFUExPWUVEIHN0YXRlIHdpdGhpbiB0aW1lb3V0IGFsbG93ZWRcbiAgICovXG4gIGFzeW5jIHdhaXRVbmRlcGxveWVkKHRpbWVvdXRJblNlY29uZHMgPSAzMDAsIGludGVydmFsSW5NaWxsaXNlY29uZHMgPSAxMDAwKSB7XG4gICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gICAgd2hpbGUgKHRoaXMuc3RhdGUgIT09ICdVTkRFUExPWUVEJyAmJiAoc3RhcnRUaW1lICsgdGltZW91dEluU2Vjb25kcyAqIDEwMDApID4gRGF0ZS5ub3coKSkge1xuICAgICAgYXdhaXQgdGhpcy5fZGVsYXkoaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyk7XG4gICAgICBhd2FpdCB0aGlzLl9wcmltYXJ5QWNjb3VudC5yZWxvYWQoKTtcbiAgICB9XG4gICAgaWYgKHRoaXMuc3RhdGUgIT09ICdVTkRFUExPWUVEJykge1xuICAgICAgdGhyb3cgbmV3IFRpbWVvdXRFcnJvcignVGltZWQgb3V0IHdhaXRpbmcgZm9yIGFjY291bnQgcmVwbGljYSAnICsgdGhpcy5pZCArICcgdG8gYmUgdW5kZXBsb3llZCcpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXYWl0cyB1bnRpbCBhY2NvdW50IHJlcGxpY2EgaGFzIGJlZW4gZGVsZXRlZFxuICAgKiBAcGFyYW0ge251bWJlcn0gdGltZW91dEluU2Vjb25kcyB3YWl0IHRpbWVvdXQgaW4gc2Vjb25kcywgZGVmYXVsdCBpcyA1bVxuICAgKiBAcGFyYW0ge251bWJlcn0gaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyBpbnRlcnZhbCBiZXR3ZWVuIGFjY291bnQgcmVwbGljYSByZWxvYWRzIHdoaWxlIHdhaXRpbmcgZm9yIGEgY2hhbmdlLCBkZWZhdWx0IGlzIDFzXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2Ugd2hpY2ggcmVzb2x2ZXMgd2hlbiBhY2NvdW50IHJlcGxpY2EgaXMgZGVsZXRlZFxuICAgKiBAdGhyb3dzIHtUaW1lb3V0RXJyb3J9IGlmIGFjY291bnQgcmVwbGljYSB3YXMgbm90IGRlbGV0ZWQgd2l0aGluIHRpbWVvdXQgYWxsb3dlZFxuICAgKi9cbiAgYXN5bmMgd2FpdFJlbW92ZWQodGltZW91dEluU2Vjb25kcyA9IDMwMCwgaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyA9IDEwMDApIHtcbiAgICBsZXQgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBhd2FpdCB0aGlzLl9wcmltYXJ5QWNjb3VudC5yZWxvYWQoKTtcbiAgICB3aGlsZSAoc3RhcnRUaW1lICsgdGltZW91dEluU2Vjb25kcyAqIDEwMDAgPiBEYXRlLm5vdygpICYmIFxuICAgICAgICB0aGlzLl9wcmltYXJ5QWNjb3VudC5hY2NvdW50UmVnaW9uc1t0aGlzLnJlZ2lvbl0gPT09IHRoaXMuaWQpIHtcbiAgICAgIGF3YWl0IHRoaXMuX2RlbGF5KGludGVydmFsSW5NaWxsaXNlY29uZHMpO1xuICAgICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gICAgfVxuICAgIGlmKHRoaXMuX3ByaW1hcnlBY2NvdW50LmFjY291bnRSZWdpb25zW3RoaXMucmVnaW9uXSA9PT0gdGhpcy5pZCkge1xuICAgICAgdGhyb3cgbmV3IFRpbWVvdXRFcnJvcignVGltZWQgb3V0IHdhaXRpbmcgZm9yIGFjY291bnQgJyArIHRoaXMuaWQgKyAnIHRvIGJlIGRlbGV0ZWQnKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogV2FpdHMgdW50aWwgQVBJIHNlcnZlciBoYXMgY29ubmVjdGVkIHRvIHRoZSB0ZXJtaW5hbCBhbmQgdGVybWluYWwgaGFzIGNvbm5lY3RlZCB0byB0aGUgYnJva2VyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSB0aW1lb3V0SW5TZWNvbmRzIHdhaXQgdGltZW91dCBpbiBzZWNvbmRzLCBkZWZhdWx0IGlzIDVtXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbnRlcnZhbEluTWlsbGlzZWNvbmRzIGludGVydmFsIGJldHdlZW4gYWNjb3VudCByZXBsaWNhIHJlbG9hZHMgd2hpbGUgd2FpdGluZyBmb3IgYSBjaGFuZ2UsIGRlZmF1bHQgaXMgMXNcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSB3aGljaCByZXNvbHZlcyB3aGVuIEFQSSBzZXJ2ZXIgaXMgY29ubmVjdGVkIHRvIHRoZSBicm9rZXJcbiAgICogQHRocm93cyB7VGltZW91dEVycm9yfSBpZiBhY2NvdW50IHJlcGxpY2EgaGFzIG5vdCBjb25uZWN0ZWQgdG8gdGhlIGJyb2tlciB3aXRoaW4gdGltZW91dCBhbGxvd2VkXG4gICAqL1xuICBhc3luYyB3YWl0Q29ubmVjdGVkKHRpbWVvdXRJblNlY29uZHMgPSAzMDAsIGludGVydmFsSW5NaWxsaXNlY29uZHMgPSAxMDAwKSB7XG4gICAgbGV0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gICAgd2hpbGUgKHRoaXMuY29ubmVjdGlvblN0YXR1cyAhPT0gJ0NPTk5FQ1RFRCcgJiYgKHN0YXJ0VGltZSArIHRpbWVvdXRJblNlY29uZHMgKiAxMDAwKSA+IERhdGUubm93KCkpIHtcbiAgICAgIGF3YWl0IHRoaXMuX2RlbGF5KGludGVydmFsSW5NaWxsaXNlY29uZHMpO1xuICAgICAgYXdhaXQgdGhpcy5fcHJpbWFyeUFjY291bnQucmVsb2FkKCk7XG4gICAgfVxuICAgIGlmICh0aGlzLmNvbm5lY3Rpb25TdGF0dXMgIT09ICdDT05ORUNURUQnKSB7XG4gICAgICB0aHJvdyBuZXcgVGltZW91dEVycm9yKCdUaW1lZCBvdXQgd2FpdGluZyBmb3IgYWNjb3VudCAnICsgdGhpcy5pZCArICcgdG8gY29ubmVjdCB0byB0aGUgYnJva2VyJyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgdHJhZGluZyBhY2NvdW50IHJlcGxpY2FcbiAgICogQHBhcmFtIHtVcGRhdGVkTWV0YXRyYWRlckFjY291bnRSZXBsaWNhRHRvfSBtZXRhdHJhZGVyQWNjb3VudCB1cGRhdGVkIGFjY291bnQgcmVwbGljYSBpbmZvcm1hdGlvblxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIGFjY291bnQgcmVwbGljYSBpcyB1cGRhdGVkXG4gICAqL1xuICBhc3luYyB1cGRhdGUobWV0YXRyYWRlckFjY291bnQpIHtcbiAgICBhd2FpdCB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudENsaWVudC51cGRhdGVBY2NvdW50UmVwbGljYSh0aGlzLl9wcmltYXJ5QWNjb3VudC5pZCwgdGhpcy5pZCwgbWV0YXRyYWRlckFjY291bnQpO1xuICAgIGF3YWl0IHRoaXMuX3ByaW1hcnlBY2NvdW50LnJlbG9hZCgpO1xuICB9XG5cbiAgX2RlbGF5KHRpbWVvdXRJbk1pbGxpc2Vjb25kcykge1xuICAgIHJldHVybiBuZXcgUHJvbWlzZShyZXMgPT4gc2V0VGltZW91dChyZXMsIHRpbWVvdXRJbk1pbGxpc2Vjb25kcykpO1xuICB9XG5cbn1cbiJdLCJuYW1lcyI6WyJNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2EiLCJpZCIsIl9kYXRhIiwiX2lkIiwic3RhdGUiLCJtYWdpYyIsImNvbm5lY3Rpb25TdGF0dXMiLCJxdW90ZVN0cmVhbWluZ0ludGVydmFsSW5TZWNvbmRzIiwic3ltYm9sIiwicmVsaWFiaWxpdHkiLCJ0YWdzIiwibWV0YWRhdGEiLCJyZXNvdXJjZVNsb3RzIiwiY29weUZhY3RvcnlSZXNvdXJjZVNsb3RzIiwicmVnaW9uIiwiY3JlYXRlZEF0IiwiRGF0ZSIsInByaW1hcnlBY2NvdW50RnJvbUR0byIsInByaW1hcnlBY2NvdW50IiwiX3ByaW1hcnlBY2NvdW50IiwidXBkYXRlRGF0YSIsImRhdGEiLCJyZW1vdmUiLCJfbWV0YXRyYWRlckFjY291bnRDbGllbnQiLCJkZWxldGVBY2NvdW50UmVwbGljYSIsInJlbG9hZCIsImVyciIsIm5hbWUiLCJkZXBsb3kiLCJkZXBsb3lBY2NvdW50UmVwbGljYSIsInVuZGVwbG95IiwidW5kZXBsb3lBY2NvdW50UmVwbGljYSIsInJlZGVwbG95IiwicmVkZXBsb3lBY2NvdW50UmVwbGljYSIsImluY3JlYXNlUmVsaWFiaWxpdHkiLCJ3YWl0RGVwbG95ZWQiLCJ0aW1lb3V0SW5TZWNvbmRzIiwiaW50ZXJ2YWxJbk1pbGxpc2Vjb25kcyIsInN0YXJ0VGltZSIsIm5vdyIsIl9kZWxheSIsIlRpbWVvdXRFcnJvciIsIndhaXRVbmRlcGxveWVkIiwid2FpdFJlbW92ZWQiLCJhY2NvdW50UmVnaW9ucyIsIndhaXRDb25uZWN0ZWQiLCJ1cGRhdGUiLCJtZXRhdHJhZGVyQWNjb3VudCIsInVwZGF0ZUFjY291bnRSZXBsaWNhIiwidGltZW91dEluTWlsbGlzZWNvbmRzIiwiUHJvbWlzZSIsInJlcyIsInNldFRpbWVvdXQiLCJjb25zdHJ1Y3RvciIsIm1ldGF0cmFkZXJBY2NvdW50Q2xpZW50Il0sIm1hcHBpbmdzIjoiOzs7Ozs7O2VBTXFCQTs7O3FFQU5JOzs7Ozs7QUFNVixJQUFBLEFBQU1BLDJCQUFOLE1BQU1BO0lBY25COzs7R0FHQyxHQUNELElBQUlDLEtBQUs7UUFDUCxPQUFPLElBQUksQ0FBQ0MsS0FBSyxDQUFDQyxHQUFHO0lBQ3ZCO0lBRUE7Ozs7R0FJQyxHQUNELElBQUlDLFFBQVE7UUFDVixPQUFPLElBQUksQ0FBQ0YsS0FBSyxDQUFDRSxLQUFLO0lBQ3pCO0lBRUE7OztHQUdDLEdBQ0QsSUFBSUMsUUFBUTtRQUNWLE9BQU8sSUFBSSxDQUFDSCxLQUFLLENBQUNHLEtBQUs7SUFDekI7SUFFQTs7O0dBR0MsR0FDRCxJQUFJQyxtQkFBbUI7UUFDckIsT0FBTyxJQUFJLENBQUNKLEtBQUssQ0FBQ0ksZ0JBQWdCO0lBQ3BDO0lBRUE7OztHQUdDLEdBQ0QsSUFBSUMsa0NBQWtDO1FBQ3BDLE9BQU8sSUFBSSxDQUFDTCxLQUFLLENBQUNLLCtCQUErQjtJQUNuRDtJQUVBOzs7R0FHQyxHQUNELElBQUlDLFNBQVM7UUFDWCxPQUFPLElBQUksQ0FBQ04sS0FBSyxDQUFDTSxNQUFNO0lB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