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)
137 lines (136 loc) • 24.7 kB
JavaScript
'use strict';
import HttpClient from '../clients/httpClient';
import ProvisioningProfileClient from '../clients/metaApi/provisioningProfile.client';
import ProvisioningProfileApi from './provisioningProfileApi';
import MetaApiWebsocketClient from '../clients/metaApi/metaApiWebsocket.client';
import MetatraderAccountApi from './metatraderAccountApi';
import MetatraderAccountClient from '../clients/metaApi/metatraderAccount.client';
import MetatraderAccountGeneratorApi from './metatraderAccountGeneratorApi';
import MetatraderAccountGeneratorClient from '../clients/metaApi/metatraderAccountGenerator.client';
import HistoricalMarketDataClient from '../clients/metaApi/historicalMarketData.client';
import ClientApiClient from '../clients/metaApi/clientApi.client';
import ConnectionRegistry from './connectionRegistry';
import { ValidationError } from '../clients/errorHandler';
import OptionsValidator from '../clients/optionsValidator';
import LatencyMonitor from './latencyMonitor';
import ExpertAdvisorClient from '../clients/metaApi/expertAdvisor.client';
import LoggerManager from '../logger';
import DomainClient from '../clients/domain.client';
import TerminalHashManager from './terminalHashManager';
import TokenManagementClient from '../clients/metaApi/tokenManagement.client';
import TokenManagementApi from './tokenManagementApi';
import _ from 'lodash';
let MetaApi = class MetaApi {
/**
* Enables using Log4js logger with extended log levels for debugging instead of
* console.* functions. Note that log4js configuration performed by the user.
*/ static enableLog4jsLogging() {
LoggerManager.useLog4js();
}
/**
* Returns provisioning profile API
* @returns {ProvisioningProfileApi} provisioning profile API
*/ get provisioningProfileApi() {
return this._provisioningProfileApi;
}
/**
* Returns MetaTrader account API
* @return {MetatraderAccountApi} MetaTrader account API
*/ get metatraderAccountApi() {
return this._metatraderAccountApi;
}
/**
* Returns MetaTrader account generator API
* @return {MetatraderDemoAccountApi} MetaTrader account generator API
*/ get metatraderAccountGeneratorApi() {
return this._metatraderAccountGeneratorApi;
}
/**
* Returns MetaApi application latency monitor
* @return {LatencyMonitor} latency monitor
*/ get latencyMonitor() {
return this._latencyMonitor;
}
/**
* Returns token management API
* @returns {TokenManagementApi} token management API
*/ get tokenManagementApi() {
return this._tokenManagementApi;
}
/**
* Closes all clients and connections and stops all internal jobs
*/ close() {
this._metaApiWebsocketClient.removeLatencyListener(this._latencyMonitor);
this._metaApiWebsocketClient.close();
this._metaApiWebsocketClient.stop();
this._terminalHashManager._stop();
}
/**
* Constructs MetaApi class instance
* @param {String} token authorization token
* @param {MetaApiOpts} opts application options
*/ // eslint-disable-next-line complexity
constructor(token, opts){
const validator = new OptionsValidator();
opts = _.omit(opts || {}, [
'connections'
]);
const application = opts.application || 'MetaApi';
const domain = opts.domain || 'agiliumtrade.agiliumtrade.ai';
const requestTimeout = validator.validateNonZero(opts.requestTimeout, 60, 'requestTimeout');
const historicalMarketDataRequestTimeout = validator.validateNonZero(opts.historicalMarketDataRequestTimeout, 240, 'historicalMarketDataRequestTimeout');
const connectTimeout = validator.validateNonZero(opts.connectTimeout, 60, 'connectTimeout');
const packetOrderingTimeout = validator.validateNonZero(opts.packetOrderingTimeout, 60, 'packetOrderingTimeout');
const retryOpts = opts.retryOpts || {};
const packetLogger = opts.packetLogger || {};
const synchronizationThrottler = opts.synchronizationThrottler || {};
const accountGeneratorRequestTimeout = validator.validateNonZero(opts.accountGeneratorRequestTimeout, 240, 'accountGeneratorRequestTimeout');
if (!application.match(/[a-zA-Z0-9_]+/)) {
throw new ValidationError('Application name must be non-empty string consisting from letters, digits and _ only');
}
const useSharedClientApi = opts.useSharedClientApi || false;
const refreshSubscriptionsOpts = opts.refreshSubscriptionsOpts || {};
const httpClient = new HttpClient(requestTimeout, retryOpts);
const domainClient = new DomainClient(httpClient, token, domain);
const historicalMarketDataHttpClient = new HttpClient(historicalMarketDataRequestTimeout, retryOpts);
const accountGeneratorHttpClient = new HttpClient(accountGeneratorRequestTimeout, retryOpts);
const clientApiClient = new ClientApiClient(httpClient, domainClient);
const tokenManagmentClient = new TokenManagementClient(httpClient, domainClient);
this._terminalHashManager = new TerminalHashManager(clientApiClient, opts.keepHashTrees);
this._metaApiWebsocketClient = new MetaApiWebsocketClient(this, domainClient, token, {
application,
domain,
requestTimeout,
connectTimeout,
packetLogger,
packetOrderingTimeout,
synchronizationThrottler,
retryOpts,
useSharedClientApi,
region: opts.region,
unsubscribeThrottlingIntervalInSeconds: opts.unsubscribeThrottlingIntervalInSeconds,
useNativeSocketIoServer: opts.useNativeSocketIoServer
});
this._provisioningProfileApi = new ProvisioningProfileApi(new ProvisioningProfileClient(httpClient, domainClient));
this._connectionRegistry = new ConnectionRegistry(opts, this._metaApiWebsocketClient, this._terminalHashManager, application, refreshSubscriptionsOpts);
let historicalMarketDataClient = new HistoricalMarketDataClient(historicalMarketDataHttpClient, domainClient);
this._metatraderAccountApi = new MetatraderAccountApi(new MetatraderAccountClient(httpClient, domainClient), this._metaApiWebsocketClient, this._connectionRegistry, new ExpertAdvisorClient(httpClient, domainClient), historicalMarketDataClient, application);
this._metatraderAccountGeneratorApi = new MetatraderAccountGeneratorApi(new MetatraderAccountGeneratorClient(accountGeneratorHttpClient, domainClient));
this._tokenManagementApi = new TokenManagementApi(tokenManagmentClient);
if (opts.enableLatencyTracking || opts.enableLatencyMonitor) {
this._latencyMonitor = new LatencyMonitor();
this._metaApiWebsocketClient.addLatencyListener(this._latencyMonitor);
}
this._logger = LoggerManager.getLogger('MetaAPI');
if (process.env.IS_BROWSER) {
if (!this._tokenManagementApi.areTokenResourcesNarrowedDown(token)) {
this._logger.warn('USING THE ADMIN TOKEN');
this._logger.info('It seems like you are using a admin API token. Since the token can be retrieven from the browser or ' + 'mobile apps by end user this can lead to your application being compromised, unless you understand what ' + 'are you doing. Please use Token Management API ' + '(https://github.com/metaapi/metaapi-javascript-sdk/blob/master/docs/tokenManagementApi.md) in your ' + 'backend application to produce secure tokens which you can then use in web UI or mobile apps.');
}
}
}
};
/**
* MetaApi MetaTrader API SDK
*/ export { MetaApi as default };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBIdHRwQ2xpZW50IGZyb20gJy4uL2NsaWVudHMvaHR0cENsaWVudCc7XG5pbXBvcnQgUHJvdmlzaW9uaW5nUHJvZmlsZUNsaWVudCBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvcHJvdmlzaW9uaW5nUHJvZmlsZS5jbGllbnQnO1xuaW1wb3J0IFByb3Zpc2lvbmluZ1Byb2ZpbGVBcGkgZnJvbSAnLi9wcm92aXNpb25pbmdQcm9maWxlQXBpJztcbmltcG9ydCBNZXRhQXBpV2Vic29ja2V0Q2xpZW50IGZyb20gJy4uL2NsaWVudHMvbWV0YUFwaS9tZXRhQXBpV2Vic29ja2V0LmNsaWVudCc7XG5pbXBvcnQgTWV0YXRyYWRlckFjY291bnRBcGkgZnJvbSAnLi9tZXRhdHJhZGVyQWNjb3VudEFwaSc7XG5pbXBvcnQgTWV0YXRyYWRlckFjY291bnRDbGllbnQgZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL21ldGF0cmFkZXJBY2NvdW50LmNsaWVudCc7XG5pbXBvcnQgTWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JBcGkgZnJvbSAnLi9tZXRhdHJhZGVyQWNjb3VudEdlbmVyYXRvckFwaSc7XG5pbXBvcnQgTWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JDbGllbnQgZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL21ldGF0cmFkZXJBY2NvdW50R2VuZXJhdG9yLmNsaWVudCc7XG5pbXBvcnQgSGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQgZnJvbSAnLi4vY2xpZW50cy9tZXRhQXBpL2hpc3RvcmljYWxNYXJrZXREYXRhLmNsaWVudCc7XG5pbXBvcnQgQ2xpZW50QXBpQ2xpZW50IGZyb20gJy4uL2NsaWVudHMvbWV0YUFwaS9jbGllbnRBcGkuY2xpZW50JztcbmltcG9ydCBDb25uZWN0aW9uUmVnaXN0cnkgZnJvbSAnLi9jb25uZWN0aW9uUmVnaXN0cnknO1xuaW1wb3J0IHtWYWxpZGF0aW9uRXJyb3J9IGZyb20gJy4uL2NsaWVudHMvZXJyb3JIYW5kbGVyJztcbmltcG9ydCBPcHRpb25zVmFsaWRhdG9yIGZyb20gJy4uL2NsaWVudHMvb3B0aW9uc1ZhbGlkYXRvcic7XG5pbXBvcnQgTGF0ZW5jeU1vbml0b3IgZnJvbSAnLi9sYXRlbmN5TW9uaXRvcic7XG5pbXBvcnQgRXhwZXJ0QWR2aXNvckNsaWVudCBmcm9tICcuLi9jbGllbnRzL21ldGFBcGkvZXhwZXJ0QWR2aXNvci5jbGllbnQnO1xuaW1wb3J0IExvZ2dlck1hbmFnZXIgZnJvbSAnLi4vbG9nZ2VyJztcbmltcG9ydCBEb21haW5DbGllbnQgZnJvbSAnLi4vY2xpZW50cy9kb21haW4uY2xpZW50JztcbmltcG9ydCBUZXJtaW5hbEhhc2hNYW5hZ2VyIGZyb20gJy4vdGVybWluYWxIYXNoTWFuYWdlcic7XG5pbXBvcnQgVG9rZW5NYW5hZ2VtZW50Q2xpZW50IGZyb20gJy4uL2NsaWVudHMvbWV0YUFwaS90b2tlbk1hbmFnZW1lbnQuY2xpZW50JztcbmltcG9ydCBUb2tlbk1hbmFnZW1lbnRBcGkgZnJvbSAnLi90b2tlbk1hbmFnZW1lbnRBcGknO1xuaW1wb3J0IHtNZXRhQXBpT3B0c30gZnJvbSAnLi9tZXRhQXBpJztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5cbi8qKlxuICogTWV0YUFwaSBNZXRhVHJhZGVyIEFQSSBTREtcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTWV0YUFwaSB7XG5cbiAgLyoqXG4gICAqIEVuYWJsZXMgdXNpbmcgTG9nNGpzIGxvZ2dlciB3aXRoIGV4dGVuZGVkIGxvZyBsZXZlbHMgZm9yIGRlYnVnZ2luZyBpbnN0ZWFkIG9mXG4gICAqIGNvbnNvbGUuKiBmdW5jdGlvbnMuIE5vdGUgdGhhdCBsb2c0anMgY29uZmlndXJhdGlvbiBwZXJmb3JtZWQgYnkgdGhlIHVzZXIuXG4gICAqL1xuICBzdGF0aWMgZW5hYmxlTG9nNGpzTG9nZ2luZygpIHtcbiAgICBMb2dnZXJNYW5hZ2VyLnVzZUxvZzRqcygpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgTWV0YUFwaSBjbGFzcyBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge1N0cmluZ30gdG9rZW4gYXV0aG9yaXphdGlvbiB0b2tlblxuICAgKiBAcGFyYW0ge01ldGFBcGlPcHRzfSBvcHRzIGFwcGxpY2F0aW9uIG9wdGlvbnNcbiAgICovXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBjb21wbGV4aXR5XG4gIGNvbnN0cnVjdG9yKHRva2VuLCBvcHRzKSB7XG4gICAgY29uc3QgdmFsaWRhdG9yID0gbmV3IE9wdGlvbnNWYWxpZGF0b3IoKTtcbiAgICBvcHRzID0gXy5vbWl0KG9wdHMgfHwge30sIFsnY29ubmVjdGlvbnMnXSk7XG4gICAgY29uc3QgYXBwbGljYXRpb24gPSBvcHRzLmFwcGxpY2F0aW9uIHx8ICdNZXRhQXBpJztcbiAgICBjb25zdCBkb21haW4gPSBvcHRzLmRvbWFpbiB8fCAnYWdpbGl1bXRyYWRlLmFnaWxpdW10cmFkZS5haSc7XG4gICAgY29uc3QgcmVxdWVzdFRpbWVvdXQgPSB2YWxpZGF0b3IudmFsaWRhdGVOb25aZXJvKG9wdHMucmVxdWVzdFRpbWVvdXQsIDYwLCAncmVxdWVzdFRpbWVvdXQnKTtcbiAgICBjb25zdCBoaXN0b3JpY2FsTWFya2V0RGF0YVJlcXVlc3RUaW1lb3V0ID0gdmFsaWRhdG9yLnZhbGlkYXRlTm9uWmVybyhcbiAgICAgIG9wdHMuaGlzdG9yaWNhbE1hcmtldERhdGFSZXF1ZXN0VGltZW91dCwgMjQwLCAnaGlzdG9yaWNhbE1hcmtldERhdGFSZXF1ZXN0VGltZW91dCcpO1xuICAgIGNvbnN0IGNvbm5lY3RUaW1lb3V0ID0gdmFsaWRhdG9yLnZhbGlkYXRlTm9uWmVybyhvcHRzLmNvbm5lY3RUaW1lb3V0LCA2MCwgJ2Nvbm5lY3RUaW1lb3V0Jyk7XG4gICAgY29uc3QgcGFja2V0T3JkZXJpbmdUaW1lb3V0ID0gdmFsaWRhdG9yLnZhbGlkYXRlTm9uWmVybyhvcHRzLnBhY2tldE9yZGVyaW5nVGltZW91dCwgNjAsICdwYWNrZXRPcmRlcmluZ1RpbWVvdXQnKTtcbiAgICBjb25zdCByZXRyeU9wdHMgPSBvcHRzLnJldHJ5T3B0cyB8fCB7fTtcbiAgICBjb25zdCBwYWNrZXRMb2dnZXIgPSBvcHRzLnBhY2tldExvZ2dlciB8fCB7fTtcbiAgICBjb25zdCBzeW5jaHJvbml6YXRpb25UaHJvdHRsZXIgPSBvcHRzLnN5bmNocm9uaXphdGlvblRocm90dGxlciB8fCB7fTtcbiAgICBjb25zdCBhY2NvdW50R2VuZXJhdG9yUmVxdWVzdFRpbWVvdXQgPSB2YWxpZGF0b3IudmFsaWRhdGVOb25aZXJvKG9wdHMuYWNjb3VudEdlbmVyYXRvclJlcXVlc3RUaW1lb3V0LCAyNDAsXG4gICAgICAnYWNjb3VudEdlbmVyYXRvclJlcXVlc3RUaW1lb3V0Jyk7XG4gICAgaWYgKCFhcHBsaWNhdGlvbi5tYXRjaCgvW2EtekEtWjAtOV9dKy8pKSB7XG4gICAgICB0aHJvdyBuZXcgVmFsaWRhdGlvbkVycm9yKCdBcHBsaWNhdGlvbiBuYW1lIG11c3QgYmUgbm9uLWVtcHR5IHN0cmluZyBjb25zaXN0aW5nIGZyb20gbGV0dGVycywgZGlnaXRzIGFuZCBfIG9ubHknKTtcbiAgICB9XG4gICAgY29uc3QgdXNlU2hhcmVkQ2xpZW50QXBpID0gb3B0cy51c2VTaGFyZWRDbGllbnRBcGkgfHwgZmFsc2U7XG4gICAgY29uc3QgcmVmcmVzaFN1YnNjcmlwdGlvbnNPcHRzID0gb3B0cy5yZWZyZXNoU3Vic2NyaXB0aW9uc09wdHMgfHwge307XG4gICAgY29uc3QgaHR0cENsaWVudCA9IG5ldyBIdHRwQ2xpZW50KHJlcXVlc3RUaW1lb3V0LCByZXRyeU9wdHMpO1xuICAgIGNvbnN0IGRvbWFpbkNsaWVudCA9IG5ldyBEb21haW5DbGllbnQoaHR0cENsaWVudCwgdG9rZW4sIGRvbWFpbik7XG4gICAgY29uc3QgaGlzdG9yaWNhbE1hcmtldERhdGFIdHRwQ2xpZW50ID0gbmV3IEh0dHBDbGllbnQoaGlzdG9yaWNhbE1hcmtldERhdGFSZXF1ZXN0VGltZW91dCwgcmV0cnlPcHRzKTtcbiAgICBjb25zdCBhY2NvdW50R2VuZXJhdG9ySHR0cENsaWVudCA9IG5ldyBIdHRwQ2xpZW50KGFjY291bnRHZW5lcmF0b3JSZXF1ZXN0VGltZW91dCwgcmV0cnlPcHRzKTtcbiAgICBjb25zdCBjbGllbnRBcGlDbGllbnQgPSBuZXcgQ2xpZW50QXBpQ2xpZW50KGh0dHBDbGllbnQsIGRvbWFpbkNsaWVudCk7IFxuICAgIGNvbnN0IHRva2VuTWFuYWdtZW50Q2xpZW50ID0gbmV3IFRva2VuTWFuYWdlbWVudENsaWVudChodHRwQ2xpZW50LCBkb21haW5DbGllbnQpOyBcbiAgICB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyID0gbmV3IFRlcm1pbmFsSGFzaE1hbmFnZXIoY2xpZW50QXBpQ2xpZW50LCBvcHRzLmtlZXBIYXNoVHJlZXMpO1xuICAgIHRoaXMuX21ldGFBcGlXZWJzb2NrZXRDbGllbnQgPSBuZXcgTWV0YUFwaVdlYnNvY2tldENsaWVudCh0aGlzLCBkb21haW5DbGllbnQsIHRva2VuLCB7XG4gICAgICBhcHBsaWNhdGlvbiwgZG9tYWluLFxuICAgICAgcmVxdWVzdFRpbWVvdXQsIGNvbm5lY3RUaW1lb3V0LCBwYWNrZXRMb2dnZXIsIHBhY2tldE9yZGVyaW5nVGltZW91dCwgc3luY2hyb25pemF0aW9uVGhyb3R0bGVyLCByZXRyeU9wdHMsXG4gICAgICB1c2VTaGFyZWRDbGllbnRBcGksIHJlZ2lvbjogb3B0cy5yZWdpb24sXG4gICAgICB1bnN1YnNjcmliZVRocm90dGxpbmdJbnRlcnZhbEluU2Vjb25kczogb3B0cy51bnN1YnNjcmliZVRocm90dGxpbmdJbnRlcnZhbEluU2Vjb25kcyxcbiAgICAgIHVzZU5hdGl2ZVNvY2tldElvU2VydmVyOiBvcHRzLnVzZU5hdGl2ZVNvY2tldElvU2VydmVyXG4gICAgfSk7XG4gICAgdGhpcy5fcHJvdmlzaW9uaW5nUHJvZmlsZUFwaSA9IG5ldyBQcm92aXNpb25pbmdQcm9maWxlQXBpKG5ldyBQcm92aXNpb25pbmdQcm9maWxlQ2xpZW50KGh0dHBDbGllbnQsIGRvbWFpbkNsaWVudCkpO1xuICAgIHRoaXMuX2Nvbm5lY3Rpb25SZWdpc3RyeSA9IG5ldyBDb25uZWN0aW9uUmVnaXN0cnkob3B0cywgdGhpcy5fbWV0YUFwaVdlYnNvY2tldENsaWVudCwgdGhpcy5fdGVybWluYWxIYXNoTWFuYWdlcixcbiAgICAgIGFwcGxpY2F0aW9uLCByZWZyZXNoU3Vic2NyaXB0aW9uc09wdHMpO1xuICAgIGxldCBoaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudCA9IG5ldyBIaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudChoaXN0b3JpY2FsTWFya2V0RGF0YUh0dHBDbGllbnQsIGRvbWFpbkNsaWVudCk7XG4gICAgdGhpcy5fbWV0YXRyYWRlckFjY291bnRBcGkgPSBuZXcgTWV0YXRyYWRlckFjY291bnRBcGkobmV3IE1ldGF0cmFkZXJBY2NvdW50Q2xpZW50KGh0dHBDbGllbnQsIGRvbWFpbkNsaWVudCksXG4gICAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LCB0aGlzLl9jb25uZWN0aW9uUmVnaXN0cnksIFxuICAgICAgbmV3IEV4cGVydEFkdmlzb3JDbGllbnQoaHR0cENsaWVudCwgZG9tYWluQ2xpZW50KSwgaGlzdG9yaWNhbE1hcmtldERhdGFDbGllbnQsIGFwcGxpY2F0aW9uKTtcbiAgICB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudEdlbmVyYXRvckFwaSA9IG5ldyBNZXRhdHJhZGVyQWNjb3VudEdlbmVyYXRvckFwaShcbiAgICAgIG5ldyBNZXRhdHJhZGVyQWNjb3VudEdlbmVyYXRvckNsaWVudChhY2NvdW50R2VuZXJhdG9ySHR0cENsaWVudCwgZG9tYWluQ2xpZW50KSk7XG4gICAgdGhpcy5fdG9rZW5NYW5hZ2VtZW50QXBpID0gbmV3IFRva2VuTWFuYWdlbWVudEFwaSh0b2tlbk1hbmFnbWVudENsaWVudCk7XG4gICAgaWYgKG9wdHMuZW5hYmxlTGF0ZW5jeVRyYWNraW5nIHx8IG9wdHMuZW5hYmxlTGF0ZW5jeU1vbml0b3IpIHtcbiAgICAgIHRoaXMuX2xhdGVuY3lNb25pdG9yID0gbmV3IExhdGVuY3lNb25pdG9yKCk7XG4gICAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LmFkZExhdGVuY3lMaXN0ZW5lcih0aGlzLl9sYXRlbmN5TW9uaXRvcik7XG4gICAgfVxuICAgIFxuICAgIHRoaXMuX2xvZ2dlciA9IExvZ2dlck1hbmFnZXIuZ2V0TG9nZ2VyKCdNZXRhQVBJJyk7XG4gICAgaWYgKHByb2Nlc3MuZW52LklTX0JST1dTRVIpIHtcbiAgICAgIGlmICghdGhpcy5fdG9rZW5NYW5hZ2VtZW50QXBpLmFyZVRva2VuUmVzb3VyY2VzTmFycm93ZWREb3duKHRva2VuKSkge1xuICAgICAgICB0aGlzLl9sb2dnZXIud2FybignVVNJTkcgVEhFIEFETUlOIFRPS0VOJyk7XG4gICAgICAgIHRoaXMuX2xvZ2dlci5pbmZvKFxuICAgICAgICAgICdJdCBzZWVtcyBsaWtlIHlvdSBhcmUgdXNpbmcgYSBhZG1pbiBBUEkgdG9rZW4uIFNpbmNlIHRoZSB0b2tlbiBjYW4gYmUgcmV0cmlldmVuIGZyb20gdGhlIGJyb3dzZXIgb3IgJyArXG4gICAgICAgICAgJ21vYmlsZSBhcHBzIGJ5IGVuZCB1c2VyIHRoaXMgY2FuIGxlYWQgdG8geW91ciBhcHBsaWNhdGlvbiBiZWluZyBjb21wcm9taXNlZCwgdW5sZXNzIHlvdSB1bmRlcnN0YW5kIHdoYXQgJyArXG4gICAgICAgICAgJ2FyZSB5b3UgZG9pbmcuIFBsZWFzZSB1c2UgVG9rZW4gTWFuYWdlbWVudCBBUEkgJyArXG4gICAgICAgICAgJyhodHRwczovL2dpdGh1Yi5jb20vbWV0YWFwaS9tZXRhYXBpLWphdmFzY3JpcHQtc2RrL2Jsb2IvbWFzdGVyL2RvY3MvdG9rZW5NYW5hZ2VtZW50QXBpLm1kKSBpbiB5b3VyICcgK1xuICAgICAgICAgICdiYWNrZW5kIGFwcGxpY2F0aW9uIHRvIHByb2R1Y2Ugc2VjdXJlIHRva2VucyB3aGljaCB5b3UgY2FuIHRoZW4gdXNlIGluIHdlYiBVSSBvciBtb2JpbGUgYXBwcy4nXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgcHJvdmlzaW9uaW5nIHByb2ZpbGUgQVBJXG4gICAqIEByZXR1cm5zIHtQcm92aXNpb25pbmdQcm9maWxlQXBpfSBwcm92aXNpb25pbmcgcHJvZmlsZSBBUElcbiAgICovXG4gIGdldCBwcm92aXNpb25pbmdQcm9maWxlQXBpKCkge1xuICAgIHJldHVybiB0aGlzLl9wcm92aXNpb25pbmdQcm9maWxlQXBpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgTWV0YVRyYWRlciBhY2NvdW50IEFQSVxuICAgKiBAcmV0dXJuIHtNZXRhdHJhZGVyQWNjb3VudEFwaX0gTWV0YVRyYWRlciBhY2NvdW50IEFQSVxuICAgKi9cbiAgZ2V0IG1ldGF0cmFkZXJBY2NvdW50QXBpKCkge1xuICAgIHJldHVybiB0aGlzLl9tZXRhdHJhZGVyQWNjb3VudEFwaTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIE1ldGFUcmFkZXIgYWNjb3VudCBnZW5lcmF0b3IgQVBJXG4gICAqIEByZXR1cm4ge01ldGF0cmFkZXJEZW1vQWNjb3VudEFwaX0gTWV0YVRyYWRlciBhY2NvdW50IGdlbmVyYXRvciBBUElcbiAgICovXG4gIGdldCBtZXRhdHJhZGVyQWNjb3VudEdlbmVyYXRvckFwaSgpIHtcbiAgICByZXR1cm4gdGhpcy5fbWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JBcGk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBNZXRhQXBpIGFwcGxpY2F0aW9uIGxhdGVuY3kgbW9uaXRvclxuICAgKiBAcmV0dXJuIHtMYXRlbmN5TW9uaXRvcn0gbGF0ZW5jeSBtb25pdG9yXG4gICAqL1xuICBnZXQgbGF0ZW5jeU1vbml0b3IoKSB7XG4gICAgcmV0dXJuIHRoaXMuX2xhdGVuY3lNb25pdG9yO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdG9rZW4gbWFuYWdlbWVudCBBUElcbiAgICogQHJldHVybnMge1Rva2VuTWFuYWdlbWVudEFwaX0gdG9rZW4gbWFuYWdlbWVudCBBUElcbiAgICovXG4gIGdldCB0b2tlbk1hbmFnZW1lbnRBcGkoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Rva2VuTWFuYWdlbWVudEFwaTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbG9zZXMgYWxsIGNsaWVudHMgYW5kIGNvbm5lY3Rpb25zIGFuZCBzdG9wcyBhbGwgaW50ZXJuYWwgam9ic1xuICAgKi9cbiAgY2xvc2UoKSB7XG4gICAgdGhpcy5fbWV0YUFwaVdlYnNvY2tldENsaWVudC5yZW1vdmVMYXRlbmN5TGlzdGVuZXIodGhpcy5fbGF0ZW5jeU1vbml0b3IpO1xuICAgIHRoaXMuX21ldGFBcGlXZWJzb2NrZXRDbGllbnQuY2xvc2UoKTtcbiAgICB0aGlzLl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50LnN0b3AoKTtcbiAgICB0aGlzLl90ZXJtaW5hbEhhc2hNYW5hZ2VyLl9zdG9wKCk7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJIdHRwQ2xpZW50IiwiUHJvdmlzaW9uaW5nUHJvZmlsZUNsaWVudCIsIlByb3Zpc2lvbmluZ1Byb2ZpbGVBcGkiLCJNZXRhQXBpV2Vic29ja2V0Q2xpZW50IiwiTWV0YXRyYWRlckFjY291bnRBcGkiLCJNZXRhdHJhZGVyQWNjb3VudENsaWVudCIsIk1ldGF0cmFkZXJBY2NvdW50R2VuZXJhdG9yQXBpIiwiTWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JDbGllbnQiLCJIaXN0b3JpY2FsTWFya2V0RGF0YUNsaWVudCIsIkNsaWVudEFwaUNsaWVudCIsIkNvbm5lY3Rpb25SZWdpc3RyeSIsIlZhbGlkYXRpb25FcnJvciIsIk9wdGlvbnNWYWxpZGF0b3IiLCJMYXRlbmN5TW9uaXRvciIsIkV4cGVydEFkdmlzb3JDbGllbnQiLCJMb2dnZXJNYW5hZ2VyIiwiRG9tYWluQ2xpZW50IiwiVGVybWluYWxIYXNoTWFuYWdlciIsIlRva2VuTWFuYWdlbWVudENsaWVudCIsIlRva2VuTWFuYWdlbWVudEFwaSIsIl8iLCJNZXRhQXBpIiwiZW5hYmxlTG9nNGpzTG9nZ2luZyIsInVzZUxvZzRqcyIsInByb3Zpc2lvbmluZ1Byb2ZpbGVBcGkiLCJfcHJvdmlzaW9uaW5nUHJvZmlsZUFwaSIsIm1ldGF0cmFkZXJBY2NvdW50QXBpIiwiX21ldGF0cmFkZXJBY2NvdW50QXBpIiwibWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JBcGkiLCJfbWV0YXRyYWRlckFjY291bnRHZW5lcmF0b3JBcGkiLCJsYXRlbmN5TW9uaXRvciIsIl9sYXRlbmN5TW9uaXRvciIsInRva2VuTWFuYWdlbWVudEFwaSIsIl90b2tlbk1hbmFnZW1lbnRBcGkiLCJjbG9zZSIsIl9tZXRhQXBpV2Vic29ja2V0Q2xpZW50IiwicmVtb3ZlTGF0ZW5jeUxpc3RlbmVyIiwic3RvcCIsIl90ZXJtaW5hbEhhc2hNYW5hZ2VyIiwiX3N0b3AiLCJjb25zdHJ1Y3RvciIsInRva2VuIiwib3B0cyIsInZhbGlkYXRvciIsIm9taXQiLCJhcHBsaWNhdGlvbiIsImRvbWFpbiIsInJlcXVlc3RUaW1lb3V0IiwidmFsaWRhdGVOb25aZXJvIiwiaGlzdG9yaWNhbE1hcmtldERhdGFSZXF1ZXN0VGltZW91dCIsImNvbm5lY3RUaW1lb3V0IiwicGFja2V0T3JkZXJpbmdUaW1lb3V0IiwicmV0cnlPcHRzIiwicGFja2V0TG9nZ2VyIiwic3luY2hyb25pemF0aW9uVGhyb3R0bGVyIiwiYWNjb3VudEdlbmVyYXRvclJlcXVlc3RUaW1lb3V0IiwibWF0Y2giLCJ1c2VTaGFyZWRDbGllbnRBcGkiLCJyZWZyZXNoU3Vic2NyaXB0aW9uc09wdHMiLCJodHRwQ2xpZW50IiwiZG9tYWluQ2xpZW50IiwiaGlzdG9yaWNhbE1hcmtldERhdGFIdHRwQ2xpZW50IiwiYWNjb3VudEdlbmVyYXRvckh0dHBDbGllbnQiLCJjbGllbnRBcGlDbGllbnQiLCJ0b2tlbk1hbmFnbWVudENsaWVudCIsImtlZXBIYXNoVHJlZXMiLCJyZWdpb24iLCJ1bnN1YnNjcmliZVRocm90dGxpbmdJbnRlcnZhbEluU2Vjb25kcyIsInVzZU5hdGl2ZVNvY2tldElvU2VydmVyIiwiX2Nvbm5lY3Rpb25SZWdpc3RyeSIsImhpc3RvcmljYWxNYXJrZXREYXRhQ2xpZW50IiwiZW5hYmxlTGF0ZW5jeVRyYWNraW5nIiwiZW5hYmxlTGF0ZW5jeU1vbml0b3IiLCJhZGRMYXRlbmN5TGlzdGVuZXIiLCJfbG9nZ2VyIiwiZ2V0TG9nZ2VyIiwicHJvY2VzcyIsImVudiIsIklTX0JST1dTRVIiLCJhcmVUb2tlblJlc291cmNlc05hcnJvd2VkRG93biIsIndhcm4iLCJpbmZvIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUVBLE9BQU9BLGdCQUFnQix3QkFBd0I7QUFDL0MsT0FBT0MsK0JBQStCLGdEQUFnRDtBQUN0RixPQUFPQyw0QkFBNEIsMkJBQTJCO0FBQzlELE9BQU9DLDRCQUE0Qiw2Q0FBNkM7QUFDaEYsT0FBT0MsMEJBQTBCLHlCQUF5QjtBQUMxRCxPQUFPQyw2QkFBNkIsOENBQThDO0FBQ2xGLE9BQU9DLG1DQUFtQyxrQ0FBa0M7QUFDNUUsT0FBT0Msc0NBQXNDLHVEQUF1RDtBQUNwRyxPQUFPQyxnQ0FBZ0MsaURBQWlEO0FBQ3hGLE9BQU9DLHFCQUFxQixzQ0FBc0M7QUFDbEUsT0FBT0Msd0JBQXdCLHVCQUF1QjtBQUN0RCxTQUFRQyxlQUFlLFFBQU8sMEJBQTBCO0FBQ3hELE9BQU9DLHNCQUFzQiw4QkFBOEI7QUFDM0QsT0FBT0Msb0JBQW9CLG1CQUFtQjtBQUM5QyxPQUFPQyx5QkFBeUIsMENBQTBDO0FBQzFFLE9BQU9DLG1CQUFtQixZQUFZO0FBQ3RDLE9BQU9DLGtCQUFrQiwyQkFBMkI7QUFDcEQsT0FBT0MseUJBQXlCLHdCQUF3QjtBQUN4RCxPQUFPQywyQkFBMkIsNENBQTRDO0FBQzlFLE9BQU9DLHdCQUF3Qix1QkFBdUI7QUFFdEQsT0FBT0MsT0FBTyxTQUFTO0FBS1IsSUFBQSxBQUFNQyxVQUFOLE1BQU1BO0lBRW5COzs7R0FHQyxHQUNELE9BQU9DLHNCQUFzQjtRQUMzQlAs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