israeli-bank-scrapers-core
Version:
Provide scrapers for all major Israeli banks and credit card companies
200 lines (195 loc) • 35.5 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 _navigation = require("../helpers/navigation");
var _transactions = 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/';
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 DATE_FORMAT = 'DD.MM.YY';
const ACCOUNT_BLOCKED_MSG = 'המנוי חסום';
const INVALID_PASSWORD_MSG = 'אחד או יותר מפרטי ההזדהות שמסרת שגויים. ניתן לנסות שוב';
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]: ['https://hb2.bankleumi.co.il/authenticate'] // NOTICE - might not be relevant starting the Leumi re-design during 2022 Sep
};
return urls;
}
function createLoginFields(credentials) {
return [{
selector: 'input[placeholder="שם משתמש"]',
value: credentials.username
}, {
selector: 'input[placeholder="סיסמה"]',
value: credentials.password
}];
}
function extractTransactionsFromPage(transactions, status) {
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: _transactions.TransactionTypes.Normal,
date,
processedDate: date,
description: rawTransaction.Description || '',
identifier: rawTransaction.ReferenceNumberLong,
memo: rawTransaction.AdditionalData || '',
originalCurrency: _constants.SHEKEL_CURRENCY,
chargedAmount: rawTransaction.Amount,
originalAmount: rawTransaction.Amount
};
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) {
// 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, _transactions.TransactionStatuses.Pending);
const completedTxns = extractTransactionsFromPage(transactions, _transactions.TransactionStatuses.Completed);
const txns = [...pendingTxns, ...completedTxns];
return {
accountNumber,
balance,
txns
};
}
async function fetchTransactions(page, startDate) {
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)));
}
return accounts;
}
async function navigateToLogin(page) {
const loginButtonSelector = '.enter-account a[originaltitle="כניסה לחשבונך"]';
debug('wait for homepage to click on login button');
await (0, _elementsInteractions.waitUntilElementFound)(page, loginButtonSelector);
debug('navigate to login page');
const loginUrl = await (0, _elementsInteractions.pageEval)(page, loginButtonSelector, null, element => {
return element.href;
});
debug(`navigating to page (${loginUrl})`);
await page.goto(loginUrl);
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, 'form[action="/changepassword"]', true, 60000) // not sure if they kept this one
]);
}
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));
await this.navigateTo(TRANSACTIONS_URL);
const accounts = await fetchTransactions(this.page, startMoment);
return {
success: true,
accounts
};
}
}
var _default = exports.default = LeumiScraper;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2RlYnVnIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfdHJhbnNhY3Rpb25zIiwiX2Jhc2VTY3JhcGVyV2l0aEJyb3dzZXIiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJkZWJ1ZyIsImdldERlYnVnIiwiQkFTRV9VUkwiLCJMT0dJTl9VUkwiLCJUUkFOU0FDVElPTlNfVVJMIiwiRklMVEVSRURfVFJBTlNBQ1RJT05TX1VSTCIsIkRBVEVfRk9STUFUIiwiQUNDT1VOVF9CTE9DS0VEX01TRyIsIklOVkFMSURfUEFTU1dPUkRfTVNHIiwiZ2V0UG9zc2libGVMb2dpblJlc3VsdHMiLCJ1cmxzIiwiTG9naW5SZXN1bHRzIiwiU3VjY2VzcyIsIkludmFsaWRQYXNzd29yZCIsIm9wdGlvbnMiLCJwYWdlIiwiRXJyb3IiLCJlcnJvck1lc3NhZ2UiLCJwYWdlRXZhbEFsbCIsImVsZW1lbnQiLCJwYXJlbnRFbGVtZW50IiwiY2hpbGRyZW4iLCJpbm5lclRleHQiLCJzdGFydHNXaXRoIiwiQWNjb3VudEJsb2NrZWQiLCJsYWJlbCIsIkNoYW5nZVBhc3N3b3JkIiwiY3JlYXRlTG9naW5GaWVsZHMiLCJjcmVkZW50aWFscyIsInNlbGVjdG9yIiwidmFsdWUiLCJ1c2VybmFtZSIsInBhc3N3b3JkIiwiZXh0cmFjdFRyYW5zYWN0aW9uc0Zyb21QYWdlIiwidHJhbnNhY3Rpb25zIiwic3RhdHVzIiwibGVuZ3RoIiwicmVzdWx0IiwibWFwIiwicmF3VHJhbnNhY3Rpb24iLCJkYXRlIiwibW9tZW50IiwiRGF0ZVVUQyIsIm1pbGxpc2Vjb25kcyIsInRvSVNPU3RyaW5nIiwibmV3VHJhbnNhY3Rpb24iLCJ0eXBlIiwiVHJhbnNhY3Rpb25UeXBlcyIsIk5vcm1hbCIsInByb2Nlc3NlZERhdGUiLCJkZXNjcmlwdGlvbiIsIkRlc2NyaXB0aW9uIiwiaWRlbnRpZmllciIsIlJlZmVyZW5jZU51bWJlckxvbmciLCJtZW1vIiwiQWRkaXRpb25hbERhdGEiLCJvcmlnaW5hbEN1cnJlbmN5IiwiU0hFS0VMX0NVUlJFTkNZIiwiY2hhcmdlZEFtb3VudCIsIkFtb3VudCIsIm9yaWdpbmFsQW1vdW50IiwiaGFuZ1Byb2Nlc3MiLCJ0aW1lb3V0IiwiUHJvbWlzZSIsInJlc29sdmUiLCJzZXRUaW1lb3V0IiwiY2xpY2tCeVhQYXRoIiwieHBhdGgiLCJ3YWl0Rm9yU2VsZWN0b3IiLCJ2aXNpYmxlIiwiZWxtIiwiJCQiLCJjbGljayIsInJlbW92ZVNwZWNpYWxDaGFyYWN0ZXJzIiwic3RyIiwicmVwbGFjZSIsImZldGNoVHJhbnNhY3Rpb25zRm9yQWNjb3VudCIsInN0YXJ0RGF0ZSIsImFjY291bnRJZCIsIndhaXRVbnRpbEVsZW1lbnRGb3VuZCIsImNsaWNrQnV0dG9uIiwiZmlsbElucHV0IiwiZm9ybWF0IiwiZm9jdXMiLCJmaW5hbFJlc3BvbnNlIiwid2FpdEZvclJlc3BvbnNlIiwicmVzcG9uc2UiLCJ1cmwiLCJyZXF1ZXN0IiwibWV0aG9kIiwicmVzcG9uc2VKc29uIiwianNvbiIsImFjY291bnROdW1iZXIiLCJKU09OIiwicGFyc2UiLCJqc29uUmVzcCIsInBlbmRpbmdUcmFuc2FjdGlvbnMiLCJUb2RheVRyYW5zYWN0aW9uc0l0ZW1zIiwiSGlzdG9yeVRyYW5zYWN0aW9uc0l0ZW1zIiwiYmFsYW5jZSIsIkJhbGFuY2VEaXNwbGF5IiwicGFyc2VGbG9hdCIsInVuZGVmaW5lZCIsInBlbmRpbmdUeG5zIiwiVHJhbnNhY3Rpb25TdGF0dXNlcyIsIlBlbmRpbmciLCJjb21wbGV0ZWRUeG5zIiwiQ29tcGxldGVkIiwidHhucyIsImZldGNoVHJhbnNhY3Rpb25zIiwiYWNjb3VudHMiLCJhY2NvdW50c0lkcyIsImV2YWx1YXRlIiwiQXJyYXkiLCJmcm9tIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yQWxsIiwidGV4dENvbnRlbnQiLCJwdXNoIiwibmF2aWdhdGVUb0xvZ2luIiwibG9naW5CdXR0b25TZWxlY3RvciIsImxvZ2luVXJsIiwicGFnZUV2YWwiLCJocmVmIiwiZ290byIsIndhaXRGb3JOYXZpZ2F0aW9uIiwid2FpdFVudGlsIiwiYWxsIiwid2FpdEZvclBvc3RMb2dpbiIsInJhY2UiLCJMZXVtaVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiZ2V0TG9naW5PcHRpb25zIiwiZmllbGRzIiwic3VibWl0QnV0dG9uU2VsZWN0b3IiLCJjaGVja1JlYWRpbmVzcyIsInBvc3RBY3Rpb24iLCJwb3NzaWJsZVJlc3VsdHMiLCJmZXRjaERhdGEiLCJtaW5pbXVtU3RhcnRNb21lbnQiLCJzdWJ0cmFjdCIsImFkZCIsImRlZmF1bHRTdGFydE1vbWVudCIsInRvRGF0ZSIsInN0YXJ0TW9tZW50IiwibWF4IiwibmF2aWdhdGVUbyIsInN1Y2Nlc3MiLCJfZGVmYXVsdCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NyYXBlcnMvbGV1bWkudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IG1vbWVudCwgeyB0eXBlIE1vbWVudCB9IGZyb20gJ21vbWVudCc7XG5pbXBvcnQgeyB0eXBlIFBhZ2UgfSBmcm9tICdwdXBwZXRlZXItY29yZSc7XG5pbXBvcnQgeyBTSEVLRUxfQ1VSUkVOQ1kgfSBmcm9tICcuLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgZ2V0RGVidWcgfSBmcm9tICcuLi9oZWxwZXJzL2RlYnVnJztcbmltcG9ydCB7IGNsaWNrQnV0dG9uLCBmaWxsSW5wdXQsIHBhZ2VFdmFsLCBwYWdlRXZhbEFsbCwgd2FpdFVudGlsRWxlbWVudEZvdW5kIH0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgd2FpdEZvck5hdmlnYXRpb24gfSBmcm9tICcuLi9oZWxwZXJzL25hdmlnYXRpb24nO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25TdGF0dXNlcywgVHJhbnNhY3Rpb25UeXBlcywgdHlwZSBUcmFuc2FjdGlvbiwgdHlwZSBUcmFuc2FjdGlvbnNBY2NvdW50IH0gZnJvbSAnLi4vdHJhbnNhY3Rpb25zJztcbmltcG9ydCB7IEJhc2VTY3JhcGVyV2l0aEJyb3dzZXIsIExvZ2luUmVzdWx0cywgdHlwZSBMb2dpbk9wdGlvbnMgfSBmcm9tICcuL2Jhc2Utc2NyYXBlci13aXRoLWJyb3dzZXInO1xuaW1wb3J0IHsgdHlwZSBTY3JhcGVyU2NyYXBpbmdSZXN1bHQgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoJ2xldW1pJyk7XG5jb25zdCBCQVNFX1VSTCA9ICdodHRwczovL2hiMi5iYW5rbGV1bWkuY28uaWwnO1xuY29uc3QgTE9HSU5fVVJMID0gJ2h0dHBzOi8vd3d3LmxldW1pLmNvLmlsLyc7XG5jb25zdCBUUkFOU0FDVElPTlNfVVJMID0gYCR7QkFTRV9VUkx9L2VCYW5raW5nL1NPL1NQQS5hc3B4Iy90cy9CdXNpbmVzc0FjY291bnRUcng/V2lkZ2V0UGFyPTFgO1xuY29uc3QgRklMVEVSRURfVFJBTlNBQ1RJT05TX1VSTCA9IGAke0JBU0VfVVJMfS9DaGFubmVsV0NGL0Jyb2tlci5zdmMvUHJvY2Vzc1JlcXVlc3Q/bW9kdWxlTmFtZT1VQ19TT18yN19HZXRCdXNpbmVzc0FjY291bnRUcnhgO1xuXG5jb25zdCBEQVRFX0ZPUk1BVCA9ICdERC5NTS5ZWSc7XG5jb25zdCBBQ0NPVU5UX0JMT0NLRURfTVNHID0gJ9eU157XoNeV15kg15fXodeV150nO1xuY29uc3QgSU5WQUxJRF9QQVNTV09SRF9NU0cgPSAn15DXl9eTINeQ15Ug15nXldeq16gg157XpNeo15jXmSDXlNeU15bXk9eU15XXqiDXqdee16HXqNeqINep15LXldeZ15nXnS4g16DXmdeq158g15zXoNeh15XXqiDXqdeV15EnO1xuXG5mdW5jdGlvbiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cygpIHtcbiAgY29uc3QgdXJsczogTG9naW5PcHRpb25zWydwb3NzaWJsZVJlc3VsdHMnXSA9IHtcbiAgICBbTG9naW5SZXN1bHRzLlN1Y2Nlc3NdOiBbL2ViYW5raW5nXFwvU09cXC9TUEEuYXNweC9pXSxcbiAgICBbTG9naW5SZXN1bHRzLkludmFsaWRQYXNzd29yZF06IFtcbiAgICAgIGFzeW5jIG9wdGlvbnMgPT4ge1xuICAgICAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMucGFnZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwYWdlIG9wdGlvbnMgYXJndW1lbnQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBhd2FpdCBwYWdlRXZhbEFsbChvcHRpb25zLnBhZ2UsICdzdmcjQ2FwYV8xJywgJycsIGVsZW1lbnQgPT4ge1xuICAgICAgICAgIHJldHVybiAoZWxlbWVudFswXT8ucGFyZW50RWxlbWVudD8uY2hpbGRyZW5bMV0gYXMgSFRNTERpdkVsZW1lbnQpPy5pbm5lclRleHQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBlcnJvck1lc3NhZ2U/LnN0YXJ0c1dpdGgoSU5WQUxJRF9QQVNTV09SRF9NU0cpO1xuICAgICAgfSxcbiAgICBdLFxuICAgIFtMb2dpblJlc3VsdHMuQWNjb3VudEJsb2NrZWRdOiBbXG4gICAgICAvLyBOT1RJQ0UgLSBtaWdodCBub3QgYmUgcmVsZXZhbnQgc3RhcnRpbmcgdGhlIExldW1pIHJlLWRlc2lnbiBkdXJpbmcgMjAyMiBTZXBcbiAgICAgIGFzeW5jIG9wdGlvbnMgPT4ge1xuICAgICAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMucGFnZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwYWdlIG9wdGlvbnMgYXJndW1lbnQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBhd2FpdCBwYWdlRXZhbEFsbChvcHRpb25zLnBhZ2UsICcuZXJySGVhZGVyJywgJycsIGxhYmVsID0+IHtcbiAgICAgICAgICByZXR1cm4gKGxhYmVsWzBdIGFzIEhUTUxFbGVtZW50KT8uaW5uZXJUZXh0O1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZXJyb3JNZXNzYWdlPy5zdGFydHNXaXRoKEFDQ09VTlRfQkxPQ0tFRF9NU0cpO1xuICAgICAgfSxcbiAgICBdLFxuICAgIFtMb2dpblJlc3VsdHMuQ2hhbmdlUGFzc3dvcmRdOiBbJ2h0dHBzOi8vaGIyLmJhbmtsZXVtaS5jby5pbC9hdXRoZW50aWNhdGUnXSwgLy8gTk9USUNFIC0gbWlnaHQgbm90IGJlIHJlbGV2YW50IHN0YXJ0aW5nIHRoZSBMZXVtaSByZS1kZXNpZ24gZHVyaW5nIDIwMjIgU2VwXG4gIH07XG4gIHJldHVybiB1cmxzO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVMb2dpbkZpZWxkcyhjcmVkZW50aWFsczogU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMpIHtcbiAgcmV0dXJuIFtcbiAgICB7IHNlbGVjdG9yOiAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXqdedINee16nXqtee16lcIl0nLCB2YWx1ZTogY3JlZGVudGlhbHMudXNlcm5hbWUgfSxcbiAgICB7IHNlbGVjdG9yOiAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXodeZ16HXnteUXCJdJywgdmFsdWU6IGNyZWRlbnRpYWxzLnBhc3N3b3JkIH0sXG4gIF07XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbnNGcm9tUGFnZSh0cmFuc2FjdGlvbnM6IGFueVtdLCBzdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMpOiBUcmFuc2FjdGlvbltdIHtcbiAgaWYgKHRyYW5zYWN0aW9ucyA9PT0gbnVsbCB8fCB0cmFuc2FjdGlvbnMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcmVzdWx0OiBUcmFuc2FjdGlvbltdID0gdHJhbnNhY3Rpb25zLm1hcChyYXdUcmFuc2FjdGlvbiA9PiB7XG4gICAgY29uc3QgZGF0ZSA9IG1vbWVudChyYXdUcmFuc2FjdGlvbi5EYXRlVVRDKS5taWxsaXNlY29uZHMoMCkudG9JU09TdHJpbmcoKTtcbiAgICBjb25zdCBuZXdUcmFuc2FjdGlvbjogVHJhbnNhY3Rpb24gPSB7XG4gICAgICBzdGF0dXMsXG4gICAgICB0eXBlOiBUcmFuc2FjdGlvblR5cGVzLk5vcm1hbCxcbiAgICAgIGRhdGUsXG4gICAgICBwcm9jZXNzZWREYXRlOiBkYXRlLFxuICAgICAgZGVzY3JpcHRpb246IHJhd1RyYW5zYWN0aW9uLkRlc2NyaXB0aW9uIHx8ICcnLFxuICAgICAgaWRlbnRpZmllcjogcmF3VHJhbnNhY3Rpb24uUmVmZXJlbmNlTnVtYmVyTG9uZyxcbiAgICAgIG1lbW86IHJhd1RyYW5zYWN0aW9uLkFkZGl0aW9uYWxEYXRhIHx8ICcnLFxuICAgICAgb3JpZ2luYWxDdXJyZW5jeTogU0hFS0VMX0NVUlJFTkNZLFxuICAgICAgY2hhcmdlZEFtb3VudDogcmF3VHJhbnNhY3Rpb24uQW1vdW50LFxuICAgICAgb3JpZ2luYWxBbW91bnQ6IHJhd1RyYW5zYWN0aW9uLkFtb3VudCxcbiAgICB9O1xuXG4gICAgcmV0dXJuIG5ld1RyYW5zYWN0aW9uO1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBoYW5nUHJvY2Vzcyh0aW1lb3V0OiBudW1iZXIpIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlPHZvaWQ+KHJlc29sdmUgPT4ge1xuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgcmVzb2x2ZSgpO1xuICAgIH0sIHRpbWVvdXQpO1xuICB9KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2xpY2tCeVhQYXRoKHBhZ2U6IFBhZ2UsIHhwYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgcGFnZS53YWl0Rm9yU2VsZWN0b3IoeHBhdGgsIHsgdGltZW91dDogMzAwMDAsIHZpc2libGU6IHRydWUgfSk7XG4gIGNvbnN0IGVsbSA9IGF3YWl0IHBhZ2UuJCQoeHBhdGgpO1xuICBhd2FpdCBlbG1bMF0uY2xpY2soKTtcbn1cblxuZnVuY3Rpb24gcmVtb3ZlU3BlY2lhbENoYXJhY3RlcnMoc3RyOiBzdHJpbmcpOiBzdHJpbmcge1xuICByZXR1cm4gc3RyLnJlcGxhY2UoL1teMC05Ly1dL2csICcnKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnNGb3JBY2NvdW50KFxuICBwYWdlOiBQYWdlLFxuICBzdGFydERhdGU6IE1vbWVudCxcbiAgYWNjb3VudElkOiBzdHJpbmcsXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnQ+IHtcbiAgLy8gREVWRUxPUEVSIE5PVElDRSB0aGUgYWNjb3VudCBudW1iZXIgcmVjZWl2ZWQgZnJvbSB0aGUgc2VydmVyIGlzIGJlaW5nIGFsdGVyZWQgYXRcbiAgLy8gcnVudGltZSBmb3Igc29tZSBhY2NvdW50cyBhZnRlciAxLTIgc2Vjb25kcyBzbyB3ZSBuZWVkIHRvIGhhbmcgdGhlIHByb2Nlc3MgZm9yIGEgc2hvcnQgd2hpbGUuXG4gIGF3YWl0IGhhbmdQcm9jZXNzKDQwMDApO1xuXG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnYnV0dG9uW3RpdGxlPVwi15fXmdek15XXqSDXnteq16fXk9edXCJdJywgdHJ1ZSk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsICdidXR0b25bdGl0bGU9XCLXl9eZ16TXldepINee16rXp9eT151cIl0nKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdibGwtcmFkaW8tYnV0dG9uJywgdHJ1ZSk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsICdibGwtcmFkaW8tYnV0dG9uOm5vdChbY2hlY2tlZF0pJyk7XG5cbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdpbnB1dFtmb3JtY29udHJvbG5hbWU9XCJ0eHRJbnB1dEZyb21cIl0nLCB0cnVlKTtcblxuICBhd2FpdCBmaWxsSW5wdXQocGFnZSwgJ2lucHV0W2Zvcm1jb250cm9sbmFtZT1cInR4dElucHV0RnJvbVwiXScsIHN0YXJ0RGF0ZS5mb3JtYXQoREFURV9GT1JNQVQpKTtcblxuICAvLyB3ZSBtdXN0IGJsdXIgdGhlIGZyb20gY29udHJvbCBvdGhlcndpc2UgdGhlIHNlYXJjaCB3aWxsIHVzZSB0aGUgcHJldmlvdXMgdmFsdWVcbiAgYXdhaXQgcGFnZS5mb2N1cyhcImJ1dHRvblthcmlhLWxhYmVsPSfXodeg158nXVwiKTtcblxuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCBcImJ1dHRvblthcmlhLWxhYmVsPSfXodeg158nXVwiKTtcbiAgY29uc3QgZmluYWxSZXNwb25zZSA9IGF3YWl0IHBhZ2Uud2FpdEZvclJlc3BvbnNlKHJlc3BvbnNlID0+IHtcbiAgICByZXR1cm4gcmVzcG9uc2UudXJsKCkgPT09IEZJTFRFUkVEX1RSQU5TQUNUSU9OU19VUkwgJiYgcmVzcG9uc2UucmVxdWVzdCgpLm1ldGhvZCgpID09PSAnUE9TVCc7XG4gIH0pO1xuXG4gIGNvbnN0IHJlc3BvbnNlSnNvbjogYW55ID0gYXdhaXQgZmluYWxSZXNwb25zZS5qc29uKCk7XG5cbiAgY29uc3QgYWNjb3VudE51bWJlciA9IGFjY291bnRJZC5yZXBsYWNlKCcvJywgJ18nKS5yZXBsYWNlKC9bXlxcZC1fXS9nLCAnJyk7XG5cbiAgY29uc3QgcmVzcG9uc2UgPSBKU09OLnBhcnNlKHJlc3BvbnNlSnNvbi5qc29uUmVzcCk7XG5cbiAgY29uc3QgcGVuZGluZ1RyYW5zYWN0aW9ucyA9IHJlc3BvbnNlLlRvZGF5VHJhbnNhY3Rpb25zSXRlbXM7XG4gIGNvbnN0IHRyYW5zYWN0aW9ucyA9IHJlc3BvbnNlLkhpc3RvcnlUcmFuc2FjdGlvbnNJdGVtcztcbiAgY29uc3QgYmFsYW5jZSA9IHJlc3BvbnNlLkJhbGFuY2VEaXNwbGF5ID8gcGFyc2VGbG9hdChyZXNwb25zZS5CYWxhbmNlRGlzcGxheSkgOiB1bmRlZmluZWQ7XG5cbiAgY29uc3QgcGVuZGluZ1R4bnMgPSBleHRyYWN0VHJhbnNhY3Rpb25zRnJvbVBhZ2UocGVuZGluZ1RyYW5zYWN0aW9ucywgVHJhbnNhY3Rpb25TdGF0dXNlcy5QZW5kaW5nKTtcbiAgY29uc3QgY29tcGxldGVkVHhucyA9IGV4dHJhY3RUcmFuc2FjdGlvbnNGcm9tUGFnZSh0cmFuc2FjdGlvbnMsIFRyYW5zYWN0aW9uU3RhdHVzZXMuQ29tcGxldGVkKTtcbiAgY29uc3QgdHhucyA9IFsuLi5wZW5kaW5nVHhucywgLi4uY29tcGxldGVkVHhuc107XG5cbiAgcmV0dXJuIHtcbiAgICBhY2NvdW50TnVtYmVyLFxuICAgIGJhbGFuY2UsXG4gICAgdHhucyxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hUcmFuc2FjdGlvbnMocGFnZTogUGFnZSwgc3RhcnREYXRlOiBNb21lbnQpOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBjb25zdCBhY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gW107XG5cbiAgLy8gREVWRUxPUEVSIE5PVElDRSB0aGUgYWNjb3VudCBudW1iZXIgcmVjZWl2ZWQgZnJvbSB0aGUgc2VydmVyIGlzIGJlaW5nIGFsdGVyZWQgYXRcbiAgLy8gcnVudGltZSBmb3Igc29tZSBhY2NvdW50cyBhZnRlciAxLTIgc2Vjb25kcyBzbyB3ZSBuZWVkIHRvIGhhbmcgdGhlIHByb2Nlc3MgZm9yIGEgc2hvcnQgd2hpbGUuXG4gIGF3YWl0IGhhbmdQcm9jZXNzKDQwMDApO1xuXG4gIGNvbnN0IGFjY291bnRzSWRzID0gKGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT5cbiAgICBBcnJheS5mcm9tKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ2FwcC1tYXNrZWQtbnVtYmVyLWNvbWJvIHNwYW4uZGlzcGxheS1udW1iZXItbGknKSwgZSA9PiBlLnRleHRDb250ZW50KSxcbiAgKSkgYXMgc3RyaW5nW107XG5cbiAgLy8gZHVlIHRvIGEgYnVnLCB0aGUgYWx0ZXJlZCB2YWx1ZSBtaWdodCBpbmNsdWRlIHVuZGVzaXJlZCBzaWducyBsaWtlICYgdGhhdCBzaG91bGQgYmUgcmVtb3ZlZFxuXG4gIGlmICghYWNjb3VudHNJZHMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZXh0cmFjdCBvciBwYXJzZSB0aGUgYWNjb3VudCBudW1iZXInKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgYWNjb3VudElkIG9mIGFjY291bnRzSWRzKSB7XG4gICAgaWYgKGFjY291bnRzSWRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIC8vIGdldCBsaXN0IG9mIGFjY291bnRzIGFuZCBjaGVjayBhY2NvdW50SWRcbiAgICAgIGF3YWl0IGNsaWNrQnlYUGF0aChwYWdlLCAneHBhdGgvLy8qW2NvbnRhaW5zKEBjbGFzcywgXCJudW1iZXJcIikgYW5kIGNvbnRhaW5zKEBjbGFzcywgXCJjb21iby1pbm5lclwiKV0nKTtcbiAgICAgIGF3YWl0IGNsaWNrQnlYUGF0aChwYWdlLCBgeHBhdGgvLy9zcGFuW2NvbnRhaW5zKHRleHQoKSwgJyR7YWNjb3VudElkfScpXWApO1xuICAgIH1cblxuICAgIGFjY291bnRzLnB1c2goYXdhaXQgZmV0Y2hUcmFuc2FjdGlvbnNGb3JBY2NvdW50KHBhZ2UsIHN0YXJ0RGF0ZSwgcmVtb3ZlU3BlY2lhbENoYXJhY3RlcnMoYWNjb3VudElkKSkpO1xuICB9XG5cbiAgcmV0dXJuIGFjY291bnRzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBuYXZpZ2F0ZVRvTG9naW4ocGFnZTogUGFnZSk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBsb2dpbkJ1dHRvblNlbGVjdG9yID0gJy5lbnRlci1hY2NvdW50IGFbb3JpZ2luYWx0aXRsZT1cIteb16DXmdeh15Qg15zXl9ep15HXldeg15pcIl0nO1xuICBkZWJ1Zygnd2FpdCBmb3IgaG9tZXBhZ2UgdG8gY2xpY2sgb24gbG9naW4gYnV0dG9uJyk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBsb2dpbkJ1dHRvblNlbGVjdG9yKTtcbiAgZGVidWcoJ25hdmlnYXRlIHRvIGxvZ2luIHBhZ2UnKTtcbiAgY29uc3QgbG9naW5VcmwgPSBhd2FpdCBwYWdlRXZhbChwYWdlLCBsb2dpbkJ1dHRvblNlbGVjdG9yLCBudWxsLCBlbGVtZW50ID0+IHtcbiAgICByZXR1cm4gKGVsZW1lbnQgYXMgYW55KS5ocmVmO1xuICB9KTtcbiAgZGVidWcoYG5hdmlnYXRpbmcgdG8gcGFnZSAoJHtsb2dpblVybH0pYCk7XG4gIGF3YWl0IHBhZ2UuZ290byhsb2dpblVybCk7XG4gIGRlYnVnKCd3YWl0aW5nIGZvciBwYWdlIHRvIGJlIGxvYWRlZCAobmV0d29ya2lkbGUyKScpO1xuICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbihwYWdlLCB7IHdhaXRVbnRpbDogJ25ldHdvcmtpZGxlMicgfSk7XG4gIGRlYnVnKCd3YWl0aW5nIGZvciBjb21wb25lbnRzIG9mIGxvZ2luIHRvIGVudGVyIGNyZWRlbnRpYWxzJyk7XG4gIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2lucHV0W3BsYWNlaG9sZGVyPVwi16nXnSDXntep16rXntepXCJdJywgdHJ1ZSksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdpbnB1dFtwbGFjZWhvbGRlcj1cIteh15nXodee15RcIl0nLCB0cnVlKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2J1dHRvblt0eXBlPVwic3VibWl0XCJdJywgdHJ1ZSksXG4gIF0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yUG9zdExvZ2luKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgUHJvbWlzZS5yYWNlKFtcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2FbdGl0bGU9XCLXk9ec15Ig15zXl9ep15HXldefXCJdJywgdHJ1ZSwgNjAwMDApLFxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnZGl2Lm1haW4tY29udGVudCcsIGZhbHNlLCA2MDAwMCksXG4gICAgcGFnZS53YWl0Rm9yU2VsZWN0b3IoYHhwYXRoLy9kaXZbY29udGFpbnMoc3RyaW5nKCksXCIke0lOVkFMSURfUEFTU1dPUkRfTVNHfVwiKV1gKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2Zvcm1bYWN0aW9uPVwiL2NoYW5nZXBhc3N3b3JkXCJdJywgdHJ1ZSwgNjAwMDApLCAvLyBub3Qgc3VyZSBpZiB0aGV5IGtlcHQgdGhpcyBvbmVcbiAgXSk7XG59XG5cbnR5cGUgU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMgPSB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfTtcblxuY2xhc3MgTGV1bWlTY3JhcGVyIGV4dGVuZHMgQmFzZVNjcmFwZXJXaXRoQnJvd3NlcjxTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscz4ge1xuICBnZXRMb2dpbk9wdGlvbnMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxvZ2luVXJsOiBMT0dJTl9VUkwsXG4gICAgICBmaWVsZHM6IGNyZWF0ZUxvZ2luRmllbGRzKGNyZWRlbnRpYWxzKSxcbiAgICAgIHN1Ym1pdEJ1dHRvblNlbGVjdG9yOiBcImJ1dHRvblt0eXBlPSdzdWJtaXQnXVwiLFxuICAgICAgY2hlY2tSZWFkaW5lc3M6IGFzeW5jICgpID0+IG5hdmlnYXRlVG9Mb2dpbih0aGlzLnBhZ2UpLFxuICAgICAgcG9zdEFjdGlvbjogYXN5bmMgKCkgPT4gd2FpdEZvclBvc3RMb2dpbih0aGlzLnBhZ2UpLFxuICAgICAgcG9zc2libGVSZXN1bHRzOiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cygpLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBmZXRjaERhdGEoKTogUHJvbWlzZTxTY3JhcGVyU2NyYXBpbmdSZXN1bHQ+IHtcbiAgICBjb25zdCBtaW5pbXVtU3RhcnRNb21lbnQgPSBtb21lbnQoKS5zdWJ0cmFjdCgzLCAneWVhcnMnKS5hZGQoMSwgJ2RheScpO1xuICAgIGNvbnN0IGRlZmF1bHRTdGFydE1vbWVudCA9IG1vbWVudCgpLnN1YnRyYWN0KDEsICd5ZWFycycpLmFkZCgxLCAnZGF5Jyk7XG4gICAgY29uc3Qgc3RhcnREYXRlID0gdGhpcy5vcHRpb25zLnN0YXJ0RGF0ZSB8fCBkZWZhdWx0U3RhcnRNb21lbnQudG9EYXRlKCk7XG4gICAgY29uc3Qgc3RhcnRNb21lbnQgPSBtb21lbnQubWF4KG1pbmltdW1TdGFydE1vbWVudCwgbW9tZW50KHN0YXJ0RGF0ZSkpO1xuXG4gICAgYXdhaXQgdGhpcy5uYXZpZ2F0ZVRvKFRSQU5TQUNUSU9OU19VUkwpO1xuXG4gICAgY29uc3QgYWNjb3VudHMgPSBhd2FpdCBmZXRjaFRyYW5zYWN0aW9ucyh0aGlzLnBhZ2UsIHN0YXJ0TW9tZW50KTtcblxuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgYWNjb3VudHMsXG4gICAgfTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBMZXVtaVNjcmFwZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUVBLElBQUFDLFVBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLHFCQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxXQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxhQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSx1QkFBQSxHQUFBTixPQUFBO0FBQXNHLFNBQUFELHVCQUFBUSxDQUFBLFdBQUFBLENBQUEsSUFBQUEsQ0FBQSxDQUFBQyxVQUFBLEdBQUFELENBQUEsS0FBQUUsT0FBQSxFQUFBRixDQUFBO0FBR3RHLE1BQU1HLEtBQUssR0FBRyxJQUFBQyxlQUFRLEVBQUMsT0FBTyxDQUFDO0FBQy9CLE1BQU1DLFFBQVEsR0FBRyw2QkFBNkI7QUFDOUMsTUFBTUMsU0FBUyxHQUFHLDBCQUEwQjtBQUM1QyxNQUFNQyxnQkFBZ0IsR0FBRyxHQUFHRixRQUFRLDBEQUEwRDtBQUM5RixNQUFNRyx5QkFBeUIsR0FB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