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)

490 lines (489 loc) 59.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, /** * metaapi.cloud CopyFactory configuration API (trade copying configuration API) client (see * https://metaapi.cloud/docs/copyfactory/) */ "default", { enumerable: true, get: function() { return ConfigurationClient; } }); const _metaapiclient = /*#__PURE__*/ _interop_require_default(require("../metaapi.client")); const _randomstring = /*#__PURE__*/ _interop_require_default(require("randomstring")); _export_star(require("./configuration.client.schemas"), exports); function _export_star(from, to) { Object.keys(from).forEach(function(k) { if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) { Object.defineProperty(to, k, { enumerable: true, get: function() { return from[k]; } }); } }); return from; } function _interop_require_default(obj) { return obj && obj.__esModule ? obj : { default: obj }; } let ConfigurationClient = class ConfigurationClient extends _metaapiclient.default { /** * Constructs CopyFactory configuration API client instance * @param {DomainClient} domainClient domain client */ constructor(domainClient){ super(domainClient); this._domainClient = domainClient; } /** * 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.default.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 */ async getStrategiesWithInfiniteScrollPagination(options) { 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 */ async getStrategiesWithClassicPagination(options) { return this._getStrategies("2", options); } async _getStrategies(apiVersion, options) { 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 */ async getPortfolioStrategiesWithInfiniteScrollPagination(options) { 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 */ async getPortfolioStrategiesWithClassicPagination(options) { return this._getPortfolioStrategies("2", options); } async _getPortfolioStrategies(apiVersion, options) { 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 */ async getSubscribersWithInfiniteScrollPagination(options) { 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 */ async getSubscribersWithClassicPagination(options) { return this._getSubscribers("2", options); } async _getSubscribers(apiVersion, options) { 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 */ async getWebhooksWithInfiniteScrollPagination(strategyId, options) { let result = await 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 */ async getWebhooksWithClassicPagination(strategyId, options) { let result = await 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: { ...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 }); } }; //# 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+IHtcbiAgICBpZiAodGhpcy5faXNOb3RKd3RUb2tlbigpKSB7XG4gICAgICByZXR1cm4gdGhpcy5faGFuZGxlTm9BY2Nlc3NFcnJvcignY3JlYXRlV2ViaG9vaycpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fZG9tYWluQ2xpZW50LnJlcXVlc3RDb3B5RmFjdG9yeSh7XG4gICAgICB1cmw6IGAvdXNlcnMvY3VycmVudC9jb25maWd1cmF0aW9uL3N0cmF0ZWdpZXMvJHtzdHJhdGVneUlkfS93ZWJob29rc2AsXG4gICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgIGhlYWRlcnM6IHsnYXV0aC10b2tlbic6IHRoaXMuX3Rva2VufSxcbiAgICAgIGRhdGE6IHdlYmhvb2ssXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVXBkYXRlcyBhIHdlYmhvb2suIFNlZSBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL3VwZGF0ZVdlYmhvb2svXG4gICAqIEBwYXJhbSBzdHJhdGVneUlkIHdlYmhvb2sgc3RyYXRlZ3kgSURcbiAgICogQHBhcmFtIHdlYmhvb2tJZCB3ZWJob29rIElEXG4gICAqIEBwYXJhbSB1cGRhdGUgd2ViaG9vayB1cGRhdGVcbiAgICogQHJldHVybnMgcHJvbWlzZSByZXNvbHZpbmcgd2hlbiB1cGRhdGVkXG4gICAqL1xuICB1cGRhdGVXZWJob29rKHN0cmF0ZWd5SWQ6IHN0cmluZywgd2ViaG9va0lkOiBzdHJpbmcsIHVwZGF0ZTogV2ViaG9va1VwZGF0ZSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGlmICh0aGlzLl9pc05vdEp3dFRva2VuKCkpIHtcbiAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVOb0FjY2Vzc0Vycm9yKCd1cGRhdGVXZWJob29rJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9kb21haW5DbGllbnQucmVxdWVzdENvcHlGYWN0b3J5KHtcbiAgICAgIHVybDogYC91c2Vycy9jdXJyZW50L2NvbmZpZ3VyYXRpb24vc3RyYXRlZ2llcy8ke3N0cmF0ZWd5SWR9L3dlYmhvb2tzLyR7d2ViaG9va0lkfWAsXG4gICAgICBtZXRob2Q6ICdQQVRDSCcsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlbn0sXG4gICAgICBkYXRhOiB1cGRhdGUsXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyBhIHdlYmhvb2suIFNlZSBodHRwczovL21ldGFhcGkuY2xvdWQvZG9jcy9jb3B5ZmFjdG9yeS9yZXN0QXBpL2FwaS9jb25maWd1cmF0aW9uL2RlbGV0ZVdlYmhvb2svXG4gICAqIEBwYXJhbSBzdHJhdGVneUlkIHdlYmhvb2sgc3RyYXRlZ3kgSURcbiAgICogQHBhcmFtIHdlYmhvb2tJZCB3ZWJob29rIElEXG4gICAqIEByZXR1cm5zIHByb21pc2UgcmVzb2x2aW5nIHdoZW4gZGVsZXRlZFxuICAgKi9cbiAgZGVsZXRlV2ViaG9vayhzdHJhdGVneUlkOiBzdHJpbmcsIHdlYmhvb2tJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX2lzTm90Snd0VG9rZW4oKSkge1xuICAgICAgcmV0dXJuIHRoaXMuX2hhbmRsZU5vQWNjZXNzRXJyb3IoJ2RlbGV0ZVdlYmhvb2snKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2RvbWFpbkNsaWVudC5yZXF1ZXN0Q29weUZhY3Rvcnkoe1xuICAgICAgdXJsOiBgL3VzZXJzL2N1cnJlbnQvY29uZmlndXJhdGlvbi9zdHJhdGVnaWVzLyR7c3RyYXRlZ3lJZH0vd2ViaG9va3MvJHt3ZWJob29rSWR9YCxcbiAgICAgIG1ldGhvZDogJ0RFTEVURScsXG4gICAgICBoZWFkZXJzOiB7J2F1dGgtdG9rZW4nOiB0aGlzLl90b2tlbn0sXG4gICAgICBqc29uOiB0cnVlXG4gICAgfSk7XG4gIH1cbn1cbiJdLCJuYW1lcyI6WyJDb25maWd1cmF0aW9uQ2xpZW50IiwiTWV0YUFwaUNsaWVudCIsImNvbnN0cnVjdG9yIiwiZG9tYWluQ2xpZW50IiwiX2RvbWFpbkNsaWVudCIsImdlbmVyYXRlU3RyYXRlZ3lJZCIsIl9pc05vdEp3dFRva2VuIiwiX2hhbmRsZU5vQWNjZXNzRXJyb3IiLCJvcHRzIiwidXJsIiwibWV0aG9kIiwiaGVhZGVycyIsIl90b2tlbiIsImpzb24iLCJyZXF1ZXN0Q29weUZhY3RvcnkiLCJnZW5lcmF0ZUFjY291bnRJZCIsInJhbmRvbXN0cmluZyIsImdlbmVyYXRlIiwiZ2V0U3RyYXRlZ2llc1dpdGhJbmZpbml0ZVNjcm9sbFBhZ2luYXRpb24iLCJvcHRpb25zIiwiX2dldFN0cmF0ZWdpZXMiLCJnZXRTdHJhdGVnaWVzV2l0aENsYXNzaWNQYWdpbmF0aW9uIiwiYXBpVmVyc2lvbiIsInBhcmFtcyIsImdldFN0cmF0ZWd5Iiwic3RyYXRlZ3lJZCIsInVwZGF0ZVN0cmF0ZWd5Iiwic3RyYXRlZ3kiLCJkYXRhIiwicmVtb3ZlU3RyYXRlZ3kiLCJjbG9zZUluc3RydWN0aW9ucyIsImdldFBvcnRmb2xpb1N0cmF0ZWdpZXNXaXRoSW5maW5pdGVTY3JvbGxQYWdpbmF0aW9uIiwiX2dldFBvcnRmb2xpb1N0cmF0ZWdpZXMiLCJnZXRQb3J0Zm9saW9TdHJhdGVnaWVzV2l0aENsYXNzaWNQYWdpbmF0aW9uIiwiZ2V0UG9ydGZvbGlvU3RyYXRlZ3kiLCJwb3J0Zm9saW9JZCIsInVwZGF0ZVBvcnRmb2xpb1N0cmF0ZWd5IiwicG9ydGZvbGlvIiwicmVtb3ZlUG9ydGZvbGlvU3RyYXRlZ3kiLCJyZW1vdmVQb3J0Zm9saW9TdHJhdGVneU1lbWJlciIsImdldFN1YnNjcmliZXJzV2l0aEluZmluaXRlU2Nyb2xsUGFnaW5hdGlvbiIsIl9nZXRTdWJzY3JpYmVycyIsImdldFN1YnNjcmliZXJzV2l0aENsYXNzaWNQYWdpbmF0aW9uIiwiZ2V0U3Vic2NyaWJlciIsInN1YnNjcmliZXJJZCIsInVwZGF0ZVN1YnNjcmliZXIiLCJzdWJzY3JpYmVyIiwicmVtb3ZlU3Vic2NyaWJlciIsInJlbW92ZVN1YnNjcmlwdGlvbiIsImdldFdlYmhvb2tzV2l0aEluZmluaXRlU2Nyb2xsUGFnaW5hdGlvbiIsInJlc3VsdCIsIl9nZXRXZWJob29rcyIsImZvckVhY2giLCJpdGVtIiwiY3JlYXRlZEF0IiwiRGF0ZSIsImdldFdlYmhvb2tzV2l0aENsYXNzaWNQYWdpbmF0aW9uIiwiaXRlbXMiLCJwYWdpbmF0aW9uU3R5bGUiLCJjcmVhdGVXZWJob29rIiwid2ViaG9vayIsInVwZGF0ZVdlYmhvb2siLCJ3ZWJob29rSWQiLCJ1cGRhdGUiLCJkZWxldGVXZWJob29rIl0sIm1hcHBpbmdzIjoiQUFBQTs7OzsrQkFjQTs7O0NBR0MsR0FDRDs7O2VBQXFCQTs7O3NFQWZLO3FFQUNEO3FCQVFYOzs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBTUMsSUFBQSxBQUFNQSxzQkFBTixNQUFNQSw0QkFBNEJDLHNCQUFhO0lBRTVEOzs7R0FHQyxHQUNEQyxZQUFZQyxZQUEwQixDQUFFO1FBQ3RDLEtBQUssQ0FBQ0E7UUFDTixJQUFJLENBQUNDLGFBQWEsR0FBR0Q7SUFDdkI7SUFFQTs7OztHQUlDLEdBRUQ7Ozs7R0FJQyxHQUNERSxxQkFBMEM7UUFDeEMsSUFBSSxJQUFJLENBQUNDLGNBQWMsSUFBSTtZQUN6QixPQUFPLElBQUksQ0FBQ0Msb0JBQW9CLENBQUM7UUFDbkMsQ0FBQztRQUNELE1BQU1DLE9BQU87WUFDWEMsS0