UNPKG

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
'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