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)
647 lines (646 loc) • 82.1 kB
JavaScript
'use strict';
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _async_to_generator(fn) {
return function() {
var self = this, args = arguments;
return new Promise(function(resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _define_property(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true
});
} else {
obj[key] = value;
}
return obj;
}
import TimeoutError from '../clients/timeoutError';
const HistoryDatabase = require('./historyDatabase/index').default;
import ExpertAdvisor from './expertAdvisor';
import { ValidationError } from '../clients/errorHandler';
import MetatraderAccountReplica from './metatraderAccountReplica';
/**
* Implements a MetaTrader account entity
*/ let MetatraderAccount = class MetatraderAccount {
/**
* Returns unique account id
* @return {string} unique account id
*/ get id() {
return this._data._id;
}
/**
* Returns current account state. One of CREATED, DEPLOYING, DEPLOYED, DEPLOY_FAILED, UNDEPLOYING,
* UNDEPLOYED, UNDEPLOY_FAILED, DELETING, DELETE_FAILED, REDEPLOY_FAILED, DRAFT
* @return {State} current account 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 reliability value
*/ get reliability() {
return this._data.reliability;
}
/**
* Returns user-defined account tags
* @return {Array<string>} user-defined account tags
*/ get tags() {
return this._data.tags;
}
/**
* Returns extra information which can be stored together with your account
* @return {Object} extra information which can be stored together with your account
*/ get metadata() {
return this._data.metadata;
}
/**
* Returns number of resource slots to allocate to account. 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
*/ get resourceSlots() {
return this._data.resourceSlots;
}
/**
* Returns the number of CopyFactory 2 resource slots to allocate to account.
* 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 to CopyFactory 2 by specifying copyFactoryRoles field.
* @return {number} number of CopyFactory 2 resource slots to allocate to account
*/ get copyFactoryResourceSlots() {
return this._data.copyFactoryResourceSlots;
}
/**
* Returns account region
* @return {string} account region value
*/ get region() {
return this._data.region;
}
/**
* Returns the time account was created at, in ISO format
* @returns {string} the time account was created at, in ISO format
*/ get createdAt() {
return new Date(this._data.createdAt);
}
/**
* Returns human-readable account name
* @return {string} human-readable account name
*/ get name() {
return this._data.name;
}
/**
* Returns flag indicating if trades should be placed as manual trades on this account
* @return {boolean} flag indicating if trades should be placed as manual trades on this account
*/ get manualTrades() {
return this._data.manualTrades;
}
/**
* Returns default trade slippage in points
* @return {number} default trade slippage in points
*/ get slippage() {
return this._data.slippage;
}
/**
* Returns id of the account's provisioning profile
* @return {string} id of the account's provisioning profile
*/ get provisioningProfileId() {
return this._data.provisioningProfileId;
}
/**
* Returns MetaTrader account login
* @return {string} MetaTrader account number
*/ get login() {
return this._data.login;
}
/**
* Returns MetaTrader server name to connect to
* @return {string} MetaTrader server name to connect to
*/ get server() {
return this._data.server;
}
/**
* Returns account type. Possible values are cloud-g1, cloud-g2
* @return {Type} account type
*/ get type() {
return this._data.type;
}
/**
* Returns MT version. Possible values are 4 and 5
* @return {Version} MT version
*/ get version() {
return this._data.version;
}
/**
* Returns hash-code of the account
* @return {number} hash-code of the account
*/ get hash() {
return this._data.hash;
}
/**
* Returns 3-character ISO currency code of the account base currency. The setting is to be used
* for copy trading accounts which use national currencies only, such as some Brazilian brokers. You should not alter
* this setting unless you understand what you are doing.
* @return {string} 3-character ISO currency code of the account base currency
*/ get baseCurrency() {
return this._data.baseCurrency;
}
/**
* Returns account roles for CopyFactory2 application. Possible values are `PROVIDER` and `SUBSCRIBER`
* @return {Array<CopyFactoryRoles>} account roles for CopyFactory2 application
*/ get copyFactoryRoles() {
return this._data.copyFactoryRoles;
}
/**
* Returns flag indicating that risk management API is enabled on account
* @return {boolean} flag indicating that risk management API is enabled on account
*/ get riskManagementApiEnabled() {
return this._data.riskManagementApiEnabled;
}
/**
* Returns flag indicating that MetaStats API is enabled on account
* @return {boolean} flag indicating that MetaStats API is enabled on account
*/ get metastatsApiEnabled() {
return this._data.metastatsApiEnabled;
}
/**
* Returns configured dedicated IP protocol to connect to the trading account terminal
* @return {DedicatedIp}
*/ get allocateDedicatedIp() {
return this._data.allocateDedicatedIp;
}
/**
* Returns active account connections
* @return {Array<AccountConnection>} active account connections
*/ get connections() {
return this._data.connections;
}
/**
* Returns flag indicating that account is primary
* @return {boolean} flag indicating that account is primary
*/ get primaryReplica() {
return this._data.primaryReplica;
}
/**
* Returns user id
* @return {string} user id
*/ get userId() {
return this._data.userId;
}
/**
* Returns primary account id
* @return {string} primary account id
*/ get primaryAccountId() {
return this._data.primaryAccountId;
}
/**
* Returns account replicas from DTO
* @return {MetatraderAccountReplica[]} account replicas from DTO
*/ get accountReplicas() {
return this._data.accountReplicas;
}
/**
* Returns account replica instances
* @return {MetatraderAccountReplica[]} account replica instances
*/ get replicas() {
return this._replicas;
}
/**
* Returns a dictionary with account's available regions and replicas
* @returns accounts by region
*/ get accountRegions() {
const regions = {
[this.region]: this.id
};
this.replicas.forEach((replica)=>regions[replica.region] = replica.id);
return regions;
}
/**
* Reloads MetaTrader account from API
* @return {Promise} promise resolving when MetaTrader account is updated
*/ reload() {
var _this = this;
return _async_to_generator(function*() {
_this._data = yield _this._metatraderAccountClient.getAccount(_this.id);
const updatedReplicaData = _this._data.accountReplicas || [];
const regions = updatedReplicaData.map((replica)=>replica.region);
const createdReplicaRegions = _this._replicas.map((replica)=>replica.region);
_this._replicas = _this._replicas.filter((replica)=>regions.includes(replica.region));
_this._replicas.forEach((replica)=>{
const updatedData = updatedReplicaData.find((replicaData)=>replicaData.region === replica.region);
replica.updateData(updatedData);
});
updatedReplicaData.forEach((replica)=>{
if (!createdReplicaRegions.includes(replica.region)) {
_this._replicas.push(new MetatraderAccountReplica(replica, _this, _this._metatraderAccountClient));
}
});
})();
}
/**
* Removes a trading account and stops the API server serving the account.
* The account state such as downloaded market data history will be removed as well when you remove the account.
* @return {Promise} promise resolving when account is scheduled for deletion
*/ remove() {
var _this = this;
return _async_to_generator(function*() {
_this._connectionRegistry.closeAllInstances(_this.id);
yield _this._metatraderAccountClient.deleteAccount(_this.id);
const fileManager = HistoryDatabase.getInstance();
yield fileManager.clear(_this.id, _this._application);
if (_this.type !== 'self-hosted') {
try {
yield _this.reload();
} catch (err) {
if (err.name !== 'NotFoundError') {
throw err;
}
}
}
})();
}
/**
* Starts API server and trading terminal for trading account.
* This request will be ignored if the account is already deployed.
* @returns {Promise} promise resolving when account is scheduled for deployment
*/ deploy() {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.deployAccount(_this.id);
yield _this.reload();
})();
}
/**
* Stops API server and trading terminal for trading account.
* This request will be ignored if trading account is already undeployed
* @returns {Promise} promise resolving when account is scheduled for undeployment
*/ undeploy() {
var _this = this;
return _async_to_generator(function*() {
_this._connectionRegistry.closeAllInstances(_this.id);
yield _this._metatraderAccountClient.undeployAccount(_this.id);
yield _this.reload();
})();
}
/**
* Redeploys trading account. This is equivalent to undeploy immediately followed by deploy
* @returns {Promise} promise resolving when account is scheduled for redeployment
*/ redeploy() {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.redeployAccount(_this.id);
yield _this.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 reliability is increased
*/ increaseReliability() {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.increaseReliability(_this.id);
yield _this.reload();
})();
}
/**
* Enables risk management API for trading account.
* The account will be temporary stopped to perform this action.
* Note that risk management API is a paid option
* @returns {Promise} promise resolving when account risk management is enabled
*/ enableRiskManagementApi() {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.enableRiskManagementApi(_this.id);
yield _this.reload();
})();
}
/**
* Enables copy factory API for trading account.
* The account will be temporary stopped to perform this action.
* Note that copy factory API is a paid option (see
* @param {Array<CopyFactoryRoles>} copyFactoryRoles copy factory roles
* @param {number} copyFactoryResourceSlots copy factory resource slots
* @return {Promise} promise resolving when account copy factory is enabled
*/ enableCopyFactoryApi(copyFactoryRoles, copyFactoryResourceSlots) {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.enableCopyFactoryApi(_this.id, copyFactoryRoles, copyFactoryResourceSlots);
yield _this.reload();
})();
}
/**
* Enables MetaStats API for trading account.
* The account will be temporary stopped to perform this action.
* Note that this is a paid option
* @returns {Promise} promise resolving when account MetaStats API is enabled
*/ enableMetaStatsApi() {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.enableMetaStatsApi(_this.id);
yield _this.reload();
})();
}
/**
* Waits until API server has finished deployment and account reached the DEPLOYED state
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account is deployed
* @throws {TimeoutError} if account have not reached the DEPLOYED state within timeout allowed
*/ waitDeployed(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
var _this = this;
return _async_to_generator(function*() {
let startTime = Date.now();
yield _this.reload();
while(_this.state !== 'DEPLOYED' && startTime + timeoutInSeconds * 1000 > Date.now()){
yield _this._delay(intervalInMilliseconds);
yield _this.reload();
}
if (_this.state !== 'DEPLOYED') {
throw new TimeoutError('Timed out waiting for account ' + _this.id + ' to be deployed');
}
})();
}
/**
* Waits until API server has finished undeployment and account reached the UNDEPLOYED state
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account is deployed
* @throws {TimeoutError} if account have not reached the UNDEPLOYED state within timeout allowed
*/ waitUndeployed(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
var _this = this;
return _async_to_generator(function*() {
let startTime = Date.now();
yield _this.reload();
while(_this.state !== 'UNDEPLOYED' && startTime + timeoutInSeconds * 1000 > Date.now()){
yield _this._delay(intervalInMilliseconds);
yield _this.reload();
}
if (_this.state !== 'UNDEPLOYED') {
throw new TimeoutError('Timed out waiting for account ' + _this.id + ' to be undeployed');
}
})();
}
/**
* Waits until account has been deleted
* @param {number} timeoutInSeconds wait timeout in seconds, default is 5m
* @param {number} intervalInMilliseconds interval between account reloads while waiting for a change, default is 1s
* @return {Promise} promise which resolves when account is deleted
* @throws {TimeoutError} if account was not deleted within timeout allowed
*/ waitRemoved(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
var _this = this;
return _async_to_generator(function*() {
let startTime = Date.now();
try {
yield _this.reload();
while(startTime + timeoutInSeconds * 1000 > Date.now()){
yield _this._delay(intervalInMilliseconds);
yield _this.reload();
}
throw new TimeoutError('Timed out waiting for account ' + _this.id + ' to be deleted');
} catch (err) {
if (err.name === 'NotFoundError') {
return;
} else {
throw err;
}
}
})();
}
/**
* 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 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 have not connected to the broker within timeout allowed
*/ waitConnected(timeoutInSeconds = 300, intervalInMilliseconds = 1000) {
var _this = this;
return _async_to_generator(function*() {
const checkConnected = ()=>{
return [
_this.connectionStatus
].concat(_this.replicas.map((replica)=>replica.connectionStatus)).includes('CONNECTED');
};
let startTime = Date.now();
yield _this.reload();
while(!checkConnected() && startTime + timeoutInSeconds * 1000 > Date.now()){
yield _this._delay(intervalInMilliseconds);
yield _this.reload();
}
if (!checkConnected()) {
throw new TimeoutError('Timed out waiting for account ' + _this.id + ' to connect to the broker');
}
})();
}
/**
* Connects to MetaApi. There is only one connection per account. Subsequent calls to this method will return the same connection.
* @param {HistoryStorage} historyStorage optional history storage
* @param {Date} [historyStartTime] history start time. Used for tests
* @return {StreamingMetaApiConnectionInstance} MetaApi connection instance
*/ getStreamingConnection(historyStorage, historyStartTime) {
if (this._metaApiWebsocketClient.region && this._metaApiWebsocketClient.region !== this.region) {
throw new ValidationError(`Account ${this.id} is not on specified region ${this._metaApiWebsocketClient.region}`);
}
return this._connectionRegistry.connectStreaming(this, historyStorage, historyStartTime);
}
/**
* Connects to MetaApi via RPC connection instance.
* @returns {RpcMetaApiConnectionInstance} MetaApi connection instance
*/ getRPCConnection() {
if (this._metaApiWebsocketClient.region && this._metaApiWebsocketClient.region !== this.region) {
throw new ValidationError(`Account ${this.id} is not on specified region ${this._metaApiWebsocketClient.region}`);
}
return this._connectionRegistry.connectRpc(this);
}
/**
* Updates trading account.
* Please redeploy the trading account in order for updated settings to take effect
* @param {MetatraderAccountUpdateDto} account updated account information
* @return {Promise} promise resolving when account is updated
*/ update(account) {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.updateAccount(_this.id, account);
yield _this.reload();
})();
}
/**
* Creates a trading account replica in a region different from trading account region and starts a cloud API server for it
* @param {NewMetaTraderAccountDto} account MetaTrader account data
* @return {Promise<MetatraderAccountReplica>} promise resolving with created MetaTrader account replica entity
*/ createReplica(account) {
var _this = this;
return _async_to_generator(function*() {
yield _this._metatraderAccountClient.createAccountReplica(_this.id, account);
yield _this.reload();
return _this._replicas.find((r)=>r.region === account.region);
})();
}
/**
* Retrieves expert advisor of current account
* @returns {Promise<ExpertAdvisor[]>} promise resolving with an array of expert advisor entities
*/ getExpertAdvisors() {
var _this = this;
return _async_to_generator(function*() {
_this._checkExpertAdvisorAllowed();
let expertAdvisors = yield _this._expertAdvisorClient.getExpertAdvisors(_this.id);
return expertAdvisors.map((e)=>new ExpertAdvisor(e, _this.id, _this._expertAdvisorClient));
})();
}
/**
* Retrieves a expert advisor of current account by id
* @param {String} expertId expert advisor id
* @returns {Promise<ExpertAdvisor>} promise resolving with expert advisor entity
*/ getExpertAdvisor(expertId) {
var _this = this;
return _async_to_generator(function*() {
_this._checkExpertAdvisorAllowed();
let expertAdvisor = yield _this._expertAdvisorClient.getExpertAdvisor(_this.id, expertId);
return new ExpertAdvisor(expertAdvisor, _this.id, _this._expertAdvisorClient);
})();
}
/**
* Creates an expert advisor
* @param {string} expertId expert advisor id
* @param {NewExpertAdvisorDto} expert expert advisor data
* @returns {Promise<ExpertAdvisor>} promise resolving with expert advisor entity
*/ createExpertAdvisor(expertId, expert) {
var _this = this;
return _async_to_generator(function*() {
_this._checkExpertAdvisorAllowed();
yield _this._expertAdvisorClient.updateExpertAdvisor(_this.id, expertId, expert);
return _this.getExpertAdvisor(expertId);
})();
}
/**
* Returns historical candles for a specific symbol and timeframe from the MetaTrader account.
* See https://metaapi.cloud/docs/client/restApi/api/retrieveMarketData/readHistoricalCandles/
* @param {string} symbol symbol to retrieve candles for (e.g. a currency pair or an index)
* @param {string} timeframe defines the timeframe according to which the candles must be generated. Allowed values
* for MT5 are 1m, 2m, 3m, 4m, 5m, 6m, 10m, 12m, 15m, 20m, 30m, 1h, 2h, 3h, 4h, 6h, 8h, 12h, 1d, 1w, 1mn. Allowed
* values for MT4 are 1m, 5m, 15m 30m, 1h, 4h, 1d, 1w, 1mn
* @param {Date} [startTime] time to start loading candles from. Note that candles are loaded in backwards direction, so
* this should be the latest time. Leave empty to request latest candles.
* @param {number} [limit] maximum number of candles to retrieve. Must be less or equal to 1000
* @return {Promise<Array<MetatraderCandle>>} promise resolving with historical candles downloaded
*/ getHistoricalCandles(symbol, timeframe, startTime, limit) {
return this._historicalMarketDataClient.getHistoricalCandles(this.id, this.region, symbol, timeframe, startTime, limit);
}
/**
* Returns historical ticks for a specific symbol from the MetaTrader account. This API is not supported by MT4
* accounts.
* See https://metaapi.cloud/docs/client/restApi/api/retrieveMarketData/readHistoricalTicks/
* @param {string} symbol symbol to retrieve ticks for (e.g. a currency pair or an index)
* @param {Date} [startTime] time to start loading ticks from. Note that candles are loaded in forward direction, so
* this should be the earliest time. Leave empty to request latest candles.
* @param {number} [offset] number of ticks to skip (you can use it to avoid requesting ticks from previous request
* twice)
* @param {number} [limit] maximum number of ticks to retrieve. Must be less or equal to 1000
* @return {Promise<Array<MetatraderTick>>} promise resolving with historical ticks downloaded
*/ getHistoricalTicks(symbol, startTime, offset, limit) {
return this._historicalMarketDataClient.getHistoricalTicks(this.id, this.region, symbol, startTime, offset, limit);
}
/**
* Generates trading account configuration link by account id.
* @param {number} [ttlInDays] Lifetime of the link in days. Default is 7.
* @return {Promise<ConfigurationLink>} promise resolving with configuration link
*/ createConfigurationLink(ttlInDays) {
var _this = this;
return _async_to_generator(function*() {
const configurationLink = yield _this._metatraderAccountClient.createConfigurationLink(_this.id, ttlInDays);
return configurationLink;
})();
}
_checkExpertAdvisorAllowed() {
if (this.version !== 4 || this.type !== 'cloud-g1') {
throw new ValidationError('Custom expert advisor is available only for MT4 G1 accounts');
}
}
_delay(timeoutInMilliseconds) {
return new Promise((res)=>setTimeout(res, timeoutInMilliseconds));
}
/**
* Constructs a MetaTrader account entity
* @param {MetatraderAccountDto} data MetaTrader account data
* @param {MetatraderAccountClient} metatraderAccountClient MetaTrader account REST API client
* @param {MetaApiWebsocketClient} metaApiWebsocketClient MetaApi websocket client
* @param {ConnectionRegistry} connectionRegistry metatrader account connection registry
* @param {ExpertAdvisorClient} expertAdvisorClient expert advisor REST API client
* @param {HistoricalMarketDataClient} historicalMarketDataClient historical market data HTTP API client
* @param {string} application application name
*/ constructor(data, metatraderAccountClient, metaApiWebsocketClient, connectionRegistry, expertAdvisorClient, historicalMarketDataClient, application){
_define_property(this, "_data", void 0);
_define_property(this, "_metatraderAccountClient", void 0);
_define_property(this, "_metaApiWebsocketClient", void 0);
_define_property(this, "_connectionRegistry", void 0);
_define_property(this, "_expertAdvisorClient", void 0);
_define_property(this, "_historicalMarketDataClient", void 0);
_define_property(this, "_application", void 0);
_define_property(this, "_replicas", void 0);
this._data = data;
this._metatraderAccountClient = metatraderAccountClient;
this._metaApiWebsocketClient = metaApiWebsocketClient;
this._connectionRegistry = connectionRegistry;
this._expertAdvisorClient = expertAdvisorClient;
this._historicalMarketDataClient = historicalMarketDataClient;
this._application = application;
this._replicas = (data.accountReplicas || []).map((replica)=>new MetatraderAccountReplica(replica, this, metatraderAccountClient));
}
};
export default MetatraderAccount;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBUaW1lb3V0RXJyb3IgZnJvbSAnLi4vY2xpZW50cy90aW1lb3V0RXJyb3InO1xuaW1wb3J0IFJwY01ldGFBcGlDb25uZWN0aW9uSW5zdGFuY2UgZnJvbSAnLi9ycGNNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlJztcbmltcG9ydCBTdHJlYW1pbmdNZXRhQXBpQ29ubmVjdGlvbkluc3RhbmNlIGZyb20gJy4vc3RyZWFtaW5nTWV0YUFwaUNvbm5lY3Rpb25JbnN0YW5jZSc7XG5jb25zdCBIaXN0b3J5RGF0YWJhc2UgPSByZXF1aXJlKCcuL2hpc3RvcnlEYXRhYmFzZS9pbmRleCcpLmRlZmF1bHQ7XG5pbXBvcnQgRXhwZXJ0QWR2aXNvciBmcm9tICcuL2V4cGVydEFkdmlzb3InO1xuaW1wb3J0IHtWYWxpZGF0aW9uRXJyb3J9IGZyb20gJy4uL2NsaWVudHMvZXJyb3JIYW5kbGVyJztcbmltcG9ydCBNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2EgZnJvbSAnLi9tZXRhdHJhZGVyQWNjb3VudFJlcGxpY2EnO1xuLy9lc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuaW1wb3J0IE1ldGF0cmFkZXJBY2NvdW50Q2xpZW50LCB7XG4gIFJlbGlhYmlsaXR5LCBTdGF0ZSwgVmVyc2lvbiwgQ29ubmVjdGlvblN0YXR1cywgQ29weUZhY3RvcnlSb2xlcywgVHlwZSwgQWNjb3VudENvbm5lY3Rpb24sIENvbmZpZ3VyYXRpb25MaW5rLFxuICBNZXRhdHJhZGVyQWNjb3VudER0bywgRGVkaWNhdGVkSXAsXG4gIE5ld01ldGFUcmFkZXJBY2NvdW50UmVwbGljYUR0byxcbiAgTWV0YXRyYWRlckFjY291bnRVcGRhdGVEdG9cbn0gZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL21ldGF0cmFkZXJBY2NvdW50LmNsaWVudCc7XG5pbXBvcnQgdHlwZSBDb25uZWN0aW9uUmVnaXN0cnkgZnJvbSAnLi9jb25uZWN0aW9uUmVnaXN0cnknO1xuaW1wb3J0IHR5cGUgTWV0YUFwaVdlYnNvY2tldENsaWVudCBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvbWV0YUFwaVdlYnNvY2tldC5jbGllbnQnO1xuaW1wb3J0IHR5cGUgRXhwZXJ0QWR2aXNvckNsaWVudCBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvZXhwZXJ0QWR2aXNvci5jbGllbnQnO1xuaW1wb3J0IHR5cGUgSGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQgZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL2hpc3RvcmljYWxNYXJrZXREYXRhLmNsaWVudCc7XG5pbXBvcnQgSGlzdG9yeVN0b3JhZ2UgZnJvbSAnLi9oaXN0b3J5U3RvcmFnZSc7XG5pbXBvcnQge05ld0V4cGVydEFkdmlzb3JEdG99IGZyb20gJy4uL2NsaWVudHMvbWV0YUFwaS9leHBlcnRBZHZpc29yLmNsaWVudCc7XG5pbXBvcnQge01ldGF0cmFkZXJDYW5kbGUsIE1ldGF0cmFkZXJUaWNrfSBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvbWV0YUFwaVdlYnNvY2tldC5jbGllbnQnO1xuXG4vKipcbiAqIEltcGxlbWVudHMgYSBNZXRhVHJhZGVyIGFjY291bnQgZW50aXR5XG4gKi9cbmNsYXNzIE1ldGF0cmFkZXJBY2NvdW50IHtcbiAgXG4gIHByaXZhdGUgX2RhdGE6IGFueTtcbiAgcHJpdmF0ZSBfbWV0YXRyYWRlckFjY291bnRDbGllbnQ6IGFueTtcbiAgcHJpdmF0ZSBfbWV0YUFwaVdlYnNvY2tldENsaWVudDogYW55O1xuICBwcml2YXRlIF9jb25uZWN0aW9uUmVnaXN0cnk6IGFueTtcbiAgcHJpdmF0ZSBfZXhwZXJ0QWR2aXNvckNsaWVudDogYW55O1xuICBwcml2YXRlIF9oaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudDogYW55O1xuICBwcml2YXRlIF9hcHBsaWNhdGlvbjogYW55O1xuICBwcml2YXRlIF9yZXBsaWNhczogYW55O1xuXG4gIC8qKlxuICAgKiBDb25zdHJ1Y3RzIGEgTWV0YVRyYWRlciBhY2NvdW50IGVudGl0eVxuICAgKiBAcGFyYW0ge01ldGF0cmFkZXJBY2NvdW50RHRvfSBkYXRhIE1ldGFUcmFkZXIgYWNjb3VudCBkYXRhXG4gICAqIEBwYXJhbSB7TWV0YXRyYWRlckFjY291bnRDbGllbnR9IG1ldGF0cmFkZXJBY2NvdW50Q2xpZW50IE1ldGFUcmFkZXIgYWNjb3VudCBSRVNUIEFQSSBjbGllbnRcbiAgICogQHBhcmFtIHtNZXRhQXBpV2Vic29ja2V0Q2xpZW50fSBtZXRhQXBpV2Vic29ja2V0Q2xpZW50IE1ldGFBcGkgd2Vic29ja2V0IGNsaWVudFxuICAgKiBAcGFyYW0ge0Nvbm5lY3Rpb25SZWdpc3RyeX0gY29ubmVjdGlvblJlZ2lzdHJ5IG1ldGF0cmFkZXIgYWNjb3VudCBjb25uZWN0aW9uIHJlZ2lzdHJ5XG4gICAqIEBwYXJhbSB7RXhwZXJ0QWR2aXNvckNsaWVudH0gZXhwZXJ0QWR2aXNvckNsaWVudCBleHBlcnQgYWR2aXNvciBSRVNUIEFQSSBjbGllbnRcbiAgICogQHBhcmFtIHtIaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudH0gaGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQgaGlzdG9yaWNhbCBtYXJrZXQgZGF0YSBIVFRQIEFQSSBjbGllbnRcbiAgICogQHBhcmFtIHtzdHJpbmd9IGFwcGxpY2F0aW9uIGFwcGxpY2F0aW9uIG5hbWVcbiAgICovXG4gIGNvbnN0cnVjdG9yKFxuICAgIGRhdGE6IE1ldGF0cmFkZXJBY2NvdW50RHRvLCBtZXRhdHJhZGVyQWNjb3VudENsaWVudDogTWV0YXRyYWRlckFjY291bnRDbGllbnQsXG4gICAgbWV0YUFwaVdlYnNvY2tldENsaWVudDogTWV0YUFwaVdlYnNvY2tldENsaWVudCwgY29ubmVjdGlvblJlZ2lzdHJ5OiBDb25uZWN0aW9uUmVnaXN0cnksXG4gICAgZXhwZXJ0QWR2aXNvckNsaWVudDogRXhwZXJ0QWR2aXNvckNsaWVudCwgaGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQ6IEhpc3RvcmljYWxNYXJrZXREYXRhQ2xpZW50LFxuICAgIGFwcGxpY2F0aW9uOiBzdHJpbmdcbiAgKSB7XG4gICAgdGhpcy5fZGF0YSA9IGRhdGE7XG4gICAgdGhpcy5fbWV0YXRyYWRlckFjY291bnRDbGllbnQgPSBtZXRhdHJhZGVyQWNjb3VudENsaWVudDtcbiAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50ID0gbWV0YUFwaVdlYnNvY2tldENsaWVudDtcbiAgICB0aGlzLl9jb25uZWN0aW9uUmVnaXN0cnkgPSBjb25uZWN0aW9uUmVnaXN0cnk7XG4gICAgdGhpcy5fZXhwZXJ0QWR2aXNvckNsaWVudCA9IGV4cGVydEFkdmlzb3JDbGllbnQ7XG4gICAgdGhpcy5faGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQgPSBoaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudDtcbiAgICB0aGlzLl9hcHBsaWNhdGlvbiA9IGFwcGxpY2F0aW9uO1xuICAgIHRoaXMuX3JlcGxpY2FzID0gKGRhdGEuYWNjb3VudFJlcGxpY2FzIHx8IFtdKVxuICAgICAgLm1hcChyZXBsaWNhID0+IG5ldyBNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2EocmVwbGljYSwgdGhpcywgbWV0YXRyYWRlckFjY291bnRDbGllbnQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHVuaXF1ZSBhY2NvdW50IGlkXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdW5pcXVlIGFjY291bnQgaWRcbiAgICovXG4gIGdldCBpZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLl9pZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGN1cnJlbnQgYWNjb3VudCBzdGF0ZS4gT25lIG9mIENSRUFURUQsIERFUExPWUlORywgREVQTE9ZRUQsIERFUExPWV9GQUlMRUQsIFVOREVQTE9ZSU5HLFxuICAgKiBVTkRFUExPWUVELCBVTkRFUExPWV9GQUlMRUQsIERFTEVUSU5HLCBERUxFVEVfRkFJTEVELCBSRURFUExPWV9GQUlMRUQsIERSQUZUXG4gICAqIEByZXR1cm4ge1N0YXRlfSBjdXJyZW50IGFjY291bnQgc3RhdGVcbiAgICovXG4gIGdldCBzdGF0ZSgpOiBTdGF0ZSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuc3RhdGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBNZXRhVHJhZGVyIG1hZ2ljIHRvIHBsYWNlIHRyYWRlcyB1c2luZ1xuICAgKiBAcmV0dXJuIHtudW1iZXJ9IE1ldGFUcmFkZXIgbWFnaWMgdG8gcGxhY2UgdHJhZGVzIHVzaW5nXG4gICAqL1xuICBnZXQgbWFnaWMoKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5tYWdpYztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRlcm1pbmFsICYgYnJva2VyIGNvbm5lY3Rpb24gc3RhdHVzLCBvbmUgb2YgQ09OTkVDVEVELCBESVNDT05ORUNURUQsIERJU0NPTk5FQ1RFRF9GUk9NX0JST0tFUlxuICAgKiBAcmV0dXJuIHtDb25uZWN0aW9uU3RhdHVzfSB0ZXJtaW5hbCAmIGJyb2tlciBjb25uZWN0aW9uIHN0YXR1c1xuICAgKi9cbiAgZ2V0IGNvbm5lY3Rpb25TdGF0dXMoKTogQ29ubmVjdGlvblN0YXR1cyB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuY29ubmVjdGlvblN0YXR1cztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgcXVvdGUgc3RyZWFtaW5nIGludGVydmFsIGluIHNlY29uZHMgXG4gICAqIEByZXR1cm4ge251bWJlcn0gcXVvdGUgc3RyZWFtaW5nIGludGVydmFsIGluIHNlY29uZHNcbiAgICovXG4gIGdldCBxdW90ZVN0cmVhbWluZ0ludGVydmFsSW5TZWNvbmRzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEucXVvdGVTdHJlYW1pbmdJbnRlcnZhbEluU2Vjb25kcztcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgc3ltYm9sIHByb3ZpZGVkIGJ5IGJyb2tlciBcbiAgICogQHJldHVybiB7c3RyaW5nfSBhbnkgc3ltYm9sIHByb3ZpZGVkIGJ5IGJyb2tlclxuICAgKi9cbiAgZ2V0IHN5bWJvbCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnN5bWJvbDtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgcmVsaWFiaWxpdHkgdmFsdWUuIFBvc3NpYmxlIHZhbHVlcyBhcmUgcmVndWxhciBhbmQgaGlnaFxuICAgKiBAcmV0dXJuIHtSZWxpYWJpbGl0eX0gYWNjb3VudCByZWxpYWJpbGl0eSB2YWx1ZVxuICAgKi9cbiAgZ2V0IHJlbGlhYmlsaXR5KCk6IFJlbGlhYmlsaXR5IHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5yZWxpYWJpbGl0eTtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgdXNlci1kZWZpbmVkIGFjY291bnQgdGFnc1xuICAgKiBAcmV0dXJuIHtBcnJheTxzdHJpbmc+fSB1c2VyLWRlZmluZWQgYWNjb3VudCB0YWdzXG4gICAqL1xuICBnZXQgdGFncygpOiBBcnJheTxzdHJpbmc+IHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS50YWdzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZXh0cmEgaW5mb3JtYXRpb24gd2hpY2ggY2FuIGJlIHN0b3JlZCB0b2dldGhlciB3aXRoIHlvdXIgYWNjb3VudFxuICAgKiBAcmV0dXJuIHtPYmplY3R9IGV4dHJhIGluZm9ybWF0aW9uIHdoaWNoIGNhbiBiZSBzdG9yZWQgdG9nZXRoZXIgd2l0aCB5b3VyIGFjY291bnRcbiAgICovXG4gIGdldCBtZXRhZGF0YSgpOiBPYmplY3Qge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLm1ldGFkYXRhO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgbnVtYmVyIG9mIHJlc291cmNlIHNsb3RzIHRvIGFsbG9jYXRlIHRvIGFjY291bnQuIEFsbG9jYXRpbmcgZXh0cmEgcmVzb3VyY2Ugc2xvdHNcbiAgICogcmVzdWx0cyBpbiBiZXR0ZXIgYWNjb3VudCBwZXJmb3JtYW5jZSB1bmRlciBsb2FkIHdoaWNoIGlzIHVzZWZ1bCBmb3Igc29tZSBhcHBsaWNhdGlvbnMuIEUuZy4gaWYgeW91IGhhdmUgbWFueVxuICAgKiBhY2NvdW50cyBjb3B5aW5nIHRoZSBzYW1lIHN0cmF0ZWd5IHZpYSBDb3B5RmFjdG9yeSBBUEksIHRoZW4geW91IGNhbiBpbmNyZWFzZSByZXNvdXJjZVNsb3RzIHRvIGdldCBhIGxvd2VyIHRyYWRlXG4gICAqIGNvcHlpbmcgbGF0ZW5jeS4gUGxlYXNlIG5vdGUgdGhhdCBhbGxvY2F0aW5nIGV4dHJhIHJlc291cmNlIHNsb3RzIGlzIGEgcGFpZCBvcHRpb24uIFBsZWFzZSBub3RlIHRoYXQgaGlnaFxuICAgKiByZWxpYWJpbGl0eSBhY2NvdW50cyB1c2UgcmVkdW5kYW50IGluZnJhc3RydWN0dXJlLCBzbyB0aGF0IGVhY2ggcmVzb3VyY2Ugc2xvdCBmb3IgYSBoaWdoIHJlbGlhYmlsaXR5IGFjY291bnRcbiAgICogaXMgYmlsbGVkIGFzIDIgc3RhbmRhcmQgcmVzb3VyY2Ugc2xvdHMuXG4gICAqIEByZXR1cm4ge251bWJlcn0gbnVtYmVyIG9mIHJlc291cmNlIHNsb3RzIHRvIGFsbG9jYXRlIHRvIGFjY291bnRcbiAgICovXG4gIGdldCByZXNvdXJjZVNsb3RzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEucmVzb3VyY2VTbG90cztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgQ29weUZhY3RvcnkgMiByZXNvdXJjZSBzbG90cyB0byBhbGxvY2F0ZSB0byBhY2NvdW50LlxuICAgKiBBbGxvY2F0aW5nIGV4dHJhIHJlc291cmNlIHNsb3RzIHJlc3VsdHMgaW4gbG93ZXIgdHJhZGUgY29weWluZyBsYXRlbmN5LiBQbGVhc2Ugbm90ZSB0aGF0IGFsbG9jYXRpbmcgZXh0cmEgcmVzb3VyY2VcbiAgICogc2xvdHMgaXMgYSBwYWlkIG9wdGlvbi4gUGxlYXNlIGFsc28gbm90ZSB0aGF0IENvcHlGYWN0b3J5IDIgdXNlcyByZWR1bmRhbnQgaW5mcmFzdHJ1Y3R1cmUgc28gdGhhdFxuICAgKiBlYWNoIENvcHlGYWN0b3J5IHJlc291cmNlIHNsb3QgaXMgYmlsbGVkIGFzIDIgc3RhbmRhcmQgcmVzb3VyY2Ugc2xvdHMuIFlvdSB3aWxsIGJlIGJpbGxlZCBmb3IgQ29weUZhY3RvcnkgMlxuICAgKiByZXNvdXJjZSBzbG90cyBvbmx5IGlmIHlvdSBoYXZlIGFkZGVkIHlvdXIgYWNjb3VudCB0byBDb3B5RmFjdG9yeSAyIGJ5IHNwZWNpZnlpbmcgY29weUZhY3RvcnlSb2xlcyBmaWVsZC5cbiAgICogQHJldHVybiB7bnVtYmVyfSBudW1iZXIgb2YgQ29weUZhY3RvcnkgMiByZXNvdXJjZSBzbG90cyB0byBhbGxvY2F0ZSB0byBhY2NvdW50XG4gICAqL1xuICBnZXQgY29weUZhY3RvcnlSZXNvdXJjZVNsb3RzKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuY29weUZhY3RvcnlSZXNvdXJjZVNsb3RzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWNjb3VudCByZWdpb25cbiAgICogQHJldHVybiB7c3RyaW5nfSBhY2NvdW50IHJlZ2lvbiB2YWx1ZVxuICAgKi9cbiAgZ2V0IHJlZ2lvbigpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnJlZ2lvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB0aW1lIGFjY291bnQgd2FzIGNyZWF0ZWQgYXQsIGluIElTTyBmb3JtYXRcbiAgICogQHJldHVybnMge3N0cmluZ30gdGhlIHRpbWUgYWNjb3VudCB3YXMgY3JlYXRlZCBhdCwgaW4gSVNPIGZvcm1hdFxuICAgKi9cbiAgZ2V0IGNyZWF0ZWRBdCgpOiBEYXRlIHtcbiAgICByZXR1cm4gbmV3IERhdGUodGhpcy5fZGF0YS5jcmVhdGVkQXQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgaHVtYW4tcmVhZGFibGUgYWNjb3VudCBuYW1lXG4gICAqIEByZXR1cm4ge3N0cmluZ30gaHVtYW4tcmVhZGFibGUgYWNjb3VudCBuYW1lXG4gICAqL1xuICBnZXQgbmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLm5hbWU7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZsYWcgaW5kaWNhdGluZyBpZiB0cmFkZXMgc2hvdWxkIGJlIHBsYWNlZCBhcyBtYW51YWwgdHJhZGVzIG9uIHRoaXMgYWNjb3VudFxuICAgKiBAcmV0dXJuIHtib29sZWFufSBmbGFnIGluZGljYXRpbmcgaWYgdHJhZGVzIHNob3VsZCBiZSBwbGFjZWQgYXMgbWFudWFsIHRyYWRlcyBvbiB0aGlzIGFjY291bnRcbiAgICovXG4gIGdldCBtYW51YWxUcmFkZXMoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEubWFudWFsVHJhZGVzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgZGVmYXVsdCB0cmFkZSBzbGlwcGFnZSBpbiBwb2ludHNcbiAgICogQHJldHVybiB7bnVtYmVyfSBkZWZhdWx0IHRyYWRlIHNsaXBwYWdlIGluIHBvaW50c1xuICAgKi9cbiAgZ2V0IHNsaXBwYWdlKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuc2xpcHBhZ2U7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGlkIG9mIHRoZSBhY2NvdW50J3MgcHJvdmlzaW9uaW5nIHByb2ZpbGVcbiAgICogQHJldHVybiB7c3RyaW5nfSBpZCBvZiB0aGUgYWNjb3VudCdzIHByb3Zpc2lvbmluZyBwcm9maWxlXG4gICAqL1xuICBnZXQgcHJvdmlzaW9uaW5nUHJvZmlsZUlkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEucHJvdmlzaW9uaW5nUHJvZmlsZUlkO1xuICB9XG4gIFxuICAvKipcbiAgICogUmV0dXJucyBNZXRhVHJhZGVyIGFjY291bnQgbG9naW5cbiAgICogQHJldHVybiB7c3RyaW5nfSBNZXRhVHJhZGVyIGFjY291bnQgbnVtYmVyXG4gICAqL1xuICBnZXQgbG9naW4oKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5sb2dpbjtcbiAgfVxuICBcbiAgLyoqXG4gICAqIFJldHVybnMgTWV0YVRyYWRlciBzZXJ2ZXIgbmFtZSB0byBjb25uZWN0IHRvXG4gICAqIEByZXR1cm4ge3N0cmluZ30gTWV0YVRyYWRlciBzZXJ2ZXIgbmFtZSB0byBjb25uZWN0IHRvXG4gICAqL1xuICBnZXQgc2VydmVyKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuc2VydmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWNjb3VudCB0eXBlLiBQb3NzaWJsZSB2YWx1ZXMgYXJlIGNsb3VkLWcxLCBjbG91ZC1nMlxuICAgKiBAcmV0dXJuIHtUeXBlfSBhY2NvdW50IHR5cGVcbiAgICovXG4gIGdldCB0eXBlKCk6IFR5cGUge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnR5cGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBNVCB2ZXJzaW9uLiBQb3NzaWJsZSB2YWx1ZXMgYXJlIDQgYW5kIDVcbiAgICogQHJldHVybiB7VmVyc2lvbn0gTVQgdmVyc2lvblxuICAgKi9cbiAgZ2V0IHZlcnNpb24oKTogVmVyc2lvbiB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEudmVyc2lvbjtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGhhc2gtY29kZSBvZiB0aGUgYWNjb3VudFxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IGhhc2gtY29kZSBvZiB0aGUgYWNjb3VudFxuICAgKi9cbiAgZ2V0IGhhc2goKTogbnVtYmVyIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5oYXNoO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgMy1jaGFyYWN0ZXIgSVNPIGN1cnJlbmN5IGNvZGUgb2YgdGhlIGFjY291bnQgYmFzZSBjdXJyZW5jeS4gVGhlIHNldHRpbmcgaXMgdG8gYmUgdXNlZFxuICAgKiBmb3IgY29weSB0cmFkaW5nIGFjY291bnRzIHdoaWNoIHVzZSBuYXRpb25hbCBjdXJyZW5jaWVzIG9ubHksIHN1Y2ggYXMgc29tZSBCcmF6aWxpYW4gYnJva2Vycy4gWW91IHNob3VsZCBub3QgYWx0ZXJcbiAgICogdGhpcyBzZXR0aW5nIHVubGVzcyB5b3UgdW5kZXJzdGFuZCB3aGF0IHlvdSBhcmUgZG9pbmcuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gMy1jaGFyYWN0ZXIgSVNPIGN1cnJlbmN5IGNvZGUgb2YgdGhlIGFjY291bnQgYmFzZSBjdXJyZW5jeVxuICAgKi9cbiAgZ2V0IGJhc2VDdXJyZW5jeSgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLmJhc2VDdXJyZW5jeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFjY291bnQgcm9sZXMgZm9yIENvcHlGYWN0b3J5MiBhcHBsaWNhdGlvbi4gUG9zc2libGUgdmFsdWVzIGFyZSBgUFJPVklERVJgIGFuZCBgU1VCU0NSSUJFUmBcbiAgICogQHJldHVybiB7QXJyYXk8Q29weUZhY3RvcnlSb2xlcz59IGFjY291bnQgcm9sZXMgZm9yIENvcHlGYWN0b3J5MiBhcHBsaWNhdGlvblxuICAgKi9cbiAgZ2V0IGNvcHlGYWN0b3J5Um9sZXMoKTogQXJyYXk8Q29weUZhY3RvcnlSb2xlcz4ge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLmNvcHlGYWN0b3J5Um9sZXM7XG4gIH1cbiAgXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZsYWcgaW5kaWNhdGluZyB0aGF0IHJpc2sgbWFuYWdlbWVudCBBUEkgaXMgZW5hYmxlZCBvbiBhY2NvdW50XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IGZsYWcgaW5kaWNhdGluZyB0aGF0IHJpc2sgbWFuYWdlbWVudCBBUEkgaXMgZW5hYmxlZCBvbiBhY2NvdW50XG4gICAqL1xuICBnZXQgcmlza01hbmFnZW1lbnRBcGlFbmFibGVkKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnJpc2tNYW5hZ2VtZW50QXBpRW5hYmxlZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGZsYWcgaW5kaWNhdGluZyB0aGF0IE1ldGFTdGF0cyBBUEkgaXMgZW5hYmxlZCBvbiBhY2NvdW50XG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IGZsYWcgaW5kaWNhdGluZyB0aGF0IE1ldGFTdGF0cyBBUEkgaXMgZW5hYmxlZCBvbiBhY2NvdW50XG4gICAqL1xuICBnZXQgbWV0YXN0YXRzQXBpRW5hYmxlZCgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5tZXRhc3RhdHNBcGlFbmFibGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgY29uZmlndXJlZCBkZWRpY2F0ZWQgSVAgcHJvdG9jb2wgdG8gY29ubmVjdCB0byB0aGUgdHJhZGluZyBhY2NvdW50IHRlcm1pbmFsXG4gICAqIEByZXR1cm4ge0RlZGljYXRlZElwfVxuICAgKi9cbiAgZ2V0IGFsbG9jYXRlRGVkaWNhdGVkSXAoKTogRGVkaWNhdGVkSXAge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLmFsbG9jYXRlRGVkaWNhdGVkSXA7XG4gIH1cbiAgICBcbiAgLyoqXG4gICAqIFJldHVybnMgYWN0aXZlIGFjY291bnQgY29ubmVjdGlvbnNcbiAgICogQHJldHVybiB7QXJyYXk8QWNjb3VudENvbm5lY3Rpb24+fSBhY3RpdmUgYWNjb3VudCBjb25uZWN0aW9uc1xuICAgKi9cbiAgZ2V0IGNvbm5lY3Rpb25zKCk6IEFycmF5PEFjY291bnRDb25uZWN0aW9uPiB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuY29ubmVjdGlvbnM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBmbGFnIGluZGljYXRpbmcgdGhhdCBhY2NvdW50IGlzIHByaW1hcnlcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gZmxhZyBpbmRpY2F0aW5nIHRoYXQgYWNjb3VudCBpcyBwcmltYXJ5XG4gICAqL1xuICBnZXQgcHJpbWFyeVJlcGxpY2EoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEucHJpbWFyeVJlcGxpY2E7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB1c2VyIGlkXG4gICAqIEByZXR1cm4ge3N0cmluZ30gdXNlciBpZFxuICAgKi9cbiAgZ2V0IHVzZXJJZCgpOiBzdHJpbmcge1xuICAgIHJldHVybiB0aGlzLl9kYXRhLnVzZXJJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHByaW1hcnkgYWNjb3VudCBpZFxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IHByaW1hcnkgYWNjb3VudCBpZFxuICAgKi9cbiAgZ2V0IHByaW1hcnlBY2NvdW50SWQoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5fZGF0YS5wcmltYXJ5QWNjb3VudElkO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWNjb3VudCByZXBsaWNhcyBmcm9tIERUT1xuICAgKiBAcmV0dXJuIHtNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2FbXX0gYWNjb3VudCByZXBsaWNhcyBmcm9tIERUT1xuICAgKi9cbiAgZ2V0IGFjY291bnRSZXBsaWNhcygpOiBNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2FbXSB7XG4gICAgcmV0dXJuIHRoaXMuX2RhdGEuYWNjb3VudFJlcGxpY2FzO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWNjb3VudCByZXBsaWNhIGluc3RhbmNlc1xuICAgKiBAcmV0dXJuIHtNZXRhdHJhZGVyQWNjb3VudFJlcGxpY2FbXX0gYWNjb3VudCByZXBsaWNhIGluc3RhbmNlc1xuICAgKi9cbiAgZ2V0IHJlcGxpY2FzKCk6IE1ldGF0cmFkZXJBY2NvdW50UmVwbGljYVtdIHtcbiAgICByZXR1cm4gdGhpcy5fcmVwbGljYXM7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIGRpY3Rpb25hcnkgd2l0aCBhY2NvdW50J3MgYXZhaWxhYmxlIHJlZ2lvbnMgYW5kIHJlcGxpY2FzXG4gICAqIEByZXR1cm5zIGFjY291bnRzIGJ5IHJlZ2lvblxuICAgKi9cbiAgZ2V0IGFjY291bnRSZWdpb25zKCk6IE1ldGF0cmFkZXJBY2NvdW50LkFjY291bnRzQnlSZWdpb24ge1xuICAgIGNvbnN0IHJlZ2lvbnMgPSB7W3RoaXMucmVnaW9uXTogdGhpcy5pZH07XG4gICAgdGhpcy5yZXBsaWNhcy5mb3JFYWNoKHJlcGxpY2EgPT4gcmVnaW9uc1tyZXBsaWNhLnJlZ2lvbl0gPSByZXBsaWNhLmlkKTtcbiAgICByZXR1cm4gcmVnaW9ucztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWxvYWRzIE1ldGFUcmFkZXIgYWNjb3VudCBmcm9tIEFQSVxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIE1ldGFUcmFkZXIgYWNjb3VudCBpcyB1cGRhdGVkXG4gICAqL1xuICBhc3luYyByZWxvYWQoKSB7XG4gICAgdGhpcy5fZGF0YSA9IGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LmdldEFjY291bnQodGhpcy5pZCk7XG4gICAgY29uc3QgdXBkYXRlZFJlcGxpY2FEYXRhID0gKHRoaXMuX2RhdGEuYWNjb3VudFJlcGxpY2FzIHx8IFtdKTtcbiAgICBjb25zdCByZWdpb25zID0gdXBkYXRlZFJlcGxpY2FEYXRhLm1hcChyZXBsaWNhID0+IHJlcGxpY2EucmVnaW9uKTtcbiAgICBjb25zdCBjcmVhdGVkUmVwbGljYVJlZ2lvbnMgPSB0aGlzLl9yZXBsaWNhcy5tYXAocmVwbGljYSA9PiByZXBsaWNhLnJlZ2lvbik7XG4gICAgdGhpcy5fcmVwbGljYXMgPSB0aGlzLl9yZXBsaWNhcy5maWx0ZXIocmVwbGljYSA9PiByZWdpb25zLmluY2x1ZGVzKHJlcGxpY2EucmVnaW9uKSk7XG4gICAgdGhpcy5fcmVwbGljYXMuZm9yRWFjaChyZXBsaWNhID0+IHtcbiAgICAgIGNvbnN0IHVwZGF0ZWREYXRhID0gdXBkYXRlZFJlcGxpY2FEYXRhLmZpbmQocmVwbGljYURhdGEgPT4gcmVwbGljYURhdGEucmVnaW9uID09PSByZXBsaWNhLnJlZ2lvbik7XG4gICAgICByZXBsaWNhLnVwZGF0ZURhdGEodXBkYXRlZERhdGEpO1xuICAgIH0pO1xuICAgIHVwZGF0ZWRSZXBsaWNhRGF0YS5mb3JFYWNoKHJlcGxpY2EgPT4ge1xuICAgICAgaWYoIWNyZWF0ZWRSZXBsaWNhUmVnaW9ucy5pbmNsdWRlcyhyZXBsaWNhLnJlZ2lvbikpIHtcbiAgICAgICAgdGhpcy5fcmVwbGljYXMucHVzaChuZXcgTWV0YXRyYWRlckFjY291bnRSZXBsaWNhKHJlcGxpY2EsIHRoaXMsIHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50KSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlcyBhIHRyYWRpbmcgYWNjb3VudCBhbmQgc3RvcHMgdGhlIEFQSSBzZXJ2ZXIgc2VydmluZyB0aGUgYWNjb3VudC5cbiAgICogVGhlIGFjY291bnQgc3RhdGUgc3VjaCBhcyBkb3dubG9hZGVkIG1hcmtldCBkYXRhIGhpc3Rvcnkgd2lsbCBiZSByZW1vdmVkIGFzIHdlbGwgd2hlbiB5b3UgcmVtb3ZlIHRoZSBhY2NvdW50LlxuICAgKiBAcmV0dXJuIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIGFjY291bnQgaXMgc2NoZWR1bGVkIGZvciBkZWxldGlvblxuICAgKi9cbiAgYXN5bmMgcmVtb3ZlKCkge1xuICAgIHRoaXMuX2Nvbm5lY3Rpb25SZWdpc3RyeS5jbG9zZUFsbEluc3RhbmNlcyh0aGlzLmlkKTtcbiAgICBhd2FpdCB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudENsaWVudC5kZWxldGVBY2NvdW50KHRoaXMuaWQpO1xuICAgIGNvbnN0IGZpbGVNYW5hZ2VyID0gSGlzdG9yeURhdGFiYXNlLmdldEluc3RhbmNlKCk7XG4gICAgYXdhaXQgZmlsZU1hbmFnZXIuY2xlYXIodGhpcy5pZCwgdGhpcy5fYXBwbGljYXRpb24pO1xuICAgIGlmICgodGhpcy50eXBlIGFzIGFueSkgIT09ICdzZWxmLWhvc3RlZCcpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMucmVsb2FkKCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgaWYgKGVyci5uYW1lICE9PSAnTm90Rm91bmRFcnJvcicpIHtcbiAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3RhcnRzIEFQSSBzZXJ2ZXIgYW5kIHRyYWRpbmcgdGVybWluYWwgZm9yIHRyYWRpbmcgYWNjb3VudC5cbiAgICogVGhpcyByZXF1ZXN0IHdpbGwgYmUgaWdub3JlZCBpZiB0aGUgYWNjb3VudCBpcyBhbHJlYWR5IGRlcGxveWVkLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IGlzIHNjaGVkdWxlZCBmb3IgZGVwbG95bWVudFxuICAgKi9cbiAgYXN5bmMgZGVwbG95KCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LmRlcGxveUFjY291bnQodGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5yZWxvYWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdG9wcyBBUEkgc2VydmVyIGFuZCB0cmFkaW5nIHRlcm1pbmFsIGZvciB0cmFkaW5nIGFjY291bnQuXG4gICAqIFRoaXMgcmVxdWVzdCB3aWxsIGJlIGlnbm9yZWQgaWYgdHJhZGluZyBhY2NvdW50IGlzIGFscmVhZHkgdW5kZXBsb3llZFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IGlzIHNjaGVkdWxlZCBmb3IgdW5kZXBsb3ltZW50XG4gICAqL1xuICBhc3luYyB1bmRlcGxveSgpIHtcbiAgICB0aGlzLl9jb25uZWN0aW9uUmVnaXN0cnkuY2xvc2VBbGxJbnN0YW5jZXModGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5fbWV0YXRyYWRlckFjY291bnRDbGllbnQudW5kZXBsb3lBY2NvdW50KHRoaXMuaWQpO1xuICAgIGF3YWl0IHRoaXMucmVsb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVkZXBsb3lzIHRyYWRpbmcgYWNjb3VudC4gVGhpcyBpcyBlcXVpdmFsZW50IHRvIHVuZGVwbG95IGltbWVkaWF0ZWx5IGZvbGxvd2VkIGJ5IGRlcGxveVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBhY2NvdW50IGlzIHNjaGVkdWxlZCBmb3IgcmVkZXBsb3ltZW50XG4gICAqL1xuICBhc3luYyByZWRlcGxveSgpIHtcbiAgICBhd2FpdCB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudENsaWVudC5yZWRlcGxveUFjY291bnQodGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5yZWxvYWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbmNyZWFzZXMgdHJhZGluZyBhY2NvdW50IHJlbGlhYmlsaXR5IGluIG9yZGVyIHRvIGluY3JlYXNlIHRoZSBleHBlY3RlZCBhY2NvdW50IHVwdGltZS5cbiAgICogVGhlIGFjY291bnQgd2lsbCBiZSB0ZW1wb3Jhcnkgc3RvcHBlZCB0byBwZXJmb3JtIHRoaXMgYWN0aW9uLlxuICAgKiBOb3RlIHRoYXQgaW5jcmVhc2luZyByZWxpYWJpbGl0eSBpcyBhIHBhaWQgb3B0aW9uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIGFjY291bnQgcmVsaWFiaWxpdHkgaXMgaW5jcmVhc2VkXG4gICAqL1xuICBhc3luYyBpbmNyZWFzZVJlbGlhYmlsaXR5KCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LmluY3JlYXNlUmVsaWFiaWxpdHkodGhpcy5pZCk7XG4gICAgYXdhaXQgdGhpcy5yZWxvYWQoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbmFibGVzIHJpc2sgbWFuYWdlbWVudCBBUEkgZm9yIHRyYWRpbmcgYWNjb3VudC5cbiAgICogVGhlIGFjY291bnQgd2lsbCBiZSB0ZW1wb3Jhcnkgc3RvcHBlZCB0byBwZXJmb3JtIHRoaXMgYWN0aW9uLlxuICAgKiBOb3RlIHRoYXQgcmlzayBtYW5hZ2VtZW50IEFQSSBpcyBhIHBhaWQgb3B0aW9uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIGFjY291bnQgcmlzayBtYW5hZ2VtZW50IGlzIGVuYWJsZWRcbiAgICovXG4gIGFzeW5jIGVuYWJsZVJpc2tNYW5hZ2VtZW50QXBpKCkge1xuICAgIGF3YWl0IHRoaXMuX21ldGF0cmFkZXJBY2NvdW50Q2xpZW50LmVuYWJsZVJpc2tNYW5hZ2VtZW50QXBpKHRoaXMuaWQpO1xuICAgIGF3YWl0IHRoaXMucmVsb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogRW5hYmxlcyBjb3B5IGZhY3RvcnkgQVBJIGZvciB0cmFkaW5nIGFjY291bnQuXG4gICAqIFRoZSBhY2NvdW50IHdpbGwgYmUgd