israeli-bank-scrapers
Version:
Provide scrapers for all major Israeli banks and credit card companies
250 lines (243 loc) • 43.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _moment = _interopRequireDefault(require("moment"));
var _constants = require("../constants");
var _elementsInteractions = require("../helpers/elements-interactions");
var _navigation = require("../helpers/navigation");
var _transactions = require("../helpers/transactions");
var _transactions2 = require("../transactions");
var _baseScraperWithBrowser = require("./base-scraper-with-browser");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const LOGIN_URL = 'https://login.yahav.co.il/login/';
const BASE_URL = 'https://digital.yahav.co.il/BaNCSDigitalUI/app/index.html#/';
const INVALID_DETAILS_SELECTOR = '.ui-dialog-buttons';
const CHANGE_PASSWORD_OLD_PASS = 'input#ef_req_parameter_old_credential';
const BASE_WELCOME_URL = `${BASE_URL}main/home`;
const PORTFOLIO_FORM = 'form[name="formPortfolioSelect"]';
const ACCOUNT_ID_SELECTOR_SINGLE = 'span.portfolio-value';
const ACCOUNT_ID_SELECTOR_MULTI = `${PORTFOLIO_FORM} .selected-item-top`;
const PORTFOLIO_OPTION_SELECTOR = `${PORTFOLIO_FORM} .drop-down-item-list li.drop-down-item`;
const ACCOUNT_DETAILS_SELECTOR = '.account-details';
const DATE_FORMAT = 'DD/MM/YYYY';
const USER_ELEM = '#username';
const PASSWD_ELEM = '#password';
const NATIONALID_ELEM = '#pinno';
const SUBMIT_LOGIN_SELECTOR = '.btn';
function getPossibleLoginResults(page) {
// checkout file `base-scraper-with-browser.ts` for available result types
const urls = {};
urls[_baseScraperWithBrowser.LoginResults.Success] = [`${BASE_WELCOME_URL}`];
urls[_baseScraperWithBrowser.LoginResults.InvalidPassword] = [async () => {
return (0, _elementsInteractions.elementPresentOnPage)(page, `${INVALID_DETAILS_SELECTOR}`);
}];
urls[_baseScraperWithBrowser.LoginResults.ChangePassword] = [async () => {
return (0, _elementsInteractions.elementPresentOnPage)(page, `${CHANGE_PASSWORD_OLD_PASS}`);
}];
return urls;
}
function getAmountData(amountStr) {
const amountStrCopy = amountStr.replace(',', '');
return parseFloat(amountStrCopy);
}
function getTxnAmount(txn) {
const credit = getAmountData(txn.credit);
const debit = getAmountData(txn.debit);
return (Number.isNaN(credit) ? 0 : credit) - (Number.isNaN(debit) ? 0 : debit);
}
function convertTransactions(txns, options) {
return txns.map(txn => {
const convertedDate = (0, _moment.default)(txn.date, DATE_FORMAT).toISOString();
const convertedAmount = getTxnAmount(txn);
const result = {
type: _transactions2.TransactionTypes.Normal,
identifier: txn.reference ? parseInt(txn.reference, 10) : undefined,
date: convertedDate,
processedDate: convertedDate,
originalAmount: convertedAmount,
originalCurrency: _constants.SHEKEL_CURRENCY,
chargedAmount: convertedAmount,
status: txn.status,
description: txn.description,
memo: txn.memo
};
if (options?.includeRawTransaction) {
result.rawTransaction = (0, _transactions.getRawTransaction)(txn);
}
return result;
});
}
function handleTransactionRow(txns, txnRow) {
const div = txnRow.innerDivs;
// Remove anything except digits.
const regex = /\D+/gm;
const tx = {
date: div[1],
reference: div[2].replace(regex, ''),
memo: '',
description: div[3],
debit: div[4],
credit: div[5],
status: _transactions2.TransactionStatuses.Completed
};
txns.push(tx);
}
async function getAccountTransactions(page, options) {
// Wait for transactions.
await (0, _elementsInteractions.waitUntilElementFound)(page, '.under-line-txn-table-header', true);
const txns = [];
const transactionsDivs = await (0, _elementsInteractions.pageEvalAll)(page, '.list-item-holder .entire-content-ctr', [], divs => {
return divs.map(div => ({
id: div.getAttribute('id') || '',
innerDivs: Array.from(div.getElementsByTagName('div')).map(el => el.innerText)
}));
});
for (const txnRow of transactionsDivs) {
handleTransactionRow(txns, txnRow);
}
return convertTransactions(txns, options);
}
// All datepicker selectors are scoped to the "from date" control to avoid ambiguity with the "to date" picker.
const FROM_PICKER = 'date-picker-access[btn-label="from"]';
async function searchByDates(page, startDate) {
await (0, _elementsInteractions.waitUntilElementFound)(page, `${FROM_PICKER} a.datepicker-button`, true);
await (0, _elementsInteractions.clickButton)(page, `${FROM_PICKER} a.datepicker-button`);
await (0, _elementsInteractions.waitUntilElementFound)(page, `${FROM_PICKER} .datepicker-calendar`, true);
// Read the input value (set by ng-value/textToDateFilter, always DD/MM/YYYY) to determine which
// month the calendar opened on — avoids parsing the header text which renders in the account's locale.
const inputValue = await page.$eval(`${FROM_PICKER} .date-picker-input`, el => el.value);
const displayedMoment = (0, _moment.default)(inputValue, 'DD/MM/YYYY');
const monthsToGoBack = (displayedMoment.year() - startDate.year()) * 12 + (displayedMoment.month() - startDate.month());
for (let i = 0; i < monthsToGoBack; i += 1) {
const prevMonthSelector = `${FROM_PICKER} .datepicker-month-prev.enabled`;
await (0, _elementsInteractions.waitUntilElementFound)(page, prevMonthSelector, true);
await (0, _elementsInteractions.clickButton)(page, prevMonthSelector);
}
// :not(.other-month) avoids adjacent-month cells sharing the same day number.
const daySelector = `${FROM_PICKER} .datepicker-calendar td.day.selectable:not(.other-month)[data-value="${startDate.date()}"]`;
await (0, _elementsInteractions.waitUntilElementFound)(page, daySelector, true);
await (0, _elementsInteractions.clickButton)(page, daySelector);
}
async function fetchAccountData(page, startDate, accountID, options) {
await (0, _elementsInteractions.waitUntilElementDisappear)(page, '.loading-bar-spinner');
await searchByDates(page, startDate);
await (0, _elementsInteractions.waitUntilElementDisappear)(page, '.loading-bar-spinner');
const txns = await getAccountTransactions(page, options);
return {
accountNumber: accountID,
txns
};
}
// Multi-portfolio iteration contributed by @mamlukishay (https://github.com/gczobel/israeli-bank-scrapers/pull/1)
// Multi-portfolio accounts render <inline-drop-down> inside form[name="formPortfolioSelect"]
// (Angular ng-if="portfolioList.length > 1") with the current portfolio at .selected-item-top
// and the unselected ones as <li>s; single-portfolio accounts render only the single selector.
// Returned selected-first so fetchAccounts can skip re-selecting on the first iteration.
async function getPortfolioIDs(page) {
await Promise.any([page.waitForSelector(ACCOUNT_ID_SELECTOR_MULTI, {
timeout: 10000
}), page.waitForSelector(ACCOUNT_ID_SELECTOR_SINGLE, {
timeout: 10000
})]).catch(() => null);
return page.evaluate((multiSelector, optionSelector, singleSelector) => {
const selected = document.querySelector(multiSelector)?.textContent?.trim();
if (selected) {
const others = Array.from(document.querySelectorAll(optionSelector)).map(li => li.textContent?.trim() ?? '');
return [selected, ...others].filter(Boolean);
}
const single = document.querySelector(singleSelector)?.textContent?.trim();
return single ? [single] : [];
}, ACCOUNT_ID_SELECTOR_MULTI, PORTFOLIO_OPTION_SELECTOR, ACCOUNT_ID_SELECTOR_SINGLE);
}
// Angular's listItemAction navigates the page back to /main/home with the new portfolio
// selected — callers must re-enter the statements flow after this returns.
async function selectPortfolio(page, targetID) {
const clicked = await page.$$eval(PORTFOLIO_OPTION_SELECTOR, (lis, id) => {
const target = lis.find(li => li.textContent?.trim() === id);
if (!target) return false;
target.click();
return true;
}, targetID);
if (!clicked) throw new Error(`Portfolio option not found for ID: ${targetID}`);
await (0, _elementsInteractions.waitUntilElementDisappear)(page, '.loading-bar-spinner');
}
async function fetchAccounts(page, startDate, options) {
// Snapshot up front: the dropdown only lists unselected portfolios, so after the first
// switch we would lose any not yet scraped.
const portfolioIDs = await getPortfolioIDs(page);
if (portfolioIDs.length === 0) {
throw new Error('No portfolios found on /main/home — Yahav DOM likely changed');
}
const accounts = [];
for (let i = 0; i < portfolioIDs.length; i += 1) {
const portfolioID = portfolioIDs[i];
if (i > 0) {
await selectPortfolio(page, portfolioID);
}
await (0, _elementsInteractions.waitUntilElementFound)(page, ACCOUNT_DETAILS_SELECTOR, true);
await (0, _elementsInteractions.clickButton)(page, ACCOUNT_DETAILS_SELECTOR);
await (0, _elementsInteractions.waitUntilElementFound)(page, '.statement-options .selected-item-top', true);
accounts.push(await fetchAccountData(page, startDate, portfolioID, options));
}
return accounts;
}
async function waitReadinessForAll(page) {
await (0, _elementsInteractions.waitUntilElementFound)(page, `${USER_ELEM}`, true);
await (0, _elementsInteractions.waitUntilElementFound)(page, `${PASSWD_ELEM}`, true);
await (0, _elementsInteractions.waitUntilElementFound)(page, `${NATIONALID_ELEM}`, true);
await (0, _elementsInteractions.waitUntilElementFound)(page, `${SUBMIT_LOGIN_SELECTOR}`, true);
}
async function redirectOrDialog(page) {
// Click on bank messages if any.
await (0, _navigation.waitForNavigation)(page);
await (0, _elementsInteractions.waitUntilElementDisappear)(page, '.loading-bar-spinner');
const hasMessage = await (0, _elementsInteractions.elementPresentOnPage)(page, '.messaging-links-container');
if (hasMessage) {
await (0, _elementsInteractions.clickButton)(page, '.link-1');
}
const promise1 = page.waitForSelector(ACCOUNT_DETAILS_SELECTOR, {
timeout: 30000
});
const promise2 = page.waitForSelector(CHANGE_PASSWORD_OLD_PASS, {
timeout: 30000
});
const promises = [promise1, promise2];
await Promise.race(promises);
await (0, _elementsInteractions.waitUntilElementDisappear)(page, '.loading-bar-spinner');
}
class YahavScraper extends _baseScraperWithBrowser.BaseScraperWithBrowser {
getLoginOptions(credentials) {
return {
loginUrl: `${LOGIN_URL}`,
fields: [{
selector: `${USER_ELEM}`,
value: credentials.username
}, {
selector: `${PASSWD_ELEM}`,
value: credentials.password
}, {
selector: `${NATIONALID_ELEM}`,
value: credentials.nationalID
}],
submitButtonSelector: `${SUBMIT_LOGIN_SELECTOR}`,
checkReadiness: async () => waitReadinessForAll(this.page),
postAction: async () => redirectOrDialog(this.page),
possibleResults: getPossibleLoginResults(this.page)
};
}
async fetchData() {
await (0, _elementsInteractions.waitUntilElementFound)(this.page, ACCOUNT_DETAILS_SELECTOR, true);
const defaultStartMoment = (0, _moment.default)().subtract(3, 'months').add(1, 'day');
const startDate = this.options.startDate || defaultStartMoment.toDate();
const startMoment = _moment.default.min(_moment.default.max(defaultStartMoment, (0, _moment.default)(startDate)), (0, _moment.default)());
const accounts = await fetchAccounts(this.page, startMoment, this.options);
return {
success: true,
accounts
};
}
}
var _default = exports.default = YahavScraper;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfdHJhbnNhY3Rpb25zIiwiX3RyYW5zYWN0aW9uczIiLCJfYmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIkxPR0lOX1VSTCIsIkJBU0VfVVJMIiwiSU5WQUxJRF9ERVRBSUxTX1NFTEVDVE9SIiwiQ0hBTkdFX1BBU1NXT1JEX09MRF9QQVNTIiwiQkFTRV9XRUxDT01FX1VSTCIsIlBPUlRGT0xJT19GT1JNIiwiQUNDT1VOVF9JRF9TRUxFQ1RPUl9TSU5HTEUiLCJBQ0NPVU5UX0lEX1NFTEVDVE9SX01VTFRJIiwiUE9SVEZPTElPX09QVElPTl9TRUxFQ1RPUiIsIkFDQ09VTlRfREVUQUlMU19TRUxFQ1RPUiIsIkRBVEVfRk9STUFUIiwiVVNFUl9FTEVNIiwiUEFTU1dEX0VMRU0iLCJOQVRJT05BTElEX0VMRU0iLCJTVUJNSVRfTE9HSU5fU0VMRUNUT1IiLCJnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cyIsInBhZ2UiLCJ1cmxzIiwiTG9naW5SZXN1bHRzIiwiU3VjY2VzcyIsIkludmFsaWRQYXNzd29yZCIsImVsZW1lbnRQcmVzZW50T25QYWdlIiwiQ2hhbmdlUGFzc3dvcmQiLCJnZXRBbW91bnREYXRhIiwiYW1vdW50U3RyIiwiYW1vdW50U3RyQ29weSIsInJlcGxhY2UiLCJwYXJzZUZsb2F0IiwiZ2V0VHhuQW1vdW50IiwidHhuIiwiY3JlZGl0IiwiZGViaXQiLCJOdW1iZXIiLCJpc05hTiIsImNvbnZlcnRUcmFuc2FjdGlvbnMiLCJ0eG5zIiwib3B0aW9ucyIsIm1hcCIsImNvbnZlcnRlZERhdGUiLCJtb21lbnQiLCJkYXRlIiwidG9JU09TdHJpbmciLCJjb252ZXJ0ZWRBbW91bnQiLCJyZXN1bHQiLCJ0eXBlIiwiVHJhbnNhY3Rpb25UeXBlcyIsIk5vcm1hbCIsImlkZW50aWZpZXIiLCJyZWZlcmVuY2UiLCJwYXJzZUludCIsInVuZGVmaW5lZCIsInByb2Nlc3NlZERhdGUiLCJvcmlnaW5hbEFtb3VudCIsIm9yaWdpbmFsQ3VycmVuY3kiLCJTSEVLRUxfQ1VSUkVOQ1kiLCJjaGFyZ2VkQW1vdW50Iiwic3RhdHVzIiwiZGVzY3JpcHRpb24iLCJtZW1vIiwiaW5jbHVkZVJhd1RyYW5zYWN0aW9uIiwicmF3VHJhbnNhY3Rpb24iLCJnZXRSYXdUcmFuc2FjdGlvbiIsImhhbmRsZVRyYW5zYWN0aW9uUm93IiwidHhuUm93IiwiZGl2IiwiaW5uZXJEaXZzIiwicmVnZXgiLCJ0eCIsIlRyYW5zYWN0aW9uU3RhdHVzZXMiLCJDb21wbGV0ZWQiLCJwdXNoIiwiZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyIsIndhaXRVbnRpbEVsZW1lbnRGb3VuZCIsInRyYW5zYWN0aW9uc0RpdnMiLCJwYWdlRXZhbEFsbCIsImRpdnMiLCJpZCIsImdldEF0dHJpYnV0ZSIsIkFycmF5IiwiZnJvbSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwiZWwiLCJpbm5lclRleHQiLCJGUk9NX1BJQ0tFUiIsInNlYXJjaEJ5RGF0ZXMiLCJzdGFydERhdGUiLCJjbGlja0J1dHRvbiIsImlucHV0VmFsdWUiLCIkZXZhbCIsInZhbHVlIiwiZGlzcGxheWVkTW9tZW50IiwibW9udGhzVG9Hb0JhY2siLCJ5ZWFyIiwibW9udGgiLCJpIiwicHJldk1vbnRoU2VsZWN0b3IiLCJkYXlTZWxlY3RvciIsImZldGNoQWNjb3VudERhdGEiLCJhY2NvdW50SUQiLCJ3YWl0VW50aWxFbGVtZW50RGlzYXBwZWFyIiwiYWNjb3VudE51bWJlciIsImdldFBvcnRmb2xpb0lEcyIsIlByb21pc2UiLCJhbnkiLCJ3YWl0Rm9yU2VsZWN0b3IiLCJ0aW1lb3V0IiwiY2F0Y2giLCJldmFsdWF0ZSIsIm11bHRpU2VsZWN0b3IiLCJvcHRpb25TZWxlY3RvciIsInNpbmdsZVNlbGVjdG9yIiwic2VsZWN0ZWQiLCJkb2N1bWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJ0ZXh0Q29udGVudCIsInRyaW0iLCJvdGhlcnMiLCJxdWVyeVNlbGVjdG9yQWxsIiwibGkiLCJmaWx0ZXIiLCJCb29sZWFuIiwic2luZ2xlIiwic2VsZWN0UG9ydGZvbGlvIiwidGFyZ2V0SUQiLCJjbGlja2VkIiwiJCRldmFsIiwibGlzIiwidGFyZ2V0IiwiZmluZCIsImNsaWNrIiwiRXJyb3IiLCJmZXRjaEFjY291bnRzIiwicG9ydGZvbGlvSURzIiwibGVuZ3RoIiwiYWNjb3VudHMiLCJwb3J0Zm9saW9JRCIsIndhaXRSZWFkaW5lc3NGb3JBbGwiLCJyZWRpcmVjdE9yRGlhbG9nIiwid2FpdEZvck5hdmlnYXRpb24iLCJoYXNNZXNzYWdlIiwicHJvbWlzZTEiLCJwcm9taXNlMiIsInByb21pc2VzIiwicmFjZSIsIllhaGF2U2NyYXBlciIsIkJhc2VTY3JhcGVyV2l0aEJyb3dzZXIiLCJnZXRMb2dpbk9wdGlvbnMiLCJjcmVkZW50aWFscyIsImxvZ2luVXJsIiwiZmllbGRzIiwic2VsZWN0b3IiLCJ1c2VybmFtZSIsInBhc3N3b3JkIiwibmF0aW9uYWxJRCIsInN1Ym1pdEJ1dHRvblNlbGVjdG9yIiwiY2hlY2tSZWFkaW5lc3MiLCJwb3N0QWN0aW9uIiwicG9zc2libGVSZXN1bHRzIiwiZmV0Y2hEYXRhIiwiZGVmYXVsdFN0YXJ0TW9tZW50Iiwic3VidHJhY3QiLCJhZGQiLCJ0b0RhdGUiLCJzdGFydE1vbWVudCIsIm1pbiIsIm1heCIsInN1Y2Nlc3MiLCJfZGVmYXVsdCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvc2NyYXBlcnMveWFoYXYudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IG1vbWVudCwgeyB0eXBlIE1vbWVudCB9IGZyb20gJ21vbWVudCc7XG5pbXBvcnQgeyB0eXBlIFBhZ2UgfSBmcm9tICdwdXBwZXRlZXInO1xuaW1wb3J0IHsgU0hFS0VMX0NVUlJFTkNZIH0gZnJvbSAnLi4vY29uc3RhbnRzJztcbmltcG9ydCB7XG4gIGNsaWNrQnV0dG9uLFxuICBlbGVtZW50UHJlc2VudE9uUGFnZSxcbiAgcGFnZUV2YWxBbGwsXG4gIHdhaXRVbnRpbEVsZW1lbnREaXNhcHBlYXIsXG4gIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCxcbn0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgd2FpdEZvck5hdmlnYXRpb24gfSBmcm9tICcuLi9oZWxwZXJzL25hdmlnYXRpb24nO1xuaW1wb3J0IHsgZ2V0UmF3VHJhbnNhY3Rpb24gfSBmcm9tICcuLi9oZWxwZXJzL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvblN0YXR1c2VzLCBUcmFuc2FjdGlvblR5cGVzLCB0eXBlIFRyYW5zYWN0aW9uLCB0eXBlIFRyYW5zYWN0aW9uc0FjY291bnQgfSBmcm9tICcuLi90cmFuc2FjdGlvbnMnO1xuaW1wb3J0IHsgQmFzZVNjcmFwZXJXaXRoQnJvd3NlciwgTG9naW5SZXN1bHRzLCB0eXBlIFBvc3NpYmxlTG9naW5SZXN1bHRzIH0gZnJvbSAnLi9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyJztcbmltcG9ydCB7IHR5cGUgU2NyYXBlck9wdGlvbnMgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5cbmNvbnN0IExPR0lOX1VSTCA9ICdodHRwczovL2xvZ2luLnlhaGF2LmNvLmlsL2xvZ2luLyc7XG5jb25zdCBCQVNFX1VSTCA9ICdodHRwczovL2RpZ2l0YWwueWFoYXYuY28uaWwvQmFOQ1NEaWdpdGFsVUkvYXBwL2luZGV4Lmh0bWwjLyc7XG5jb25zdCBJTlZBTElEX0RFVEFJTFNfU0VMRUNUT1IgPSAnLnVpLWRpYWxvZy1idXR0b25zJztcbmNvbnN0IENIQU5HRV9QQVNTV09SRF9PTERfUEFTUyA9ICdpbnB1dCNlZl9yZXFfcGFyYW1ldGVyX29sZF9jcmVkZW50aWFsJztcbmNvbnN0IEJBU0VfV0VMQ09NRV9VUkwgPSBgJHtCQVNFX1VSTH1tYWluL2hvbWVgO1xuXG5jb25zdCBQT1JURk9MSU9fRk9STSA9ICdmb3JtW25hbWU9XCJmb3JtUG9ydGZvbGlvU2VsZWN0XCJdJztcbmNvbnN0IEFDQ09VTlRfSURfU0VMRUNUT1JfU0lOR0xFID0gJ3NwYW4ucG9ydGZvbGlvLXZhbHVlJztcbmNvbnN0IEFDQ09VTlRfSURfU0VMRUNUT1JfTVVMVEkgPSBgJHtQT1JURk9MSU9fRk9STX0gLnNlbGVjdGVkLWl0ZW0tdG9wYDtcbmNvbnN0IFBPUlRGT0xJT19PUFRJT05fU0VMRUNUT1IgPSBgJHtQT1JURk9MSU9fRk9STX0gLmRyb3AtZG93bi1pdGVtLWxpc3QgbGkuZHJvcC1kb3duLWl0ZW1gO1xuY29uc3QgQUNDT1VOVF9ERVRBSUxTX1NFTEVDVE9SID0gJy5hY2NvdW50LWRldGFpbHMnO1xuY29uc3QgREFURV9GT1JNQVQgPSAnREQvTU0vWVlZWSc7XG5cbmNvbnN0IFVTRVJfRUxFTSA9ICcjdXNlcm5hbWUnO1xuY29uc3QgUEFTU1dEX0VMRU0gPSAnI3Bhc3N3b3JkJztcbmNvbnN0IE5BVElPTkFMSURfRUxFTSA9ICcjcGlubm8nO1xuY29uc3QgU1VCTUlUX0xPR0lOX1NFTEVDVE9SID0gJy5idG4nO1xuXG5pbnRlcmZhY2UgU2NyYXBlZFRyYW5zYWN0aW9uIHtcbiAgY3JlZGl0OiBzdHJpbmc7XG4gIGRlYml0OiBzdHJpbmc7XG4gIGRhdGU6IHN0cmluZztcbiAgcmVmZXJlbmNlPzogc3RyaW5nO1xuICBkZXNjcmlwdGlvbjogc3RyaW5nO1xuICBtZW1vOiBzdHJpbmc7XG4gIHN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcztcbn1cblxuZnVuY3Rpb24gZ2V0UG9zc2libGVMb2dpblJlc3VsdHMocGFnZTogUGFnZSk6IFBvc3NpYmxlTG9naW5SZXN1bHRzIHtcbiAgLy8gY2hlY2tvdXQgZmlsZSBgYmFzZS1zY3JhcGVyLXdpdGgtYnJvd3Nlci50c2AgZm9yIGF2YWlsYWJsZSByZXN1bHQgdHlwZXNcbiAgY29uc3QgdXJsczogUG9zc2libGVMb2dpblJlc3VsdHMgPSB7fTtcbiAgdXJsc1tMb2dpblJlc3VsdHMuU3VjY2Vzc10gPSBbYCR7QkFTRV9XRUxDT01FX1VSTH1gXTtcbiAgdXJsc1tMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkXSA9IFtcbiAgICBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gZWxlbWVudFByZXNlbnRPblBhZ2UocGFnZSwgYCR7SU5WQUxJRF9ERVRBSUxTX1NFTEVDVE9SfWApO1xuICAgIH0sXG4gIF07XG5cbiAgdXJsc1tMb2dpblJlc3VsdHMuQ2hhbmdlUGFzc3dvcmRdID0gW1xuICAgIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBlbGVtZW50UHJlc2VudE9uUGFnZShwYWdlLCBgJHtDSEFOR0VfUEFTU1dPUkRfT0xEX1BBU1N9YCk7XG4gICAgfSxcbiAgXTtcblxuICByZXR1cm4gdXJscztcbn1cblxuZnVuY3Rpb24gZ2V0QW1vdW50RGF0YShhbW91bnRTdHI6IHN0cmluZykge1xuICBjb25zdCBhbW91bnRTdHJDb3B5ID0gYW1vdW50U3RyLnJlcGxhY2UoJywnLCAnJyk7XG4gIHJldHVybiBwYXJzZUZsb2F0KGFtb3VudFN0ckNvcHkpO1xufVxuXG5mdW5jdGlvbiBnZXRUeG5BbW91bnQodHhuOiBTY3JhcGVkVHJhbnNhY3Rpb24pIHtcbiAgY29uc3QgY3JlZGl0ID0gZ2V0QW1vdW50RGF0YSh0eG4uY3JlZGl0KTtcbiAgY29uc3QgZGViaXQgPSBnZXRBbW91bnREYXRhKHR4bi5kZWJpdCk7XG4gIHJldHVybiAoTnVtYmVyLmlzTmFOKGNyZWRpdCkgPyAwIDogY3JlZGl0KSAtIChOdW1iZXIuaXNOYU4oZGViaXQpID8gMCA6IGRlYml0KTtcbn1cblxudHlwZSBUcmFuc2FjdGlvbnNUciA9IHsgaWQ6IHN0cmluZzsgaW5uZXJEaXZzOiBzdHJpbmdbXSB9O1xuXG5mdW5jdGlvbiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnM6IFNjcmFwZWRUcmFuc2FjdGlvbltdLCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpOiBUcmFuc2FjdGlvbltdIHtcbiAgcmV0dXJuIHR4bnMubWFwKHR4biA9PiB7XG4gICAgY29uc3QgY29udmVydGVkRGF0ZSA9IG1vbWVudCh0eG4uZGF0ZSwgREFURV9GT1JNQVQpLnRvSVNPU3RyaW5nKCk7XG4gICAgY29uc3QgY29udmVydGVkQW1vdW50ID0gZ2V0VHhuQW1vdW50KHR4bik7XG4gICAgY29uc3QgcmVzdWx0OiBUcmFuc2FjdGlvbiA9IHtcbiAgICAgIHR5cGU6IFRyYW5zYWN0aW9uVHlwZXMuTm9ybWFsLFxuICAgICAgaWRlbnRpZmllcjogdHhuLnJlZmVyZW5jZSA/IHBhcnNlSW50KHR4bi5yZWZlcmVuY2UsIDEwKSA6IHVuZGVmaW5lZCxcbiAgICAgIGRhdGU6IGNvbnZlcnRlZERhdGUsXG4gICAgICBwcm9jZXNzZWREYXRlOiBjb252ZXJ0ZWREYXRlLFxuICAgICAgb3JpZ2luYWxBbW91bnQ6IGNvbnZlcnRlZEFtb3VudCxcbiAgICAgIG9yaWdpbmFsQ3VycmVuY3k6IFNIRUtFTF9DVVJSRU5DWSxcbiAgICAgIGNoYXJnZWRBbW91bnQ6IGNvbnZlcnRlZEFtb3VudCxcbiAgICAgIHN0YXR1czogdHhuLnN0YXR1cyxcbiAgICAgIGRlc2NyaXB0aW9uOiB0eG4uZGVzY3JpcHRpb24sXG4gICAgICBtZW1vOiB0eG4ubWVtbyxcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnM/LmluY2x1ZGVSYXdUcmFuc2FjdGlvbikge1xuICAgICAgcmVzdWx0LnJhd1RyYW5zYWN0aW9uID0gZ2V0UmF3VHJhbnNhY3Rpb24odHhuKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9KTtcbn1cblxuZnVuY3Rpb24gaGFuZGxlVHJhbnNhY3Rpb25Sb3codHhuczogU2NyYXBlZFRyYW5zYWN0aW9uW10sIHR4blJvdzogVHJhbnNhY3Rpb25zVHIpIHtcbiAgY29uc3QgZGl2ID0gdHhuUm93LmlubmVyRGl2cztcblxuICAvLyBSZW1vdmUgYW55dGhpbmcgZXhjZXB0IGRpZ2l0cy5cbiAgY29uc3QgcmVnZXggPSAvXFxEKy9nbTtcblxuICBjb25zdCB0eDogU2NyYXBlZFRyYW5zYWN0aW9uID0ge1xuICAgIGRhdGU6IGRpdlsxXSxcbiAgICByZWZlcmVuY2U6IGRpdlsyXS5yZXBsYWNlKHJlZ2V4LCAnJyksXG4gICAgbWVtbzogJycsXG4gICAgZGVzY3JpcHRpb246IGRpdlszXSxcbiAgICBkZWJpdDogZGl2WzRdLFxuICAgIGNyZWRpdDogZGl2WzVdLFxuICAgIHN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcy5Db21wbGV0ZWQsXG4gIH07XG5cbiAgdHhucy5wdXNoKHR4KTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyhwYWdlOiBQYWdlLCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpOiBQcm9taXNlPFRyYW5zYWN0aW9uW10+IHtcbiAgLy8gV2FpdCBmb3IgdHJhbnNhY3Rpb25zLlxuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJy51bmRlci1saW5lLXR4bi10YWJsZS1oZWFkZXInLCB0cnVlKTtcblxuICBjb25zdCB0eG5zOiBTY3JhcGVkVHJhbnNhY3Rpb25bXSA9IFtdO1xuICBjb25zdCB0cmFuc2FjdGlvbnNEaXZzID0gYXdhaXQgcGFnZUV2YWxBbGw8VHJhbnNhY3Rpb25zVHJbXT4oXG4gICAgcGFnZSxcbiAgICAnLmxpc3QtaXRlbS1ob2xkZXIgLmVudGlyZS1jb250ZW50LWN0cicsXG4gICAgW10sXG4gICAgZGl2cyA9PiB7XG4gICAgICByZXR1cm4gKGRpdnMgYXMgSFRNTEVsZW1lbnRbXSkubWFwKGRpdiA9PiAoe1xuICAgICAgICBpZDogZGl2LmdldEF0dHJpYnV0ZSgnaWQnKSB8fCAnJyxcbiAgICAgICAgaW5uZXJEaXZzOiBBcnJheS5mcm9tKGRpdi5nZXRFbGVtZW50c0J5VGFnTmFtZSgnZGl2JykpLm1hcChlbCA9PiAoZWwgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dCksXG4gICAgICB9KSk7XG4gICAgfSxcbiAgKTtcblxuICBmb3IgKGNvbnN0IHR4blJvdyBvZiB0cmFuc2FjdGlvbnNEaXZzKSB7XG4gICAgaGFuZGxlVHJhbnNhY3Rpb25Sb3codHhucywgdHhuUm93KTtcbiAgfVxuXG4gIHJldHVybiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnMsIG9wdGlvbnMpO1xufVxuXG4vLyBBbGwgZGF0ZXBpY2tlciBzZWxlY3RvcnMgYXJlIHNjb3BlZCB0byB0aGUgXCJmcm9tIGRhdGVcIiBjb250cm9sIHRvIGF2b2lkIGFtYmlndWl0eSB3aXRoIHRoZSBcInRvIGRhdGVcIiBwaWNrZXIuXG5jb25zdCBGUk9NX1BJQ0tFUiA9ICdkYXRlLXBpY2tlci1hY2Nlc3NbYnRuLWxhYmVsPVwiZnJvbVwiXSc7XG5cbmFzeW5jIGZ1bmN0aW9uIHNlYXJjaEJ5RGF0ZXMocGFnZTogUGFnZSwgc3RhcnREYXRlOiBNb21lbnQpIHtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGAke0ZST01fUElDS0VSfSBhLmRhdGVwaWNrZXItYnV0dG9uYCwgdHJ1ZSk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGAke0ZST01fUElDS0VSfSBhLmRhdGVwaWNrZXItYnV0dG9uYCk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBgJHtGUk9NX1BJQ0tFUn0gLmRhdGVwaWNrZXItY2FsZW5kYXJgLCB0cnVlKTtcblxuICAvLyBSZWFkIHRoZSBpbnB1dCB2YWx1ZSAoc2V0IGJ5IG5nLXZhbHVlL3RleHRUb0RhdGVGaWx0ZXIsIGFsd2F5cyBERC9NTS9ZWVlZKSB0byBkZXRlcm1pbmUgd2hpY2hcbiAgLy8gbW9udGggdGhlIGNhbGVuZGFyIG9wZW5lZCBvbiDigJQgYXZvaWRzIHBhcnNpbmcgdGhlIGhlYWRlciB0ZXh0IHdoaWNoIHJlbmRlcnMgaW4gdGhlIGFjY291bnQncyBsb2NhbGUuXG4gIGNvbnN0IGlucHV0VmFsdWUgPSBhd2FpdCBwYWdlLiRldmFsKGAke0ZST01fUElDS0VSfSAuZGF0ZS1waWNrZXItaW5wdXRgLCBlbCA9PiAoZWwgYXMgSFRNTElucHV0RWxlbWVudCkudmFsdWUpO1xuICBjb25zdCBkaXNwbGF5ZWRNb21lbnQgPSBtb21lbnQoaW5wdXRWYWx1ZSwgJ0REL01NL1lZWVknKTtcbiAgY29uc3QgbW9udGhzVG9Hb0JhY2sgPVxuICAgIChkaXNwbGF5ZWRNb21lbnQueWVhcigpIC0gc3RhcnREYXRlLnllYXIoKSkgKiAxMiArIChkaXNwbGF5ZWRNb21lbnQubW9udGgoKSAtIHN0YXJ0RGF0ZS5tb250aCgpKTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBtb250aHNUb0dvQmFjazsgaSArPSAxKSB7XG4gICAgY29uc3QgcHJldk1vbnRoU2VsZWN0b3IgPSBgJHtGUk9NX1BJQ0tFUn0gLmRhdGVwaWNrZXItbW9udGgtcHJldi5lbmFibGVkYDtcbiAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgcHJldk1vbnRoU2VsZWN0b3IsIHRydWUpO1xuICAgIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIHByZXZNb250aFNlbGVjdG9yKTtcbiAgfVxuXG4gIC8vIDpub3QoLm90aGVyLW1vbnRoKSBhdm9pZHMgYWRqYWNlbnQtbW9udGggY2VsbHMgc2hhcmluZyB0aGUgc2FtZSBkYXkgbnVtYmVyLlxuICBjb25zdCBkYXlTZWxlY3RvciA9IGAke0ZST01fUElDS0VSfSAuZGF0ZXBpY2tlci1jYWxlbmRhciB0ZC5kYXkuc2VsZWN0YWJsZTpub3QoLm90aGVyLW1vbnRoKVtkYXRhLXZhbHVlPVwiJHtzdGFydERhdGUuZGF0ZSgpfVwiXWA7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBkYXlTZWxlY3RvciwgdHJ1ZSk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGRheVNlbGVjdG9yKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hBY2NvdW50RGF0YShcbiAgcGFnZTogUGFnZSxcbiAgc3RhcnREYXRlOiBNb21lbnQsXG4gIGFjY291bnRJRDogc3RyaW5nLFxuICBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMsXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnQ+IHtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudERpc2FwcGVhcihwYWdlLCAnLmxvYWRpbmctYmFyLXNwaW5uZXInKTtcbiAgYXdhaXQgc2VhcmNoQnlEYXRlcyhwYWdlLCBzdGFydERhdGUpO1xuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50RGlzYXBwZWFyKHBhZ2UsICcubG9hZGluZy1iYXItc3Bpbm5lcicpO1xuICBjb25zdCB0eG5zID0gYXdhaXQgZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyhwYWdlLCBvcHRpb25zKTtcblxuICByZXR1cm4ge1xuICAgIGFjY291bnROdW1iZXI6IGFjY291bnRJRCxcbiAgICB0eG5zLFxuICB9O1xufVxuXG4vLyBNdWx0aS1wb3J0Zm9saW8gaXRlcmF0aW9uIGNvbnRyaWJ1dGVkIGJ5IEBtYW1sdWtpc2hheSAoaHR0cHM6Ly9naXRodWIuY29tL2djem9iZWwvaXNyYWVsaS1iYW5rLXNjcmFwZXJzL3B1bGwvMSlcbi8vIE11bHRpLXBvcnRmb2xpbyBhY2NvdW50cyByZW5kZXIgPGlubGluZS1kcm9wLWRvd24+IGluc2lkZSBmb3JtW25hbWU9XCJmb3JtUG9ydGZvbGlvU2VsZWN0XCJdXG4vLyAoQW5ndWxhciBuZy1pZj1cInBvcnRmb2xpb0xpc3QubGVuZ3RoID4gMVwiKSB3aXRoIHRoZSBjdXJyZW50IHBvcnRmb2xpbyBhdCAuc2VsZWN0ZWQtaXRlbS10b3Bcbi8vIGFuZCB0aGUgdW5zZWxlY3RlZCBvbmVzIGFzIDxsaT5zOyBzaW5nbGUtcG9ydGZvbGlvIGFjY291bnRzIHJlbmRlciBvbmx5IHRoZSBzaW5nbGUgc2VsZWN0b3IuXG4vLyBSZXR1cm5lZCBzZWxlY3RlZC1maXJzdCBzbyBmZXRjaEFjY291bnRzIGNhbiBza2lwIHJlLXNlbGVjdGluZyBvbiB0aGUgZmlyc3QgaXRlcmF0aW9uLlxuYXN5bmMgZnVuY3Rpb24gZ2V0UG9ydGZvbGlvSURzKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGF3YWl0IFByb21pc2UuYW55KFtcbiAgICBwYWdlLndhaXRGb3JTZWxlY3RvcihBQ0NPVU5UX0lEX1NFTEVDVE9SX01VTFRJLCB7IHRpbWVvdXQ6IDEwMDAwIH0pLFxuICAgIHBhZ2Uud2FpdEZvclNlbGVjdG9yKEFDQ09VTlRfSURfU0VMRUNUT1JfU0lOR0xFLCB7IHRpbWVvdXQ6IDEwMDAwIH0pLFxuICBdKS5jYXRjaCgoKSA9PiBudWxsKTtcblxuICByZXR1cm4gcGFnZS5ldmFsdWF0ZShcbiAgICAobXVsdGlTZWxlY3Rvciwgb3B0aW9uU2VsZWN0b3IsIHNpbmdsZVNlbGVjdG9yKSA9PiB7XG4gICAgICBjb25zdCBzZWxlY3RlZCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IobXVsdGlTZWxlY3Rvcik/LnRleHRDb250ZW50Py50cmltKCk7XG4gICAgICBpZiAoc2VsZWN0ZWQpIHtcbiAgICAgICAgY29uc3Qgb3RoZXJzID0gQXJyYXkuZnJvbShkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKG9wdGlvblNlbGVjdG9yKSkubWFwKGxpID0+IGxpLnRleHRDb250ZW50Py50cmltKCkgPz8gJycpO1xuICAgICAgICByZXR1cm4gW3NlbGVjdGVkLCAuLi5vdGhlcnNdLmZpbHRlcihCb29sZWFuKTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHNpbmdsZSA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3Ioc2luZ2xlU2VsZWN0b3IpPy50ZXh0Q29udGVudD8udHJpbSgpO1xuICAgICAgcmV0dXJuIHNpbmdsZSA/IFtzaW5nbGVdIDogW107XG4gICAgfSxcbiAgICBBQ0NPVU5UX0lEX1NFTEVDVE9SX01VTFRJLFxuICAgIFBPUlRGT0xJT19PUFRJT05fU0VMRUNUT1IsXG4gICAgQUNDT1VOVF9JRF9TRUxFQ1RPUl9TSU5HTEUsXG4gICk7XG59XG5cbi8vIEFuZ3VsYXIncyBsaXN0SXRlbUFjdGlvbiBuYXZpZ2F0ZXMgdGhlIHBhZ2UgYmFjayB0byAvbWFpbi9ob21lIHdpdGggdGhlIG5ldyBwb3J0Zm9saW9cbi8vIHNlbGVjdGVkIOKAlCBjYWxsZXJzIG11c3QgcmUtZW50ZXIgdGhlIHN0YXRlbWVudHMgZmxvdyBhZnRlciB0aGlzIHJldHVybnMuXG5hc3luYyBmdW5jdGlvbiBzZWxlY3RQb3J0Zm9saW8ocGFnZTogUGFnZSwgdGFyZ2V0SUQ6IHN0cmluZykge1xuICBjb25zdCBjbGlja2VkID0gYXdhaXQgcGFnZS4kJGV2YWwoXG4gICAgUE9SVEZPTElPX09QVElPTl9TRUxFQ1RPUixcbiAgICAobGlzLCBpZCkgPT4ge1xuICAgICAgY29uc3QgdGFyZ2V0ID0gKGxpcyBhcyBIVE1MRWxlbWVudFtdKS5maW5kKGxpID0+IGxpLnRleHRDb250ZW50Py50cmltKCkgPT09IGlkKTtcbiAgICAgIGlmICghdGFyZ2V0KSByZXR1cm4gZmFsc2U7XG4gICAgICB0YXJnZXQuY2xpY2soKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0sXG4gICAgdGFyZ2V0SUQsXG4gICk7XG4gIGlmICghY2xpY2tlZCkgdGhyb3cgbmV3IEVycm9yKGBQb3J0Zm9saW8gb3B0aW9uIG5vdCBmb3VuZCBmb3IgSUQ6ICR7dGFyZ2V0SUR9YCk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnREaXNhcHBlYXIocGFnZSwgJy5sb2FkaW5nLWJhci1zcGlubmVyJyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoQWNjb3VudHMocGFnZTogUGFnZSwgc3RhcnREYXRlOiBNb21lbnQsIG9wdGlvbnM/OiBTY3JhcGVyT3B0aW9ucyk6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIC8vIFNuYXBzaG90IHVwIGZyb250OiB0aGUgZHJvcGRvd24gb25seSBsaXN0cyB1bnNlbGVjdGVkIHBvcnRmb2xpb3MsIHNvIGFmdGVyIHRoZSBmaXJzdFxuICAvLyBzd2l0Y2ggd2Ugd291bGQgbG9zZSBhbnkgbm90IHlldCBzY3JhcGVkLlxuICBjb25zdCBwb3J0Zm9saW9JRHMgPSBhd2FpdCBnZXRQb3J0Zm9saW9JRHMocGFnZSk7XG4gIGlmIChwb3J0Zm9saW9JRHMubGVuZ3RoID09PSAwKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdObyBwb3J0Zm9saW9zIGZvdW5kIG9uIC9tYWluL2hvbWUg4oCUIFlhaGF2IERPTSBsaWtlbHkgY2hhbmdlZCcpO1xuICB9XG4gIGNvbnN0IGFjY291bnRzOiBUcmFuc2FjdGlvbnNBY2NvdW50W10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb3J0Zm9saW9JRHMubGVuZ3RoOyBpICs9IDEpIHtcbiAgICBjb25zdCBwb3J0Zm9saW9JRCA9IHBvcnRmb2xpb0lEc1tpXTtcbiAgICBpZiAoaSA+IDApIHtcbiAgICAgIGF3YWl0IHNlbGVjdFBvcnRmb2xpbyhwYWdlLCBwb3J0Zm9saW9JRCk7XG4gICAgfVxuICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBBQ0NPVU5UX0RFVEFJTFNfU0VMRUNUT1IsIHRydWUpO1xuICAgIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIEFDQ09VTlRfREVUQUlMU19TRUxFQ1RPUik7XG4gICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICcuc3RhdGVtZW50LW9wdGlvbnMgLnNlbGVjdGVkLWl0ZW0tdG9wJywgdHJ1ZSk7XG4gICAgYWNjb3VudHMucHVzaChhd2FpdCBmZXRjaEFjY291bnREYXRhKHBhZ2UsIHN0YXJ0RGF0ZSwgcG9ydGZvbGlvSUQsIG9wdGlvbnMpKTtcbiAgfVxuXG4gIHJldHVybiBhY2NvdW50cztcbn1cblxuYXN5bmMgZnVuY3Rpb24gd2FpdFJlYWRpbmVzc0ZvckFsbChwYWdlOiBQYWdlKSB7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBgJHtVU0VSX0VMRU19YCwgdHJ1ZSk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBgJHtQQVNTV0RfRUxFTX1gLCB0cnVlKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGAke05BVElPTkFMSURfRUxFTX1gLCB0cnVlKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGAke1NVQk1JVF9MT0dJTl9TRUxFQ1RPUn1gLCB0cnVlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcmVkaXJlY3RPckRpYWxvZyhwYWdlOiBQYWdlKSB7XG4gIC8vIENsaWNrIG9uIGJhbmsgbWVzc2FnZXMgaWYgYW55LlxuICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbihwYWdlKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudERpc2FwcGVhcihwYWdlLCAnLmxvYWRpbmctYmFyLXNwaW5uZXInKTtcbiAgY29uc3QgaGFzTWVzc2FnZSA9IGF3YWl0IGVsZW1lbnRQcmVzZW50T25QYWdlKHBhZ2UsICcubWVzc2FnaW5nLWxpbmtzLWNvbnRhaW5lcicpO1xuICBpZiAoaGFzTWVzc2FnZSkge1xuICAgIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsICcubGluay0xJyk7XG4gIH1cblxuICBjb25zdCBwcm9taXNlMSA9IHBhZ2Uud2FpdEZvclNlbGVjdG9yKEFDQ09VTlRfREVUQUlMU19TRUxFQ1RPUiwgeyB0aW1lb3V0OiAzMDAwMCB9KTtcbiAgY29uc3QgcHJvbWlzZTIgPSBwYWdlLndhaXRGb3JTZWxlY3RvcihDSEFOR0VfUEFTU1dPUkRfT0xEX1BBU1MsIHsgdGltZW91dDogMzAwMDAgfSk7XG4gIGNvbnN0IHByb21pc2VzID0gW3Byb21pc2UxLCBwcm9taXNlMl07XG5cbiAgYXdhaXQgUHJvbWlzZS5yYWNlKHByb21pc2VzKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudERpc2FwcGVhcihwYWdlLCAnLmxvYWRpbmctYmFyLXNwaW5uZXInKTtcbn1cblxudHlwZSBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyA9IHsgdXNlcm5hbWU6IHN0cmluZzsgcGFzc3dvcmQ6IHN0cmluZzsgbmF0aW9uYWxJRDogc3RyaW5nIH07XG5cbmNsYXNzIFlhaGF2U2NyYXBlciBleHRlbmRzIEJhc2VTY3JhcGVyV2l0aEJyb3dzZXI8U2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHM+IHtcbiAgZ2V0TG9naW5PcHRpb25zKGNyZWRlbnRpYWxzOiBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscykge1xuICAgIHJldHVybiB7XG4gICAgICBsb2dpblVybDogYCR7TE9HSU5fVVJMfWAsXG4gICAgICBmaWVsZHM6IFtcbiAgICAgICAgeyBzZWxlY3RvcjogYCR7VVNFUl9FTEVNfWAsIHZhbHVlOiBjcmVkZW50aWFscy51c2VybmFtZSB9LFxuICAgICAgICB7IHNlbGVjdG9yOiBgJHtQQVNTV0RfRUxFTX1gLCB2YWx1ZTogY3JlZGVudGlhbHMucGFzc3dvcmQgfSxcbiAgICAgICAgeyBzZWxlY3RvcjogYCR7TkFUSU9OQUxJRF9FTEVNfWAsIHZhbHVlOiBjcmVkZW50aWFscy5uYXRpb25hbElEIH0sXG4gICAgICBdLFxuICAgICAgc3VibWl0QnV0dG9uU2VsZWN0b3I6IGAke1NVQk1JVF9MT0dJTl9TRUxFQ1RPUn1gLFxuICAgICAgY2hlY2tSZWFkaW5lc3M6IGFzeW5jICgpID0+IHdhaXRSZWFkaW5lc3NGb3JBbGwodGhpcy5wYWdlKSxcbiAgICAgIHBvc3RBY3Rpb246IGFzeW5jICgpID0+IHJlZGlyZWN0T3JEaWFsb2codGhpcy5wYWdlKSxcbiAgICAgIHBvc3NpYmxlUmVzdWx0czogZ2V0UG9zc2libGVMb2dpblJlc3VsdHModGhpcy5wYWdlKSxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZmV0Y2hEYXRhKCkge1xuICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZCh0aGlzLnBhZ2UsIEFDQ09VTlRfREVUQUlMU19TRUxFQ1RPUiwgdHJ1ZSk7XG5cbiAgICBjb25zdCBkZWZhdWx0U3RhcnRNb21lbnQgPSBtb21lbnQoKS5zdWJ0cmFjdCgzLCAnbW9udGhzJykuYWRkKDEsICdkYXknKTtcbiAgICBjb25zdCBzdGFydERhdGUgPSB0aGlzLm9wdGlvbnMuc3RhcnREYXRlIHx8IGRlZmF1bHRTdGFydE1vbWVudC50b0RhdGUoKTtcbiAgICBjb25zdCBzdGFydE1vbWVudCA9IG1vbWVudC5taW4obW9tZW50Lm1heChkZWZhdWx0U3RhcnRNb21lbnQsIG1vbWVudChzdGFydERhdGUpKSwgbW9tZW50KCkpO1xuXG4gICAgY29uc3QgYWNjb3VudHMgPSBhd2FpdCBmZXRjaEFjY291bnRzKHRoaXMucGFnZSwgc3RhcnRNb21lbnQsIHRoaXMub3B0aW9ucyk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIGFjY291bnRzLFxuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgWWFoYXZTY3JhcGVyO1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxxQkFBQSxHQUFBRixPQUFBO0FBT0EsSUFBQUcsV0FBQSxHQUFBSCxPQUFBO0FBQ0EsSUFBQUksYUFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssY0FBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sdUJBQUEsR0FBQU4sT0FBQTtBQUE4RyxTQUFBRCx1QkFBQVEsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUc5RyxNQUFNRyxTQUFTLEdBQUcsa0NBQWtDO0FBQ3BELE1BQU1DLFFBQVEsR0FBRyw2REFBNkQ7QUFDOUUsTUFBTUMsd0JBQXdCLEdBQUcsb0JBQW9CO0FBQ3JELE1BQU1DLHdCQUF3QixHQUFHLHVDQUF1QztBQUN4RSxNQUFNQyxnQkFBZ0IsR0FBRyxHQUFHSCxRQUFRLFdBQVc7QUFFL0MsTUFBTUksY0FBYyxHQUFHLGtDQUFrQztBQUN6RCxNQUFNQywwQkFBMEIsR0FBRyxzQkFBc0I7QUFDekQsTUFBTUMseUJBQXlCLEdBQUcsR0FBR0YsY0FBYyxxQkFBcUI7QUFDeEUsTUFBTUcseUJBQXlCLEdBQUcsR0FBR0gsY0FBYyx5Q0FBeUM7QUFD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