metaapi.cloud-copyfactory-sdk
Version:
Javascript SDK for SDK for CopyFactory trade copying API. Can copy trades both between MetaTrader 5 (MT5) and MetaTrader 4 (MT4). (https://metaapi.cloud)
235 lines (234 loc) • 24.7 kB
JavaScript
;
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;
}
function _object_spread(target) {
for(var i = 1; i < arguments.length; i++){
var source = arguments[i] != null ? arguments[i] : {};
var ownKeys = Object.keys(source);
if (typeof Object.getOwnPropertySymbols === "function") {
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
return Object.getOwnPropertyDescriptor(source, sym).enumerable;
}));
}
ownKeys.forEach(function(key) {
_define_property(target, key, source[key]);
});
}
return target;
}
import axios from 'axios';
import { UnauthorizedError, ForbiddenError, ApiError, ValidationError, InternalError, NotFoundError, TooManyRequestsError } from './errorHandler';
import TimeoutError from './timeoutError';
let HttpClient = class HttpClient {
/**
* Performs a request. Response errors are returned as ApiError or subclasses.
* @param {Object} options request options
* @param {Boolean} isExtendedTimeout whether to run the request with an extended timeout
* @returns {Object|String|any} request result
*/ request(options, isExtendedTimeout, endTime = Date.now() + this._maxRetryDelay * this._retries) {
var _this = this;
return _async_to_generator(function*() {
options.timeout = isExtendedTimeout ? _this._extendedTimeout : _this._timeout;
try {
const response = yield _this._makeRequest(options);
return response && response.data || undefined;
} catch (err) {
const error = _this._convertError(err);
if (error.name === 'TooManyRequestsError') {
const retryTime = Date.parse(error.metadata.recommendedRetryTime);
const date = Date.now();
if (retryTime < endTime) {
if (retryTime > date) {
yield _this._wait(retryTime - date);
}
return yield _this.request(options, isExtendedTimeout, endTime);
} else {
throw error;
}
} else {
throw error;
}
}
})();
}
/**
* Performs a request with a failover. Response errors are returned as ApiError or subclasses.
* @param {Object} options request options
* @returns {Object|String|any} request result
*/ requestWithFailover(options, retryCounter = 0, endTime = Date.now() + this._maxRetryDelay * this._retries) {
var _this = this;
return _async_to_generator(function*() {
options.timeout = _this._timeout;
let retryAfterSeconds = 0;
options.callback = (e, res)=>{
if (res && res.status === 202) {
retryAfterSeconds = res.headers['retry-after'];
}
};
let body;
try {
const response = yield _this._makeRequest(options);
options.callback(null, response);
body = response && response.data || undefined;
} catch (err) {
retryCounter = yield _this._handleError(err, retryCounter, endTime);
return _this.requestWithFailover(options, retryCounter, endTime);
}
if (retryAfterSeconds) {
yield _this._handleRetry(endTime, retryAfterSeconds * 1000);
body = yield _this.requestWithFailover(options, retryCounter, endTime);
}
return body;
})();
}
_makeRequest(options) {
return axios(_object_spread({
transitional: {
clarifyTimeoutError: true
}
}, options));
}
_wait(pause) {
return _async_to_generator(function*() {
yield new Promise((res)=>setTimeout(res, pause));
})();
}
_handleRetry(endTime, retryAfter) {
var _this = this;
return _async_to_generator(function*() {
if (endTime > Date.now() + retryAfter) {
yield _this._wait(retryAfter);
} else {
throw new TimeoutError('Timed out waiting for the response');
}
})();
}
_handleError(err, retryCounter, endTime) {
var _this = this;
return _async_to_generator(function*() {
const error = _this._convertError(err);
if ([
'ConflictError',
'InternalError',
'ApiError',
'TimeoutError'
].includes(error.name) && retryCounter < _this._retries) {
const pause = Math.min(Math.pow(2, retryCounter) * _this._minRetryDelay, _this._maxRetryDelay);
yield _this._wait(pause);
return retryCounter + 1;
} else if (error.name === 'TooManyRequestsError') {
const retryTime = Date.parse(error.metadata.recommendedRetryTime);
if (retryTime < endTime) {
yield _this._wait(retryTime - Date.now());
return retryCounter;
}
}
throw error;
})();
}
// eslint-disable-next-line complexity
_convertError(err) {
var _err_config;
const errorResponse = err.response || {};
const errorData = errorResponse.data || {};
const status = errorResponse.status || err.status;
const url = err === null || err === void 0 ? void 0 : (_err_config = err.config) === null || _err_config === void 0 ? void 0 : _err_config.url;
const errMsg = errorData.message || err.message;
const errMsgDefault = errorData.message || err.code || err.message;
switch(status){
case 400:
return new ValidationError(errMsg, errorData.details || err.details, url);
case 401:
return new UnauthorizedError(errMsg, url);
case 403:
return new ForbiddenError(errMsg, url);
case 404:
return new NotFoundError(errMsg, url);
case 409:
return new NotFoundError(errMsg, url);
case 429:
return new TooManyRequestsError(errMsg, errorData.metadata || err.metadata, url);
case 500:
return new InternalError(errMsg, url);
default:
return new ApiError(ApiError, errMsgDefault, status, url);
}
}
/**
* @typedef {Object} RetryOptions retry options
* @property {Number} [retries] the number of attempts to retry failed request, default 5
* @property {Number} [minDelayInSeconds] minimum delay in seconds before retrying, default 1
* @property {Number} [maxDelayInSeconds] maximum delay in seconds before retrying, default 30
*/ /**
* Constructs HttpClient class instance
* @param {Number} [timeout] request timeout in seconds
* @param {Number} [extendedTimeout] request timeout in seconds
* @param {RetryOptions} [retryOpts] retry options
*/ constructor(timeout = 10, extendedTimeout = 70, retryOpts = {}){
this._timeout = timeout * 1000;
this._extendedTimeout = extendedTimeout * 1000;
this._retries = retryOpts.retries || 5;
this._minRetryDelay = (retryOpts.minDelayInSeconds || 1) * 1000;
this._maxRetryDelay = (retryOpts.maxDelayInSeconds || 30) * 1000;
}
};
/**
* HTTP client library based on request-promise
*/ export { HttpClient as default };
/**
* HTTP client service mock for tests
*/ export class HttpClientMock extends HttpClient {
_makeRequest() {
return this._requestFn.apply(this, arguments);
}
/**
* Constructs HTTP client mock
* @param {Function(options:Object):Promise} requestFn mocked request function
* @param {Number} timeout request timeout in seconds
* @param {RetryOptions} retryOpts retry options
*/ constructor(requestFn, timeout, extendedTimeout, retryOpts){
super(timeout, extendedTimeout, retryOpts);
this._requestFn = requestFn;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBheGlvcyBmcm9tICdheGlvcyc7XG5pbXBvcnQge1xuICBVbmF1dGhvcml6ZWRFcnJvciwgRm9yYmlkZGVuRXJyb3IsIEFwaUVycm9yLCBWYWxpZGF0aW9uRXJyb3IsIEludGVybmFsRXJyb3IsIFxuICBOb3RGb3VuZEVycm9yLCBUb29NYW55UmVxdWVzdHNFcnJvciwgQ29uZmxpY3RFcnJvclxufSBmcm9tICcuL2Vycm9ySGFuZGxlcic7XG5pbXBvcnQgVGltZW91dEVycm9yIGZyb20gJy4vdGltZW91dEVycm9yJztcblxuLyoqXG4gKiBIVFRQIGNsaWVudCBsaWJyYXJ5IGJhc2VkIG9uIHJlcXVlc3QtcHJvbWlzZVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBIdHRwQ2xpZW50IHtcblxuICAvKipcbiAgICogQHR5cGVkZWYge09iamVjdH0gUmV0cnlPcHRpb25zIHJldHJ5IG9wdGlvbnNcbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFtyZXRyaWVzXSB0aGUgbnVtYmVyIG9mIGF0dGVtcHRzIHRvIHJldHJ5IGZhaWxlZCByZXF1ZXN0LCBkZWZhdWx0IDVcbiAgICogQHByb3BlcnR5IHtOdW1iZXJ9IFttaW5EZWxheUluU2Vjb25kc10gbWluaW11bSBkZWxheSBpbiBzZWNvbmRzIGJlZm9yZSByZXRyeWluZywgZGVmYXVsdCAxXG4gICAqIEBwcm9wZXJ0eSB7TnVtYmVyfSBbbWF4RGVsYXlJblNlY29uZHNdIG1heGltdW0gZGVsYXkgaW4gc2Vjb25kcyBiZWZvcmUgcmV0cnlpbmcsIGRlZmF1bHQgMzBcbiAgICovXG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgSHR0cENsaWVudCBjbGFzcyBpbnN0YW5jZVxuICAgKiBAcGFyYW0ge051bWJlcn0gW3RpbWVvdXRdIHJlcXVlc3QgdGltZW91dCBpbiBzZWNvbmRzXG4gICAqIEBwYXJhbSB7TnVtYmVyfSBbZXh0ZW5kZWRUaW1lb3V0XSByZXF1ZXN0IHRpbWVvdXQgaW4gc2Vjb25kc1xuICAgKiBAcGFyYW0ge1JldHJ5T3B0aW9uc30gW3JldHJ5T3B0c10gcmV0cnkgb3B0aW9uc1xuICAgKi9cbiAgY29uc3RydWN0b3IodGltZW91dCA9IDEwLCBleHRlbmRlZFRpbWVvdXQgPSA3MCwgcmV0cnlPcHRzID0ge30pIHtcbiAgICB0aGlzLl90aW1lb3V0ID0gdGltZW91dCAqIDEwMDA7XG4gICAgdGhpcy5fZXh0ZW5kZWRUaW1lb3V0ID0gZXh0ZW5kZWRUaW1lb3V0ICogMTAwMDtcbiAgICB0aGlzLl9yZXRyaWVzID0gcmV0cnlPcHRzLnJldHJpZXMgfHwgNTtcbiAgICB0aGlzLl9taW5SZXRyeURlbGF5ID0gKHJldHJ5T3B0cy5taW5EZWxheUluU2Vjb25kcyB8fCAxKSAqIDEwMDA7XG4gICAgdGhpcy5fbWF4UmV0cnlEZWxheSA9IChyZXRyeU9wdHMubWF4RGVsYXlJblNlY29uZHMgfHwgMzApICogMTAwMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtcyBhIHJlcXVlc3QuIFJlc3BvbnNlIGVycm9ycyBhcmUgcmV0dXJuZWQgYXMgQXBpRXJyb3Igb3Igc3ViY2xhc3Nlcy5cbiAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgcmVxdWVzdCBvcHRpb25zXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNFeHRlbmRlZFRpbWVvdXQgd2hldGhlciB0byBydW4gdGhlIHJlcXVlc3Qgd2l0aCBhbiBleHRlbmRlZCB0aW1lb3V0XG4gICAqIEByZXR1cm5zIHtPYmplY3R8U3RyaW5nfGFueX0gcmVxdWVzdCByZXN1bHRcbiAgICovXG4gIGFzeW5jIHJlcXVlc3Qob3B0aW9ucywgaXNFeHRlbmRlZFRpbWVvdXQsIGVuZFRpbWUgPSBEYXRlLm5vdygpICsgdGhpcy5fbWF4UmV0cnlEZWxheSAqIHRoaXMuX3JldHJpZXMpIHtcbiAgICBvcHRpb25zLnRpbWVvdXQgPSBpc0V4dGVuZGVkVGltZW91dCA/IHRoaXMuX2V4dGVuZGVkVGltZW91dCA6IHRoaXMuX3RpbWVvdXQ7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgdGhpcy5fbWFrZVJlcXVlc3Qob3B0aW9ucyk7XG4gICAgICByZXR1cm4gKHJlc3BvbnNlICYmIHJlc3BvbnNlLmRhdGEpIHx8IHVuZGVmaW5lZDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIGNvbnN0IGVycm9yID0gdGhpcy5fY29udmVydEVycm9yKGVycik7XG4gICAgICBpZihlcnJvci5uYW1lID09PSAnVG9vTWFueVJlcXVlc3RzRXJyb3InKSB7XG4gICAgICAgIGNvbnN0IHJldHJ5VGltZSA9IERhdGUucGFyc2UoZXJyb3IubWV0YWRhdGEucmVjb21tZW5kZWRSZXRyeVRpbWUpO1xuICAgICAgICBjb25zdCBkYXRlID0gRGF0ZS5ub3coKTtcbiAgICAgICAgaWYgKHJldHJ5VGltZSA8IGVuZFRpbWUpIHtcbiAgICAgICAgICBpZihyZXRyeVRpbWUgPiBkYXRlKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl93YWl0KHJldHJ5VGltZSAtIGRhdGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5yZXF1ZXN0KG9wdGlvbnMsIGlzRXh0ZW5kZWRUaW1lb3V0LCBlbmRUaW1lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBlcmZvcm1zIGEgcmVxdWVzdCB3aXRoIGEgZmFpbG92ZXIuIFJlc3BvbnNlIGVycm9ycyBhcmUgcmV0dXJuZWQgYXMgQXBpRXJyb3Igb3Igc3ViY2xhc3Nlcy5cbiAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgcmVxdWVzdCBvcHRpb25zXG4gICAqIEByZXR1cm5zIHtPYmplY3R8U3RyaW5nfGFueX0gcmVxdWVzdCByZXN1bHRcbiAgICovXG4gIGFzeW5jIHJlcXVlc3RXaXRoRmFpbG92ZXIob3B0aW9ucywgcmV0cnlDb3VudGVyID0gMCwgZW5kVGltZSA9IERhdGUubm93KCkgKyB0aGlzLl9tYXhSZXRyeURlbGF5ICogdGhpcy5fcmV0cmllcykge1xuICAgIG9wdGlvbnMudGltZW91dCA9IHRoaXMuX3RpbWVvdXQ7XG4gICAgbGV0IHJldHJ5QWZ0ZXJTZWNvbmRzID0gMDtcbiAgICBvcHRpb25zLmNhbGxiYWNrID0gKGUsIHJlcykgPT4ge1xuICAgICAgaWYgKHJlcyAmJiByZXMuc3RhdHVzID09PSAyMDIpIHtcbiAgICAgICAgcmV0cnlBZnRlclNlY29uZHMgPSByZXMuaGVhZGVyc1sncmV0cnktYWZ0ZXInXTtcbiAgICAgIH1cbiAgICB9O1xuICAgIGxldCBib2R5O1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX21ha2VSZXF1ZXN0KG9wdGlvbnMpO1xuICAgICAgb3B0aW9ucy5jYWxsYmFjayhudWxsLCByZXNwb25zZSk7XG4gICAgICBib2R5ID0gKHJlc3BvbnNlICYmIHJlc3BvbnNlLmRhdGEpIHx8IHVuZGVmaW5lZDtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIHJldHJ5Q291bnRlciA9IGF3YWl0IHRoaXMuX2hhbmRsZUVycm9yKGVyciwgcmV0cnlDb3VudGVyLCBlbmRUaW1lKTtcbiAgICAgIHJldHVybiB0aGlzLnJlcXVlc3RXaXRoRmFpbG92ZXIob3B0aW9ucywgcmV0cnlDb3VudGVyLCBlbmRUaW1lKTtcbiAgICB9XG4gICAgaWYgKHJldHJ5QWZ0ZXJTZWNvbmRzKSB7XG4gICAgICBhd2FpdCB0aGlzLl9oYW5kbGVSZXRyeShlbmRUaW1lLCByZXRyeUFmdGVyU2Vjb25kcyAqIDEwMDApO1xuICAgICAgYm9keSA9IGF3YWl0IHRoaXMucmVxdWVzdFdpdGhGYWlsb3ZlcihvcHRpb25zLCByZXRyeUNvdW50ZXIsIGVuZFRpbWUpO1xuICAgIH1cbiAgICByZXR1cm4gYm9keTtcbiAgfVxuXG4gIF9tYWtlUmVxdWVzdChvcHRpb25zKSB7XG4gICAgcmV0dXJuIGF4aW9zKHtcbiAgICAgIHRyYW5zaXRpb25hbDoge1xuICAgICAgICBjbGFyaWZ5VGltZW91dEVycm9yOiB0cnVlLFxuICAgICAgfSxcbiAgICAgIC4uLm9wdGlvbnNcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIF93YWl0KHBhdXNlKSB7XG4gICAgYXdhaXQgbmV3IFByb21pc2UocmVzID0+IHNldFRpbWVvdXQocmVzLCBwYXVzZSkpO1xuICB9XG5cbiAgYXN5bmMgX2hhbmRsZVJldHJ5KGVuZFRpbWUsIHJldHJ5QWZ0ZXIpIHtcbiAgICBpZihlbmRUaW1lID4gRGF0ZS5ub3coKSArIHJldHJ5QWZ0ZXIpIHtcbiAgICAgIGF3YWl0IHRoaXMuX3dhaXQocmV0cnlBZnRlcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBUaW1lb3V0RXJyb3IoJ1RpbWVkIG91dCB3YWl0aW5nIGZvciB0aGUgcmVzcG9uc2UnKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBfaGFuZGxlRXJyb3IoZXJyLCByZXRyeUNvdW50ZXIsIGVuZFRpbWUpIHtcbiAgICBjb25zdCBlcnJvciA9IHRoaXMuX2NvbnZlcnRFcnJvcihlcnIpO1xuICAgIGlmKFsnQ29uZmxpY3RFcnJvcicsICdJbnRlcm5hbEVycm9yJywgJ0FwaUVycm9yJywgJ1RpbWVvdXRFcnJvciddLmluY2x1ZGVzKGVycm9yLm5hbWUpXG4gICAgICAmJiByZXRyeUNvdW50ZXIgPCB0aGlzLl9yZXRyaWVzKSB7XG4gICAgICBjb25zdCBwYXVzZSA9IE1hdGgubWluKE1hdGgucG93KDIsIHJldHJ5Q291bnRlcikgKiB0aGlzLl9taW5SZXRyeURlbGF5LCB0aGlzLl9tYXhSZXRyeURlbGF5KTtcbiAgICAgIGF3YWl0IHRoaXMuX3dhaXQocGF1c2UpO1xuICAgICAgcmV0dXJuIHJldHJ5Q291bnRlciArIDE7XG4gICAgfSBlbHNlIGlmKGVycm9yLm5hbWUgPT09ICdUb29NYW55UmVxdWVzdHNFcnJvcicpIHtcbiAgICAgIGNvbnN0IHJldHJ5VGltZSA9IERhdGUucGFyc2UoZXJyb3IubWV0YWRhdGEucmVjb21tZW5kZWRSZXRyeVRpbWUpO1xuICAgICAgaWYgKHJldHJ5VGltZSA8IGVuZFRpbWUpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5fd2FpdChyZXRyeVRpbWUgLSBEYXRlLm5vdygpKTtcbiAgICAgICAgcmV0dXJuIHJldHJ5Q291bnRlcjtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGxleGl0eVxuICBfY29udmVydEVycm9yKGVycikge1xuICAgIGNvbnN0IGVycm9yUmVzcG9uc2UgPSBlcnIucmVzcG9uc2UgfHwge307XG4gICAgY29uc3QgZXJyb3JEYXRhID0gZXJyb3JSZXNwb25zZS5kYXRhIHx8IHt9O1xuICAgIGNvbnN0IHN0YXR1cyA9IGVycm9yUmVzcG9uc2Uuc3RhdHVzIHx8IGVyci5zdGF0dXM7XG4gICAgY29uc3QgdXJsID0gZXJyPy5jb25maWc/LnVybDtcblxuICAgIGNvbnN0IGVyck1zZyA9IGVycm9yRGF0YS5tZXNzYWdlIHx8IGVyci5tZXNzYWdlO1xuICAgIGNvbnN0IGVyck1zZ0RlZmF1bHQgPSBlcnJvckRhdGEubWVzc2FnZSB8fCBlcnIuY29kZSB8fCBlcnIubWVzc2FnZTtcblxuICAgIHN3aXRjaCAoc3RhdHVzKSB7XG4gICAgY2FzZSA0MDA6XG4gICAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25FcnJvcihlcnJNc2csIGVycm9yRGF0YS5kZXRhaWxzIHx8IGVyci5kZXRhaWxzLCB1cmwpO1xuICAgIGNhc2UgNDAxOlxuICAgICAgcmV0dXJuIG5ldyBVbmF1dGhvcml6ZWRFcnJvcihlcnJNc2csIHVybCk7XG4gICAgY2FzZSA0MDM6XG4gICAgICByZXR1cm4gbmV3IEZvcmJpZGRlbkVycm9yKGVyck1zZywgdXJsKTtcbiAgICBjYXNlIDQwNDpcbiAgICAgIHJldHVybiBuZXcgTm90Rm91bmRFcnJvcihlcnJNc2csIHVybCk7XG4gICAgY2FzZSA0MDk6XG4gICAgICByZXR1cm4gbmV3IE5vdEZvdW5kRXJyb3IoZXJyTXNnLCB1cmwpO1xuICAgIGNhc2UgNDI5OlxuICAgICAgcmV0dXJuIG5ldyBUb29NYW55UmVxdWVzdHNFcnJvcihlcnJNc2csIGVycm9yRGF0YS5tZXRhZGF0YSB8fCBlcnIubWV0YWRhdGEsIHVybCk7XG4gICAgY2FzZSA1MDA6XG4gICAgICByZXR1cm4gbmV3IEludGVybmFsRXJyb3IoZXJyTXNnLCB1cmwpO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gbmV3IEFwaUVycm9yKEFwaUVycm9yLCBlcnJNc2dEZWZhdWx0LCBzdGF0dXMsIHVybCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogSFRUUCBjbGllbnQgc2VydmljZSBtb2NrIGZvciB0ZXN0c1xuICovXG5leHBvcnQgY2xhc3MgSHR0cENsaWVudE1vY2sgZXh0ZW5kcyBIdHRwQ2xpZW50IHtcblxuICAvKipcbiAgICogQ29uc3RydWN0cyBIVFRQIGNsaWVudCBtb2NrXG4gICAqIEBwYXJhbSB7RnVuY3Rpb24ob3B0aW9uczpPYmplY3QpOlByb21pc2V9IHJlcXVlc3RGbiBtb2NrZWQgcmVxdWVzdCBmdW5jdGlvblxuICAgKiBAcGFyYW0ge051bWJlcn0gdGltZW91dCByZXF1ZXN0IHRpbWVvdXQgaW4gc2Vjb25kc1xuICAgKiBAcGFyYW0ge1JldHJ5T3B0aW9uc30gcmV0cnlPcHRzIHJldHJ5IG9wdGlvbnNcbiAgICovXG4gIGNvbnN0cnVjdG9yKHJlcXVlc3RGbiwgdGltZW91dCwgZXh0ZW5kZWRUaW1lb3V0LCByZXRyeU9wdHMpIHtcbiAgICBzdXBlcih0aW1lb3V0LCBleHRlbmRlZFRpbWVvdXQsIHJldHJ5T3B0cyk7XG4gICAgdGhpcy5fcmVxdWVzdEZuID0gcmVxdWVzdEZuO1xuICB9XG5cbiAgX21ha2VSZXF1ZXN0KCkge1xuICAgIHJldHVybiB0aGlzLl9yZXF1ZXN0Rm4uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgfVxuXG59XG4iXSwibmFtZXMiOlsiYXhpb3MiLCJVbmF1dGhvcml6ZWRFcnJvciIsIkZvcmJpZGRlbkVycm9yIiwiQXBpRXJyb3IiLCJWYWxpZGF0aW9uRXJyb3IiLCJJbnRlcm5hbEVycm9yIiwiTm90Rm91bmRFcnJvciIsIlRvb01hbnlSZXF1ZXN0c0Vycm9yIiwiVGltZW91dEVycm9yIiwiSHR0cENsaWVudCIsInJlcXVlc3QiLCJvcHRpb25zIiwiaXNFeHRlbmRlZFRpbWVvdXQiLCJlbmRUaW1lIiwiRGF0ZSIsIm5vdyIsIl9tYXhSZXRyeURlbGF5IiwiX3JldHJpZXMiLCJ0aW1lb3V0IiwiX2V4dGVuZGVkVGltZW91dCIsIl90aW1lb3V0IiwicmVzcG9uc2UiLCJfbWFrZVJlcXVlc3QiLCJkYXRhIiwidW5kZWZpbmVkIiwiZXJyIiwiZXJyb3IiLCJfY29udmVydEVycm9yIiwibmFtZSIsInJldHJ5VGltZSIsInBhcnNlIiwibWV0YWRhdGEiLCJyZWNvbW1lbmRlZFJldHJ5VGltZSIsImRhdGUiLCJfd2FpdCIsInJlcXVlc3RXaXRoRmFpbG92ZXIiLCJyZXRyeUNvdW50ZXIiLCJyZXRyeUFmdGVyU2Vjb25kcyIsImNhbGxiYWNrIiwiZSIsInJlcyIsInN0YXR1cyIsImhlYWRlcnMiLCJib2R5IiwiX2hhbmRsZUVycm9yIiwiX2hhbmRsZVJldHJ5IiwidHJhbnNpdGlvbmFsIiwiY2xhcmlmeVRpbWVvdXRFcnJvciIsInBhdXNlIiwiUHJvbWlzZSIsInNldFRpbWVvdXQiLCJyZXRyeUFmdGVyIiwiaW5jbHVkZXMiLCJNYXRoIiwibWluIiwicG93IiwiX21pblJldHJ5RGVsYXkiLCJlcnJvclJlc3BvbnNlIiwiZXJyb3JEYXRhIiwidXJsIiwiY29uZmlnIiwiZXJyTXNnIiwibWVzc2FnZSIsImVyck1zZ0RlZmF1bHQiLCJjb2RlIiwiZGV0YWlscyIsImNvbnN0cnVjdG9yIiwiZXh0ZW5kZWRUaW1lb3V0IiwicmV0cnlPcHRzIiwicmV0cmllcyIsIm1pbkRlbGF5SW5TZWNvbmRzIiwibWF4RGVsYXlJblNlY29uZHMiLCJIdHRwQ2xpZW50TW9jayIsIl9yZXF1ZXN0Rm4iLCJhcHBseSIsImFyZ3VtZW50cyIsInJlcXVlc3RGbiJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFQSxPQUFPQSxXQUFXLFFBQVE7QUFDMUIsU0FDRUMsaUJBQWlCLEVBQUVDLGNBQWMsRUFBRUMsUUFBUSxFQUFFQyxlQUFlLEVBQUVDLGFBQWEsRUFDM0VDLGFBQWEsRUFBRUMsb0JBQW9CLFFBQzlCLGlCQUFpQjtBQUN4QixPQUFPQyxrQkFBa0IsaUJBQWlCO0FBSzNCLElBQUEsQUFBTUMsYUFBTixNQUFNQTtJQXVCbkI7Ozs7O0dBS0MsR0FDRCxBQUFNQyxRQUFRQyxPQUFPLEVBQUVDLGlCQUFpQixFQUFFQyxVQUFVQyxLQUFLQyxHQUFHLEtBQUssSUFBSSxDQUFDQyxjQUFjLEdBQUcsSUFBSSxDQUFDQyxRQUFROztlQUFwRyxvQkFBQSxZQUFzRztZQUNwR04sUUFBUU8sT0FBTyxHQUFHTixvQkFBb0IsTUFBS08sZ0JBQWdCLEdBQUcsTUFBS0MsUUFBUTtZQUMzRSxJQUFJO2dCQUNGLE1BQU1DLFdBQVcsTUFBTSxNQUFLQyxZQUFZLENBQUNYO2dCQUN6QyxPQUFPLEFBQUNVLFlBQVlBLFNBQVNFLElBQUksSUFBS0M7WUFDeEMsRUFBRSxPQUFPQyxLQUFLO2dCQUNaLE1BQU1DLFFBQVEsTUFBS0MsYUFBYSxDQUFDRjtnQkFDakMsSUFBR0MsTUFBTUUsSUFBSSxLQUFLLHdCQUF3QjtvQkFDeEMsTUFBTUMsWUFBWWYsS0FBS2dCLEtBQUssQ0FBQ0osTUFBTUssUUFBUSxDQUFDQyxvQkFBb0I7b0JBQ2hFLE1BQU1DLE9BQU9uQixLQUFLQyxHQUFHO29CQUNyQixJQUFJYyxZQUFZaEIsU0FBUzt3QkFDdkIsSUFBR2dCLFlBQVlJLE1BQU07NEJBQ25CLE1BQU0sTUFBS0MsS0FBSyxDQUFDTCxZQUFZSTt3QkFDL0IsQ0FBQzt3QkFDRCxPQUFPLE1BQU0sTUFBS3ZCLE9BQU8sQ0FBQ0MsU0FBU0MsbUJBQW1CQztvQkFDeEQsT0FBTzt3QkFDTCxNQUFNYSxNQUFNO29CQUNkLENBQUM7Z0JBQ0gsT0FBTztvQkFDTCxNQUFNQSxNQUFNO2dCQUNkLENBQUM7WUFDSDtRQUNGOztJQUVBOzs7O0dBSUMsR0FDRCxBQUFNUyxvQkFBb0J4QixPQUFPLEVBQUV5QixlQUFlLENBQUMsRUFBRXZCLFVBQVVDLEtBQUtDLEdBQUcsS0FBSyxJQUFJLENBQUNDLGNBQWMsR0FBRyxJQUFJLENBQUNDLFFBQVE7O2VBQS9HLG9CQUFBLFlBQWlIO1lBQy9HTixRQUFRTyxPQUFPLEdBQUcsTUFBS0UsUUFBUTtZQUMvQixJQUFJaUIsb0JBQW9CO1lBQ3hCMUIsUUFBUTJCLFFBQVEsR0FBRyxDQUFDQyxHQUFHQyxNQUFRO2dCQUM3QixJQUFJQSxPQUFPQSxJQUFJQyxNQUFNLEtBQUssS0FBSztvQkFDN0JKLG9CQUFvQkcsSUFBSUUsT0FBTyxDQUFDLGNBQWM7Z0JBQ2hELENBQUM7WUFDSDtZQUNBLElBQUlDO1lBQ0osSUFBSTtnQkFDRixNQUFNdEIsV0FBVyxNQUFNLE1BQUtDLFlBQVksQ0FBQ1g7Z0JBQ3pDQSxRQUFRMkIsUUFBUSxDQUFDLElBQUksRUFBRWpCO2dCQUN2QnNCLE9BQU8sQUFBQ3RCLFlBQVlBLFNBQVNFLElBQUksSUFBS0M7WUFDeEMsRUFBRSxPQUFPQyxLQUFLO2dCQUNaVyxlQUFlLE1BQU0sTUFBS1EsWUFBWSxDQUFDbkIsS0FBS1csY0FBY3ZCO2dCQUMxRCxPQUFPLE1BQUtzQixtQkFBbUIsQ0FBQ3hCLFNBQVN5QixjQUFjdkI7WUFDekQ7WUFDQSxJQUFJd0IsbUJBQW1CO2dCQUNyQixNQUFNLE1BQUtRLFlBQVksQ0FBQ2hDLFNBQVN3QixvQkFBb0I7Z0JBQ3JETSxPQUFPLE1BQU0sTUFBS1IsbUJBQW1CLENBQUN4QixTQUFTeUIsY0FBY3ZCO1lBQy9ELENBQUM7WUFDRCxPQUFPOEI7UUFDVDs7SUFFQXJCLGFBQWFYLE9BQU8sRUFBRTtRQUNwQixPQUFPWCxNQUFNO1lBQ1g4QyxjQUFjO2dCQUNaQyxxQkFBcUIsSUFBSTtZQUMzQjtXQUNHcEM7SUFFUDtJQUVNdUIsTUFBTWMsS0FBSztlQUFqQixvQkFBQSxZQUFtQjtZQUNqQixNQUFNLElBQUlDLFFBQVFULENBQUFBLE1BQU9VLFdBQVdWLEtBQUtRO1FBQzNDOztJQUVNSCxhQUFhaEMsT0FBTyxFQUFFc0MsVUFBVTs7ZUFBdEMsb0JBQUEsWUFBd0M7WUFDdEMsSUFBR3RDLFVBQVVDLEtBQUtDLEdBQUcsS0FBS29DLFlBQVk7Z0JBQ3BDLE1BQU0sTUFBS2pCLEtBQUssQ0FBQ2lCO1lBQ25CLE9BQU87Z0JBQ0wsTUFBTSxJQUFJM0MsYUFBYSxzQ0FBc0M7WUFDL0QsQ0FBQztRQUNIOztJQUVNb0MsYUFBYW5CLEdBQUcsRUFBRVcsWUFBWSxFQUFFdkIsT0FBTzs7ZUFBN0Msb0JBQUEsWUFBK0M7WUFDN0MsTUFBTWEsUUFBUSxNQUFLQyxhQUFhLENBQUNGO1lBQ2pDLElBQUc7Z0JBQUM7Z0JBQWlCO2dCQUFpQjtnQkFBWTthQUFlLENBQUMyQixRQUFRLENBQUMxQixNQUFNRSxJQUFJLEtBQ2hGUSxlQUFlLE1BQUtuQixRQUFRLEVBQUU7Z0JBQ2pDLE1BQU0rQixRQUFRSyxLQUFLQyxHQUFHLENBQUNELEtBQUtFLEdBQUcsQ0FBQyxHQUFHbkIsZ0JBQWdCLE1BQUtvQixjQUFjLEVBQUUsTUFBS3hDLGNBQWM7Z0JBQzNGLE1BQU0sTUFBS2tCLEtBQUssQ0FBQ2M7Z0JBQ2pCLE9BQU9aLGVBQWU7WUFDeEIsT0FBTyxJQUFHVixNQUFNRSxJQUFJLEtBQUssd0JBQXdCO2dCQUMvQyxNQUFNQyxZQUFZZixLQUFLZ0IsS0FBSyxDQUFDSixNQUFNSyxRQUFRLENBQUNDLG9CQUFvQjtnQkFDaEUsSUFBSUgsWUFBWWhCLFNBQVM7b0JBQ3ZCLE1BQU0sTUFBS3FCLEtBQUssQ0FBQ0wsWUFBWWYsS0FBS0MsR0FBRztvQkFDckMsT0FBT3FCO2dCQUNULENBQUM7WUFDSCxDQUFDO1lBQ0QsTUFBTVYsTUFBTTtRQUNkOztJQUVBLHNDQUFzQztJQUN0Q0MsY0FBY0YsR0FBRyxFQUFFO1lBSUxBO1FBSFosTUFBTWdDLGdCQUFnQmhDLElBQUlKLFFBQVEsSUFBSSxDQUFDO1FBQ3ZDLE1BQU1xQyxZQUFZRCxjQUFjbEMsSUFBSSxJQUFJLENBQUM7UUFDekMsTUFBTWtCLFNBQVNnQixjQUFjaEIsTUFBTSxJQUFJaEIsSUFBSWdCLE1BQU07UUFDakQsTUFBTWtCLE1BQU1sQyxnQkFBQUEsaUJBQUFBLEtBQUFBLElBQUFBLENBQUFBLGNBQUFBLElBQUttQyxNQUFNLGNBQVhuQyx5QkFBQUEsS0FBQUEsSUFBQUEsWUFBYWtDLEdBQUY7UUFFdkIsTUFBTUUsU0FBU0gsVUFBVUksT0FBTyxJQUFJckMsSUFBSXFDLE9BQU87UUFDL0MsTUFBTUMsZ0JBQWdCTCxVQUFVSSxPQUFPLElBQUlyQyxJQUFJdUMsSUFBSSxJQUFJdkMsSUFBSXFDLE9BQU87UUFFbEUsT0FBUXJCO1lBQ1IsS0FBSztnQkFDSCxPQUFPLElBQUlyQyxnQkFBZ0J5RCxRQUFRSCxVQUFVTyxPQUFPLElBQUl4QyxJQUFJd0MsT0FBTyxFQUFFTjtZQUN2RSxLQUFLO2dCQUNILE9BQU8sSUFBSTFELGtCQUFrQjRELFFBQVFGO1lBQ3ZDLEtBQUs7Z0JBQ0gsT0FBTyxJQUFJekQsZUFBZTJELFFBQVFGO1lBQ3BDLEtBQUs7Z0JBQ0gsT0FBTyxJQUFJckQsY0FBY3VELFFBQVFGO1lBQ25DLEtBQUs7Z0JBQ0gsT0FBTyxJQUFJckQsY0FBY3VELFFBQVFGO1lBQ25DLEtBQUs7Z0JBQ0gsT0FBTyxJQUFJcEQscUJBQXFCc0QsUUFBUUgsVUFBVTNCLFFBQVEsSUFBSU4sSUFBSU0sUUFBUSxFQUFFNEI7WUFDOUUsS0FBSztnQkFDSCxPQUFPLElBQUl0RCxjQUFjd0QsUUFBUUY7WUFDbkM7Z0JBQ0UsT0FBTyxJQUFJeEQsU0FBU0EsVUFBVTRELGVBQWV0QixRQUFRa0I7UUFDdkQ7SUFDRjtJQWxKQTs7Ozs7R0FLQyxHQUVEOzs7OztHQUtDLEdBQ0RPLFlBQVloRCxVQUFVLEVBQUUsRUFBRWlELGtCQUFrQixFQUFFLEVBQUVDLFlBQVksQ0FBQyxDQUFDLENBQUU7UUFDOUQsSUFBSSxDQUFDaEQsUUFBUSxHQUFHRixVQUFVO1FBQzFCLElBQUksQ0FBQ0MsZ0JBQWdCLEdBQUdnRCxrQkFBa0I7UUFDMUMsSUFBSSxDQUFDbEQsUUFBUSxHQUFHbUQsVUFBVUMsT0FBTyxJQUFJO1FBQ3JDLElBQUksQ0FBQ2IsY0FBYyxHQUFHLEFBQUNZLENBQUFBLFVBQVVFLGlCQUFpQixJQUFJLENBQUEsSUFBSztRQUMzRCxJQUFJLENBQUN0RCxjQUFjLEdBQUcsQUFBQ29ELENBQUFBLFVBQVVHLGlCQUFpQixJQUFJLEVBQUMsSUFBSztJQUM5RDtBQWdJRjtBQXhKQTs7Q0FFQyxHQUNELFNBQXFCOUQsd0JBcUpwQjtBQUVEOztDQUVDLEdBQ0QsT0FBTyxNQUFNK0QsdUJBQXVCL0Q7SUFhbENhLGVBQWU7UUFDYixPQUFPLElBQUksQ0FBQ21ELFVBQVUsQ0FBQ0MsS0FBSyxDQUFDLElBQUksRUFBRUM7SUFDckM7SUFiQTs7Ozs7R0FLQyxHQUNEVCxZQUFZVSxTQUFTLEVBQUUxRCxPQUFPLEVBQUVpRCxlQUFlLEVBQUVDLFNBQVMsQ0FBRTtRQUMxRCxLQUFLLENBQUNsRCxTQUFTaUQsaUJBQWlCQztRQUNoQyxJQUFJLENBQUNLLFVBQVUsR0FBR0c7SUFDcEI7QUFNRixDQUFDIn0=