israeli-bank-scrapers-core
Version:
Provide scrapers for all major Israeli banks and credit card companies
254 lines (248 loc) • 46.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _moment = _interopRequireDefault(require("moment"));
var _constants = require("../constants");
var _debug = require("../helpers/debug");
var _elementsInteractions = require("../helpers/elements-interactions");
var _fetch = require("../helpers/fetch");
var _transactions = require("../helpers/transactions");
var _navigation = require("../helpers/navigation");
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)('leumi');
const BASE_URL = 'https://hb2.bankleumi.co.il';
const LOGIN_URL = 'https://www.leumi.co.il/he';
const TRANSACTIONS_URL = `${BASE_URL}/eBanking/SO/SPA.aspx#/ts/BusinessAccountTrx?WidgetPar=1`;
const FILTERED_TRANSACTIONS_URL = `${BASE_URL}/ChannelWCF/Broker.svc/ProcessRequest?moduleName=UC_SO_27_GetBusinessAccountTrx`;
const SAVINGS_URL = `${BASE_URL}/uiapiproxy/v1/digital-retails/mobile/accounts/1/Deposits?operationList=true`;
const DATE_FORMAT = 'DD.MM.YY';
const ACCOUNT_BLOCKED_MSG = 'המנוי חסום';
const INVALID_PASSWORD_MSG = 'אחד או יותר מפרטי ההזדהות שמסרת שגויים. ניתן לנסות שוב';
const CHANGE_PASSWORD_MODAL_SELECTOR = 'form input[name="newPwd"]';
function getPossibleLoginResults() {
const urls = {
[_baseScraperWithBrowser.LoginResults.Success]: [/ebanking\/SO\/SPA.aspx/i],
[_baseScraperWithBrowser.LoginResults.InvalidPassword]: [async options => {
if (!options || !options.page) {
throw new Error('missing page options argument');
}
const errorMessage = await (0, _elementsInteractions.pageEvalAll)(options.page, 'svg#Capa_1', '', element => {
return element[0]?.parentElement?.children[1]?.innerText;
});
return errorMessage?.startsWith(INVALID_PASSWORD_MSG);
}],
[_baseScraperWithBrowser.LoginResults.AccountBlocked]: [
// NOTICE - might not be relevant starting the Leumi re-design during 2022 Sep
async options => {
if (!options || !options.page) {
throw new Error('missing page options argument');
}
const errorMessage = await (0, _elementsInteractions.pageEvalAll)(options.page, '.errHeader', '', label => {
return label[0]?.innerText;
});
return errorMessage?.startsWith(ACCOUNT_BLOCKED_MSG);
}],
[_baseScraperWithBrowser.LoginResults.ChangePassword]: [async options => {
if (!options || !options.page) {
throw new Error('missing page options argument');
}
return !!(await options.page.$(CHANGE_PASSWORD_MODAL_SELECTOR));
}]
};
return urls;
}
function createLoginFields(credentials) {
return [{
selector: 'input[placeholder="שם משתמש"]',
value: credentials.username
}, {
selector: 'input[placeholder="סיסמה"]',
value: credentials.password
}];
}
function extractTransactionsFromPage(transactions, status, options) {
if (transactions === null || transactions.length === 0) {
return [];
}
const result = transactions.map(rawTransaction => {
const date = (0, _moment.default)(rawTransaction.DateUTC).milliseconds(0).toISOString();
const newTransaction = {
status,
type: _transactions2.TransactionTypes.Normal,
date,
processedDate: date,
description: rawTransaction.Description || '',
identifier: rawTransaction.ReferenceNumberLong,
memo: rawTransaction.AdditionalData || '',
originalCurrency: _constants.SHEKEL_CURRENCY,
chargedAmount: rawTransaction.Amount,
originalAmount: rawTransaction.Amount
};
if (options?.includeRawTransaction) {
newTransaction.rawTransaction = (0, _transactions.getRawTransaction)(rawTransaction);
}
return newTransaction;
});
return result;
}
function hangProcess(timeout) {
return new Promise(resolve => {
setTimeout(() => {
resolve();
}, timeout);
});
}
async function clickByXPath(page, xpath) {
await page.waitForSelector(xpath, {
timeout: 30000,
visible: true
});
const elm = await page.$$(xpath);
await elm[0].click();
}
function removeSpecialCharacters(str) {
return str.replace(/[^0-9/-]/g, '');
}
async function fetchTransactionsForAccount(page, startDate, accountId, options) {
// DEVELOPER NOTICE the account number received from the server is being altered at
// runtime for some accounts after 1-2 seconds so we need to hang the process for a short while.
await hangProcess(4000);
await (0, _elementsInteractions.waitUntilElementFound)(page, 'button[title="חיפוש מתקדם"]', true);
await (0, _elementsInteractions.clickButton)(page, 'button[title="חיפוש מתקדם"]');
await (0, _elementsInteractions.waitUntilElementFound)(page, 'bll-radio-button', true);
await (0, _elementsInteractions.clickButton)(page, 'bll-radio-button:not([checked])');
await (0, _elementsInteractions.waitUntilElementFound)(page, 'input[formcontrolname="txtInputFrom"]', true);
await (0, _elementsInteractions.fillInput)(page, 'input[formcontrolname="txtInputFrom"]', startDate.format(DATE_FORMAT));
// we must blur the from control otherwise the search will use the previous value
await page.focus("button[aria-label='סנן']");
await (0, _elementsInteractions.clickButton)(page, "button[aria-label='סנן']");
const finalResponse = await page.waitForResponse(response => {
return response.url() === FILTERED_TRANSACTIONS_URL && response.request().method() === 'POST';
});
const responseJson = await finalResponse.json();
const accountNumber = accountId.replace('/', '_').replace(/[^\d-_]/g, '');
const response = JSON.parse(responseJson.jsonResp);
const pendingTransactions = response.TodayTransactionsItems;
const transactions = response.HistoryTransactionsItems;
const balance = response.BalanceDisplay ? parseFloat(response.BalanceDisplay) : undefined;
const pendingTxns = extractTransactionsFromPage(pendingTransactions, _transactions2.TransactionStatuses.Pending, options);
const completedTxns = extractTransactionsFromPage(transactions, _transactions2.TransactionStatuses.Completed, options);
const txns = [...pendingTxns, ...completedTxns];
return {
accountNumber,
balance,
txns
};
}
async function fetchRegularAccounts(scraper, page, startDate, options) {
await scraper.navigateTo(TRANSACTIONS_URL);
return fetchTransactions(page, startDate, options);
}
async function getSavingsAccounts(page, accountId) {
debug('========== FETCHING SAVINGS ACCOUNTS ==========');
debug('Account: %s', accountId);
const accounts = [];
try {
debug('Trying savings URL: %s', SAVINGS_URL);
const savingsData = await (0, _fetch.fetchGetWithinPage)(page, SAVINGS_URL);
if (!savingsData || !savingsData.depositsAndSavingsItems || savingsData.depositsAndSavingsItems.length === 0) {
debug('No savings accounts found for account %s', accountId);
return [];
}
debug('✓ Found %d savings deposits', savingsData.depositsAndSavingsItems.length);
// Create a separate account for each individual deposit
for (const deposit of savingsData.depositsAndSavingsItems) {
const balance = deposit.currentBalance;
const savingsAccountNumber = `${accountId}-${deposit.depositId}`;
accounts.push({
accountNumber: savingsAccountNumber,
savingsAccount: true,
balance,
txns: []
});
debug('Added savings account %s with balance %s (product: %s)', savingsAccountNumber, balance, deposit.productName);
}
} catch (error) {
debug(' - Error fetching savings accounts: %s', error);
}
debug('Returning %d savings accounts', accounts.length);
return accounts;
}
async function fetchTransactions(page, startDate, options) {
const accounts = [];
// DEVELOPER NOTICE the account number received from the server is being altered at
// runtime for some accounts after 1-2 seconds so we need to hang the process for a short while.
await hangProcess(4000);
const accountsIds = await page.evaluate(() => Array.from(document.querySelectorAll('app-masked-number-combo span.display-number-li'), e => e.textContent));
// due to a bug, the altered value might include undesired signs like & that should be removed
if (!accountsIds.length) {
throw new Error('Failed to extract or parse the account number');
}
for (const accountId of accountsIds) {
if (accountsIds.length > 1) {
// get list of accounts and check accountId
await clickByXPath(page, 'xpath///*[contains(@class, "number") and contains(@class, "combo-inner")]');
await clickByXPath(page, `xpath///span[contains(text(), '${accountId}')]`);
}
accounts.push(await fetchTransactionsForAccount(page, startDate, removeSpecialCharacters(accountId), options));
}
return accounts;
}
async function fetchSavingsAccounts(page, regularAccounts) {
const allSavingsAccounts = [];
const regularAccountCount = regularAccounts.length;
for (let i = 0; i < regularAccountCount; i++) {
try {
const savingsAccounts = await getSavingsAccounts(page, regularAccounts[i].accountNumber);
allSavingsAccounts.push(...savingsAccounts);
debug('Added %d savings accounts to results', savingsAccounts.length);
} catch (error) {
debug('Error fetching savings accounts for %s: %s', regularAccounts[i].accountNumber, error);
}
}
return allSavingsAccounts;
}
async function navigateToLogin(page) {
debug('navigating directly to login page');
await page.goto('https://hb2.bankleumi.co.il/authenticate/logon');
debug('waiting for page to be loaded (networkidle2)');
await (0, _navigation.waitForNavigation)(page, {
waitUntil: 'networkidle2'
});
debug('waiting for components of login to enter credentials');
await Promise.all([(0, _elementsInteractions.waitUntilElementFound)(page, 'input[placeholder="שם משתמש"]', true), (0, _elementsInteractions.waitUntilElementFound)(page, 'input[placeholder="סיסמה"]', true), (0, _elementsInteractions.waitUntilElementFound)(page, 'button[type="submit"]', true)]);
}
async function waitForPostLogin(page) {
await Promise.race([(0, _elementsInteractions.waitUntilElementFound)(page, 'a[title="דלג לחשבון"]', true, 60000), (0, _elementsInteractions.waitUntilElementFound)(page, 'div.main-content', false, 60000), page.waitForSelector(`xpath//div[contains(string(),"${INVALID_PASSWORD_MSG}")]`), (0, _elementsInteractions.waitUntilElementFound)(page, CHANGE_PASSWORD_MODAL_SELECTOR, true, 60000)]);
}
class LeumiScraper extends _baseScraperWithBrowser.BaseScraperWithBrowser {
getLoginOptions(credentials) {
return {
loginUrl: LOGIN_URL,
fields: createLoginFields(credentials),
submitButtonSelector: "button[type='submit']",
checkReadiness: async () => navigateToLogin(this.page),
postAction: async () => waitForPostLogin(this.page),
possibleResults: getPossibleLoginResults()
};
}
async fetchData() {
const minimumStartMoment = (0, _moment.default)().subtract(3, 'years').add(1, 'day');
const defaultStartMoment = (0, _moment.default)().subtract(1, 'years').add(1, 'day');
const startDate = this.options.startDate || defaultStartMoment.toDate();
const startMoment = _moment.default.max(minimumStartMoment, (0, _moment.default)(startDate));
const accounts = await fetchRegularAccounts(this, this.page, startMoment, this.options);
const savingsAccounts = await fetchSavingsAccounts(this.page, accounts);
accounts.push(...savingsAccounts);
return {
success: true,
accounts
};
}
}
var _default = exports.default = LeumiScraper;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2RlYnVnIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX2ZldGNoIiwiX3RyYW5zYWN0aW9ucyIsIl9uYXZpZ2F0aW9uIiwiX3RyYW5zYWN0aW9uczIiLCJfYmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImRlYnVnIiwiZ2V0RGVidWciLCJCQVNFX1VSTCIsIkxPR0lOX1VSTCIsIlRSQU5TQUNUSU9OU19VUkwiLCJGSUxURVJFRF9UUkFOU0FDVElPTlNfVVJMIiwiU0FWSU5HU19VUkwiLCJEQVRFX0ZPUk1BVCIsIkFDQ09VTlRfQkxPQ0tFRF9NU0ciLCJJTlZBTElEX1BBU1NXT1JEX01TRyIsIkNIQU5HRV9QQVNTV09SRF9NT0RBTF9TRUxFQ1RPUiIsImdldFBvc3NpYmxlTG9naW5SZXN1bHRzIiwidXJscyIsIkxvZ2luUmVzdWx0cyIsIlN1Y2Nlc3MiLCJJbnZhbGlkUGFzc3dvcmQiLCJvcHRpb25zIiwicGFnZSIsIkVycm9yIiwiZXJyb3JNZXNzYWdlIiwicGFnZUV2YWxBbGwiLCJlbGVtZW50IiwicGFyZW50RWxlbWVudCIsImNoaWxkcmVuIiwiaW5uZXJUZXh0Iiwic3RhcnRzV2l0aCIsIkFjY291bnRCbG9ja2VkIiwibGFiZWwiLCJDaGFuZ2VQYXNzd29yZCIsIiQiLCJjcmVhdGVMb2dpbkZpZWxkcyIsImNyZWRlbnRpYWxzIiwic2VsZWN0b3IiLCJ2YWx1ZSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJleHRyYWN0VHJhbnNhY3Rpb25zRnJvbVBhZ2UiLCJ0cmFuc2FjdGlvbnMiLCJzdGF0dXMiLCJsZW5ndGgiLCJyZXN1bHQiLCJtYXAiLCJyYXdUcmFuc2FjdGlvbiIsImRhdGUiLCJtb21lbnQiLCJEYXRlVVRDIiwibWlsbGlzZWNvbmRzIiwidG9JU09TdHJpbmciLCJuZXdUcmFuc2FjdGlvbiIsInR5cGUiLCJUcmFuc2FjdGlvblR5cGVzIiwiTm9ybWFsIiwicHJvY2Vzc2VkRGF0ZSIsImRlc2NyaXB0aW9uIiwiRGVzY3JpcHRpb24iLCJpZGVudGlmaWVyIiwiUmVmZXJlbmNlTnVtYmVyTG9uZyIsIm1lbW8iLCJBZGRpdGlvbmFsRGF0YSIsIm9yaWdpbmFsQ3VycmVuY3kiLCJTSEVLRUxfQ1VSUkVOQ1kiLCJjaGFyZ2VkQW1vdW50IiwiQW1vdW50Iiwib3JpZ2luYWxBbW91bnQiLCJpbmNsdWRlUmF3VHJhbnNhY3Rpb24iLCJnZXRSYXdUcmFuc2FjdGlvbiIsImhhbmdQcm9jZXNzIiwidGltZW91dCIsIlByb21pc2UiLCJyZXNvbHZlIiwic2V0VGltZW91dCIsImNsaWNrQnlYUGF0aCIsInhwYXRoIiwid2FpdEZvclNlbGVjdG9yIiwidmlzaWJsZSIsImVsbSIsIiQkIiwiY2xpY2siLCJyZW1vdmVTcGVjaWFsQ2hhcmFjdGVycyIsInN0ciIsInJlcGxhY2UiLCJmZXRjaFRyYW5zYWN0aW9uc0ZvckFjY291bnQiLCJzdGFydERhdGUiLCJhY2NvdW50SWQiLCJ3YWl0VW50aWxFbGVtZW50Rm91bmQiLCJjbGlja0J1dHRvbiIsImZpbGxJbnB1dCIsImZvcm1hdCIsImZvY3VzIiwiZmluYWxSZXNwb25zZSIsIndhaXRGb3JSZXNwb25zZSIsInJlc3BvbnNlIiwidXJsIiwicmVxdWVzdCIsIm1ldGhvZCIsInJlc3BvbnNlSnNvbiIsImpzb24iLCJhY2NvdW50TnVtYmVyIiwiSlNPTiIsInBhcnNlIiwianNvblJlc3AiLCJwZW5kaW5nVHJhbnNhY3Rpb25zIiwiVG9kYXlUcmFuc2FjdGlvbnNJdGVtcyIsIkhpc3RvcnlUcmFuc2FjdGlvbnNJdGVtcyIsImJhbGFuY2UiLCJCYWxhbmNlRGlzcGxheSIsInBhcnNlRmxvYXQiLCJ1bmRlZmluZWQiLCJwZW5kaW5nVHhucyIsIlRyYW5zYWN0aW9uU3RhdHVzZXMiLCJQZW5kaW5nIiwiY29tcGxldGVkVHhucyIsIkNvbXBsZXRlZCIsInR4bnMiLCJmZXRjaFJlZ3VsYXJBY2NvdW50cyIsInNjcmFwZXIiLCJuYXZpZ2F0ZVRvIiwiZmV0Y2hUcmFuc2FjdGlvbnMiLCJnZXRTYXZpbmdzQWNjb3VudHMiLCJhY2NvdW50cyIsInNhdmluZ3NEYXRhIiwiZmV0Y2hHZXRXaXRoaW5QYWdlIiwiZGVwb3NpdHNBbmRTYXZpbmdzSXRlbXMiLCJkZXBvc2l0IiwiY3VycmVudEJhbGFuY2UiLCJzYXZpbmdzQWNjb3VudE51bWJlciIsImRlcG9zaXRJZCIsInB1c2giLCJzYXZpbmdzQWNjb3VudCIsInByb2R1Y3ROYW1lIiwiZXJyb3IiLCJhY2NvdW50c0lkcyIsImV2YWx1YXRlIiwiQXJyYXkiLCJmcm9tIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yQWxsIiwidGV4dENvbnRlbnQiLCJmZXRjaFNhdmluZ3NBY2NvdW50cyIsInJlZ3VsYXJBY2NvdW50cyIsImFsbFNhdmluZ3NBY2NvdW50cyIsInJlZ3VsYXJBY2NvdW50Q291bnQiLCJpIiwic2F2aW5nc0FjY291bnRzIiwibmF2aWdhdGVUb0xvZ2luIiwiZ290byIsIndhaXRGb3JOYXZpZ2F0aW9uIiwid2FpdFVudGlsIiwiYWxsIiwid2FpdEZvclBvc3RMb2dpbiIsInJhY2UiLCJMZXVtaVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiZ2V0TG9naW5PcHRpb25zIiwibG9naW5VcmwiLCJmaWVsZHMiLCJzdWJtaXRCdXR0b25TZWxlY3RvciIsImNoZWNrUmVhZGluZXNzIiwicG9zdEFjdGlvbiIsInBvc3NpYmxlUmVzdWx0cyIsImZldGNoRGF0YSIsIm1pbmltdW1TdGFydE1vbWVudCIsInN1YnRyYWN0IiwiYWRkIiwiZGVmYXVsdFN0YXJ0TW9tZW50IiwidG9EYXRlIiwic3RhcnRNb21lbnQiLCJtYXgiLCJzdWNjZXNzIiwiX2RlZmF1bHQiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmFwZXJzL2xldW1pLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBtb21lbnQsIHsgdHlwZSBNb21lbnQgfSBmcm9tICdtb21lbnQnO1xuaW1wb3J0IHsgdHlwZSBQYWdlIH0gZnJvbSAncHVwcGV0ZWVyLWNvcmUnO1xuaW1wb3J0IHsgU0hFS0VMX0NVUlJFTkNZIH0gZnJvbSAnLi4vY29uc3RhbnRzJztcbmltcG9ydCB7IGdldERlYnVnIH0gZnJvbSAnLi4vaGVscGVycy9kZWJ1Zyc7XG5pbXBvcnQgeyBjbGlja0J1dHRvbiwgZmlsbElucHV0LCBwYWdlRXZhbEFsbCwgd2FpdFVudGlsRWxlbWVudEZvdW5kIH0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgZmV0Y2hHZXRXaXRoaW5QYWdlIH0gZnJvbSAnLi4vaGVscGVycy9mZXRjaCc7XG5pbXBvcnQgeyBnZXRSYXdUcmFuc2FjdGlvbiB9IGZyb20gJy4uL2hlbHBlcnMvdHJhbnNhY3Rpb25zJztcbmltcG9ydCB7IHdhaXRGb3JOYXZpZ2F0aW9uIH0gZnJvbSAnLi4vaGVscGVycy9uYXZpZ2F0aW9uJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uU3RhdHVzZXMsIFRyYW5zYWN0aW9uVHlwZXMsIHR5cGUgVHJhbnNhY3Rpb24sIHR5cGUgVHJhbnNhY3Rpb25zQWNjb3VudCB9IGZyb20gJy4uL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQgeyBCYXNlU2NyYXBlcldpdGhCcm93c2VyLCBMb2dpblJlc3VsdHMsIHR5cGUgTG9naW5PcHRpb25zIH0gZnJvbSAnLi9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyJztcbmltcG9ydCB7IHR5cGUgU2NyYXBlck9wdGlvbnMsIHR5cGUgU2NyYXBlclNjcmFwaW5nUmVzdWx0IH0gZnJvbSAnLi9pbnRlcmZhY2UnO1xuXG5jb25zdCBkZWJ1ZyA9IGdldERlYnVnKCdsZXVtaScpO1xuY29uc3QgQkFTRV9VUkwgPSAnaHR0cHM6Ly9oYjIuYmFua2xldW1pLmNvLmlsJztcbmNvbnN0IExPR0lOX1VSTCA9ICdodHRwczovL3d3dy5sZXVtaS5jby5pbC9oZSc7XG5jb25zdCBUUkFOU0FDVElPTlNfVVJMID0gYCR7QkFTRV9VUkx9L2VCYW5raW5nL1NPL1NQQS5hc3B4Iy90cy9CdXNpbmVzc0FjY291bnRUcng/V2lkZ2V0UGFyPTFgO1xuY29uc3QgRklMVEVSRURfVFJBTlNBQ1RJT05TX1VSTCA9IGAke0JBU0VfVVJMfS9DaGFubmVsV0NGL0Jyb2tlci5zdmMvUHJvY2Vzc1JlcXVlc3Q/bW9kdWxlTmFtZT1VQ19TT18yN19HZXRCdXNpbmVzc0FjY291bnRUcnhgO1xuY29uc3QgU0FWSU5HU19VUkwgPSBgJHtCQVNFX1VSTH0vdWlhcGlwcm94eS92MS9kaWdpdGFsLXJldGFpbHMvbW9iaWxlL2FjY291bnRzLzEvRGVwb3NpdHM/b3BlcmF0aW9uTGlzdD10cnVlYDtcblxuY29uc3QgREFURV9GT1JNQVQgPSAnREQuTU0uWVknO1xuY29uc3QgQUNDT1VOVF9CTE9DS0VEX01TRyA9ICfXlNee16DXldeZINeX16HXldedJztcbmNvbnN0IElOVkFMSURfUEFTU1dPUkRfTVNHID0gJ9eQ15fXkyDXkNeVINeZ15XXqteoINee16TXqNeY15kg15TXlNeW15PXlNeV16og16nXnteh16jXqiDXqdeS15XXmdeZ150uINeg15nXqtefINec16DXodeV16og16nXldeRJztcbmNvbnN0IENIQU5HRV9QQVNTV09SRF9NT0RBTF9TRUxFQ1RPUiA9ICdmb3JtIGlucHV0W25hbWU9XCJuZXdQd2RcIl0nO1xuXG5pbnRlcmZhY2UgU2F2aW5nc0RlcG9zaXRJdGVtIHtcbiAgaW5kZXg6IHN0cmluZztcbiAgZGVwb3NpdElkOiBzdHJpbmc7XG4gIGRlcG9zaXRJbmRleDogbnVtYmVyO1xuICBkZXBvc2l0U291cmNlSWQ6IHN0cmluZztcbiAgdHlwZTogbnVtYmVyO1xuICBkaXNwbGF5TmFtZTogc3RyaW5nO1xuICBwcm9kdWN0TmFtZTogc3RyaW5nO1xuICBmcmllbmRseUFjY291bnROYW1lOiBzdHJpbmc7XG4gIGRlZXBMaW5rOiBzdHJpbmc7XG4gIGlzRm9yZWNsb3NlZDogYm9vbGVhbjtcbiAgYXNPZkRhdGU6IHN0cmluZztcbiAgY3JlYXRlRGF0ZTogc3RyaW5nO1xuICBleGl0UG9pbnREYXRlOiBzdHJpbmc7XG4gIGN1cnJlbnRCYWxhbmNlOiBudW1iZXI7XG4gIGluaXRpYWxBbW91bnQ6IG51bWJlciB8IG51bGw7XG4gIGluc3RhbGxtZW50c1NhdmluZ0ZsYWc6IGJvb2xlYW47XG4gIG1hcmdpblJhdGU6IHN0cmluZztcbiAgcHJvZHVjdEludGVyZXN0VHlwZTogc3RyaW5nIHwgbnVsbDtcbiAgcHJvZHVjdExpbmthZ2VUeXBlOiBzdHJpbmcgfCBudWxsO1xuICBzb3VyY2VTeXN0ZW06IHN0cmluZztcbiAgZGVwb3NpdE51bWJlcjogc3RyaW5nO1xuICByZWxhdGVkQWNjb3VudE51bWJlcjogc3RyaW5nO1xuICB3aXRoZHJhd2FsUmVxdWVzdFRleHQ6IHN0cmluZyB8IG51bGw7XG4gIFdpdGhkcmF3YWxBdmFpbGFibGVGcmVxdWVuY3k6IHN0cmluZyB8IG51bGw7XG4gIGRlcG9zaXRPcGVyYXRpb25zSXRlbXM6IGFueVtdO1xufVxuXG5pbnRlcmZhY2UgU2F2aW5nc0FjY291bnREYXRhIHtcbiAgdG90YWxEZXBvc2l0c0FuZFNhdmluZ3NCYWxhbmNlOiBudW1iZXI7XG4gIHByZXZpb3VzQnVzaW5lc3NEYXlEYXRlOiBzdHJpbmc7XG4gIGRlcG9zaXRzQW5kU2F2aW5nc0l0ZW1zOiBTYXZpbmdzRGVwb3NpdEl0ZW1bXTtcbiAgb3BlcmF0aW9uc0l0ZW1zVG90YWw6IHN0cmluZztcbiAgb3BlcmF0aW9uc0xpc3RJdGVtczogYW55W107XG59XG5cbmZ1bmN0aW9uIGdldFBvc3NpYmxlTG9naW5SZXN1bHRzKCkge1xuICBjb25zdCB1cmxzOiBMb2dpbk9wdGlvbnNbJ3Bvc3NpYmxlUmVzdWx0cyddID0ge1xuICAgIFtMb2dpblJlc3VsdHMuU3VjY2Vzc106IFsvZWJhbmtpbmdcXC9TT1xcL1NQQS5hc3B4L2ldLFxuICAgIFtMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkXTogW1xuICAgICAgYXN5bmMgb3B0aW9ucyA9PiB7XG4gICAgICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy5wYWdlKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHBhZ2Ugb3B0aW9ucyBhcmd1bWVudCcpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGF3YWl0IHBhZ2VFdmFsQWxsKG9wdGlvbnMucGFnZSwgJ3N2ZyNDYXBhXzEnLCAnJywgZWxlbWVudCA9PiB7XG4gICAgICAgICAgcmV0dXJuIChlbGVtZW50WzBdPy5wYXJlbnRFbGVtZW50Py5jaGlsZHJlblsxXSBhcyBIVE1MRGl2RWxlbWVudCk/LmlubmVyVGV4dDtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGVycm9yTWVzc2FnZT8uc3RhcnRzV2l0aChJTlZBTElEX1BBU1NXT1JEX01TRyk7XG4gICAgICB9LFxuICAgIF0sXG4gICAgW0xvZ2luUmVzdWx0cy5BY2NvdW50QmxvY2tlZF06IFtcbiAgICAgIC8vIE5PVElDRSAtIG1pZ2h0IG5vdCBiZSByZWxldmFudCBzdGFydGluZyB0aGUgTGV1bWkgcmUtZGVzaWduIGR1cmluZyAyMDIyIFNlcFxuICAgICAgYXN5bmMgb3B0aW9ucyA9PiB7XG4gICAgICAgIGlmICghb3B0aW9ucyB8fCAhb3B0aW9ucy5wYWdlKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdtaXNzaW5nIHBhZ2Ugb3B0aW9ucyBhcmd1bWVudCcpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IGF3YWl0IHBhZ2VFdmFsQWxsKG9wdGlvbnMucGFnZSwgJy5lcnJIZWFkZXInLCAnJywgbGFiZWwgPT4ge1xuICAgICAgICAgIHJldHVybiAobGFiZWxbMF0gYXMgSFRNTEVsZW1lbnQpPy5pbm5lclRleHQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBlcnJvck1lc3NhZ2U/LnN0YXJ0c1dpdGgoQUNDT1VOVF9CTE9DS0VEX01TRyk7XG4gICAgICB9LFxuICAgIF0sXG4gICAgW0xvZ2luUmVzdWx0cy5DaGFuZ2VQYXNzd29yZF06IFtcbiAgICAgIGFzeW5jIG9wdGlvbnMgPT4ge1xuICAgICAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMucGFnZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwYWdlIG9wdGlvbnMgYXJndW1lbnQnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gISEoYXdhaXQgb3B0aW9ucy5wYWdlLiQoQ0hBTkdFX1BBU1NXT1JEX01PREFMX1NFTEVDVE9SKSk7XG4gICAgICB9LFxuICAgIF0sXG4gIH07XG4gIHJldHVybiB1cmxzO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVMb2dpbkZpZWxkcyhjcmVkZW50aWFsczogU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMpIHtcbiAgcmV0dXJuIFtcbiAgICB7IHNlbGVjdG9yOiAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXqdedINee16nXqtee16lcIl0nLCB2YWx1ZTogY3JlZGVudGlhbHMudXNlcm5hbWUgfSxcbiAgICB7IHNlbGVjdG9yOiAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXodeZ16HXnteUXCJdJywgdmFsdWU6IGNyZWRlbnRpYWxzLnBhc3N3b3JkIH0sXG4gIF07XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbnNGcm9tUGFnZShcbiAgdHJhbnNhY3Rpb25zOiBhbnlbXSxcbiAgc3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzLFxuICBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMsXG4pOiBUcmFuc2FjdGlvbltdIHtcbiAgaWYgKHRyYW5zYWN0aW9ucyA9PT0gbnVsbCB8fCB0cmFuc2FjdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0OiBUcmFuc2FjdGlvbltdID0gdHJhbnNhY3Rpb25zLm1hcChyYXdUcmFuc2FjdGlvbiA9PiB7XG4gICAgY29uc3QgZGF0ZSA9IG1vbWVudChyYXdUcmFuc2FjdGlvbi5EYXRlVVRDKS5taWxsaXNlY29uZHMoMCkudG9JU09TdHJpbmcoKTtcbiAgICBjb25zdCBuZXdUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb24gPSB7XG4gICAgICBzdGF0dXMsXG4gICAgICB0eXBlOiBUcmFuc2FjdGlvblR5cGVzLk5vcm1hbCxcbiAgICAgIGRhdGUsXG4gICAgICBwcm9jZXNzZWREYXRlOiBkYXRlLFxuICAgICAgZGVzY3JpcHRpb246IHJhd1RyYW5zYWN0aW9uLkRlc2NyaXB0aW9uIHx8ICcnLFxuICAgICAgaWRlbnRpZmllcjogcmF3VHJhbnNhY3Rpb24uUmVmZXJlbmNlTnVtYmVyTG9uZyxcbiAgICAgIG1lbW86IHJhd1RyYW5zYWN0aW9uLkFkZGl0aW9uYWxEYXRhIHx8ICcnLFxuICAgICAgb3JpZ2luYWxDdXJyZW5jeTogU0hFS0VMX0NVUlJFTkNZLFxuICAgICAgY2hhcmdlZEFtb3VudDogcmF3VHJhbnNhY3Rpb24uQW1vdW50LFxuICAgICAgb3JpZ2luYWxBbW91bnQ6IHJhd1RyYW5zYWN0aW9uLkFtb3VudCxcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnM/LmluY2x1ZGVSYXdUcmFuc2FjdGlvbikge1xuICAgICAgbmV3VHJhbnNhY3Rpb24ucmF3VHJhbnNhY3Rpb24gPSBnZXRSYXdUcmFuc2FjdGlvbihyYXdUcmFuc2FjdGlvbik7XG4gICAgfVxuXG4gICAgcmV0dXJuIG5ld1RyYW5zYWN0aW9uO1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBoYW5nUHJvY2Vzcyh0aW1lb3V0OiBudW1iZXIpIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KHJlc29sdmUgPT4ge1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgcmVzb2x2ZSgpO1xuICAgIH0sIHRpbWVvdXQpO1xuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2xpY2tCeVhQYXRoKHBhZ2U6IFBhZ2UsIHhwYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgcGFnZS53YWl0Rm9yU2VsZWN0b3IoeHBhdGgsIHsgdGltZW91dDogMzAwMDAsIHZpc2libGU6IHRydWUgfSk7XG4gIGNvbnN0IGVsbSA9IGF3YWl0IHBhZ2UuJCQoeHBhdGgpO1xuICBhd2FpdCBlbG1bMF0uY2xpY2soKTtcbn1cblxuZnVuY3Rpb24gcmVtb3ZlU3BlY2lhbENoYXJhY3RlcnMoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gc3RyLnJlcGxhY2UoL1teMC05Ly1dL2csICcnKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnNGb3JBY2NvdW50KFxuICBwYWdlOiBQYWdlLFxuICBzdGFydERhdGU6IE1vbWVudCxcbiAgYWNjb3VudElkOiBzdHJpbmcsXG4gIG9wdGlvbnM6IFNjcmFwZXJPcHRpb25zLFxuKTogUHJvbWlzZTxUcmFuc2FjdGlvbnNBY2NvdW50PiB7XG4gIC8vIERFVkVMT1BFUiBOT1RJQ0UgdGhlIGFjY291bnQgbnVtYmVyIHJlY2VpdmVkIGZyb20gdGhlIHNlcnZlciBpcyBiZWluZyBhbHRlcmVkIGF0XG4gIC8vIHJ1bnRpbWUgZm9yIHNvbWUgYWNjb3VudHMgYWZ0ZXIgMS0yIHNlY29uZHMgc28gd2UgbmVlZCB0byBoYW5nIHRoZSBwcm9jZXNzIGZvciBhIHNob3J0IHdoaWxlLlxuICBhd2FpdCBoYW5nUHJvY2Vzcyg0MDAwKTtcblxuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2J1dHRvblt0aXRsZT1cIteX15nXpNeV16kg157Xqten15PXnVwiXScsIHRydWUpO1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCAnYnV0dG9uW3RpdGxlPVwi15fXmdek15XXqSDXnteq16fXk9edXCJdJyk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnYmxsLXJhZGlvLWJ1dHRvbicsIHRydWUpO1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCAnYmxsLXJhZGlvLWJ1dHRvbjpub3QoW2NoZWNrZWRdKScpO1xuXG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnaW5wdXRbZm9ybWNvbnRyb2xuYW1lPVwidHh0SW5wdXRGcm9tXCJdJywgdHJ1ZSk7XG5cbiAgYXdhaXQgZmlsbElucHV0KHBhZ2UsICdpbnB1dFtmb3JtY29udHJvbG5hbWU9XCJ0eHRJbnB1dEZyb21cIl0nLCBzdGFydERhdGUuZm9ybWF0KERBVEVfRk9STUFUKSk7XG5cbiAgLy8gd2UgbXVzdCBibHVyIHRoZSBmcm9tIGNvbnRyb2wgb3RoZXJ3aXNlIHRoZSBzZWFyY2ggd2lsbCB1c2UgdGhlIHByZXZpb3VzIHZhbHVlXG4gIGF3YWl0IHBhZ2UuZm9jdXMoXCJidXR0b25bYXJpYS1sYWJlbD0n16HXoNefJ11cIik7XG5cbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgXCJidXR0b25bYXJpYS1sYWJlbD0n16HXoNefJ11cIik7XG4gIGNvbnN0IGZpbmFsUmVzcG9uc2UgPSBhd2FpdCBwYWdlLndhaXRGb3JSZXNwb25zZShyZXNwb25zZSA9PiB7XG4gICAgcmV0dXJuIHJlc3BvbnNlLnVybCgpID09PSBGSUxURVJFRF9UUkFOU0FDVElPTlNfVVJMICYmIHJlc3BvbnNlLnJlcXVlc3QoKS5tZXRob2QoKSA9PT0gJ1BPU1QnO1xuICB9KTtcblxuICBjb25zdCByZXNwb25zZUpzb246IGFueSA9IGF3YWl0IGZpbmFsUmVzcG9uc2UuanNvbigpO1xuXG4gIGNvbnN0IGFjY291bnROdW1iZXIgPSBhY2NvdW50SWQucmVwbGFjZSgnLycsICdfJykucmVwbGFjZSgvW15cXGQtX10vZywgJycpO1xuXG4gIGNvbnN0IHJlc3BvbnNlID0gSlNPTi5wYXJzZShyZXNwb25zZUpzb24uanNvblJlc3ApO1xuXG4gIGNvbnN0IHBlbmRpbmdUcmFuc2FjdGlvbnMgPSByZXNwb25zZS5Ub2RheVRyYW5zYWN0aW9uc0l0ZW1zO1xuICBjb25zdCB0cmFuc2FjdGlvbnMgPSByZXNwb25zZS5IaXN0b3J5VHJhbnNhY3Rpb25zSXRlbXM7XG4gIGNvbnN0IGJhbGFuY2UgPSByZXNwb25zZS5CYWxhbmNlRGlzcGxheSA/IHBhcnNlRmxvYXQocmVzcG9uc2UuQmFsYW5jZURpc3BsYXkpIDogdW5kZWZpbmVkO1xuXG4gIGNvbnN0IHBlbmRpbmdUeG5zID0gZXh0cmFjdFRyYW5zYWN0aW9uc0Zyb21QYWdlKHBlbmRpbmdUcmFuc2FjdGlvbnMsIFRyYW5zYWN0aW9uU3RhdHVzZXMuUGVuZGluZywgb3B0aW9ucyk7XG4gIGNvbnN0IGNvbXBsZXRlZFR4bnMgPSBleHRyYWN0VHJhbnNhY3Rpb25zRnJvbVBhZ2UodHJhbnNhY3Rpb25zLCBUcmFuc2FjdGlvblN0YXR1c2VzLkNvbXBsZXRlZCwgb3B0aW9ucyk7XG4gIGNvbnN0IHR4bnMgPSBbLi4ucGVuZGluZ1R4bnMsIC4uLmNvbXBsZXRlZFR4bnNdO1xuXG4gIHJldHVybiB7XG4gICAgYWNjb3VudE51bWJlcixcbiAgICBiYWxhbmNlLFxuICAgIHR4bnMsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoUmVndWxhckFjY291bnRzKFxuICBzY3JhcGVyOiBMZXVtaVNjcmFwZXIsXG4gIHBhZ2U6IFBhZ2UsXG4gIHN0YXJ0RGF0ZTogTW9tZW50LFxuICBvcHRpb25zOiBTY3JhcGVyT3B0aW9ucyxcbik6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIGF3YWl0IHNjcmFwZXIubmF2aWdhdGVUbyhUUkFOU0FDVElPTlNfVVJMKTtcbiAgcmV0dXJuIGZldGNoVHJhbnNhY3Rpb25zKHBhZ2UsIHN0YXJ0RGF0ZSwgb3B0aW9ucyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFNhdmluZ3NBY2NvdW50cyhwYWdlOiBQYWdlLCBhY2NvdW50SWQ6IHN0cmluZyk6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIGRlYnVnKCc9PT09PT09PT09IEZFVENISU5HIFNBVklOR1MgQUNDT1VOVFMgPT09PT09PT09PScpO1xuICBkZWJ1ZygnQWNjb3VudDogJXMnLCBhY2NvdW50SWQpO1xuXG4gIGNvbnN0IGFjY291bnRzOiBUcmFuc2FjdGlvbnNBY2NvdW50W10gPSBbXTtcblxuICB0cnkge1xuICAgIGRlYnVnKCdUcnlpbmcgc2F2aW5ncyBVUkw6ICVzJywgU0FWSU5HU19VUkwpO1xuXG4gICAgY29uc3Qgc2F2aW5nc0RhdGEgPSBhd2FpdCBmZXRjaEdldFdpdGhpblBhZ2U8U2F2aW5nc0FjY291bnREYXRhPihwYWdlLCBTQVZJTkdTX1VSTCk7XG4gICAgaWYgKCFzYXZpbmdzRGF0YSB8fCAhc2F2aW5nc0RhdGEuZGVwb3NpdHNBbmRTYXZpbmdzSXRlbXMgfHwgc2F2aW5nc0RhdGEuZGVwb3NpdHNBbmRTYXZpbmdzSXRlbXMubGVuZ3RoID09PSAwKSB7XG4gICAgICBkZWJ1ZygnTm8gc2F2aW5ncyBhY2NvdW50cyBmb3VuZCBmb3IgYWNjb3VudCAlcycsIGFjY291bnRJZCk7XG4gICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIGRlYnVnKCfinJMgRm91bmQgJWQgc2F2aW5ncyBkZXBvc2l0cycsIHNhdmluZ3NEYXRhLmRlcG9zaXRzQW5kU2F2aW5nc0l0ZW1zLmxlbmd0aCk7XG5cbiAgICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBhY2NvdW50IGZvciBlYWNoIGluZGl2aWR1YWwgZGVwb3NpdFxuICAgIGZvciAoY29uc3QgZGVwb3NpdCBvZiBzYXZpbmdzRGF0YS5kZXBvc2l0c0FuZFNhdmluZ3NJdGVtcykge1xuICAgICAgY29uc3QgYmFsYW5jZSA9IGRlcG9zaXQuY3VycmVudEJhbGFuY2U7XG4gICAgICBjb25zdCBzYXZpbmdzQWNjb3VudE51bWJlciA9IGAke2FjY291bnRJZH0tJHtkZXBvc2l0LmRlcG9zaXRJZH1gO1xuXG4gICAgICBhY2NvdW50cy5wdXNoKHtcbiAgICAgICAgYWNjb3VudE51bWJlcjogc2F2aW5nc0FjY291bnROdW1iZXIsXG4gICAgICAgIHNhdmluZ3NBY2NvdW50OiB0cnVlLFxuICAgICAgICBiYWxhbmNlLFxuICAgICAgICB0eG5zOiBbXSxcbiAgICAgIH0pO1xuXG4gICAgICBkZWJ1ZyhcbiAgICAgICAgJ0FkZGVkIHNhdmluZ3MgYWNjb3VudCAlcyB3aXRoIGJhbGFuY2UgJXMgKHByb2R1Y3Q6ICVzKScsXG4gICAgICAgIHNhdmluZ3NBY2NvdW50TnVtYmVyLFxuICAgICAgICBiYWxhbmNlLFxuICAgICAgICBkZXBvc2l0LnByb2R1Y3ROYW1lLFxuICAgICAgKTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgZGVidWcoJyAgLSBFcnJvciBmZXRjaGluZyBzYXZpbmdzIGFjY291bnRzOiAlcycsIGVycm9yKTtcbiAgfVxuXG4gIGRlYnVnKCdSZXR1cm5pbmcgJWQgc2F2aW5ncyBhY2NvdW50cycsIGFjY291bnRzLmxlbmd0aCk7XG4gIHJldHVybiBhY2NvdW50cztcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnMoXG4gIHBhZ2U6IFBhZ2UsXG4gIHN0YXJ0RGF0ZTogTW9tZW50LFxuICBvcHRpb25zOiBTY3JhcGVyT3B0aW9ucyxcbik6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIGNvbnN0IGFjY291bnRzOiBUcmFuc2FjdGlvbnNBY2NvdW50W10gPSBbXTtcblxuICAvLyBERVZFTE9QRVIgTk9USUNFIHRoZSBhY2NvdW50IG51bWJlciByZWNlaXZlZCBmcm9tIHRoZSBzZXJ2ZXIgaXMgYmVpbmcgYWx0ZXJlZCBhdFxuICAvLyBydW50aW1lIGZvciBzb21lIGFjY291bnRzIGFmdGVyIDEtMiBzZWNvbmRzIHNvIHdlIG5lZWQgdG8gaGFuZyB0aGUgcHJvY2VzcyBmb3IgYSBzaG9ydCB3aGlsZS5cbiAgYXdhaXQgaGFuZ1Byb2Nlc3MoNDAwMCk7XG5cbiAgY29uc3QgYWNjb3VudHNJZHMgPSAoYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PlxuICAgIEFycmF5LmZyb20oZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnYXBwLW1hc2tlZC1udW1iZXItY29tYm8gc3Bhbi5kaXNwbGF5LW51bWJlci1saScpLCBlID0+IGUudGV4dENvbnRlbnQpLFxuICApKSBhcyBzdHJpbmdbXTtcblxuICAvLyBkdWUgdG8gYSBidWcsIHRoZSBhbHRlcmVkIHZhbHVlIG1pZ2h0IGluY2x1ZGUgdW5kZXNpcmVkIHNpZ25zIGxpa2UgJiB0aGF0IHNob3VsZCBiZSByZW1vdmVkXG5cbiAgaWYgKCFhY2NvdW50c0lkcy5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ZhaWxlZCB0byBleHRyYWN0IG9yIHBhcnNlIHRoZSBhY2NvdW50IG51bWJlcicpO1xuICB9XG5cbiAgZm9yIChjb25zdCBhY2NvdW50SWQgb2YgYWNjb3VudHNJZHMpIHtcbiAgICBpZiAoYWNjb3VudHNJZHMubGVuZ3RoID4gMSkge1xuICAgICAgLy8gZ2V0IGxpc3Qgb2YgYWNjb3VudHMgYW5kIGNoZWNrIGFjY291bnRJZFxuICAgICAgYXdhaXQgY2xpY2tCeVhQYXRoKHBhZ2UsICd4cGF0aC8vLypbY29udGFpbnMoQGNsYXNzLCBcIm51bWJlclwiKSBhbmQgY29udGFpbnMoQGNsYXNzLCBcImNvbWJvLWlubmVyXCIpXScpO1xuICAgICAgYXdhaXQgY2xpY2tCeVhQYXRoKHBhZ2UsIGB4cGF0aC8vL3NwYW5bY29udGFpbnModGV4dCgpLCAnJHthY2NvdW50SWR9JyldYCk7XG4gICAgfVxuXG4gICAgYWNjb3VudHMucHVzaChhd2FpdCBmZXRjaFRyYW5zYWN0aW9uc0ZvckFjY291bnQocGFnZSwgc3RhcnREYXRlLCByZW1vdmVTcGVjaWFsQ2hhcmFjdGVycyhhY2NvdW50SWQpLCBvcHRpb25zKSk7XG4gIH1cblxuICByZXR1cm4gYWNjb3VudHM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoU2F2aW5nc0FjY291bnRzKFxuICBwYWdlOiBQYWdlLFxuICByZWd1bGFyQWNjb3VudHM6IFRyYW5zYWN0aW9uc0FjY291bnRbXSxcbik6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIGNvbnN0IGFsbFNhdmluZ3NBY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gW107XG4gIGNvbnN0IHJlZ3VsYXJBY2NvdW50Q291bnQgPSByZWd1bGFyQWNjb3VudHMubGVuZ3RoO1xuXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgcmVndWxhckFjY291bnRDb3VudDsgaSsrKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHNhdmluZ3NBY2NvdW50cyA9IGF3YWl0IGdldFNhdmluZ3NBY2NvdW50cyhwYWdlLCByZWd1bGFyQWNjb3VudHNbaV0uYWNjb3VudE51bWJlcik7XG4gICAgICBhbGxTYXZpbmdzQWNjb3VudHMucHVzaCguLi5zYXZpbmdzQWNjb3VudHMpO1xuICAgICAgZGVidWcoJ0FkZGVkICVkIHNhdmluZ3MgYWNjb3VudHMgdG8gcmVzdWx0cycsIHNhdmluZ3NBY2NvdW50cy5sZW5ndGgpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBkZWJ1ZygnRXJyb3IgZmV0Y2hpbmcgc2F2aW5ncyBhY2NvdW50cyBmb3IgJXM6ICVzJywgcmVndWxhckFjY291bnRzW2ldLmFjY291bnROdW1iZXIsIGVycm9yKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYWxsU2F2aW5nc0FjY291bnRzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBuYXZpZ2F0ZVRvTG9naW4ocGFnZTogUGFnZSk6IFByb21pc2U8dm9pZD4ge1xuICBkZWJ1ZygnbmF2aWdhdGluZyBkaXJlY3RseSB0byBsb2dpbiBwYWdlJyk7XG4gIGF3YWl0IHBhZ2UuZ290bygnaHR0cHM6Ly9oYjIuYmFua2xldW1pLmNvLmlsL2F1dGhlbnRpY2F0ZS9sb2dvbicpO1xuICBkZWJ1Zygnd2FpdGluZyBmb3IgcGFnZSB0byBiZSBsb2FkZWQgKG5ldHdvcmtpZGxlMiknKTtcbiAgYXdhaXQgd2FpdEZvck5hdmlnYXRpb24ocGFnZSwgeyB3YWl0VW50aWw6ICduZXR3b3JraWRsZTInIH0pO1xuICBkZWJ1Zygnd2FpdGluZyBmb3IgY29tcG9uZW50cyBvZiBsb2dpbiB0byBlbnRlciBjcmVkZW50aWFscycpO1xuICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdpbnB1dFtwbGFjZWhvbGRlcj1cItep150g157Xqdeq157XqVwiXScsIHRydWUpLFxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXodeZ16HXnteUXCJdJywgdHJ1ZSksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdidXR0b25bdHlwZT1cInN1Ym1pdFwiXScsIHRydWUpLFxuICBdKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdEZvclBvc3RMb2dpbihwYWdlOiBQYWdlKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdhW3RpdGxlPVwi15PXnNeSINec15fXqdeR15XXn1wiXScsIHRydWUsIDYwMDAwKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2Rpdi5tYWluLWNvbnRlbnQnLCBmYWxzZSwgNjAwMDApLFxuICAgIHBhZ2Uud2FpdEZvclNlbGVjdG9yKGB4cGF0aC8vZGl2W2NvbnRhaW5zKHN0cmluZygpLFwiJHtJTlZBTElEX1BBU1NXT1JEX01TR31cIildYCksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIENIQU5HRV9QQVNTV09SRF9NT0RBTF9TRUxFQ1RPUiwgdHJ1ZSwgNjAwMDApLFxuICBdKTtcbn1cblxudHlwZSBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyA9IHsgdXNlcm5hbWU6IHN0cmluZzsgcGFzc3dvcmQ6IHN0cmluZyB9O1xuXG5jbGFzcyBMZXVtaVNjcmFwZXIgZXh0ZW5kcyBCYXNlU2NyYXBlcldpdGhCcm93c2VyPFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzPiB7XG4gIGdldExvZ2luT3B0aW9ucyhjcmVkZW50aWFsczogU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbG9naW5Vcmw6IExPR0lOX1VSTCxcbiAgICAgIGZpZWxkczogY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHMpLFxuICAgICAgc3VibWl0QnV0dG9uU2VsZWN0b3I6IFwiYnV0dG9uW3R5cGU9J3N1Ym1pdCddXCIsXG4gICAgICBjaGVja1JlYWRpbmVzczogYXN5bmMgKCkgPT4gbmF2aWdhdGVUb0xvZ2luKHRoaXMucGFnZSksXG4gICAgICBwb3N0QWN0aW9uOiBhc3luYyAoKSA9PiB3YWl0Rm9yUG9zdExvZ2luKHRoaXMucGFnZSksXG4gICAgICBwb3NzaWJsZVJlc3VsdHM6IGdldFBvc3NpYmxlTG9naW5SZXN1bHRzKCksXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIGZldGNoRGF0YSgpOiBQcm9taXNlPFNjcmFwZXJTY3JhcGluZ1Jlc3VsdD4ge1xuICAgIGNvbnN0IG1pbmltdW1TdGFydE1vbWVudCA9IG1vbWVudCgpLnN1YnRyYWN0KDMsICd5ZWFycycpLmFkZCgxLCAnZGF5Jyk7XG4gICAgY29uc3QgZGVmYXVsdFN0YXJ0TW9tZW50ID0gbW9tZW50KCkuc3VidHJhY3QoMSwgJ3llYXJzJykuYWRkKDEsICdkYXknKTtcbiAgICBjb25zdCBzdGFydERhdGUgPSB0aGlzLm9wdGlvbnMuc3RhcnREYXRlIHx8IGRlZmF1bHRTdGFydE1vbWVudC50b0RhdGUoKTtcbiAgICBjb25zdCBzdGFydE1vbWVudCA9IG1vbWVudC5tYXgobWluaW11bVN0YXJ0TW9tZW50LCBtb21lbnQoc3RhcnREYXRlKSk7XG5cbiAgICBjb25zdCBhY2NvdW50cyA9IGF3YWl0IGZldGNoUmVndWxhckFjY291bnRzKHRoaXMsIHRoaXMucGFnZSwgc3RhcnRNb21lbnQsIHRoaXMub3B0aW9ucyk7XG4gICAgY29uc3Qgc2F2aW5nc0FjY291bnRzID0gYXdhaXQgZmV0Y2hTYXZpbmdzQWNjb3VudHModGhpcy5wYWdlLCBhY2NvdW50cyk7XG4gICAgYWNjb3VudHMucHVzaCguLi5zYXZpbmdzQWNjb3VudHMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBhY2NvdW50cyxcbiAgICB9O1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IExldW1pU2NyYXBlcjtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBRUEsSUFBQUMsVUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsTUFBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcscUJBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLE1BQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGFBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLFdBQUEsR0FBQU4sT0FBQTtBQUNBLElBQUFPLGNBQUEsR0FBQVAsT0FBQTtBQUNBLElBQUFRLHVCQUFBLEdBQUFSLE9BQUE7QUFBc0csU0FBQUQsdUJBQUFVLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7QUFHdEcsTUFBTUcsS0FBSyxHQUFHLElBQUFDLGVBQVEsRUFBQyxPQUFPLENBQUM7QUFDL0IsTUFBTUMsUUFBUSxHQUFHLDZCQUE2QjtBQUM5QyxNQUFNQyxTQUFTLEdBQUcsNEJBQTRCO0FBQzlDLE1BQU1DLGdCQUFnQixHQUFHLEdBQUdGLFFBQVEsMERBQTBEO0FBQzlGLE1BQU1HLHlCQUF5QixHQUFHLEdBQUdILFFBQVEsaUZBQWlGO0FBQzlILE1BQU1JLFdBQVcsR0FBRyxHQUFHSixRQUFRLDhFQUE4RTtBQUU3RyxNQUFNSyxXQUFXLEdBQUcsVUFBVTtBQUM5QixNQUFNQyxtQkFBbUIsR0FBRyxZQUFZO0FBQ3hDLE1BQU1DLG9CQUFvQixHQUFHLHdEQUF3RDtBQUNyRixNQUFNQyw4QkFBOEIsR0FBRywyQkFBMkI7QUFzQ2xFLFNBQVNDLHVCQUF1QkEsQ0FBQSxFQUFHO0VBQ2pDLE1BQU1DLElB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