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)
577 lines (576 loc) • 62.5 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;
}
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;
}
function ownKeys(object, enumerableOnly) {
var keys = Object.keys(object);
if (Object.getOwnPropertySymbols) {
var symbols = Object.getOwnPropertySymbols(object);
if (enumerableOnly) {
symbols = symbols.filter(function(sym) {
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
});
}
keys.push.apply(keys, symbols);
}
return keys;
}
function _object_spread_props(target, source) {
source = source != null ? source : {};
if (Object.getOwnPropertyDescriptors) {
Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
} else {
ownKeys(Object(source)).forEach(function(key) {
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
});
}
return target;
}
import MetaApiClient from '../metaapi.client';
import randomstring from 'randomstring';
export * from './configuration.client.schemas';
let ConfigurationClient = class ConfigurationClient extends MetaApiClient {
/**
* Strategy id
* @typedef {Object} StrategyId
* @property {String} id strategy id
*/ /**
* Retrieves new unused strategy id. Method is accessible only with API access token. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/generateStrategyId/
* @return {Promise<StrategyId>} promise resolving with strategy id generated
*/ generateStrategyId() {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('generateStrategyId');
}
const opts = {
url: '/users/current/configuration/unused-strategy-id',
method: 'GET',
headers: {
'auth-token': this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Generates random account id
* @return {String} account id
*/ generateAccountId() {
return randomstring.generate(64);
}
/**
* Retrieves CopyFactory copy trading strategies with pagination in infinite scroll style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getStrategies/
* @param {GetStrategiesOptions} [options] options
* @return {Promise<Array<CopyFactoryStrategy>>} promise resolving with CopyFactory strategies found
*/ getStrategiesWithInfiniteScrollPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getStrategies('1', options);
})();
}
/**
* Retrieves CopyFactory copy trading strategies with pagination in classic style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getStrategies/
* @param {GetStrategiesOptions} [options] options
* @return {Promise<ClassicPaginationList<CopyFactoryStrategy>>} promise resolving with CopyFactory strategies found
*/ getStrategiesWithClassicPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getStrategies('2', options);
})();
}
_getStrategies(apiVersion, options) {
var _this = this;
return _async_to_generator(function*() {
if (_this._isNotJwtToken()) {
return _this._handleNoAccessError('getStrategies');
}
return _this._domainClient.requestCopyFactory({
url: '/users/current/configuration/strategies',
method: 'GET',
params: options,
headers: {
'auth-token': _this._token,
'api-version': apiVersion
},
json: true
}, true);
})();
}
/**
* Retrieves CopyFactory copy trading strategy by id. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getStrategy/
* @param {string} strategyId trading strategy id
* @return {Promise<CopyFactoryStrategy>} promise resolving with CopyFactory strategy found
*/ getStrategy(strategyId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('getStrategy');
}
const opts = {
url: `/users/current/configuration/strategies/${strategyId}`,
method: 'GET',
headers: {
'auth-token': this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Updates a CopyFactory strategy or creates it if it does not exist. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/updateStrategy/
* @param {String} strategyId copy trading strategy id
* @param {CopyFactoryStrategyUpdate} strategy trading strategy update
* @return {Promise} promise resolving when strategy is updated
*/ updateStrategy(strategyId, strategy) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('updateStrategy');
}
const opts = {
url: `/users/current/configuration/strategies/${strategyId}`,
method: 'PUT',
headers: {
'auth-token': this._token
},
data: strategy,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Deletes a CopyFactory strategy. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/removeStrategy/
* @param {String} strategyId copy trading strategy id
* @param {CopyFactoryCloseInstructions} [closeInstructions] strategy close instructions
* @return {Promise} promise resolving when strategy is removed
*/ removeStrategy(strategyId, closeInstructions) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('removeStrategy');
}
const opts = {
url: `/users/current/configuration/strategies/${strategyId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
data: closeInstructions,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Retrieves CopyFactory copy portfolio strategies with pagination in infinite scroll style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getPortfolioStrategies/
* @param {GetPortfolioStrategiesOptions} [options] options
* @return {Promise<Array<CopyFactoryPortfolioStrategy>>} promise resolving with CopyFactory portfolio strategies
*/ getPortfolioStrategiesWithInfiniteScrollPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getPortfolioStrategies('1', options);
})();
}
/**
* Retrieves CopyFactory copy portfolio strategies with pagination in classic style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getPortfolioStrategies/
* @param {GetPortfolioStrategiesOptions} [options] options
* @return {Promise<ClassicPaginationList<CopyFactoryStrategy>>} promise resolving with CopyFactory strategies found
*/ getPortfolioStrategiesWithClassicPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getPortfolioStrategies('2', options);
})();
}
_getPortfolioStrategies(apiVersion, options) {
var _this = this;
return _async_to_generator(function*() {
if (_this._isNotJwtToken()) {
return _this._handleNoAccessError('getPortfolioStrategies');
}
return _this._domainClient.requestCopyFactory({
url: '/users/current/configuration/portfolio-strategies',
method: 'GET',
params: options,
headers: {
'auth-token': _this._token,
'api-version': apiVersion
},
json: true
}, true);
})();
}
/**
* Retrieves CopyFactory copy portfolio strategy by id. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getPortfolioStrategy/
* @param {string} portfolioId portfolio strategy id
* @return {Promise<CopyFactoryPortfolioStrategy>} promise resolving with CopyFactory portfolio strategy found
*/ getPortfolioStrategy(portfolioId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('getPortfolioStrategy');
}
const opts = {
url: `/users/current/configuration/portfolio-strategies/${portfolioId}`,
method: 'GET',
headers: {
'auth-token': this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Updates a CopyFactory portfolio strategy or creates it if it does not exist. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/updatePortfolioStrategy/
* @param {String} portfolioId copy trading portfolio strategy id
* @param {CopyFactoryPortfolioStrategyUpdate} portfolio portfolio strategy update
* @return {Promise} promise resolving when portfolio strategy is updated
*/ updatePortfolioStrategy(portfolioId, portfolio) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('updatePortfolioStrategy');
}
const opts = {
url: `/users/current/configuration/portfolio-strategies/${portfolioId}`,
method: 'PUT',
headers: {
'auth-token': this._token
},
data: portfolio,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Deletes a CopyFactory portfolio strategy. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/removePortfolioStrategy/
* @param {String} portfolioId portfolio strategy id
* @param {CopyFactoryCloseInstructions} [closeInstructions] strategy close instructions
* @return {Promise} promise resolving when portfolio strategy is removed
*/ removePortfolioStrategy(portfolioId, closeInstructions) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('removePortfolioStrategy');
}
const opts = {
url: `/users/current/configuration/portfolio-strategies/${portfolioId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
data: closeInstructions,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Deletes a CopyFactory portfolio strategy member. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/removePortfolioStrategyMember/
* @param {String} portfolioId portfolio strategy id
* @param {String} strategyId id of the strategy to delete member for
* @param {CopyFactoryCloseInstructions} [closeInstructions] strategy close instructions
* @return {Promise} promise resolving when portfolio strategy is removed
*/ removePortfolioStrategyMember(portfolioId, strategyId, closeInstructions) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('removePortfolioStrategyMember');
}
const opts = {
url: `/users/current/configuration/portfolio-strategies/${portfolioId}/members/${strategyId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
data: closeInstructions,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Returns CopyFactory subscribers the user has configured with pagination in infinite scroll style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/history/getSubscribers/
* @param {GetSubscribersOptions} [options] options
* @return {Promise<Array<CopyFactorySubscriber>>} promise resolving with subscribers found
*/ getSubscribersWithInfiniteScrollPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getSubscribers('1', options);
})();
}
/**
* Returns CopyFactory subscribers the user has configured with pagination in classic style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/history/getSubscribers/
* @param {GetSubscribersOptions} [options] options
* @return {Promise<ClassicPaginationList<CopyFactorySubscriber>>} promise resolving with subscribers found
*/ getSubscribersWithClassicPagination(options) {
var _this = this;
return _async_to_generator(function*() {
return _this._getSubscribers('2', options);
})();
}
_getSubscribers(apiVersion, options) {
var _this = this;
return _async_to_generator(function*() {
if (_this._isNotJwtToken()) {
return _this._handleNoAccessError('getSubscribers');
}
return _this._domainClient.requestCopyFactory({
url: '/users/current/configuration/subscribers',
method: 'GET',
params: options,
headers: {
'auth-token': _this._token,
'api-version': apiVersion
},
json: true
}, true);
})();
}
/**
* Returns CopyFactory subscriber by id. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getSubscriber/
* @param {String} subscriberId subscriber id
* @returns {Promise<CopyFactorySubscriber>} promise resolving with subscriber found
*/ getSubscriber(subscriberId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('getSubscriber');
}
const opts = {
url: `/users/current/configuration/subscribers/${subscriberId}`,
method: 'GET',
headers: {
'auth-token': this._token
},
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Updates CopyFactory subscriber configuration or creates it if it does not exist. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/updateSubscriber/
* @param {String} subscriberId subscriber id
* @param {CopyFactorySubscriberUpdate} subscriber subscriber update
* @returns {Promise} promise resolving when subscriber is updated
*/ updateSubscriber(subscriberId, subscriber) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('updateSubscriber');
}
const opts = {
url: `/users/current/configuration/subscribers/${subscriberId}`,
method: 'PUT',
headers: {
'auth-token': this._token
},
data: subscriber,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Deletes subscriber configuration. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/removeSubscriber/
* @param {String} subscriberId subscriber id
* @param {CopyFactoryCloseInstructions} [closeInstructions] subscriber close instructions
* @returns {Promise} promise resolving when subscriber is removed
*/ removeSubscriber(subscriberId, closeInstructions) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('removeSubscriber');
}
const opts = {
url: `/users/current/configuration/subscribers/${subscriberId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
data: closeInstructions,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Deletes a subscription of subscriber to a strategy. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/removeSubscription/
* @param {String} subscriberId subscriber id
* @param {String} strategyId strategy id
* @param {CopyFactoryCloseInstructions} [closeInstructions] subscriber close instructions
* @returns {Promise} promise resolving when subscriber is removed
*/ removeSubscription(subscriberId, strategyId, closeInstructions) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('removeSubscription');
}
const opts = {
url: `/users/current/configuration/subscribers/${subscriberId}/subscriptions/${strategyId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
data: closeInstructions,
json: true
};
return this._domainClient.requestCopyFactory(opts);
}
/**
* Retrieves CopyFactory user webhooks list with pagination in infinite scroll style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getWebhooks/
* @param strategyId strategy ID
* @param options additional options
* @return promise resolving with webhooks found
*/ getWebhooksWithInfiniteScrollPagination(strategyId, options) {
var _this = this;
return _async_to_generator(function*() {
let result = yield _this._getWebhooks(strategyId, 'infiniteScroll', options);
result.forEach((item)=>item.createdAt = new Date(item.createdAt));
return result;
})();
}
/**
* Retrieves CopyFactory user webhooks list with pagination in classic style. See
* https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/getWebhooks/
* @param strategyId strategy ID
* @param options additional options
* @return promise resolving with webhooks found
*/ getWebhooksWithClassicPagination(strategyId, options) {
var _this = this;
return _async_to_generator(function*() {
let result = yield _this._getWebhooks(strategyId, 'classic', options);
result.items.forEach((item)=>item.createdAt = new Date(item.createdAt));
return result;
})();
}
_getWebhooks(strategyId, paginationStyle, options) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('getWebhooks');
}
return this._domainClient.requestCopyFactory({
url: `/users/current/configuration/strategies/${strategyId}/webhooks`,
method: 'GET',
params: _object_spread_props(_object_spread({}, options), {
paginationStyle
}),
headers: {
'auth-token': this._token
},
json: true
}, true);
}
/**
* Creates a new webhook. The webhook can be used for an external app (e.g. TradingView) to submit trading signals to
* CopyFactory. See https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/createWebhook/
* @param strategyId strategy ID
* @param webhook webhook
* @returns promise resolving with created webhook ID and URL
*/ createWebhook(strategyId, webhook) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('createWebhook');
}
return this._domainClient.requestCopyFactory({
url: `/users/current/configuration/strategies/${strategyId}/webhooks`,
method: 'POST',
headers: {
'auth-token': this._token
},
data: webhook,
json: true
});
}
/**
* Updates a webhook. See https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/updateWebhook/
* @param strategyId webhook strategy ID
* @param webhookId webhook ID
* @param update webhook update
* @returns promise resolving when updated
*/ updateWebhook(strategyId, webhookId, update) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('updateWebhook');
}
return this._domainClient.requestCopyFactory({
url: `/users/current/configuration/strategies/${strategyId}/webhooks/${webhookId}`,
method: 'PATCH',
headers: {
'auth-token': this._token
},
data: update,
json: true
});
}
/**
* Deletes a webhook. See https://metaapi.cloud/docs/copyfactory/restApi/api/configuration/deleteWebhook/
* @param strategyId webhook strategy ID
* @param webhookId webhook ID
* @returns promise resolving when deleted
*/ deleteWebhook(strategyId, webhookId) {
if (this._isNotJwtToken()) {
return this._handleNoAccessError('deleteWebhook');
}
return this._domainClient.requestCopyFactory({
url: `/users/current/configuration/strategies/${strategyId}/webhooks/${webhookId}`,
method: 'DELETE',
headers: {
'auth-token': this._token
},
json: true
});
}
/**
* Constructs CopyFactory configuration API client instance
* @param {DomainClient} domainClient domain client
*/ constructor(domainClient){
super(domainClient);
this._domainClient = domainClient;
}
};
/**
* metaapi.cloud CopyFactory configuration API (trade copying configuration API) client (see
* https://metaapi.cloud/docs/copyfactory/)
*/ export { ConfigurationClient as default };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIjxhbm9uPiJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbmltcG9ydCBEb21haW5DbGllbnQgZnJvbSAnLi4vZG9tYWluLmNsaWVudCc7XG5pbXBvcnQgTWV0YUFwaUNsaWVudCBmcm9tICcuLi9tZXRhYXBpLmNsaWVudCc7XG5pbXBvcnQgcmFuZG9tc3RyaW5nIGZyb20gJ3JhbmRvbXN0cmluZyc7XG5pbXBvcnQge1xuICBDbGFzc2ljUGFnaW5hdGlvbkxpc3QsIENvcHlGYWN0b3J5Q2xvc2VJbnN0cnVjdGlvbnMsIENvcHlGYWN0b3J5UG9ydGZvbGlvU3RyYXRlZ3ksIENvcHlGYWN0b3J5UG9ydGZvbGlvU3RyYXRlZ3lVcGRhdGUsXG4gIENvcHlGYWN0b3J5U3RyYXRlZ3ksIENvcHlGYWN0b3J5U3RyYXRlZ3lVcGRhdGUsIENvcHlGYWN0b3J5U3Vic2NyaWJlciwgQ29weUZhY3RvcnlTdWJzY3JpYmVyVXBkYXRlLCBXZWJob29rLFxuICBHZXRQb3J0Zm9saW9TdHJhdGVnaWVzT3B0aW9ucywgR2V0U3RyYXRlZ2llc09wdGlvbnMsIEdldFN1YnNjcmliZXJzT3B0aW9ucywgR2V0V2ViaG9va3NPcHRpb25zLCBTdHJhdGVneUlkLFxuICBOZXdXZWJob29rLCBXZWJob29rSWRBbmRVcmwsIFdlYmhvb2tVcGRhdGVcbn0gZnJvbSAnLi9jb25maWd1cmF0aW9uLmNsaWVudC5zY2hlbWFzJztcblxuZXhwb3J0ICogZnJvbSAnLi9jb25maWd1cmF0aW9uLmNsaWVudC5zY2hlbWFzJztcblxuLyoqXG4gKiBtZXRhYXBpLmNsb3VkIENvcHlGYWN0b3J5IGNvbmZpZ3VyYXRpb24gQVBJICh0cmFkZSBjb3B5aW5nIGNvbmZpZ3VyYXRpb24gQVBJKSBjbGllbnQgKHNlZVxuICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvKVxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBDb25maWd1cmF0aW9uQ2xpZW50IGV4dGVuZHMgTWV0YUFwaUNsaWVudCB7XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgQ29weUZhY3RvcnkgY29uZmlndXJhdGlvbiBBUEkgY2xpZW50IGluc3RhbmNlXG4gICAqIEBwYXJhbSB7RG9tYWluQ2xpZW50fSBkb21haW5DbGllbnQgZG9tYWluIGNsaWVudFxuICAgKi9cbiAgY29uc3RydWN0b3IoZG9tYWluQ2xpZW50OiBEb21haW5DbGllbnQpIHtcbiAgICBzdXBlcihkb21haW5DbGllbnQpO1xuICAgIHRoaXMuX2RvbWFpbkNsaWVudCA9IGRvbWFpbkNsaWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdHJhdGVneSBpZFxuICAgKiBAdHlwZWRlZiB7T2JqZWN0fSBTdHJhdGVneUlkXG4gICAqIEBwcm9wZXJ0eSB7U3RyaW5nfSBpZCBzdHJhdGVneSBpZFxuICAgKi9cblxuICAvKipcbiAgICogUmV0cmlldmVzIG5ldyB1bnVzZWQgc3RyYXRlZ3kgaWQuIE1ldGhvZCBpcyBhY2Nlc3NpYmxlIG9ubHkgd2l0aCBBUEkgYWNjZXNzIHRva2VuLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9nZW5lcmF0ZVN0cmF0ZWd5SWQvXG4gICAqIEByZXR1cm4ge1Byb21pc2U8U3RyYXRlZ3lJZD59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggc3RyYXRlZ3kgaWQgZ2VuZXJhdGVkXG4gICAqL1xuICBnZW5lcmF0ZVN0cmF0ZWd5SWQoKTogUHJvbWlzZTxTdHJhdGVneUlkPiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2dlbmVyYXRlU3RyYXRlZ3lJZCcpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiAnL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi91bnVzZWQtc3RyYXRlZ3ktaWQnLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdlbmVyYXRlcyByYW5kb20gYWNjb3VudCBpZFxuICAgKiBAcmV0dXJuIHtTdHJpbmd9IGFjY291bnQgaWRcbiAgICovXG4gIGdlbmVyYXRlQWNjb3VudElkKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHJhbmRvbXN0cmluZy5nZW5lcmF0ZSg2NCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIENvcHlGYWN0b3J5IGNvcHkgdHJhZGluZyBzdHJhdGVnaWVzIHdpdGggcGFnaW5hdGlvbiBpbiBpbmZpbml0ZSBzY3JvbGwgc3R5bGUuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL2dldFN0cmF0ZWdpZXMvXG4gICAqIEBwYXJhbSB7R2V0U3RyYXRlZ2llc09wdGlvbnN9IFtvcHRpb25zXSBvcHRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneT4+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIENvcHlGYWN0b3J5IHN0cmF0ZWdpZXMgZm91bmRcbiAgICovXG4gIGFzeW5jIGdldFN0cmF0ZWdpZXNXaXRoSW5maW5pdGVTY3JvbGxQYWdpbmF0aW9uKG9wdGlvbnM/OiBHZXRTdHJhdGVnaWVzT3B0aW9ucyk6IFByb21pc2U8QXJyYXk8Q29weUZhY3RvcnlTdHJhdGVneT4+IHtcbiAgICByZXR1cm4gdGhpcy5fZ2V0U3RyYXRlZ2llcygnMScsIG9wdGlvbnMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBDb3B5RmFjdG9yeSBjb3B5IHRyYWRpbmcgc3RyYXRlZ2llcyB3aXRoIHBhZ2luYXRpb24gaW4gY2xhc3NpYyBzdHlsZS4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vZ2V0U3RyYXRlZ2llcy9cbiAgICogQHBhcmFtIHtHZXRTdHJhdGVnaWVzT3B0aW9uc30gW29wdGlvbnNdIG9wdGlvbnNcbiAgICogQHJldHVybiB7UHJvbWlzZTxDbGFzc2ljUGFnaW5hdGlvbkxpc3Q8Q29weUZhY3RvcnlTdHJhdGVneT4+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIENvcHlGYWN0b3J5IHN0cmF0ZWdpZXMgZm91bmRcbiAgICovXG4gIGFzeW5jIGdldFN0cmF0ZWdpZXNXaXRoQ2xhc3NpY1BhZ2luYXRpb24ob3B0aW9ucz86IEdldFN0cmF0ZWdpZXNPcHRpb25zKTpcbiAgICBQcm9taXNlPENsYXNzaWNQYWdpbmF0aW9uTGlzdDxDb3B5RmFjdG9yeVN0cmF0ZWd5Pj4ge1xuICAgIHJldHVybiB0aGlzLl9nZXRTdHJhdGVnaWVzKCcyJywgb3B0aW9ucyk7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIF9nZXRTdHJhdGVnaWVzKGFwaVZlcnNpb24sIG9wdGlvbnMpIHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0U3RyYXRlZ2llcycpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeSh7XG4gICAgICB1cmw6ICcvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3N0cmF0ZWdpZXMnLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIHBhcmFtczogb3B0aW9ucyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlbixcbiAgICAgICAgJ2FwaS12ZXJzaW9uJzogYXBpVmVyc2lvblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9LCB0cnVlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgQ29weUZhY3RvcnkgY29weSB0cmFkaW5nIHN0cmF0ZWd5IGJ5IGlkLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9nZXRTdHJhdGVneS9cbiAgICogQHBhcmFtIHtzdHJpbmd9IHN0cmF0ZWd5SWQgdHJhZGluZyBzdHJhdGVneSBpZFxuICAgKiBAcmV0dXJuIHtQcm9taXNlPENvcHlGYWN0b3J5U3RyYXRlZ3k+fSBwcm9taXNlIHJlc29sdmluZyB3aXRoIENvcHlGYWN0b3J5IHN0cmF0ZWd5IGZvdW5kXG4gICAqL1xuICBnZXRTdHJhdGVneShzdHJhdGVneUlkOiBzdHJpbmcpOiBQcm9taXNlPENvcHlGYWN0b3J5U3RyYXRlZ3k+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0U3RyYXRlZ3knKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vc3RyYXRlZ2llcy8ke3N0cmF0ZWd5SWR9YCxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGVzIGEgQ29weUZhY3Rvcnkgc3RyYXRlZ3kgb3IgY3JlYXRlcyBpdCBpZiBpdCBkb2VzIG5vdCBleGlzdC4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vdXBkYXRlU3RyYXRlZ3kvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdHJhdGVneUlkIGNvcHkgdHJhZGluZyBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5U3RyYXRlZ3lVcGRhdGV9IHN0cmF0ZWd5IHRyYWRpbmcgc3RyYXRlZ3kgdXBkYXRlXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gc3RyYXRlZ3kgaXMgdXBkYXRlZFxuICAgKi9cbiAgdXBkYXRlU3RyYXRlZ3koc3RyYXRlZ3lJZDogc3RyaW5nLCBzdHJhdGVneTogQ29weUZhY3RvcnlTdHJhdGVneVVwZGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCd1cGRhdGVTdHJhdGVneScpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9zdHJhdGVnaWVzLyR7c3RyYXRlZ3lJZH1gLFxuICAgICAgbWV0aG9kOiAnUFVUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGRhdGE6IHN0cmF0ZWd5LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhIENvcHlGYWN0b3J5IHN0cmF0ZWd5LiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9yZW1vdmVTdHJhdGVneS9cbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0cmF0ZWd5SWQgY29weSB0cmFkaW5nIHN0cmF0ZWd5IGlkXG4gICAqIEBwYXJhbSB7Q29weUZhY3RvcnlDbG9zZUluc3RydWN0aW9uc30gW2Nsb3NlSW5zdHJ1Y3Rpb25zXSBzdHJhdGVneSBjbG9zZSBpbnN0cnVjdGlvbnNcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBzdHJhdGVneSBpcyByZW1vdmVkXG4gICAqL1xuICByZW1vdmVTdHJhdGVneShzdHJhdGVneUlkOiBzdHJpbmcsIGNsb3NlSW5zdHJ1Y3Rpb25zPzogQ29weUZhY3RvcnlDbG9zZUluc3RydWN0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdyZW1vdmVTdHJhdGVneScpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9zdHJhdGVnaWVzLyR7c3RyYXRlZ3lJZH1gLFxuICAgICAgbWV0aG9kOiAnREVMRVRFJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGRhdGE6IGNsb3NlSW5zdHJ1Y3Rpb25zLFxuICAgICAganNvbjogdHJ1ZVxuICAgIH07XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkob3B0cyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIENvcHlGYWN0b3J5IGNvcHkgcG9ydGZvbGlvIHN0cmF0ZWdpZXMgd2l0aCBwYWdpbmF0aW9uIGluIGluZmluaXRlIHNjcm9sbCBzdHlsZS4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vZ2V0UG9ydGZvbGlvU3RyYXRlZ2llcy9cbiAgICogQHBhcmFtIHtHZXRQb3J0Zm9saW9TdHJhdGVnaWVzT3B0aW9uc30gW29wdGlvbnNdIG9wdGlvbnNcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVBvcnRmb2xpb1N0cmF0ZWd5Pj59IHByb21pc2UgcmVzb2x2aW5nIHdpdGggQ29weUZhY3RvcnkgcG9ydGZvbGlvIHN0cmF0ZWdpZXNcbiAgICovXG4gIGFzeW5jIGdldFBvcnRmb2xpb1N0cmF0ZWdpZXNXaXRoSW5maW5pdGVTY3JvbGxQYWdpbmF0aW9uKG9wdGlvbnM/OiBHZXRQb3J0Zm9saW9TdHJhdGVnaWVzT3B0aW9ucyk6XG4gICAgUHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVBvcnRmb2xpb1N0cmF0ZWd5Pj4ge1xuICAgIHJldHVybiB0aGlzLl9nZXRQb3J0Zm9saW9TdHJhdGVnaWVzKCcxJywgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIENvcHlGYWN0b3J5IGNvcHkgcG9ydGZvbGlvIHN0cmF0ZWdpZXMgd2l0aCBwYWdpbmF0aW9uIGluIGNsYXNzaWMgc3R5bGUuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL2dldFBvcnRmb2xpb1N0cmF0ZWdpZXMvXG4gICAqIEBwYXJhbSB7R2V0UG9ydGZvbGlvU3RyYXRlZ2llc09wdGlvbnN9IFtvcHRpb25zXSBvcHRpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2U8Q2xhc3NpY1BhZ2luYXRpb25MaXN0PENvcHlGYWN0b3J5U3RyYXRlZ3k+Pn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBDb3B5RmFjdG9yeSBzdHJhdGVnaWVzIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRQb3J0Zm9saW9TdHJhdGVnaWVzV2l0aENsYXNzaWNQYWdpbmF0aW9uKG9wdGlvbnM/OiBHZXRQb3J0Zm9saW9TdHJhdGVnaWVzT3B0aW9ucyk6XG4gICAgUHJvbWlzZTxDbGFzc2ljUGFnaW5hdGlvbkxpc3Q8Q29weUZhY3RvcnlTdHJhdGVneT4+IHtcbiAgICByZXR1cm4gdGhpcy5fZ2V0UG9ydGZvbGlvU3RyYXRlZ2llcygnMicsIG9wdGlvbnMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfZ2V0UG9ydGZvbGlvU3RyYXRlZ2llcyhhcGlWZXJzaW9uLCBvcHRpb25zKSB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2dldFBvcnRmb2xpb1N0cmF0ZWdpZXMnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkoe1xuICAgICAgdXJsOiAnL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9wb3J0Zm9saW8tc3RyYXRlZ2llcycsXG4gICAgICBtZXRob2Q6ICdHRVQnLFxuICAgICAgcGFyYW1zOiBvcHRpb25zLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuLFxuICAgICAgICAnYXBpLXZlcnNpb24nOiBhcGlWZXJzaW9uXG4gICAgICB9LFxuICAgICAganNvbjogdHJ1ZVxuICAgIH0sIHRydWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBDb3B5RmFjdG9yeSBjb3B5IHBvcnRmb2xpbyBzdHJhdGVneSBieSBpZC4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vZ2V0UG9ydGZvbGlvU3RyYXRlZ3kvXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBwb3J0Zm9saW9JZCBwb3J0Zm9saW8gc3RyYXRlZ3kgaWRcbiAgICogQHJldHVybiB7UHJvbWlzZTxDb3B5RmFjdG9yeVBvcnRmb2xpb1N0cmF0ZWd5Pn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBDb3B5RmFjdG9yeSBwb3J0Zm9saW8gc3RyYXRlZ3kgZm91bmRcbiAgICovXG4gIGdldFBvcnRmb2xpb1N0cmF0ZWd5KHBvcnRmb2xpb0lkOiBzdHJpbmcpOiBQcm9taXNlPENvcHlGYWN0b3J5UG9ydGZvbGlvU3RyYXRlZ3k+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0UG9ydGZvbGlvU3RyYXRlZ3knKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vcG9ydGZvbGlvLXN0cmF0ZWdpZXMvJHtwb3J0Zm9saW9JZH1gLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgYSBDb3B5RmFjdG9yeSBwb3J0Zm9saW8gc3RyYXRlZ3kgb3IgY3JlYXRlcyBpdCBpZiBpdCBkb2VzIG5vdCBleGlzdC4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vdXBkYXRlUG9ydGZvbGlvU3RyYXRlZ3kvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwb3J0Zm9saW9JZCBjb3B5IHRyYWRpbmcgcG9ydGZvbGlvIHN0cmF0ZWd5IGlkXG4gICAqIEBwYXJhbSB7Q29weUZhY3RvcnlQb3J0Zm9saW9TdHJhdGVneVVwZGF0ZX0gcG9ydGZvbGlvIHBvcnRmb2xpbyBzdHJhdGVneSB1cGRhdGVcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBwb3J0Zm9saW8gc3RyYXRlZ3kgaXMgdXBkYXRlZFxuICAgKi9cbiAgdXBkYXRlUG9ydGZvbGlvU3RyYXRlZ3kocG9ydGZvbGlvSWQ6IHN0cmluZywgcG9ydGZvbGlvOiBDb3B5RmFjdG9yeVBvcnRmb2xpb1N0cmF0ZWd5VXBkYXRlKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ3VwZGF0ZVBvcnRmb2xpb1N0cmF0ZWd5Jyk7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3BvcnRmb2xpby1zdHJhdGVnaWVzLyR7cG9ydGZvbGlvSWR9YCxcbiAgICAgIG1ldGhvZDogJ1BVVCcsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBkYXRhOiBwb3J0Zm9saW8sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGEgQ29weUZhY3RvcnkgcG9ydGZvbGlvIHN0cmF0ZWd5LiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9yZW1vdmVQb3J0Zm9saW9TdHJhdGVneS9cbiAgICogQHBhcmFtIHtTdHJpbmd9IHBvcnRmb2xpb0lkIHBvcnRmb2xpbyBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5Q2xvc2VJbnN0cnVjdGlvbnN9IFtjbG9zZUluc3RydWN0aW9uc10gc3RyYXRlZ3kgY2xvc2UgaW5zdHJ1Y3Rpb25zXG4gICAqIEByZXR1cm4ge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gcG9ydGZvbGlvIHN0cmF0ZWd5IGlzIHJlbW92ZWRcbiAgICovXG4gIHJlbW92ZVBvcnRmb2xpb1N0cmF0ZWd5KHBvcnRmb2xpb0lkOiBzdHJpbmcsIGNsb3NlSW5zdHJ1Y3Rpb25zPzogQ29weUZhY3RvcnlDbG9zZUluc3RydWN0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdyZW1vdmVQb3J0Zm9saW9TdHJhdGVneScpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9wb3J0Zm9saW8tc3RyYXRlZ2llcy8ke3BvcnRmb2xpb0lkfWAsXG4gICAgICBtZXRob2Q6ICdERUxFVEUnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAgZGF0YTogY2xvc2VJbnN0cnVjdGlvbnMsXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGVzIGEgQ29weUZhY3RvcnkgcG9ydGZvbGlvIHN0cmF0ZWd5IG1lbWJlci4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2NvbmZpZ3VyYXRpb24vcmVtb3ZlUG9ydGZvbGlvU3RyYXRlZ3lNZW1iZXIvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBwb3J0Zm9saW9JZCBwb3J0Zm9saW8gc3RyYXRlZ3kgaWRcbiAgICogQHBhcmFtIHtTdHJpbmd9IHN0cmF0ZWd5SWQgaWQgb2YgdGhlIHN0cmF0ZWd5IHRvIGRlbGV0ZSBtZW1iZXIgZm9yXG4gICAqIEBwYXJhbSB7Q29weUZhY3RvcnlDbG9zZUluc3RydWN0aW9uc30gW2Nsb3NlSW5zdHJ1Y3Rpb25zXSBzdHJhdGVneSBjbG9zZSBpbnN0cnVjdGlvbnNcbiAgICogQHJldHVybiB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBwb3J0Zm9saW8gc3RyYXRlZ3kgaXMgcmVtb3ZlZFxuICAgKi9cbiAgcmVtb3ZlUG9ydGZvbGlvU3RyYXRlZ3lNZW1iZXIoXG4gICAgcG9ydGZvbGlvSWQ6IHN0cmluZywgc3RyYXRlZ3lJZDogc3RyaW5nLCBjbG9zZUluc3RydWN0aW9ucz86IENvcHlGYWN0b3J5Q2xvc2VJbnN0cnVjdGlvbnNcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ3JlbW92ZVBvcnRmb2xpb1N0cmF0ZWd5TWVtYmVyJyk7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3BvcnRmb2xpby1zdHJhdGVnaWVzLyR7cG9ydGZvbGlvSWR9L21lbWJlcnMvJHtzdHJhdGVneUlkfWAsXG4gICAgICBtZXRob2Q6ICdERUxFVEUnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAgZGF0YTogY2xvc2VJbnN0cnVjdGlvbnMsXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIENvcHlGYWN0b3J5IHN1YnNjcmliZXJzIHRoZSB1c2VyIGhhcyBjb25maWd1cmVkIHdpdGggcGFnaW5hdGlvbiBpbiBpbmZpbml0ZSBzY3JvbGwgc3R5bGUuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9oaXN0b3J5L2dldFN1YnNjcmliZXJzL1xuICAgKiBAcGFyYW0ge0dldFN1YnNjcmliZXJzT3B0aW9uc30gW29wdGlvbnNdIG9wdGlvbnNcbiAgICogQHJldHVybiB7UHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVN1YnNjcmliZXI+Pn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBzdWJzY3JpYmVycyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3Vic2NyaWJlcnNXaXRoSW5maW5pdGVTY3JvbGxQYWdpbmF0aW9uKFxuICAgIG9wdGlvbnM/OiBHZXRTdWJzY3JpYmVyc09wdGlvbnNcbiAgKTogUHJvbWlzZTxBcnJheTxDb3B5RmFjdG9yeVN1YnNjcmliZXI+PiB7XG4gICAgcmV0dXJuIHRoaXMuX2dldFN1YnNjcmliZXJzKCcxJywgb3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBDb3B5RmFjdG9yeSBzdWJzY3JpYmVycyB0aGUgdXNlciBoYXMgY29uZmlndXJlZCB3aXRoIHBhZ2luYXRpb24gaW4gY2xhc3NpYyBzdHlsZS4gU2VlXG4gICAqIGh0dHBzOi8vbWV0YWFwaS5jbG91ZC9kb2NzL2NvcHlmYWN0b3J5L3Jlc3RBcGkvYXBpL2hpc3RvcnkvZ2V0U3Vic2NyaWJlcnMvXG4gICAqIEBwYXJhbSB7R2V0U3Vic2NyaWJlcnNPcHRpb25zfSBbb3B0aW9uc10gb3B0aW9uc1xuICAgKiBAcmV0dXJuIHtQcm9taXNlPENsYXNzaWNQYWdpbmF0aW9uTGlzdDxDb3B5RmFjdG9yeVN1YnNjcmliZXI+Pn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBzdWJzY3JpYmVycyBmb3VuZFxuICAgKi9cbiAgYXN5bmMgZ2V0U3Vic2NyaWJlcnNXaXRoQ2xhc3NpY1BhZ2luYXRpb24ob3B0aW9ucz86IEdldFN1YnNjcmliZXJzT3B0aW9ucyk6XG4gICAgUHJvbWlzZTxDbGFzc2ljUGFnaW5hdGlvbkxpc3Q8Q29weUZhY3RvcnlTdWJzY3JpYmVyPj4ge1xuICAgIHJldHVybiB0aGlzLl9nZXRTdWJzY3JpYmVycygnMicsIG9wdGlvbnMpO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBfZ2V0U3Vic2NyaWJlcnMoYXBpVmVyc2lvbiwgb3B0aW9ucykge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdnZXRTdWJzY3JpYmVycycpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeSh7XG4gICAgICB1cmw6ICcvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3N1YnNjcmliZXJzJyxcbiAgICAgIG1ldGhvZDogJ0dFVCcsXG4gICAgICBwYXJhbXM6IG9wdGlvbnMsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW4sXG4gICAgICAgICdhcGktdmVyc2lvbic6IGFwaVZlcnNpb25cbiAgICAgIH0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSwgdHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBDb3B5RmFjdG9yeSBzdWJzY3JpYmVyIGJ5IGlkLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9nZXRTdWJzY3JpYmVyL1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHJldHVybnMge1Byb21pc2U8Q29weUZhY3RvcnlTdWJzY3JpYmVyPn0gcHJvbWlzZSByZXNvbHZpbmcgd2l0aCBzdWJzY3JpYmVyIGZvdW5kXG4gICAqL1xuICBnZXRTdWJzY3JpYmVyKHN1YnNjcmliZXJJZDogc3RyaW5nKTogUHJvbWlzZTxDb3B5RmFjdG9yeVN1YnNjcmliZXI+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0U3Vic2NyaWJlcicpO1xuICAgIH1cbiAgICBjb25zdCBvcHRzID0ge1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9zdWJzY3JpYmVycy8ke3N1YnNjcmliZXJJZH1gLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgJ2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlblxuICAgICAgfSxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFVwZGF0ZXMgQ29weUZhY3Rvcnkgc3Vic2NyaWJlciBjb25maWd1cmF0aW9uIG9yIGNyZWF0ZXMgaXQgaWYgaXQgZG9lcyBub3QgZXhpc3QuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL3VwZGF0ZVN1YnNjcmliZXIvXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdWJzY3JpYmVySWQgc3Vic2NyaWJlciBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5U3Vic2NyaWJlclVwZGF0ZX0gc3Vic2NyaWJlciBzdWJzY3JpYmVyIHVwZGF0ZVxuICAgKiBAcmV0dXJucyB7UHJvbWlzZX0gcHJvbWlzZSByZXNvbHZpbmcgd2hlbiBzdWJzY3JpYmVyIGlzIHVwZGF0ZWRcbiAgICovXG4gIHVwZGF0ZVN1YnNjcmliZXIoc3Vic2NyaWJlcklkOiBzdHJpbmcsIHN1YnNjcmliZXI6IENvcHlGYWN0b3J5U3Vic2NyaWJlclVwZGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCd1cGRhdGVTdWJzY3JpYmVyJyk7XG4gICAgfVxuICAgIGNvbnN0IG9wdHMgPSB7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3N1YnNjcmliZXJzLyR7c3Vic2NyaWJlcklkfWAsXG4gICAgICBtZXRob2Q6ICdQVVQnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAgZGF0YTogc3Vic2NyaWJlcixcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgc3Vic2NyaWJlciBjb25maWd1cmF0aW9uLiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9yZW1vdmVTdWJzY3JpYmVyL1xuICAgKiBAcGFyYW0ge1N0cmluZ30gc3Vic2NyaWJlcklkIHN1YnNjcmliZXIgaWRcbiAgICogQHBhcmFtIHtDb3B5RmFjdG9yeUNsb3NlSW5zdHJ1Y3Rpb25zfSBbY2xvc2VJbnN0cnVjdGlvbnNdIHN1YnNjcmliZXIgY2xvc2UgaW5zdHJ1Y3Rpb25zXG4gICAqIEByZXR1cm5zIHtQcm9taXNlfSBwcm9taXNlIHJlc29sdmluZyB3aGVuIHN1YnNjcmliZXIgaXMgcmVtb3ZlZFxuICAgKi9cbiAgcmVtb3ZlU3Vic2NyaWJlcihzdWJzY3JpYmVySWQ6IHN0cmluZywgY2xvc2VJbnN0cnVjdGlvbnM/OiBDb3B5RmFjdG9yeUNsb3NlSW5zdHJ1Y3Rpb25zKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ3JlbW92ZVN1YnNjcmliZXInKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vc3Vic2NyaWJlcnMvJHtzdWJzY3JpYmVySWR9YCxcbiAgICAgIG1ldGhvZDogJ0RFTEVURScsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdhdXRoLXRva2VuJzogdGhpcy5fdG9rZW5cbiAgICAgIH0sXG4gICAgICBkYXRhOiBjbG9zZUluc3RydWN0aW9ucyxcbiAgICAgIGpzb246IHRydWVcbiAgICB9O1xuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KG9wdHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZXMgYSBzdWJzY3JpcHRpb24gb2Ygc3Vic2NyaWJlciB0byBhIHN0cmF0ZWd5LiBTZWVcbiAgICogaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9yZW1vdmVTdWJzY3JpcHRpb24vXG4gICAqIEBwYXJhbSB7U3RyaW5nfSBzdWJzY3JpYmVySWQgc3Vic2NyaWJlciBpZFxuICAgKiBAcGFyYW0ge1N0cmluZ30gc3RyYXRlZ3lJZCBzdHJhdGVneSBpZFxuICAgKiBAcGFyYW0ge0NvcHlGYWN0b3J5Q2xvc2VJbnN0cnVjdGlvbnN9IFtjbG9zZUluc3RydWN0aW9uc10gc3Vic2NyaWJlciBjbG9zZSBpbnN0cnVjdGlvbnNcbiAgICogQHJldHVybnMge1Byb21pc2V9IHByb21pc2UgcmVzb2x2aW5nIHdoZW4gc3Vic2NyaWJlciBpcyByZW1vdmVkXG4gICAqL1xuICByZW1vdmVTdWJzY3JpcHRpb24oXG4gICAgc3Vic2NyaWJlcklkOiBzdHJpbmcsIHN0cmF0ZWd5SWQ6IHN0cmluZywgY2xvc2VJbnN0cnVjdGlvbnM/OiBDb3B5RmFjdG9yeUNsb3NlSW5zdHJ1Y3Rpb25zXG4gICk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCdyZW1vdmVTdWJzY3JpcHRpb24nKTtcbiAgICB9XG4gICAgY29uc3Qgb3B0cyA9IHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vc3Vic2NyaWJlcnMvJHtzdWJzY3JpYmVySWR9L3N1YnNjcmlwdGlvbnMvJHtzdHJhdGVneUlkfWAsXG4gICAgICBtZXRob2Q6ICdERUxFVEUnLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VuXG4gICAgICB9LFxuICAgICAgZGF0YTogY2xvc2VJbnN0cnVjdGlvbnMsXG4gICAgICBqc29uOiB0cnVlXG4gICAgfTtcbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeShvcHRzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgQ29weUZhY3RvcnkgdXNlciB3ZWJob29rcyBsaXN0IHdpdGggcGFnaW5hdGlvbiBpbiBpbmZpbml0ZSBzY3JvbGwgc3R5bGUuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL2dldFdlYmhvb2tzL1xuICAgKiBAcGFyYW0gc3RyYXRlZ3lJZCBzdHJhdGVneSBJRFxuICAgKiBAcGFyYW0gb3B0aW9ucyBhZGRpdGlvbmFsIG9wdGlvbnNcbiAgICogQHJldHVybiBwcm9taXNlIHJlc29sdmluZyB3aXRoIHdlYmhvb2tzIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRXZWJob29rc1dpdGhJbmZpbml0ZVNjcm9sbFBhZ2luYXRpb24oc3RyYXRlZ3lJZDogc3RyaW5nLCBvcHRpb25zPzogR2V0V2ViaG9va3NPcHRpb25zKTogUHJvbWlzZTxXZWJob29rW10+IHtcbiAgICBsZXQgcmVzdWx0OiBXZWJob29rW10gPSBhd2FpdCB0aGlzLl9nZXRXZWJob29rcyhzdHJhdGVneUlkLCAnaW5maW5pdGVTY3JvbGwnLCBvcHRpb25zKTtcbiAgICByZXN1bHQuZm9yRWFjaChpdGVtID0+IGl0ZW0uY3JlYXRlZEF0ID0gbmV3IERhdGUoaXRlbS5jcmVhdGVkQXQpKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBDb3B5RmFjdG9yeSB1c2VyIHdlYmhvb2tzIGxpc3Qgd2l0aCBwYWdpbmF0aW9uIGluIGNsYXNzaWMgc3R5bGUuIFNlZVxuICAgKiBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL2dldFdlYmhvb2tzL1xuICAgKiBAcGFyYW0gc3RyYXRlZ3lJZCBzdHJhdGVneSBJRFxuICAgKiBAcGFyYW0gb3B0aW9ucyBhZGRpdGlvbmFsIG9wdGlvbnNcbiAgICogQHJldHVybiBwcm9taXNlIHJlc29sdmluZyB3aXRoIHdlYmhvb2tzIGZvdW5kXG4gICAqL1xuICBhc3luYyBnZXRXZWJob29rc1dpdGhDbGFzc2ljUGFnaW5hdGlvbihcbiAgICBzdHJhdGVneUlkOiBzdHJpbmcsIG9wdGlvbnM/OiBHZXRXZWJob29rc09wdGlvbnNcbiAgKTogUHJvbWlzZTxDbGFzc2ljUGFnaW5hdGlvbkxpc3Q8V2ViaG9vaz4+IHtcbiAgICBsZXQgcmVzdWx0OiBDbGFzc2ljUGFnaW5hdGlvbkxpc3Q8V2ViaG9vaz4gPSBhd2FpdCB0aGlzLl9nZXRXZWJob29rcyhzdHJhdGVneUlkLCAnY2xhc3NpYycsIG9wdGlvbnMpO1xuICAgIHJlc3VsdC5pdGVtcy5mb3JFYWNoKGl0ZW0gPT4gaXRlbS5jcmVhdGVkQXQgPSBuZXcgRGF0ZShpdGVtLmNyZWF0ZWRBdCkpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBwcml2YXRlIF9nZXRXZWJob29rcyhcbiAgICBzdHJhdGVneUlkOiBzdHJpbmcsIHBhZ2luYXRpb25TdHlsZTogJ2luZmluaXRlU2Nyb2xsJyB8ICdjbGFzc2ljJywgb3B0aW9ucz86IEdldFdlYmhvb2tzT3B0aW9uc1xuICApIHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignZ2V0V2ViaG9va3MnKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkoe1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9zdHJhdGVnaWVzLyR7c3RyYXRlZ3lJZH0vd2ViaG9va3NgLFxuICAgICAgbWV0aG9kOiAnR0VUJyxcbiAgICAgIHBhcmFtczoge1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICBwYWdpbmF0aW9uU3R5bGVcbiAgICAgIH0sXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlbn0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSwgdHJ1ZSk7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyB3ZWJob29rLiBUaGUgd2ViaG9vayBjYW4gYmUgdXNlZCBmb3IgYW4gZXh0ZXJuYWwgYXBwIChlLmcuIFRyYWRpbmdWaWV3KSB0byBzdWJtaXQgdHJhZGluZyBzaWduYWxzIHRvXG4gICAqIENvcHlGYWN0b3J5LiBTZWUgaHR0cHM6Ly9tZXRhYXBpLmNsb3VkL2RvY3MvY29weWZhY3RvcnkvcmVzdEFwaS9hcGkvY29uZmlndXJhdGlvbi9jcmVhdGVXZWJob29rL1xuICAgKiBAcGFyYW0gc3RyYXRlZ3lJZCBzdHJhdGVneSBJRFxuICAgKiBAcGFyYW0gd2ViaG9vayB3ZWJob29rXG4gICAqIEByZXR1cm5zIHByb21pc2UgcmVzb2x2aW5nIHdpdGggY3JlYXRlZCB3ZWJob29rIElEIGFuZCBVUkxcbiAgICovXG4gIGNyZWF0ZVdlYmhvb2soc3RyYXRlZ3lJZDogc3RyaW5nLCB3ZWJob29rOiBOZXdXZWJob29rKTogUHJvbWlzZTxXZWJob29rSWRBbmRVcmw+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignY3JlYXRlV2ViaG9vaycpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeSh7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3N0cmF0ZWdpZXMvJHtzdHJhdGVneUlkfS93ZWJob29rc2AsXG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHsnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VufSxcbiAgICAgIGRhdGE6IHdlYmhvb2ssXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBhIHdlYmhvb2suIFNlZSBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL3VwZGF0ZVdlYmhvb2svXG4gICAqIEBwYXJhbSBzdHJhdGVneUlkIHdlYmhvb2sgc3RyYXRlZ3kgSURcbiAgICogQHBhcmFtIHdlYmhvb2tJZCB3ZWJob29rIElEXG4gICAqIEBwYXJhbSB1cGRhdGUgd2ViaG9vayB1cGRhdGVcbiAgICogQHJldHVybnMgcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB1cGRhdGVkXG4gICAqL1xuICB1cGRhdGVXZWJob29rKHN0cmF0ZWd5SWQ6IHN0cmluZywgd2ViaG9va0lkOiBzdHJpbmcsIHVwZGF0ZTogV2ViaG9va1VwZGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCd1cGRhdGVXZWJob29rJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vc3RyYXRlZ2llcy8ke3N0cmF0ZWd5SWR9L3dlYmhvb2tzLyR7d2ViaG9va0lkfWAsXG4gICAgICBtZXRob2Q6ICdQQVRDSCcsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlbn0sXG4gICAgICBkYXRhOiB1cGRhdGUsXG4gICAgICBqc29uOiB0c