UNPKG

israeli-bank-scrapers

Version:

Provide scrapers for all major Israeli banks and credit card companies

344 lines (342 loc) 57.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; exports.getMemo = getMemo; var _moment = _interopRequireDefault(require("moment")); var _constants = require("../constants"); var _dates = _interopRequireDefault(require("../helpers/dates")); var _debug = require("../helpers/debug"); var _elementsInteractions = require("../helpers/elements-interactions"); var _fetch = require("../helpers/fetch"); var _navigation = require("../helpers/navigation"); var _transactions = require("../helpers/transactions"); var _waiting = require("../helpers/waiting"); var _transactions2 = require("../transactions"); var _baseScraperWithBrowser = require("./base-scraper-with-browser"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } const debug = (0, _debug.getDebug)('max'); const BASE_API_ACTIONS_URL = 'https://onlinelcapi.max.co.il'; const BASE_WELCOME_URL = 'https://www.max.co.il'; const HOME_PAGE_DATA_URL = `${BASE_WELCOME_URL}/api/registered/getHomePageData`; const LOGIN_URL = `${BASE_WELCOME_URL}/login`; const PASSWORD_EXPIRED_URL = `${BASE_WELCOME_URL}/renew-password`; const SUCCESS_URL = `${BASE_WELCOME_URL}/homepage/personal`; var MaxPlanName = /*#__PURE__*/function (MaxPlanName) { MaxPlanName["Normal"] = "\u05E8\u05D2\u05D9\u05DC\u05D4"; MaxPlanName["ImmediateCharge"] = "\u05D7\u05D9\u05D5\u05D1 \u05E2\u05E1\u05E7\u05D5\u05EA \u05DE\u05D9\u05D9\u05D3\u05D9"; MaxPlanName["InternetShopping"] = "\u05D0\u05D9\u05E0\u05D8\u05E8\u05E0\u05D8/\u05D7\u05D5\"\u05DC"; MaxPlanName["Installments"] = "\u05EA\u05E9\u05DC\u05D5\u05DE\u05D9\u05DD"; MaxPlanName["MonthlyCharge"] = "\u05D7\u05D9\u05D5\u05D1 \u05D7\u05D5\u05D3\u05E9\u05D9"; MaxPlanName["OneMonthPostponed"] = "\u05D3\u05D7\u05D5\u05D9 \u05D7\u05D5\u05D3\u05E9"; MaxPlanName["MonthlyPostponed"] = "\u05D3\u05D7\u05D5\u05D9 \u05DC\u05D7\u05D9\u05D5\u05D1 \u05D4\u05D7\u05D5\u05D3\u05E9\u05D9"; MaxPlanName["MonthlyPayment"] = "\u05EA\u05E9\u05DC\u05D5\u05DD \u05D7\u05D5\u05D3\u05E9\u05D9"; MaxPlanName["FuturePurchaseFinancing"] = "\u05DE\u05D9\u05DE\u05D5\u05DF \u05DC\u05E8\u05DB\u05D9\u05E9\u05D4 \u05E2\u05EA\u05D9\u05D3\u05D9\u05EA"; MaxPlanName["MonthlyPostponedInstallments"] = "\u05D3\u05D7\u05D5\u05D9 \u05D7\u05D5\u05D3\u05E9 \u05EA\u05E9\u05DC\u05D5\u05DE\u05D9\u05DD"; MaxPlanName["ThirtyDaysPlus"] = "\u05E2\u05E1\u05E7\u05EA 30 \u05E4\u05DC\u05D5\u05E1"; MaxPlanName["TwoMonthsPostponed"] = "\u05D3\u05D7\u05D5\u05D9 \u05D7\u05D5\u05D3\u05E9\u05D9\u05D9\u05DD"; MaxPlanName["TwoMonthsPostponed2"] = "\u05D3\u05D7\u05D5\u05D9 2 \u05D7' \u05EA\u05E9\u05DC\u05D5\u05DE\u05D9\u05DD"; MaxPlanName["MonthlyChargePlusInterest"] = "\u05D7\u05D5\u05D3\u05E9\u05D9 + \u05E8\u05D9\u05D1\u05D9\u05EA"; MaxPlanName["Credit"] = "\u05E7\u05E8\u05D3\u05D9\u05D8"; MaxPlanName["CreditOutsideTheLimit"] = "\u05E7\u05E8\u05D3\u05D9\u05D8-\u05DE\u05D7\u05D5\u05E5 \u05DC\u05DE\u05E1\u05D2\u05E8\u05EA"; MaxPlanName["AccumulatingBasket"] = "\u05E1\u05DC \u05DE\u05E6\u05D8\u05D1\u05E8"; MaxPlanName["PostponedTransactionInstallments"] = "\u05E4\u05E8\u05D9\u05E1\u05EA \u05D4\u05E2\u05E1\u05E7\u05D4 \u05D4\u05D3\u05D7\u05D5\u05D9\u05D4"; MaxPlanName["ReplacementCard"] = "\u05DB\u05E8\u05D8\u05D9\u05E1 \u05D7\u05DC\u05D9\u05E4\u05D9"; MaxPlanName["EarlyRepayment"] = "\u05E4\u05E8\u05E2\u05D5\u05DF \u05DE\u05D5\u05E7\u05D3\u05DD"; MaxPlanName["MonthlyCardFee"] = "\u05D3\u05DE\u05D9 \u05DB\u05E8\u05D8\u05D9\u05E1"; MaxPlanName["CurrencyPocket"] = "\u05D7\u05D9\u05D5\u05D1 \u05D0\u05E8\u05E0\u05E7 \u05DE\u05D8\u05D7"; MaxPlanName["MonthlyChargeDistribution"] = "\u05D7\u05DC\u05D5\u05E7\u05EA \u05D7\u05D9\u05D5\u05D1 \u05D7\u05D5\u05D3\u05E9\u05D9"; return MaxPlanName; }(MaxPlanName || {}); const INVALID_DETAILS_SELECTOR = '#popupWrongDetails'; const LOGIN_ERROR_SELECTOR = '#popupCardHoldersLoginError'; const categories = new Map(); function redirectOrDialog(page) { return Promise.race([(0, _navigation.waitForRedirect)(page, 20000, false, [BASE_WELCOME_URL, `${BASE_WELCOME_URL}/`]), (0, _elementsInteractions.waitUntilElementFound)(page, INVALID_DETAILS_SELECTOR, true), (0, _elementsInteractions.waitUntilElementFound)(page, LOGIN_ERROR_SELECTOR, true)]); } function getTransactionsUrl(monthMoment) { const month = monthMoment.month() + 1; const year = monthMoment.year(); const date = `${year}-${month}-01`; /** * url explanation: * userIndex: -1 for all account owners * cardIndex: -1 for all cards under the account * all other query params are static, beside the date which changes for request per month */ const url = new URL(`${BASE_API_ACTIONS_URL}/api/registered/transactionDetails/getTransactionsAndGraphs`); url.searchParams.set('filterData', `{"userIndex":-1,"cardIndex":-1,"monthView":true,"date":"${date}","dates":{"startDate":"0","endDate":"0"},"bankAccount":{"bankAccountIndex":-1,"cards":null}}`); url.searchParams.set('firstCallCardIndex', '-1'); return url.toString(); } async function loadHomePageData(page) { debug('Loading home page data for card balances'); const res = await (0, _fetch.fetchGetWithinPage)(page, HOME_PAGE_DATA_URL); const cardMap = new Map(); if (res?.Result?.UserCards?.Cards) { for (const card of res.Result.UserCards.Cards) { cardMap.set(card.Last4Digits, card); } } return cardMap; } function getCardBalance(card) { if (card.CreditLimit == null || card.OpenToBuy == null) return undefined; const balance = -(card.CreditLimit - card.OpenToBuy); return Math.round(balance * 100) / 100; } function getCardBalanceDate(card) { const shekelEntry = card.CycleSummary?.find(entry => entry.CurrencySymbol.includes('₪')); return shekelEntry ? shekelEntry.Date : undefined; } async function loadCategories(page) { debug('Loading categories'); const res = await (0, _fetch.fetchGetWithinPage)(page, `${BASE_API_ACTIONS_URL}/api/contents/getCategories`); if (res && Array.isArray(res.result)) { debug(`${res.result.length} categories loaded`); res.result?.forEach(({ id, name }) => categories.set(id, name)); } } function getTransactionType(planName, planTypeId) { const cleanedUpTxnTypeStr = planName.replace('\t', ' ').trim(); switch (cleanedUpTxnTypeStr) { case MaxPlanName.ImmediateCharge: case MaxPlanName.Normal: case MaxPlanName.MonthlyCharge: case MaxPlanName.OneMonthPostponed: case MaxPlanName.MonthlyPostponed: case MaxPlanName.FuturePurchaseFinancing: case MaxPlanName.MonthlyPayment: case MaxPlanName.MonthlyPostponedInstallments: case MaxPlanName.ThirtyDaysPlus: case MaxPlanName.TwoMonthsPostponed: case MaxPlanName.TwoMonthsPostponed2: case MaxPlanName.AccumulatingBasket: case MaxPlanName.InternetShopping: case MaxPlanName.MonthlyChargePlusInterest: case MaxPlanName.PostponedTransactionInstallments: case MaxPlanName.ReplacementCard: case MaxPlanName.EarlyRepayment: case MaxPlanName.MonthlyCardFee: case MaxPlanName.CurrencyPocket: case MaxPlanName.MonthlyChargeDistribution: return _transactions2.TransactionTypes.Normal; case MaxPlanName.Installments: case MaxPlanName.Credit: case MaxPlanName.CreditOutsideTheLimit: return _transactions2.TransactionTypes.Installments; default: switch (planTypeId) { case 2: case 3: return _transactions2.TransactionTypes.Installments; case 5: return _transactions2.TransactionTypes.Normal; default: throw new Error(`Unknown transaction type ${cleanedUpTxnTypeStr}`); } } } function getInstallmentsInfo(comments) { if (!comments) { return undefined; } const matches = comments.match(/\d+/g); if (!matches || matches.length < 2) { return undefined; } return { number: parseInt(matches[0], 10), total: parseInt(matches[1], 10) }; } function getChargedCurrency(currencyId) { switch (currencyId) { case 376: return _constants.SHEKEL_CURRENCY; case 840: return _constants.DOLLAR_CURRENCY; case 978: return _constants.EURO_CURRENCY; default: return undefined; } } function getMemo({ comments, fundsTransferReceiverOrTransfer, fundsTransferComment }) { if (fundsTransferReceiverOrTransfer) { const memo = comments ? `${comments} ${fundsTransferReceiverOrTransfer}` : fundsTransferReceiverOrTransfer; return fundsTransferComment ? `${memo}: ${fundsTransferComment}` : memo; } return comments; } function mapTransaction(rawTransaction, options) { const isPending = rawTransaction.paymentDate === null; const processedDate = (0, _moment.default)(isPending ? rawTransaction.purchaseDate : rawTransaction.paymentDate).toISOString(); const status = isPending ? _transactions2.TransactionStatuses.Pending : _transactions2.TransactionStatuses.Completed; const installments = getInstallmentsInfo(rawTransaction.comments); const identifier = installments ? `${rawTransaction.dealData?.arn}_${installments.number}` : rawTransaction.dealData?.arn; const result = { type: getTransactionType(rawTransaction.planName, rawTransaction.planTypeId), date: (0, _moment.default)(rawTransaction.purchaseDate).toISOString(), processedDate, originalAmount: -rawTransaction.originalAmount, originalCurrency: rawTransaction.originalCurrency, chargedAmount: -rawTransaction.actualPaymentAmount, chargedCurrency: getChargedCurrency(rawTransaction.paymentCurrency), description: rawTransaction.merchantName.trim(), memo: getMemo(rawTransaction), category: categories.get(rawTransaction?.categoryId), installments, identifier, status }; if (options?.includeRawTransaction) { result.rawTransaction = (0, _transactions.getRawTransaction)(rawTransaction); } return result; } async function fetchTransactionsForMonth(page, monthMoment, options) { const url = getTransactionsUrl(monthMoment); const data = await (0, _fetch.fetchGetWithinPage)(page, url); const transactionsByAccount = {}; if (!data || !data.result) return transactionsByAccount; data.result.transactions // Filter out non-transactions without a plan type, e.g. summary rows .filter(transaction => !!transaction.planName).forEach(transaction => { if (!transactionsByAccount[transaction.shortCardNumber]) { transactionsByAccount[transaction.shortCardNumber] = []; } const mappedTransaction = mapTransaction(transaction, options); transactionsByAccount[transaction.shortCardNumber].push(mappedTransaction); }); return transactionsByAccount; } function addResult(allResults, result) { const clonedResults = { ...allResults }; Object.keys(result).forEach(accountNumber => { if (!clonedResults[accountNumber]) { clonedResults[accountNumber] = []; } clonedResults[accountNumber].push(...result[accountNumber]); }); return clonedResults; } function prepareTransactions(txns, startMoment, combineInstallments, enableTransactionsFilterByDate) { let clonedTxns = Array.from(txns); if (!combineInstallments) { clonedTxns = (0, _transactions.fixInstallments)(clonedTxns); } clonedTxns = (0, _transactions.sortTransactionsByDate)(clonedTxns); clonedTxns = enableTransactionsFilterByDate ? (0, _transactions.filterOldTransactions)(clonedTxns, startMoment, combineInstallments || false) : clonedTxns; return clonedTxns; } async function fetchTransactions(page, options) { const futureMonthsToScrape = options.futureMonthsToScrape ?? 1; const defaultStartMoment = (0, _moment.default)().subtract(1, 'years'); const startMomentLimit = (0, _moment.default)().subtract(4, 'years'); const startDate = options.startDate || defaultStartMoment.toDate(); const startMoment = _moment.default.max(startMomentLimit, (0, _moment.default)(startDate)); const allMonths = (0, _dates.default)(startMoment, futureMonthsToScrape); await loadCategories(page); const homePageCards = await loadHomePageData(page); let allResults = {}; for (let i = 0; i < allMonths.length; i += 1) { const result = await fetchTransactionsForMonth(page, allMonths[i], options); allResults = addResult(allResults, result); } Object.keys(allResults).forEach(accountNumber => { let txns = allResults[accountNumber]; txns = prepareTransactions(txns, startMoment, options.combineInstallments || false, options.outputData?.enableTransactionsFilterByDate ?? true); allResults[accountNumber] = txns; }); return { allResults, homePageCards }; } function getPossibleLoginResults(page) { const urls = {}; urls[_baseScraperWithBrowser.LoginResults.Success] = [SUCCESS_URL]; urls[_baseScraperWithBrowser.LoginResults.ChangePassword] = [PASSWORD_EXPIRED_URL]; urls[_baseScraperWithBrowser.LoginResults.InvalidPassword] = [async () => { return (0, _elementsInteractions.elementPresentOnPage)(page, INVALID_DETAILS_SELECTOR); }]; urls[_baseScraperWithBrowser.LoginResults.UnknownError] = [async () => { return (0, _elementsInteractions.elementPresentOnPage)(page, LOGIN_ERROR_SELECTOR); }]; return urls; } function createLoginFields(credentials) { return [{ selector: '#user-name', value: credentials.username }, { selector: '#password', value: credentials.password }]; } class MaxScraper extends _baseScraperWithBrowser.BaseScraperWithBrowser { getLoginOptions(credentials) { return { loginUrl: LOGIN_URL, fields: createLoginFields(credentials), submitButtonSelector: 'app-user-login-form .general-button.send-me-code', preAction: async () => { if (await (0, _elementsInteractions.elementPresentOnPage)(this.page, '#closePopup')) { await (0, _elementsInteractions.clickButton)(this.page, '#closePopup'); } await (0, _elementsInteractions.clickButton)(this.page, '.personal-area > a.go-to-personal-area'); if (await (0, _elementsInteractions.elementPresentOnPage)(this.page, '.login-link#private')) { await (0, _elementsInteractions.clickButton)(this.page, '.login-link#private'); } // Try twice in case it can't find it the first time try { await (0, _elementsInteractions.waitUntilElementFound)(this.page, '#login-password-link', true, 10000); } catch { await (0, _waiting.sleep)(1000); await (0, _elementsInteractions.waitUntilElementFound)(this.page, '#login-password-link', true, 10000); } await (0, _elementsInteractions.clickButton)(this.page, '#login-password-link'); await (0, _elementsInteractions.waitUntilElementFound)(this.page, '#login-password.tab-pane.active app-user-login-form', true); }, checkReadiness: async () => { await (0, _elementsInteractions.waitUntilElementFound)(this.page, '.personal-area > a.go-to-personal-area', true); }, postAction: async () => redirectOrDialog(this.page), possibleResults: getPossibleLoginResults(this.page), waitUntil: 'domcontentloaded' }; } async fetchData() { const { allResults, homePageCards } = await fetchTransactions(this.page, this.options); const accounts = Object.keys(allResults).map(accountNumber => { const card = homePageCards.get(accountNumber); return { accountNumber, txns: allResults[accountNumber], balance: card ? getCardBalance(card) : undefined, balanceDate: card ? getCardBalanceDate(card) : undefined, cardFrame: card?.CreditLimit ?? undefined }; }); return { success: true, accounts }; } } var _default = exports.default = MaxScraper; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2RhdGVzIiwiX2RlYnVnIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX2ZldGNoIiwiX25hdmlnYXRpb24iLCJfdHJhbnNhY3Rpb25zIiwiX3dhaXRpbmciLCJfdHJhbnNhY3Rpb25zMiIsIl9iYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiZGVidWciLCJnZXREZWJ1ZyIsIkJBU0VfQVBJX0FDVElPTlNfVVJMIiwiQkFTRV9XRUxDT01FX1VSTCIsIkhPTUVfUEFHRV9EQVRBX1VSTCIsIkxPR0lOX1VSTCIsIlBBU1NXT1JEX0VYUElSRURfVVJMIiwiU1VDQ0VTU19VUkwiLCJNYXhQbGFuTmFtZSIsIklOVkFMSURfREVUQUlMU19TRUxFQ1RPUiIsIkxPR0lOX0VSUk9SX1NFTEVDVE9SIiwiY2F0ZWdvcmllcyIsIk1hcCIsInJlZGlyZWN0T3JEaWFsb2ciLCJwYWdlIiwiUHJvbWlzZSIsInJhY2UiLCJ3YWl0Rm9yUmVkaXJlY3QiLCJ3YWl0VW50aWxFbGVtZW50Rm91bmQiLCJnZXRUcmFuc2FjdGlvbnNVcmwiLCJtb250aE1vbWVudCIsIm1vbnRoIiwieWVhciIsImRhdGUiLCJ1cmwiLCJVUkwiLCJzZWFyY2hQYXJhbXMiLCJzZXQiLCJ0b1N0cmluZyIsImxvYWRIb21lUGFnZURhdGEiLCJyZXMiLCJmZXRjaEdldFdpdGhpblBhZ2UiLCJjYXJkTWFwIiwiUmVzdWx0IiwiVXNlckNhcmRzIiwiQ2FyZHMiLCJjYXJkIiwiTGFzdDREaWdpdHMiLCJnZXRDYXJkQmFsYW5jZSIsIkNyZWRpdExpbWl0IiwiT3BlblRvQnV5IiwidW5kZWZpbmVkIiwiYmFsYW5jZSIsIk1hdGgiLCJyb3VuZCIsImdldENhcmRCYWxhbmNlRGF0ZSIsInNoZWtlbEVudHJ5IiwiQ3ljbGVTdW1tYXJ5IiwiZmluZCIsImVudHJ5IiwiQ3VycmVuY3lTeW1ib2wiLCJpbmNsdWRlcyIsIkRhdGUiLCJsb2FkQ2F0ZWdvcmllcyIsIkFycmF5IiwiaXNBcnJheSIsInJlc3VsdCIsImxlbmd0aCIsImZvckVhY2giLCJpZCIsIm5hbWUiLCJnZXRUcmFuc2FjdGlvblR5cGUiLCJwbGFuTmFtZSIsInBsYW5UeXBlSWQiLCJjbGVhbmVkVXBUeG5UeXBlU3RyIiwicmVwbGFjZSIsInRyaW0iLCJJbW1lZGlhdGVDaGFyZ2UiLCJOb3JtYWwiLCJNb250aGx5Q2hhcmdlIiwiT25lTW9udGhQb3N0cG9uZWQiLCJNb250aGx5UG9zdHBvbmVkIiwiRnV0dXJlUHVyY2hhc2VGaW5hbmNpbmciLCJNb250aGx5UGF5bWVudCIsIk1vbnRobHlQb3N0cG9uZWRJbnN0YWxsbWVudHMiLCJUaGlydHlEYXlzUGx1cyIsIlR3b01vbnRoc1Bvc3Rwb25lZCIsIlR3b01vbnRoc1Bvc3Rwb25lZDIiLCJBY2N1bXVsYXRpbmdCYXNrZXQiLCJJbnRlcm5ldFNob3BwaW5nIiwiTW9udGhseUNoYXJnZVBsdXNJbnRlcmVzdCIsIlBvc3Rwb25lZFRyYW5zYWN0aW9uSW5zdGFsbG1lbnRzIiwiUmVwbGFjZW1lbnRDYXJkIiwiRWFybHlSZXBheW1lbnQiLCJNb250aGx5Q2FyZEZlZSIsIkN1cnJlbmN5UG9ja2V0IiwiTW9udGhseUNoYXJnZURpc3RyaWJ1dGlvbiIsIlRyYW5zYWN0aW9uVHlwZXMiLCJJbnN0YWxsbWVudHMiLCJDcmVkaXQiLCJDcmVkaXRPdXRzaWRlVGhlTGltaXQiLCJFcnJvciIsImdldEluc3RhbGxtZW50c0luZm8iLCJjb21tZW50cyIsIm1hdGNoZXMiLCJtYXRjaCIsIm51bWJlciIsInBhcnNlSW50IiwidG90YWwiLCJnZXRDaGFyZ2VkQ3VycmVuY3kiLCJjdXJyZW5jeUlkIiwiU0hFS0VMX0NVUlJFTkNZIiwiRE9MTEFSX0NVUlJFTkNZIiwiRVVST19DVVJSRU5DWSIsImdldE1lbW8iLCJmdW5kc1RyYW5zZmVyUmVjZWl2ZXJPclRyYW5zZmVyIiwiZnVuZHNUcmFuc2ZlckNvbW1lbnQiLCJtZW1vIiwibWFwVHJhbnNhY3Rpb24iLCJyYXdUcmFuc2FjdGlvbiIsIm9wdGlvbnMiLCJpc1BlbmRpbmciLCJwYXltZW50RGF0ZSIsInByb2Nlc3NlZERhdGUiLCJtb21lbnQiLCJwdXJjaGFzZURhdGUiLCJ0b0lTT1N0cmluZyIsInN0YXR1cyIsIlRyYW5zYWN0aW9uU3RhdHVzZXMiLCJQZW5kaW5nIiwiQ29tcGxldGVkIiwiaW5zdGFsbG1lbnRzIiwiaWRlbnRpZmllciIsImRlYWxEYXRhIiwiYXJuIiwidHlwZSIsIm9yaWdpbmFsQW1vdW50Iiwib3JpZ2luYWxDdXJyZW5jeSIsImNoYXJnZWRBbW91bnQiLCJhY3R1YWxQYXltZW50QW1vdW50IiwiY2hhcmdlZEN1cnJlbmN5IiwicGF5bWVudEN1cnJlbmN5IiwiZGVzY3JpcHRpb24iLCJtZXJjaGFudE5hbWUiLCJjYXRlZ29yeSIsImdldCIsImNhdGVnb3J5SWQiLCJpbmNsdWRlUmF3VHJhbnNhY3Rpb24iLCJnZXRSYXdUcmFuc2FjdGlvbiIsImZldGNoVHJhbnNhY3Rpb25zRm9yTW9udGgiLCJkYXRhIiwidHJhbnNhY3Rpb25zQnlBY2NvdW50IiwidHJhbnNhY3Rpb25zIiwiZmlsdGVyIiwidHJhbnNhY3Rpb24iLCJzaG9ydENhcmROdW1iZXIiLCJtYXBwZWRUcmFuc2FjdGlvbiIsInB1c2giLCJhZGRSZXN1bHQiLCJhbGxSZXN1bHRzIiwiY2xvbmVkUmVzdWx0cyIsIk9iamVjdCIsImtleXMiLCJhY2NvdW50TnVtYmVyIiwicHJlcGFyZVRyYW5zYWN0aW9ucyIsInR4bnMiLCJzdGFydE1vbWVudCIsImNvbWJpbmVJbnN0YWxsbWVudHMiLCJlbmFibGVUcmFuc2FjdGlvbnNGaWx0ZXJCeURhdGUiLCJjbG9uZWRUeG5zIiwiZnJvbSIsImZpeEluc3RhbGxtZW50cyIsInNvcnRUcmFuc2FjdGlvbnNCeURhdGUiLCJmaWx0ZXJPbGRUcmFuc2FjdGlvbnMiLCJmZXRjaFRyYW5zYWN0aW9ucyIsImZ1dHVyZU1vbnRoc1RvU2NyYXBlIiwiZGVmYXVsdFN0YXJ0TW9tZW50Iiwic3VidHJhY3QiLCJzdGFydE1vbWVudExpbWl0Iiwic3RhcnREYXRlIiwidG9EYXRlIiwibWF4IiwiYWxsTW9udGhzIiwiZ2V0QWxsTW9udGhNb21lbnRzIiwiaG9tZVBhZ2VDYXJkcyIsImkiLCJvdXRwdXREYXRhIiwiZ2V0UG9zc2libGVMb2dpblJlc3VsdHMiLCJ1cmxzIiwiTG9naW5SZXN1bHRzIiwiU3VjY2VzcyIsIkNoYW5nZVBhc3N3b3JkIiwiSW52YWxpZFBhc3N3b3JkIiwiZWxlbWVudFByZXNlbnRPblBhZ2UiLCJVbmtub3duRXJyb3IiLCJjcmVhdGVMb2dpbkZpZWxkcyIsImNyZWRlbnRpYWxzIiwic2VsZWN0b3IiLCJ2YWx1ZSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJNYXhTY3JhcGVyIiwiQmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImdldExvZ2luT3B0aW9ucyIsImxvZ2luVXJsIiwiZmllbGRzIiwic3VibWl0QnV0dG9uU2VsZWN0b3IiLCJwcmVBY3Rpb24iLCJjbGlja0J1dHRvbiIsInNsZWVwIiwiY2hlY2tSZWFkaW5lc3MiLCJwb3N0QWN0aW9uIiwicG9zc2libGVSZXN1bHRzIiwid2FpdFVudGlsIiwiZmV0Y2hEYXRhIiwiYWNjb3VudHMiLCJtYXAiLCJiYWxhbmNlRGF0ZSIsImNhcmRGcmFtZSIsInN1Y2Nlc3MiLCJfZGVmYXVsdCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NyYXBlcnMvbWF4LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBtb21lbnQsIHsgdHlwZSBNb21lbnQgfSBmcm9tICdtb21lbnQnO1xuaW1wb3J0IHsgdHlwZSBQYWdlIH0gZnJvbSAncHVwcGV0ZWVyJztcbmltcG9ydCB7IERPTExBUl9DVVJSRU5DWSwgRVVST19DVVJSRU5DWSwgU0hFS0VMX0NVUlJFTkNZIH0gZnJvbSAnLi4vY29uc3RhbnRzJztcbmltcG9ydCBnZXRBbGxNb250aE1vbWVudHMgZnJvbSAnLi4vaGVscGVycy9kYXRlcyc7XG5pbXBvcnQgeyBnZXREZWJ1ZyB9IGZyb20gJy4uL2hlbHBlcnMvZGVidWcnO1xuaW1wb3J0IHsgY2xpY2tCdXR0b24sIGVsZW1lbnRQcmVzZW50T25QYWdlLCB3YWl0VW50aWxFbGVtZW50Rm91bmQgfSBmcm9tICcuLi9oZWxwZXJzL2VsZW1lbnRzLWludGVyYWN0aW9ucyc7XG5pbXBvcnQgeyBmZXRjaEdldFdpdGhpblBhZ2UgfSBmcm9tICcuLi9oZWxwZXJzL2ZldGNoJztcbmltcG9ydCB7IHdhaXRGb3JSZWRpcmVjdCB9IGZyb20gJy4uL2hlbHBlcnMvbmF2aWdhdGlvbic7XG5pbXBvcnQge1xuICBmaWx0ZXJPbGRUcmFuc2FjdGlvbnMsXG4gIGZpeEluc3RhbGxtZW50cyxcbiAgc29ydFRyYW5zYWN0aW9uc0J5RGF0ZSxcbiAgZ2V0UmF3VHJhbnNhY3Rpb24sXG59IGZyb20gJy4uL2hlbHBlcnMvdHJhbnNhY3Rpb25zJztcbmltcG9ydCB7IHNsZWVwIH0gZnJvbSAnLi4vaGVscGVycy93YWl0aW5nJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uU3RhdHVzZXMsIFRyYW5zYWN0aW9uVHlwZXMsIHR5cGUgVHJhbnNhY3Rpb24sIHR5cGUgVHJhbnNhY3Rpb25zQWNjb3VudCB9IGZyb20gJy4uL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQge1xuICBCYXNlU2NyYXBlcldpdGhCcm93c2VyLFxuICBMb2dpblJlc3VsdHMsXG4gIHR5cGUgTG9naW5PcHRpb25zLFxuICB0eXBlIFBvc3NpYmxlTG9naW5SZXN1bHRzLFxufSBmcm9tICcuL2Jhc2Utc2NyYXBlci13aXRoLWJyb3dzZXInO1xuaW1wb3J0IHsgdHlwZSBTY3JhcGVyT3B0aW9ucyB9IGZyb20gJy4vaW50ZXJmYWNlJztcblxuY29uc3QgZGVidWcgPSBnZXREZWJ1ZygnbWF4Jyk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgU2NyYXBlZFRyYW5zYWN0aW9uIHtcbiAgc2hvcnRDYXJkTnVtYmVyOiBzdHJpbmc7XG4gIHBheW1lbnREYXRlPzogc3RyaW5nO1xuICBwdXJjaGFzZURhdGU6IHN0cmluZztcbiAgYWN0dWFsUGF5bWVudEFtb3VudDogc3RyaW5nO1xuICBwYXltZW50Q3VycmVuY3k6IG51bWJlciB8IG51bGw7XG4gIG9yaWdpbmFsQ3VycmVuY3k6IHN0cmluZztcbiAgb3JpZ2luYWxBbW91bnQ6IG51bWJlcjtcbiAgcGxhbk5hbWU6IHN0cmluZztcbiAgcGxhblR5cGVJZDogbnVtYmVyO1xuICBjb21tZW50czogc3RyaW5nO1xuICBtZXJjaGFudE5hbWU6IHN0cmluZztcbiAgY2F0ZWdvcnlJZDogbnVtYmVyO1xuICBmdW5kc1RyYW5zZmVyQ29tbWVudD86IHN0cmluZztcbiAgZnVuZHNUcmFuc2ZlclJlY2VpdmVyT3JUcmFuc2Zlcj86IHN0cmluZztcbiAgZGVhbERhdGE/OiB7XG4gICAgYXJuOiBzdHJpbmc7XG4gIH07XG59XG5cbmNvbnN0IEJBU0VfQVBJX0FDVElPTlNfVVJMID0gJ2h0dHBzOi8vb25saW5lbGNhcGkubWF4LmNvLmlsJztcbmNvbnN0IEJBU0VfV0VMQ09NRV9VUkwgPSAnaHR0cHM6Ly93d3cubWF4LmNvLmlsJztcbmNvbnN0IEhPTUVfUEFHRV9EQVRBX1VSTCA9IGAke0JBU0VfV0VMQ09NRV9VUkx9L2FwaS9yZWdpc3RlcmVkL2dldEhvbWVQYWdlRGF0YWA7XG5cbmNvbnN0IExPR0lOX1VSTCA9IGAke0JBU0VfV0VMQ09NRV9VUkx9L2xvZ2luYDtcbmNvbnN0IFBBU1NXT1JEX0VYUElSRURfVVJMID0gYCR7QkFTRV9XRUxDT01FX1VSTH0vcmVuZXctcGFzc3dvcmRgO1xuY29uc3QgU1VDQ0VTU19VUkwgPSBgJHtCQVNFX1dFTENPTUVfVVJMfS9ob21lcGFnZS9wZXJzb25hbGA7XG5cbmVudW0gTWF4UGxhbk5hbWUge1xuICBOb3JtYWwgPSAn16jXkteZ15zXlCcsXG4gIEltbWVkaWF0ZUNoYXJnZSA9ICfXl9eZ15XXkSDXoteh16fXldeqINee15nXmdeT15knLFxuICBJbnRlcm5ldFNob3BwaW5nID0gJ9eQ15nXoNeY16jXoNeYL9eX15VcItecJyxcbiAgSW5zdGFsbG1lbnRzID0gJ9eq16nXnNeV157XmdedJyxcbiAgTW9udGhseUNoYXJnZSA9ICfXl9eZ15XXkSDXl9eV15PXqdeZJyxcbiAgT25lTW9udGhQb3N0cG9uZWQgPSAn15PXl9eV15kg15fXldeT16knLFxuICBNb250aGx5UG9zdHBvbmVkID0gJ9eT15fXldeZINec15fXmdeV15Eg15TXl9eV15PXqdeZJyxcbiAgTW9udGhseVBheW1lbnQgPSAn16rXqdec15XXnSDXl9eV15PXqdeZJyxcbiAgRnV0dXJlUHVyY2hhc2VGaW5hbmNpbmcgPSAn157Xmdee15XXnyDXnNeo15vXmdep15Qg16LXqteZ15PXmdeqJyxcbiAgTW9udGhseVBvc3Rwb25lZEluc3RhbGxtZW50cyA9ICfXk9eX15XXmSDXl9eV15PXqSDXqtep15zXldee15nXnScsXG4gIFRoaXJ0eURheXNQbHVzID0gJ9ei16HXp9eqIDMwINek15zXldehJyxcbiAgVHdvTW9udGhzUG9zdHBvbmVkID0gJ9eT15fXldeZINeX15XXk9ep15nXmdedJyxcbiAgVHdvTW9udGhzUG9zdHBvbmVkMiA9IFwi15PXl9eV15kgMiDXlycg16rXqdec15XXnteZ151cIixcbiAgTW9udGhseUNoYXJnZVBsdXNJbnRlcmVzdCA9ICfXl9eV15PXqdeZICsg16jXmdeR15nXqicsXG4gIENyZWRpdCA9ICfXp9eo15PXmdeYJyxcbiAgQ3JlZGl0T3V0c2lkZVRoZUxpbWl0ID0gJ9en16jXk9eZ15gt157Xl9eV16Ug15zXnteh15LXqNeqJyxcbiAgQWNjdW11bGF0aW5nQmFza2V0ID0gJ9eh15wg157XpteY15HXqCcsXG4gIFBvc3Rwb25lZFRyYW5zYWN0aW9uSW5zdGFsbG1lbnRzID0gJ9ek16jXmdeh16og15TXoteh16fXlCDXlNeT15fXldeZ15QnLFxuICBSZXBsYWNlbWVudENhcmQgPSAn15vXqNeY15nXoSDXl9ec15nXpNeZJyxcbiAgRWFybHlSZXBheW1lbnQgPSAn16TXqNei15XXnyDXnteV16fXk9edJyxcbiAgTW9udGhseUNhcmRGZWUgPSAn15PXnteZINeb16jXmNeZ16EnLFxuICBDdXJyZW5jeVBvY2tldCA9ICfXl9eZ15XXkSDXkNeo16DXpyDXnteY15cnLFxuICBNb250aGx5Q2hhcmdlRGlzdHJpYnV0aW9uID0gJ9eX15zXlden16og15fXmdeV15Eg15fXldeT16nXmScsXG59XG5cbmNvbnN0IElOVkFMSURfREVUQUlMU19TRUxFQ1RPUiA9ICcjcG9wdXBXcm9uZ0RldGFpbHMnO1xuY29uc3QgTE9HSU5fRVJST1JfU0VMRUNUT1IgPSAnI3BvcHVwQ2FyZEhvbGRlcnNMb2dpbkVycm9yJztcblxuaW50ZXJmYWNlIEhvbWVQYWdlQ2FyZCB7XG4gIExhc3Q0RGlnaXRzOiBzdHJpbmc7XG4gIENyZWRpdExpbWl0OiBudW1iZXIgfCBudWxsO1xuICBPcGVuVG9CdXk6IG51bWJlciB8IG51bGw7XG4gIEN5Y2xlU3VtbWFyeTogQXJyYXk8e1xuICAgIERhdGU6IHN0cmluZztcbiAgICBDdXJyZW5jeVN5bWJvbDogc3RyaW5nO1xuICB9Pjtcbn1cblxuaW50ZXJmYWNlIEhvbWVQYWdlRGF0YVJlc3VsdCB7XG4gIFJlc3VsdD86IHtcbiAgICBVc2VyQ2FyZHM/OiB7XG4gICAgICBDYXJkcz86IEhvbWVQYWdlQ2FyZFtdO1xuICAgIH07XG4gIH07XG59XG5cbmNvbnN0IGNhdGVnb3JpZXMgPSBuZXcgTWFwPG51bWJlciwgc3RyaW5nPigpO1xuXG5mdW5jdGlvbiByZWRpcmVjdE9yRGlhbG9nKHBhZ2U6IFBhZ2UpIHtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgd2FpdEZvclJlZGlyZWN0KHBhZ2UsIDIwMDAwLCBmYWxzZSwgW0JBU0VfV0VMQ09NRV9VUkwsIGAke0JBU0VfV0VMQ09NRV9VUkx9L2BdKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgSU5WQUxJRF9ERVRBSUxTX1NFTEVDVE9SLCB0cnVlKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgTE9HSU5fRVJST1JfU0VMRUNUT1IsIHRydWUpLFxuICBdKTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25zVXJsKG1vbnRoTW9tZW50OiBNb21lbnQpIHtcbiAgY29uc3QgbW9udGggPSBtb250aE1vbWVudC5tb250aCgpICsgMTtcbiAgY29uc3QgeWVhciA9IG1vbnRoTW9tZW50LnllYXIoKTtcbiAgY29uc3QgZGF0ZSA9IGAke3llYXJ9LSR7bW9udGh9LTAxYDtcblxuICAvKipcbiAgICogdXJsIGV4cGxhbmF0aW9uOlxuICAgKiB1c2VySW5kZXg6IC0xIGZvciBhbGwgYWNjb3VudCBvd25lcnNcbiAgICogY2FyZEluZGV4OiAtMSBmb3IgYWxsIGNhcmRzIHVuZGVyIHRoZSBhY2NvdW50XG4gICAqIGFsbCBvdGhlciBxdWVyeSBwYXJhbXMgYXJlIHN0YXRpYywgYmVzaWRlIHRoZSBkYXRlIHdoaWNoIGNoYW5nZXMgZm9yIHJlcXVlc3QgcGVyIG1vbnRoXG4gICAqL1xuICBjb25zdCB1cmwgPSBuZXcgVVJMKGAke0JBU0VfQVBJX0FDVElPTlNfVVJMfS9hcGkvcmVnaXN0ZXJlZC90cmFuc2FjdGlvbkRldGFpbHMvZ2V0VHJhbnNhY3Rpb25zQW5kR3JhcGhzYCk7XG4gIHVybC5zZWFyY2hQYXJhbXMuc2V0KFxuICAgICdmaWx0ZXJEYXRhJyxcbiAgICBge1widXNlckluZGV4XCI6LTEsXCJjYXJkSW5kZXhcIjotMSxcIm1vbnRoVmlld1wiOnRydWUsXCJkYXRlXCI6XCIke2RhdGV9XCIsXCJkYXRlc1wiOntcInN0YXJ0RGF0ZVwiOlwiMFwiLFwiZW5kRGF0ZVwiOlwiMFwifSxcImJhbmtBY2NvdW50XCI6e1wiYmFua0FjY291bnRJbmRleFwiOi0xLFwiY2FyZHNcIjpudWxsfX1gLFxuICApO1xuICB1cmwuc2VhcmNoUGFyYW1zLnNldCgnZmlyc3RDYWxsQ2FyZEluZGV4JywgJy0xJyk7XG4gIHJldHVybiB1cmwudG9TdHJpbmcoKTtcbn1cblxuaW50ZXJmYWNlIEZldGNoQ2F0ZWdvcnlSZXN1bHQge1xuICByZXN1bHQ/OiBBcnJheTx7XG4gICAgaWQ6IG51bWJlcjtcbiAgICBuYW1lOiBzdHJpbmc7XG4gIH0+O1xufVxuXG5hc3luYyBmdW5jdGlvbiBsb2FkSG9tZVBhZ2VEYXRhKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPE1hcDxzdHJpbmcsIEhvbWVQYWdlQ2FyZD4+IHtcbiAgZGVidWcoJ0xvYWRpbmcgaG9tZSBwYWdlIGRhdGEgZm9yIGNhcmQgYmFsYW5jZXMnKTtcbiAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2hHZXRXaXRoaW5QYWdlPEhvbWVQYWdlRGF0YVJlc3VsdD4ocGFnZSwgSE9NRV9QQUdFX0RBVEFfVVJMKTtcbiAgY29uc3QgY2FyZE1hcCA9IG5ldyBNYXA8c3RyaW5nLCBIb21lUGFnZUNhcmQ+KCk7XG4gIGlmIChyZXM/LlJlc3VsdD8uVXNlckNhcmRzPy5DYXJkcykge1xuICAgIGZvciAoY29uc3QgY2FyZCBvZiByZXMuUmVzdWx0LlVzZXJDYXJkcy5DYXJkcykge1xuICAgICAgY2FyZE1hcC5zZXQoY2FyZC5MYXN0NERpZ2l0cywgY2FyZCk7XG4gICAgfVxuICB9XG4gIHJldHVybiBjYXJkTWFwO1xufVxuXG5mdW5jdGlvbiBnZXRDYXJkQmFsYW5jZShjYXJkOiBIb21lUGFnZUNhcmQpOiBudW1iZXIgfCB1bmRlZmluZWQge1xuICBpZiAoY2FyZC5DcmVkaXRMaW1pdCA9PSBudWxsIHx8IGNhcmQuT3BlblRvQnV5ID09IG51bGwpIHJldHVybiB1bmRlZmluZWQ7XG4gIGNvbnN0IGJhbGFuY2UgPSAtKGNhcmQuQ3JlZGl0TGltaXQgLSBjYXJkLk9wZW5Ub0J1eSk7XG4gIHJldHVybiBNYXRoLnJvdW5kKGJhbGFuY2UgKiAxMDApIC8gMTAwO1xufVxuXG5mdW5jdGlvbiBnZXRDYXJkQmFsYW5jZURhdGUoY2FyZDogSG9tZVBhZ2VDYXJkKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc2hla2VsRW50cnkgPSBjYXJkLkN5Y2xlU3VtbWFyeT8uZmluZChlbnRyeSA9PiBlbnRyeS5DdXJyZW5jeVN5bWJvbC5pbmNsdWRlcygn4oKqJykpO1xuICByZXR1cm4gc2hla2VsRW50cnkgPyBzaGVrZWxFbnRyeS5EYXRlIDogdW5kZWZpbmVkO1xufVxuXG5hc3luYyBmdW5jdGlvbiBsb2FkQ2F0ZWdvcmllcyhwYWdlOiBQYWdlKSB7XG4gIGRlYnVnKCdMb2FkaW5nIGNhdGVnb3JpZXMnKTtcbiAgY29uc3QgcmVzID0gYXdhaXQgZmV0Y2hHZXRXaXRoaW5QYWdlPEZldGNoQ2F0ZWdvcnlSZXN1bHQ+KHBhZ2UsIGAke0JBU0VfQVBJX0FDVElPTlNfVVJMfS9hcGkvY29udGVudHMvZ2V0Q2F0ZWdvcmllc2ApO1xuICBpZiAocmVzICYmIEFycmF5LmlzQXJyYXkocmVzLnJlc3VsdCkpIHtcbiAgICBkZWJ1ZyhgJHtyZXMucmVzdWx0Lmxlbmd0aH0gY2F0ZWdvcmllcyBsb2FkZWRgKTtcbiAgICByZXMucmVzdWx0Py5mb3JFYWNoKCh7IGlkLCBuYW1lIH0pID0+IGNhdGVnb3JpZXMuc2V0KGlkLCBuYW1lKSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25UeXBlKHBsYW5OYW1lOiBzdHJpbmcsIHBsYW5UeXBlSWQ6IG51bWJlcikge1xuICBjb25zdCBjbGVhbmVkVXBUeG5UeXBlU3RyID0gcGxhbk5hbWUucmVwbGFjZSgnXFx0JywgJyAnKS50cmltKCkgYXMgTWF4UGxhbk5hbWU7XG4gIHN3aXRjaCAoY2xlYW5lZFVwVHhuVHlwZVN0cikge1xuICAgIGNhc2UgTWF4UGxhbk5hbWUuSW1tZWRpYXRlQ2hhcmdlOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuTm9ybWFsOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuTW9udGhseUNoYXJnZTpcbiAgICBjYXNlIE1heFBsYW5OYW1lLk9uZU1vbnRoUG9zdHBvbmVkOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuTW9udGhseVBvc3Rwb25lZDpcbiAgICBjYXNlIE1heFBsYW5OYW1lLkZ1dHVyZVB1cmNoYXNlRmluYW5jaW5nOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuTW9udGhseVBheW1lbnQ6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5Nb250aGx5UG9zdHBvbmVkSW5zdGFsbG1lbnRzOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuVGhpcnR5RGF5c1BsdXM6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5Ud29Nb250aHNQb3N0cG9uZWQ6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5Ud29Nb250aHNQb3N0cG9uZWQyOlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuQWNjdW11bGF0aW5nQmFza2V0OlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuSW50ZXJuZXRTaG9wcGluZzpcbiAgICBjYXNlIE1heFBsYW5OYW1lLk1vbnRobHlDaGFyZ2VQbHVzSW50ZXJlc3Q6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5Qb3N0cG9uZWRUcmFuc2FjdGlvbkluc3RhbGxtZW50czpcbiAgICBjYXNlIE1heFBsYW5OYW1lLlJlcGxhY2VtZW50Q2FyZDpcbiAgICBjYXNlIE1heFBsYW5OYW1lLkVhcmx5UmVwYXltZW50OlxuICAgIGNhc2UgTWF4UGxhbk5hbWUuTW9udGhseUNhcmRGZWU6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5DdXJyZW5jeVBvY2tldDpcbiAgICBjYXNlIE1heFBsYW5OYW1lLk1vbnRobHlDaGFyZ2VEaXN0cmlidXRpb246XG4gICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlcy5Ob3JtYWw7XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5JbnN0YWxsbWVudHM6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5DcmVkaXQ6XG4gICAgY2FzZSBNYXhQbGFuTmFtZS5DcmVkaXRPdXRzaWRlVGhlTGltaXQ6XG4gICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlcy5JbnN0YWxsbWVudHM7XG4gICAgZGVmYXVsdDpcbiAgICAgIHN3aXRjaCAocGxhblR5cGVJZCkge1xuICAgICAgICBjYXNlIDI6XG4gICAgICAgIGNhc2UgMzpcbiAgICAgICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlcy5JbnN0YWxsbWVudHM7XG4gICAgICAgIGNhc2UgNTpcbiAgICAgICAgICByZXR1cm4gVHJhbnNhY3Rpb25UeXBlcy5Ob3JtYWw7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmtub3duIHRyYW5zYWN0aW9uIHR5cGUgJHtjbGVhbmVkVXBUeG5UeXBlU3RyIGFzIHN0cmluZ31gKTtcbiAgICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBnZXRJbnN0YWxsbWVudHNJbmZvKGNvbW1lbnRzOiBzdHJpbmcpIHtcbiAgaWYgKCFjb21tZW50cykge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgY29uc3QgbWF0Y2hlcyA9IGNvbW1lbnRzLm1hdGNoKC9cXGQrL2cpO1xuICBpZiAoIW1hdGNoZXMgfHwgbWF0Y2hlcy5sZW5ndGggPCAyKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgbnVtYmVyOiBwYXJzZUludChtYXRjaGVzWzBdLCAxMCksXG4gICAgdG90YWw6IHBhcnNlSW50KG1hdGNoZXNbMV0sIDEwKSxcbiAgfTtcbn1cblxuZnVuY3Rpb24gZ2V0Q2hhcmdlZEN1cnJlbmN5KGN1cnJlbmN5SWQ6IG51bWJlciB8IG51bGwpIHtcbiAgc3dpdGNoIChjdXJyZW5jeUlkKSB7XG4gICAgY2FzZSAzNzY6XG4gICAgICByZXR1cm4gU0hFS0VMX0NVUlJFTkNZO1xuICAgIGNhc2UgODQwOlxuICAgICAgcmV0dXJuIERPTExBUl9DVVJSRU5DWTtcbiAgICBjYXNlIDk3ODpcbiAgICAgIHJldHVybiBFVVJPX0NVUlJFTkNZO1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRNZW1vKHtcbiAgY29tbWVudHMsXG4gIGZ1bmRzVHJhbnNmZXJSZWNlaXZlck9yVHJhbnNmZXIsXG4gIGZ1bmRzVHJhbnNmZXJDb21tZW50LFxufTogUGljazxTY3JhcGVkVHJhbnNhY3Rpb24sICdjb21tZW50cycgfCAnZnVuZHNUcmFuc2ZlclJlY2VpdmVyT3JUcmFuc2ZlcicgfCAnZnVuZHNUcmFuc2ZlckNvbW1lbnQnPikge1xuICBpZiAoZnVuZHNUcmFuc2ZlclJlY2VpdmVyT3JUcmFuc2Zlcikge1xuICAgIGNvbnN0IG1lbW8gPSBjb21tZW50cyA/IGAke2NvbW1lbnRzfSAke2Z1bmRzVHJhbnNmZXJSZWNlaXZlck9yVHJhbnNmZXJ9YCA6IGZ1bmRzVHJhbnNmZXJSZWNlaXZlck9yVHJhbnNmZXI7XG4gICAgcmV0dXJuIGZ1bmRzVHJhbnNmZXJDb21tZW50ID8gYCR7bWVtb306ICR7ZnVuZHNUcmFuc2ZlckNvbW1lbnR9YCA6IG1lbW87XG4gIH1cblxuICByZXR1cm4gY29tbWVudHM7XG59XG5cbmZ1bmN0aW9uIG1hcFRyYW5zYWN0aW9uKHJhd1RyYW5zYWN0aW9uOiBTY3JhcGVkVHJhbnNhY3Rpb24sIG9wdGlvbnM/OiBTY3JhcGVyT3B0aW9ucyk6IFRyYW5zYWN0aW9uIHtcbiAgY29uc3QgaXNQZW5kaW5nID0gcmF3VHJhbnNhY3Rpb24ucGF5bWVudERhdGUgPT09IG51bGw7XG4gIGNvbnN0IHByb2Nlc3NlZERhdGUgPSBtb21lbnQoaXNQZW5kaW5nID8gcmF3VHJhbnNhY3Rpb24ucHVyY2hhc2VEYXRlIDogcmF3VHJhbnNhY3Rpb24ucGF5bWVudERhdGUpLnRvSVNPU3RyaW5nKCk7XG4gIGNvbnN0IHN0YXR1cyA9IGlzUGVuZGluZyA/IFRyYW5zYWN0aW9uU3RhdHVzZXMuUGVuZGluZyA6IFRyYW5zYWN0aW9uU3RhdHVzZXMuQ29tcGxldGVkO1xuXG4gIGNvbnN0IGluc3RhbGxtZW50cyA9IGdldEluc3RhbGxtZW50c0luZm8ocmF3VHJhbnNhY3Rpb24uY29tbWVudHMpO1xuICBjb25zdCBpZGVudGlmaWVyID0gaW5zdGFsbG1lbnRzXG4gICAgPyBgJHtyYXdUcmFuc2FjdGlvbi5kZWFsRGF0YT8uYXJufV8ke2luc3RhbGxtZW50cy5udW1iZXJ9YFxuICAgIDogcmF3VHJhbnNhY3Rpb24uZGVhbERhdGE/LmFybjtcblxuICBjb25zdCByZXN1bHQ6IFRyYW5zYWN0aW9uID0ge1xuICAgIHR5cGU6IGdldFRyYW5zYWN0aW9uVHlwZShyYXdUcmFuc2FjdGlvbi5wbGFuTmFtZSwgcmF3VHJhbnNhY3Rpb24ucGxhblR5cGVJZCksXG4gICAgZGF0ZTogbW9tZW50KHJhd1RyYW5zYWN0aW9uLnB1cmNoYXNlRGF0ZSkudG9JU09TdHJpbmcoKSxcbiAgICBwcm9jZXNzZWREYXRlLFxuICAgIG9yaWdpbmFsQW1vdW50OiAtcmF3VHJhbnNhY3Rpb24ub3JpZ2luYWxBbW91bnQsXG4gICAgb3JpZ2luYWxDdXJyZW5jeTogcmF3VHJhbnNhY3Rpb24ub3JpZ2luYWxDdXJyZW5jeSxcbiAgICBjaGFyZ2VkQW1vdW50OiAtcmF3VHJhbnNhY3Rpb24uYWN0dWFsUGF5bWVudEFtb3VudCxcbiAgICBjaGFyZ2VkQ3VycmVuY3k6IGdldENoYXJnZWRDdXJyZW5jeShyYXdUcmFuc2FjdGlvbi5wYXltZW50Q3VycmVuY3kpLFxuICAgIGRlc2NyaXB0aW9uOiByYXdUcmFuc2FjdGlvbi5tZXJjaGFudE5hbWUudHJpbSgpLFxuICAgIG1lbW86IGdldE1lbW8ocmF3VHJhbnNhY3Rpb24pLFxuICAgIGNhdGVnb3J5OiBjYXRlZ29yaWVzLmdldChyYXdUcmFuc2FjdGlvbj8uY2F0ZWdvcnlJZCksXG4gICAgaW5zdGFsbG1lbnRzLFxuICAgIGlkZW50aWZpZXIsXG4gICAgc3RhdHVzLFxuICB9O1xuXG4gIGlmIChvcHRpb25zPy5pbmNsdWRlUmF3VHJhbnNhY3Rpb24pIHtcbiAgICByZXN1bHQucmF3VHJhbnNhY3Rpb24gPSBnZXRSYXdUcmFuc2FjdGlvbihyYXdUcmFuc2FjdGlvbik7XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufVxuaW50ZXJmYWNlIFNjcmFwZWRUcmFuc2FjdGlvbnNSZXN1bHQge1xuICByZXN1bHQ/OiB7XG4gICAgdHJhbnNhY3Rpb25zOiBTY3JhcGVkVHJhbnNhY3Rpb25bXTtcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnNGb3JNb250aChwYWdlOiBQYWdlLCBtb250aE1vbWVudDogTW9tZW50LCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpIHtcbiAgY29uc3QgdXJsID0gZ2V0VHJhbnNhY3Rpb25zVXJsKG1vbnRoTW9tZW50KTtcblxuICBjb25zdCBkYXRhID0gYXdhaXQgZmV0Y2hHZXRXaXRoaW5QYWdlPFNjcmFwZWRUcmFuc2FjdGlvbnNSZXN1bHQ+KHBhZ2UsIHVybCk7XG4gIGNvbnN0IHRyYW5zYWN0aW9uc0J5QWNjb3VudDogUmVjb3JkPHN0cmluZywgVHJhbnNhY3Rpb25bXT4gPSB7fTtcblxuICBpZiAoIWRhdGEgfHwgIWRhdGEucmVzdWx0KSByZXR1cm4gdHJhbnNhY3Rpb25zQnlBY2NvdW50O1xuXG4gIGRhdGEucmVzdWx0LnRyYW5zYWN0aW9uc1xuICAgIC8vIEZpbHRlciBvdXQgbm9uLXRyYW5zYWN0aW9ucyB3aXRob3V0IGEgcGxhbiB0eXBlLCBlLmcuIHN1bW1hcnkgcm93c1xuICAgIC5maWx0ZXIodHJhbnNhY3Rpb24gPT4gISF0cmFuc2FjdGlvbi5wbGFuTmFtZSlcbiAgICAuZm9yRWFjaCgodHJhbnNhY3Rpb246IFNjcmFwZWRUcmFuc2FjdGlvbikgPT4ge1xuICAgICAgaWYgKCF0cmFuc2FjdGlvbnNCeUFjY291bnRbdHJhbnNhY3Rpb24uc2hvcnRDYXJkTnVtYmVyXSkge1xuICAgICAgICB0cmFuc2FjdGlvbnNCeUFjY291bnRbdHJhbnNhY3Rpb24uc2hvcnRDYXJkTnVtYmVyXSA9IFtdO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBtYXBwZWRUcmFuc2FjdGlvbiA9IG1hcFRyYW5zYWN0aW9uKHRyYW5zYWN0aW9uLCBvcHRpb25zKTtcbiAgICAgIHRyYW5zYWN0aW9uc0J5QWNjb3VudFt0cmFuc2FjdGlvbi5zaG9ydENhcmROdW1iZXJdLnB1c2gobWFwcGVkVHJhbnNhY3Rpb24pO1xuICAgIH0pO1xuXG4gIHJldHVybiB0cmFuc2FjdGlvbnNCeUFjY291bnQ7XG59XG5cbmZ1bmN0aW9uIGFkZFJlc3VsdChhbGxSZXN1bHRzOiBSZWNvcmQ8c3RyaW5nLCBUcmFuc2FjdGlvbltdPiwgcmVzdWx0OiBSZWNvcmQ8c3RyaW5nLCBUcmFuc2FjdGlvbltdPikge1xuICBjb25zdCBjbG9uZWRSZXN1bHRzOiBSZWNvcmQ8c3RyaW5nLCBUcmFuc2FjdGlvbltdPiA9IHsgLi4uYWxsUmVzdWx0cyB9O1xuICBPYmplY3Qua2V5cyhyZXN1bHQpLmZvckVhY2goYWNjb3VudE51bWJlciA9PiB7XG4gICAgaWYgKCFjbG9uZWRSZXN1bHRzW2FjY291bnROdW1iZXJdKSB7XG4gICAgICBjbG9uZWRSZXN1bHRzW2FjY291bnROdW1iZXJdID0gW107XG4gICAgfVxuICAgIGNsb25lZFJlc3VsdHNbYWNjb3VudE51bWJlcl0ucHVzaCguLi5yZXN1bHRbYWNjb3VudE51bWJlcl0pO1xuICB9KTtcbiAgcmV0dXJuIGNsb25lZFJlc3VsdHM7XG59XG5cbmZ1bmN0aW9uIHByZXBhcmVUcmFuc2FjdGlvbnMoXG4gIHR4bnM6IFRyYW5zYWN0aW9uW10sXG4gIHN0YXJ0TW9tZW50OiBtb21lbnQuTW9tZW50LFxuICBjb21iaW5lSW5zdGFsbG1lbnRzOiBib29sZWFuLFxuICBlbmFibGVUcmFuc2FjdGlvbnNGaWx0ZXJCeURhdGU6IGJvb2xlYW4sXG4pIHtcbiAgbGV0IGNsb25lZFR4bnMgPSBBcnJheS5mcm9tKHR4bnMpO1xuICBpZiAoIWNvbWJpbmVJbnN0YWxsbWVudHMpIHtcbiAgICBjbG9uZWRUeG5zID0gZml4SW5zdGFsbG1lbnRzKGNsb25lZFR4bnMpO1xuICB9XG4gIGNsb25lZFR4bnMgPSBzb3J0VHJhbnNhY3Rpb25zQnlEYXRlKGNsb25lZFR4bnMpO1xuICBjbG9uZWRUeG5zID0gZW5hYmxlVHJhbnNhY3Rpb25zRmlsdGVyQnlEYXRlXG4gICAgPyBmaWx0ZXJPbGRUcmFuc2FjdGlvbnMoY2xvbmVkVHhucywgc3RhcnRNb21lbnQsIGNvbWJpbmVJbnN0YWxsbWVudHMgfHwgZmFsc2UpXG4gICAgOiBjbG9uZWRUeG5zO1xuICByZXR1cm4gY2xvbmVkVHhucztcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnMocGFnZTogUGFnZSwgb3B0aW9uczogU2NyYXBlck9wdGlvbnMpIHtcbiAgY29uc3QgZnV0dXJlTW9udGhzVG9TY3JhcGUgPSBvcHRpb25zLmZ1dHVyZU1vbnRoc1RvU2NyYXBlID8/IDE7XG4gIGNvbnN0IGRlZmF1bHRTdGFydE1vbWVudCA9IG1vbWVudCgpLnN1YnRyYWN0KDEsICd5ZWFycycpO1xuICBjb25zdCBzdGFydE1vbWVudExpbWl0ID0gbW9tZW50KCkuc3VidHJhY3QoNCwgJ3llYXJzJyk7XG4gIGNvbnN0IHN0YXJ0RGF0ZSA9IG9wdGlvbnMuc3RhcnREYXRlIHx8IGRlZmF1bHRTdGFydE1vbWVudC50b0RhdGUoKTtcbiAgY29uc3Qgc3RhcnRNb21lbnQgPSBtb21lbnQubWF4KHN0YXJ0TW9tZW50TGltaXQsIG1vbWVudChzdGFydERhdGUpKTtcbiAgY29uc3QgYWxsTW9udGhzID0gZ2V0QWxsTW9udGhNb21lbnRzKHN0YXJ0TW9tZW50LCBmdXR1cmVNb250aHNUb1NjcmFwZSk7XG5cbiAgYXdhaXQgbG9hZENhdGVnb3JpZXMocGFnZSk7XG4gIGNvbnN0IGhvbWVQYWdlQ2FyZHMgPSBhd2FpdCBsb2FkSG9tZVBhZ2VEYXRhKHBhZ2UpO1xuXG4gIGxldCBhbGxSZXN1bHRzOiBSZWNvcmQ8c3RyaW5nLCBUcmFuc2FjdGlvbltdPiA9IHt9O1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFsbE1vbnRocy5sZW5ndGg7IGkgKz0gMSkge1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGZldGNoVHJhbnNhY3Rpb25zRm9yTW9udGgocGFnZSwgYWxsTW9udGhzW2ldLCBvcHRpb25zKTtcbiAgICBhbGxSZXN1bHRzID0gYWRkUmVzdWx0KGFsbFJlc3VsdHMsIHJlc3VsdCk7XG4gIH1cblxuICBPYmplY3Qua2V5cyhhbGxSZXN1bHRzKS5mb3JFYWNoKGFjY291bnROdW1iZXIgPT4ge1xuICAgIGxldCB0eG5zID0gYWxsUmVzdWx0c1thY2NvdW50TnVtYmVyXTtcbiAgICB0eG5zID0gcHJlcGFyZVRyYW5zYWN0aW9ucyhcbiAgICAgIHR4bnMsXG4gICAgICBzdGFydE1vbWVudCxcbiAgICAgIG9wdGlvbnMuY29tYmluZUluc3RhbGxtZW50cyB8fCBmYWxzZSxcbiAgICAgIG9wdGlvbnMub3V0cHV0RGF0YT8uZW5hYmxlVHJhbnNhY3Rpb25zRmlsdGVyQnlEYXRlID8/IHRydWUsXG4gICAgKTtcbiAgICBhbGxSZXN1bHRzW2FjY291bnROdW1iZXJdID0gdHhucztcbiAgfSk7XG5cbiAgcmV0dXJuIHsgYWxsUmVzdWx0cywgaG9tZVBhZ2VDYXJkcyB9O1xufVxuXG5mdW5jdGlvbiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cyhwYWdlOiBQYWdlKTogUG9zc2libGVMb2dpblJlc3VsdHMge1xuICBjb25zdCB1cmxzOiBQb3NzaWJsZUxvZ2luUmVzdWx0cyA9IHt9O1xuICB1cmxzW0xvZ2luUmVzdWx0cy5TdWNjZXNzXSA9IFtTVUNDRVNTX1VSTF07XG4gIHVybHNbTG9naW5SZXN1bHRzLkNoYW5nZVBhc3N3b3JkXSA9IFtQQVNTV09SRF9FWFBJUkVEX1VSTF07XG4gIHVybHNbTG9naW5SZXN1bHRzLkludmFsaWRQYXNzd29yZF0gPSBbXG4gICAgYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIGVsZW1lbnRQcmVzZW50T25QYWdlKHBhZ2UsIElOVkFMSURfREVUQUlMU19TRUxFQ1RPUik7XG4gICAgfSxcbiAgXTtcbiAgdXJsc1tMb2dpblJlc3VsdHMuVW5rbm93bkVycm9yXSA9IFtcbiAgICBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gZWxlbWVudFByZXNlbnRPblBhZ2UocGFnZSwgTE9HSU5fRVJST1JfU0VMRUNUT1IpO1xuICAgIH0sXG4gIF07XG4gIHJldHVybiB1cmxzO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVMb2dpbkZpZWxkcyhjcmVkZW50aWFsczogU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMpIHtcbiAgcmV0dXJuIFtcbiAgICB7IHNlbGVjdG9yOiAnI3VzZXItbmFtZScsIHZhbHVlOiBjcmVkZW50aWFscy51c2VybmFtZSB9LFxuICAgIHsgc2VsZWN0b3I6ICcjcGFzc3dvcmQnLCB2YWx1ZTogY3JlZGVudGlhbHMucGFzc3dvcmQgfSxcbiAgXTtcbn1cblxudHlwZSBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyA9IHsgdXNlcm5hbWU6IHN0cmluZzsgcGFzc3dvcmQ6IHN0cmluZyB9O1xuXG5jbGFzcyBNYXhTY3JhcGVyIGV4dGVuZHMgQmFzZVNjcmFwZXJXaXRoQnJvd3NlcjxTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscz4ge1xuICBnZXRMb2dpbk9wdGlvbnMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKTogTG9naW5PcHRpb25zIHtcbiAgICByZXR1cm4ge1xuICAgICAgbG9naW5Vcmw6IExPR0lOX1VSTCxcbiAgICAgIGZpZWxkczogY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHMpLFxuICAgICAgc3VibWl0QnV0dG9uU2VsZWN0b3I6ICdhcHAtdXNlci1sb2dpbi1mb3JtIC5nZW5lcmFsLWJ1dHRvbi5zZW5kLW1lLWNvZGUnLFxuICAgICAgcHJlQWN0aW9uOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGlmIChhd2FpdCBlbGVtZW50UHJlc2VudE9uUGFnZSh0aGlzLnBhZ2UsICcjY2xvc2VQb3B1cCcpKSB7XG4gICAgICAgICAgYXdhaXQgY2xpY2tCdXR0b24odGhpcy5wYWdlLCAnI2Nsb3NlUG9wdXAnKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBjbGlja0J1dHRvbih0aGlzLnBhZ2UsICcucGVyc29uYWwtYXJlYSA+IGEuZ28tdG8tcGVyc29uYWwtYXJlYScpO1xuICAgICAgICBpZiAoYXdhaXQgZWxlbWVudFByZXNlbnRPblBhZ2UodGhpcy5wYWdlLCAnLmxvZ2luLWxpbmsjcHJpdmF0ZScpKSB7XG4gICAgICAgICAgYXdhaXQgY2xpY2tCdXR0b24odGhpcy5wYWdlLCAnLmxvZ2luLWxpbmsjcHJpdmF0ZScpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFRyeSB0d2ljZSBpbiBjYXNlIGl0IGNhbid0IGZpbmQgaXQgdGhlIGZpcnN0IHRpbWVcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQodGhpcy5wYWdlLCAnI2xvZ2luLXBhc3N3b3JkLWxpbmsnLCB0cnVlLCAxMDAwMCk7XG4gICAgICAgIH0gY2F0Y2gge1xuICAgICAgICAgIGF3YWl0IHNsZWVwKDEwMDApO1xuICAgICAgICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZCh0aGlzLnBhZ2UsICcjbG9naW4tcGFzc3dvcmQtbGluaycsIHRydWUsIDEwMDAwKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBjbGlja0J1dHRvbih0aGlzLnBhZ2UsICcjbG9naW4tcGFzc3dvcmQtbGluaycpO1xuICAgICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQodGhpcy5wYWdlLCAnI2xvZ2luLXBhc3N3b3JkLnRhYi1wYW5lLmFjdGl2ZSBhcHAtdXNlci1sb2dpbi1mb3JtJywgdHJ1ZSk7XG4gICAgICB9LFxuICAgICAgY2hlY2tSZWFkaW5lc3M6IGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHRoaXMucGFnZSwgJy5wZXJzb25hbC1hcmVhID4gYS5nby10by1wZXJzb25hbC1hcmVhJywgdHJ1ZSk7XG4gICAgICB9LFxuICAgICAgcG9zdEFjdGlvbjogYXN5bmMgKCkgPT4gcmVkaXJlY3RPckRpYWxvZyh0aGlzLnBhZ2UpLFxuICAgICAgcG9zc2libGVSZXN1bHRzOiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cyh0aGlzLnBhZ2UpLFxuICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcsXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIGZldGNoRGF0YSgpIHtcbiAgICBjb25zdCB7IGFsbFJlc3VsdHMsIGhvbWVQYWdlQ2FyZHMgfSA9IGF3YWl0IGZldGNoVHJhbnNhY3Rpb25zKHRoaXMucGFnZSwgdGhpcy5vcHRpb25zKTtcbiAgICBjb25zdCBhY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gT2JqZWN0LmtleXMoYWxsUmVzdWx0cykubWFwKGFjY291bnROdW1iZXIgPT4ge1xuICAgICAgY29uc3QgY2FyZCA9IGhvbWVQYWdlQ2FyZHMuZ2V0KGFjY291bnROdW1iZXIpO1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgYWNjb3VudE51bWJlcixcbiAgICAgICAgdHhuczogYWxsUmVzdWx0c1thY2NvdW50TnVtYmVyXSxcbiAgICAgICAgYmFsYW5jZTogY2FyZCA/IGdldENhcmRCYWxhbmNlKGNhcmQpIDogdW5kZWZpbmVkLFxuICAgICAgICBiYWxhbmNlRGF0ZTogY2FyZCA/IGdldENhcmRCYWxhbmNlRGF0ZShjYXJkKSA6IHVuZGVmaW5lZCxcbiAgICAgICAgY2FyZEZyYW1lOiBjYXJkPy5DcmVkaXRMaW1pdCA/PyB1bmRlZmluZWQsXG4gICAgICB9O1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBhY2NvdW50cyxcbiAgICB9O1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IE1heFNjcmFwZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7QUFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxNQUFBLEdBQUFILHNCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBRyxNQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxxQkFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssTUFBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sV0FBQSxHQUFBTixPQUFBO0FBQ0EsSUFBQU8sYUFBQSxHQUFBUCxPQUFBO0FBTUEsSUFBQVEsUUFBQSxHQUFBUixPQUFBO0FBQ0EsSUFBQVMsY0FBQSxHQUFBVCxPQUFBO0FBQ0EsSUFBQVUsdUJBQUEsR0FBQVYsT0FBQTtBQUtxQyxTQUFBRCx1QkFBQVksQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUdyQyxNQUFNRyxLQUFLLEdBQUcsSUFBQUMsZUFBUSxFQUFDLEtBQUssQ0FBQztBQXNCN0IsTUFBTUMsb0JBQW9CLEdBQUcsK0JBQStCO0FBQzVELE1BQU1DLGdCQUFnQixHQUFHLHVCQUF1QjtBQUNoRCxNQUFNQyxrQkFBa0IsR0FBRyxHQUFHRCxnQkFBZ0IsaUNBQWlDO0FBRS9FLE1BQU1FLFNBQVMsR0FBRyxHQUFHRixnQkFBZ0IsUUFBUTtBQUM3QyxNQUFNRyxvQkFBb0IsR0FBRyxHQUFHSCxnQkFBZ0IsaUJBQWlCO0FBQ2pFLE1BQU1JLFdBQVcsR0FBRyxHQUFHSixnQkFBZ0Isb0JBQW9CO0FBQUMsSUFFdkRLLFdBQVcsMEJBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQVhBLFdBQVc7RUFBWEEsV0FBVztFQUFYQSxXQUFXO0VBQUEsT0FBWEEsV0FBVztBQUFBLEVBQVhBLFdBQVc7QUEwQmhCLE1BQU1DLHdCQUF3QixHQUFHLG9CQUFvQjtBQUNyRCxNQUFNQyxvQkFBb0IsR0FBRyw2QkFBNkI7QUFvQjFELE1BQU1DLFVBQVUsR0FBRyxJQUFJQyxHQUFHLENBQWlCLENBQUM7QUFFNUMsU0FBU0MsZ0JBQWdCQSxDQUFDQyxJQUFVLEVBQUU7RUFDcEMsT0FBT0MsT0FBTyxDQUFDQyxJQUFJLENBQUMsQ0FDbEIsSUFBQUMsMkJBQWUsRUFBQ0gsSUFBSSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsQ0FBQ1gsZ0JBQWdCLEVBQUUsR0FBR0EsZ0JBQWdCLEdBQUcsQ0FBQyxDQUFDLEVBQy9FLElBQUFlLDJDQUFxQixFQUFDSixJQUFJLEVBQUVMLHdCQUF3QixFQUFFLElBQUksQ0FBQyxFQUMzRCxJQUFBUywyQ0FBcUIsRUFBQ0osSUFBSSxFQUFFSixvQkFBb0IsRUFBRSxJQUFJLENBQUMsQ0FDeEQsQ0FBQztBQUNKO0FBRUEsU0FBU1Msa0JBQWtCQSxDQUFDQyxXQUFtQixFQUFFO0VBQy9DLE1BQU1DLEtBQUssR0FBR0QsV0FBVyxDQUFDQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUM7RUFDckMsTUFBTUMsSUFBSSxHQUFHRixXQUFXLENBQUNFLElBQUksQ0FBQyxDQUFDO0VBQy9CLE1BQU1DLElBQUksR0FBRyxHQUFHRCxJQUFJLElBQUlELEtBQUssS0FBSzs7RUFFbEM7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUcsR0FBRyxHQUFHLElBQUlDLEdBQUcsQ0FBQyxHQUFHdkIsb0JBQW9CLDZEQUE2RCxDQUFDO0VBQ3pHc0IsR0FBRyxDQUFDRSxZQUFZLENBQUNDLEdBQUcsQ0FDbEIsWUFBWSxFQUNaLDJEQUEyREosSUFBSSwrRkFDakUsQ0FBQztFQUNEQyxHQUFHLENBQUNFLFlBQVksQ0FBQ0MsR0FBRyxDQUFDLG9CQUFvQixFQUFFLElBQUksQ0FBQztFQUNoRCxPQUFPSCxHQUFHLENBQUNJLFFBQVEsQ0FBQyxDQUFDO0FBQ3ZCO0FBU0EsZUFBZUMsZ0JBQWdCQSxDQUFDZixJQUFVLEVBQXNDO0VBQzlFZCxLQUFLLENBQUMsMENBQTBDLENBQUM7RUFDakQsTUFBTThCLEdBQUcsR0FBRyxNQUFNLElBQUFDLHlCQUFrQixFQUFxQmpCLElBQUksRUFBRVYsa0JBQWtCLENBQUM7RUFDbEYsTUFBTTRCLE9BQU8sR0FBRyxJQUFJcEIsR0FBRyxDQUF1QixDQUFDO0VBQy9DLElBQUlrQixHQUFHLEVBQUVHLE1BQU0sRUFBRUMsU0FBUyxFQUFFQyxLQUFLLEVBQUU7SUFDakMsS0FBSyxNQUFNQyxJQUFJLElBQUlOLEdBQUcsQ0FBQ0csTUFBTSxDQUFDQyxTQUFTLENBQUNDLEtBQUssRUFBRTtNQUM3Q0gsT0FBTyxDQUFDTCxHQUFHLENBQUNTLElBQUksQ0FBQ0MsV0FBVyxFQUFFRCxJQUFJLENBQUM7SUFDckM7RUFDRjtFQUNBLE9BQU9KLE9BQU87QUFDaEI7QUFFQSxTQUFTTSxjQUFjQSxDQUFDRixJQUFrQixFQUFzQjtFQUM5RCxJQUFJQSxJQUFJLENBQUNHLFdBQVcsSUFBSSxJQUFJLElBQUlILElBQUksQ0FBQ0ksU0FBUyxJQUFJLElBQUksRUFBRSxPQUFPQyxTQUFTO0VBQ3hFLE1BQU1DLE9BQU8sR0FBRyxFQUFFTixJQUFJLENBQUNHLFdBQVcsR0FBR0gsSUFBSSxDQUFDSSxTQUFTLENBQUM7RUFDcEQsT0FBT0csSUFBSSxDQUFDQyxLQUFLLENBQUNGLE9BQU8sR0FBRyxHQUFHLENBQUMsR0FBRyxHQUFHO0FBQ3hDO0FBRUEsU0FBU0csa0JBQWtCQSxDQUFDVCxJQUFrQixFQUFzQjtFQUNsRSxNQUFNVSxXQUFXLEdBQUdWLElBQUksQ0FBQ1csWUFBWSxFQUFFQyxJQUFJLENBQUNDLEtBQUssSUFBSUEsS0FBSyxDQUFDQyxjQUFjLENBQUNDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztFQUN4RixPQUFPTCxXQUFXLEdBQUdBLFdBQVcsQ0FBQ00sSUFBSSxHQUFHWCxTQUFTO0FBQ25EO0FBRUEsZUFBZVksY0FBY0EsQ0FBQ3ZDLElBQVUsRUFBRTtFQUN4Q2QsS0FBSyxDQUFDLG9CQUFvQixDQUFDO0VBQzNCLE1BQU04QixHQUFHLEdBQUcsTUFBTSxJQUFBQyx5QkFBa0IsRUFBc0JqQixJQUFJLEVBQUUsR0FBR1osb0JBQW9CLDZCQUE2QixDQUFDO0VBQ3JILElBQUk0QixHQUFHLElBQUl3QixLQUFLLENBQUNDLE9BQU8sQ0FBQ3pCLEdBQUcsQ0FBQzBCLE1BQU0sQ0FBQyxFQUFFO0lBQ3BDeEQsS0FBSyxDQUFDLEdBQUc4QixHQUFHLENBQUMwQixNQUFNLENBQUNDLE1BQU0sb0JBQW9CLENBQUM7SUFDL0MzQixHQUFHLENBQUMwQixNQUFNLEVBQUVFLE9BQU8sQ0FBQyxDQUFDO01BQUVDLEVBQUU7TUFBRUM7SUFBSyxDQUFDLEtBQUtqRCxVQUFVLENBQUNnQixHQUFHLENBQUNnQyxFQUFFLEVBQUVDLElBQUksQ0FBQyxDQUFDO0VBQ2pFO0FBQ0Y7QUFFQSxTQUFTQyxrQkFBa0JBLENBQUNDLFFBQWdCLEVBQUVDLFVBQWtCLEVBQUU7RUFDaEUsTUFBTUMsbUJBQW1CLEdBQUdGLFFBQVEsQ0FBQ0csT0FBTyxDQUFDLElBQUksRUFBRSxHQUFHLENBQUMsQ0FBQ0MsSUFBSSxDQUFDLENBQWdCO0VBQzdFLFFBQVFGLG1CQUFtQjtJQUN6QixLQUFLeEQsV0FBVyxDQUFDMkQsZUFBZTtJQUNoQyxLQUFLM0QsV0FBVyxDQUFDNEQsTUFBTTtJQUN2QixLQUFLNUQsV0FBVyxDQUFDNkQsYUFBYTtJQUM5QixLQUFLN0QsV0FBVyxDQUFDOEQsaUJBQWlCO0lBQ2xDLEtBQUs5RCxXQUFXLENBQUMrRCxnQkFBZ0I7SUFDakMsS0FBSy9ELFdBQVcsQ0FBQ2dFLHVCQUF1QjtJQUN4QyxLQUFLaEUsV0FBVyxDQUFDaUUsY0FBYztJQUMvQixLQUFLakUsV0FBVyxDQUFDa0UsNEJBQTRCO0lBQzdDLEtBQUtsRSxXQUFXLENBQUNtRSxjQUFjO0lBQy9CLEtBQUtuRSxXQUFXLENBQUNvRSxrQkFBa0I7SUFDbkMsS0FBS3BFLFdBQVcsQ0FBQ3FFLG1CQUFtQjtJQUNwQyxLQUFLckUsV0FBVyxDQUFDc0Usa0JBQWtCO0lBQ25DLEtBQUt0RSxXQUFXLENBQUN1RSxnQkFBZ0I7SUFDakMsS0FBS3ZFLFdBQVcsQ0FBQ3dFLHlCQUF5QjtJQUMxQyxLQUFLeEUsV0FBVyxDQUFDeUUsZ0NBQWdDO0lBQ2pELEtBQUt6RSxXQUFXLENBQUMwRSxlQUFlO0lBQ2hDLEtBQUsxRSxXQUFXLENBQUMyRSxjQUFjO0lBQy9CLEtBQUszRSxXQUFXLENBQUM0RSxjQUFjO0lBQy9CLEtBQUs1RSxXQUFXLENBQUM2RSxjQUFjO0lBQy9CLEtBQUs3RSxXQUFXLENBQUM4RSx5QkFBeUI7TUFDeEMsT0FBT0MsK0JBQWdCLENBQUNuQixNQUFNO0lBQ2hDLEtBQUs1RCxXQUFXLENBQUNnRixZQUFZO0lBQzdCLEtBQUtoRixXQUFXLENBQUNpRixNQUFNO0lBQ3ZCLEtBQUtqRixXQUFXLENBQUNrRixxQkFBcUI7TUFDcEMsT0FBT0gsK0JBQWdCLENBQUNDLFlBQVk7SUFDdEM7TUFDRSxRQUFRekIsVUFBVTtRQUNoQixLQUFLLENBQUM7UUFDTixLQUFLLENBQUM7VUFDSixPQUFPd0IsK0JBQWdCLENBQUNDLFlBQVk7UUFDdEMsS0FBSyxDQUFDO1VBQ0osT0FBT0QsK0JBQWdCLENBQUNuQixNQUFNO1FBQ2hDO1VBQ0UsTUFBTSxJQUFJdUIsS0FBSyxDQUFDLDRCQUE0QjNCLG1CQUFtQixFQUFZLENBQUM7TUFDaEY7RUFDSjtBQUNGO0FBRUEsU0FBUzRCLG1CQUFtQkEsQ0FBQ0MsUUFBZ0IsRUFBRTtFQUM3QyxJQUFJLENBQUNBLFFBQVEsRUFBRTtJQUNiLE9BQU9wRCxTQUFTO0VBQ2xCO0VBQ0EsTUFBTXFELE9BQU8sR0FBR0QsUUFBUSxDQUFDRSxLQUFLLENBQUMsTUFBTSxDQUFDO0VBQ3RDLElBQUksQ0FBQ0QsT0FBTyxJQUFJQSxPQUFPLENBQUNyQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO0lBQ2xDLE9BQU9oQixTQUFTO0VBQ2xCO0VBRUEsT0FBTztJQUNMdUQsTUFBTSxFQUFFQyxRQUFRLENBQUNILE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUM7SUFDaENJLEtBQUssRUFBRUQsUUFBUSxDQUFDSCxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtFQUNoQyxDQUFDO0FBQ0g7QUFFQSxTQUFTSyxrQkFBa0JBLENBQUNDLFVBQXlCLEVBQUU7RUFDckQsUUFBUUEsVUFBVTtJQUNoQixLQUFLLEdBQUc7TUFDTixPQUFPQywwQkFBZTtJQUN4QixLQUFLLEdBQUc7TUFDTixPQUFPQywwQkFBZTtJQUN4QixLQUFLLEdBQUc7TUFDTixPQUFPQyx3QkFBYTtJQUN0QjtNQUNFLE9BQU85RCxTQUFTO0VBQ3BCO0FBQ0Y7QUFFTyxTQUFTK0QsT0FBT0EsQ0FBQztFQUN0QlgsUUFBUTtFQUNSWSwrQkFBK0I7RUFDL0JDO0FBQ2lHLENBQUMsRUFBRTtFQUNwRyxJQUFJRCwrQkFBK0IsRUFBRTtJQUNuQyxNQUFNRSxJQUFJLEdBQUdkLFFBQVEsR0FBRyxHQUFHQSxRQUFRLElBQUlZLCtCQUErQixFQUFFLEdBQUdBLCtCQUErQjtJQUMxRyxPQUFPQyxvQkFBb0IsR0FBRyxHQUFHQyxJQUFJLEtBQUtELG9CQUFvQixFQUFFLEdBQUdDLElBQUk7RUFDekU7RUFFQSxPQUFPZCxRQUFRO0FBQ2pCO0FBRUEsU0FBU2UsY0FBY0EsQ0FBQ0MsY0FBa0MsRUFBRUMsT0FBd0IsRUFBZTtFQUNqRyxNQUFNQyxTQUFTLEdBQUdGLGNBQWMsQ0FBQ0csV0FBVyxLQUFLLElBQUk7RUFDckQsTUFBTUMsYUFBYSxHQUFHLElBQUFDLGVBQU0sRUFBQ0gsU0FBUyxHQUFHRixjQUFjLENBQUNNLFlBQVksR0FBR04sY0FBYyxDQUFDRyxXQUFXLENBQUMsQ0FBQ0ksV0FBVyxDQUFDLENBQUM7RUFDaEgsTUFBTUMsTUFBTSxHQUFHTixTQUFTLEdBQUdPLGtDQUFtQixDQUFDQyxPQUFPLEdBQUdELGtDQUFtQixDQUFDRSxTQUFTO0VBRXRGLE1BQU1DLFlBQVksR0FBRzdCLG1CQUFtQixDQUFDaUIsY0FBYyxDQUFDaEIsUUFBUSxDQUFDO0VBQ2pFLE1BQU02QixVQUFVLEdBQUdELFlBQVksR0FDM0IsR0FBR1osY0FBYyxDQUFDYyxRQUFRLEVBQUVDLEdBQUcsSUFBSUgsWUFBWSxDQUFDekIsTUFBTSxFQUFFLEdBQ3hEYSxjQUFjLENBQUNjLFFBQVEsRUFBRUMsR0FBRztFQUVoQyxNQUFNcEUsTUFBbUIsR0FBRztJQUMxQnFFLElBQUksRUFBRWhFLGtCQUFrQixDQUFDZ0QsY0FBYyxDQUFDL0MsUUFBUSxFQUFFK0MsY0FBYyxDQUFDOUMsVUFBVSxDQUFDO0lBQzVFeEMsSUFBSSxFQUFFLElBQUEyRixlQUFNLEVBQUNMLGNBQWMsQ0FBQ00sWUFBWSxDQUFDLENBQUNDLFdBQVcsQ0FBQyxDQUFDO0lBQ3ZESCxhQUFhO0lBQ2JhLGNBQWMsRUFBRSxDQUFDakIsY0FBYyxDQUFDaUIsY0FBYztJQUM5Q0MsZ0JBQWdCLEVBQUVsQixjQUFjLENBQUNrQixnQkFBZ0I7SUFDakRDLGFBQWEsRUFBRSxDQUFDbkIsY0FBYyxDQUFDb0IsbUJBQW1CO0lBQ2xEQyxlQUFlLEVBQUUvQixrQkFBa0IsQ0FBQ1UsY0FBYyxDQUFDc0IsZUFBZSxDQUFDO0lBQ25FQyxXQUFXLEVBQUV2QixjQUFjLENBQUN3QixZQUFZLENBQUNuRSxJQUFJLENBQUMsQ0FBQztJQUMvQ3lDLElBQUksRUFBRUgsT0FBTyxDQUFDS