israeli-bank-scrapers
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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2RlYnVnIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX2ZldGNoIiwiX3RyYW5zYWN0aW9ucyIsIl9uYXZpZ2F0aW9uIiwiX3RyYW5zYWN0aW9uczIiLCJfYmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsImRlYnVnIiwiZ2V0RGVidWciLCJCQVNFX1VSTCIsIkxPR0lOX1VSTCIsIlRSQU5TQUNUSU9OU19VUkwiLCJGSUxURVJFRF9UUkFOU0FDVElPTlNfVVJMIiwiU0FWSU5HU19VUkwiLCJEQVRFX0ZPUk1BVCIsIkFDQ09VTlRfQkxPQ0tFRF9NU0ciLCJJTlZBTElEX1BBU1NXT1JEX01TRyIsIkNIQU5HRV9QQVNTV09SRF9NT0RBTF9TRUxFQ1RPUiIsImdldFBvc3NpYmxlTG9naW5SZXN1bHRzIiwidXJscyIsIkxvZ2luUmVzdWx0cyIsIlN1Y2Nlc3MiLCJJbnZhbGlkUGFzc3dvcmQiLCJvcHRpb25zIiwicGFnZSIsIkVycm9yIiwiZXJyb3JNZXNzYWdlIiwicGFnZUV2YWxBbGwiLCJlbGVtZW50IiwicGFyZW50RWxlbWVudCIsImNoaWxkcmVuIiwiaW5uZXJUZXh0Iiwic3RhcnRzV2l0aCIsIkFjY291bnRCbG9ja2VkIiwibGFiZWwiLCJDaGFuZ2VQYXNzd29yZCIsIiQiLCJjcmVhdGVMb2dpbkZpZWxkcyIsImNyZWRlbnRpYWxzIiwic2VsZWN0b3IiLCJ2YWx1ZSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJleHRyYWN0VHJhbnNhY3Rpb25zRnJvbVBhZ2UiLCJ0cmFuc2FjdGlvbnMiLCJzdGF0dXMiLCJsZW5ndGgiLCJyZXN1bHQiLCJtYXAiLCJyYXdUcmFuc2FjdGlvbiIsImRhdGUiLCJtb21lbnQiLCJEYXRlVVRDIiwibWlsbGlzZWNvbmRzIiwidG9JU09TdHJpbmciLCJuZXdUcmFuc2FjdGlvbiIsInR5cGUiLCJUcmFuc2FjdGlvblR5cGVzIiwiTm9ybWFsIiwicHJvY2Vzc2VkRGF0ZSIsImRlc2NyaXB0aW9uIiwiRGVzY3JpcHRpb24iLCJpZGVudGlmaWVyIiwiUmVmZXJlbmNlTnVtYmVyTG9uZyIsIm1lbW8iLCJBZGRpdGlvbmFsRGF0YSIsIm9yaWdpbmFsQ3VycmVuY3kiLCJTSEVLRUxfQ1VSUkVOQ1kiLCJjaGFyZ2VkQW1vdW50IiwiQW1vdW50Iiwib3JpZ2luYWxBbW91bnQiLCJpbmNsdWRlUmF3VHJhbnNhY3Rpb24iLCJnZXRSYXdUcmFuc2FjdGlvbiIsImhhbmdQcm9jZXNzIiwidGltZW91dCIsIlByb21pc2UiLCJyZXNvbHZlIiwic2V0VGltZW91dCIsImNsaWNrQnlYUGF0aCIsInhwYXRoIiwid2FpdEZvclNlbGVjdG9yIiwidmlzaWJsZSIsImVsbSIsIiQkIiwiY2xpY2siLCJyZW1vdmVTcGVjaWFsQ2hhcmFjdGVycyIsInN0ciIsInJlcGxhY2UiLCJmZXRjaFRyYW5zYWN0aW9uc0ZvckFjY291bnQiLCJzdGFydERhdGUiLCJhY2NvdW50SWQiLCJ3YWl0VW50aWxFbGVtZW50Rm91bmQiLCJjbGlja0J1dHRvbiIsImZpbGxJbnB1dCIsImZvcm1hdCIsImZvY3VzIiwiZmluYWxSZXNwb25zZSIsIndhaXRGb3JSZXNwb25zZSIsInJlc3BvbnNlIiwidXJsIiwicmVxdWVzdCIsIm1ldGhvZCIsInJlc3BvbnNlSnNvbiIsImpzb24iLCJhY2NvdW50TnVtYmVyIiwiSlNPTiIsInBhcnNlIiwianNvblJlc3AiLCJwZW5kaW5nVHJhbnNhY3Rpb25zIiwiVG9kYXlUcmFuc2FjdGlvbnNJdGVtcyIsIkhpc3RvcnlUcmFuc2FjdGlvbnNJdGVtcyIsImJhbGFuY2UiLCJCYWxhbmNlRGlzcGxheSIsInBhcnNlRmxvYXQiLCJ1bmRlZmluZWQiLCJwZW5kaW5nVHhucyIsIlRyYW5zYWN0aW9uU3RhdHVzZXMiLCJQZW5kaW5nIiwiY29tcGxldGVkVHhucyIsIkNvbXBsZXRlZCIsInR4bnMiLCJmZXRjaFJlZ3VsYXJBY2NvdW50cyIsInNjcmFwZXIiLCJuYXZpZ2F0ZVRvIiwiZmV0Y2hUcmFuc2FjdGlvbnMiLCJnZXRTYXZpbmdzQWNjb3VudHMiLCJhY2NvdW50cyIsInNhdmluZ3NEYXRhIiwiZmV0Y2hHZXRXaXRoaW5QYWdlIiwiZGVwb3NpdHNBbmRTYXZpbmdzSXRlbXMiLCJkZXBvc2l0IiwiY3VycmVudEJhbGFuY2UiLCJzYXZpbmdzQWNjb3VudE51bWJlciIsImRlcG9zaXRJZCIsInB1c2giLCJzYXZpbmdzQWNjb3VudCIsInByb2R1Y3ROYW1lIiwiZXJyb3IiLCJhY2NvdW50c0lkcyIsImV2YWx1YXRlIiwiQXJyYXkiLCJmcm9tIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yQWxsIiwidGV4dENvbnRlbnQiLCJmZXRjaFNhdmluZ3NBY2NvdW50cyIsInJlZ3VsYXJBY2NvdW50cyIsImFsbFNhdmluZ3NBY2NvdW50cyIsInJlZ3VsYXJBY2NvdW50Q291bnQiLCJpIiwic2F2aW5nc0FjY291bnRzIiwibmF2aWdhdGVUb0xvZ2luIiwiZ290byIsIndhaXRGb3JOYXZpZ2F0aW9uIiwid2FpdFVudGlsIiwiYWxsIiwid2FpdEZvclBvc3RMb2dpbiIsInJhY2UiLCJMZXVtaVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiZ2V0TG9naW5PcHRpb25zIiwibG9naW5VcmwiLCJmaWVsZHMiLCJzdWJtaXRCdXR0b25TZWxlY3RvciIsImNoZWNrUmVhZGluZXNzIiwicG9zdEFjdGlvbiIsInBvc3NpYmxlUmVzdWx0cyIsImZldGNoRGF0YSIsIm1pbmltdW1TdGFydE1vbWVudCIsInN1YnRyYWN0IiwiYWRkIiwiZGVmYXVsdFN0YXJ0TW9tZW50IiwidG9EYXRlIiwic3RhcnRNb21lbnQiLCJtYXgiLCJzdWNjZXNzIiwiX2RlZmF1bHQiLCJleHBvcnRzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmFwZXJzL2xldW1pLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBtb21lbnQsIHsgdHlwZSBNb21lbnQgfSBmcm9tICdtb21lbnQnO1xuaW1wb3J0IHsgdHlwZSBQYWdlIH0gZnJvbSAncHVwcGV0ZWVyJztcbmltcG9ydCB7IFNIRUtFTF9DVVJSRU5DWSB9IGZyb20gJy4uL2NvbnN0YW50cyc7XG5pbXBvcnQgeyBnZXREZWJ1ZyB9IGZyb20gJy4uL2hlbHBlcnMvZGVidWcnO1xuaW1wb3J0IHsgY2xpY2tCdXR0b24sIGZpbGxJbnB1dCwgcGFnZUV2YWxBbGwsIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCB9IGZyb20gJy4uL2hlbHBlcnMvZWxlbWVudHMtaW50ZXJhY3Rpb25zJztcbmltcG9ydCB7IGZldGNoR2V0V2l0aGluUGFnZSB9IGZyb20gJy4uL2hlbHBlcnMvZmV0Y2gnO1xuaW1wb3J0IHsgZ2V0UmF3VHJhbnNhY3Rpb24gfSBmcm9tICcuLi9oZWxwZXJzL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQgeyB3YWl0Rm9yTmF2aWdhdGlvbiB9IGZyb20gJy4uL2hlbHBlcnMvbmF2aWdhdGlvbic7XG5pbXBvcnQgeyBUcmFuc2FjdGlvblN0YXR1c2VzLCBUcmFuc2FjdGlvblR5cGVzLCB0eXBlIFRyYW5zYWN0aW9uLCB0eXBlIFRyYW5zYWN0aW9uc0FjY291bnQgfSBmcm9tICcuLi90cmFuc2FjdGlvbnMnO1xuaW1wb3J0IHsgQmFzZVNjcmFwZXJXaXRoQnJvd3NlciwgTG9naW5SZXN1bHRzLCB0eXBlIExvZ2luT3B0aW9ucyB9IGZyb20gJy4vYmFzZS1zY3JhcGVyLXdpdGgtYnJvd3Nlcic7XG5pbXBvcnQgeyB0eXBlIFNjcmFwZXJPcHRpb25zLCB0eXBlIFNjcmFwZXJTY3JhcGluZ1Jlc3VsdCB9IGZyb20gJy4vaW50ZXJmYWNlJztcblxuY29uc3QgZGVidWcgPSBnZXREZWJ1ZygnbGV1bWknKTtcbmNvbnN0IEJBU0VfVVJMID0gJ2h0dHBzOi8vaGIyLmJhbmtsZXVtaS5jby5pbCc7XG5jb25zdCBMT0dJTl9VUkwgPSAnaHR0cHM6Ly93d3cubGV1bWkuY28uaWwvaGUnO1xuY29uc3QgVFJBTlNBQ1RJT05TX1VSTCA9IGAke0JBU0VfVVJMfS9lQmFua2luZy9TTy9TUEEuYXNweCMvdHMvQnVzaW5lc3NBY2NvdW50VHJ4P1dpZGdldFBhcj0xYDtcbmNvbnN0IEZJTFRFUkVEX1RSQU5TQUNUSU9OU19VUkwgPSBgJHtCQVNFX1VSTH0vQ2hhbm5lbFdDRi9Ccm9rZXIuc3ZjL1Byb2Nlc3NSZXF1ZXN0P21vZHVsZU5hbWU9VUNfU09fMjdfR2V0QnVzaW5lc3NBY2NvdW50VHJ4YDtcbmNvbnN0IFNBVklOR1NfVVJMID0gYCR7QkFTRV9VUkx9L3VpYXBpcHJveHkvdjEvZGlnaXRhbC1yZXRhaWxzL21vYmlsZS9hY2NvdW50cy8xL0RlcG9zaXRzP29wZXJhdGlvbkxpc3Q9dHJ1ZWA7XG5cbmNvbnN0IERBVEVfRk9STUFUID0gJ0RELk1NLllZJztcbmNvbnN0IEFDQ09VTlRfQkxPQ0tFRF9NU0cgPSAn15TXnteg15XXmSDXl9eh15XXnSc7XG5jb25zdCBJTlZBTElEX1BBU1NXT1JEX01TRyA9ICfXkNeX15Mg15DXlSDXmdeV16rXqCDXntek16jXmNeZINeU15TXlteT15TXldeqINep157Xodeo16og16nXkteV15nXmdedLiDXoNeZ16rXnyDXnNeg16HXldeqINep15XXkSc7XG5jb25zdCBDSEFOR0VfUEFTU1dPUkRfTU9EQUxfU0VMRUNUT1IgPSAnZm9ybSBpbnB1dFtuYW1lPVwibmV3UHdkXCJdJztcblxuaW50ZXJmYWNlIFNhdmluZ3NEZXBvc2l0SXRlbSB7XG4gIGluZGV4OiBzdHJpbmc7XG4gIGRlcG9zaXRJZDogc3RyaW5nO1xuICBkZXBvc2l0SW5kZXg6IG51bWJlcjtcbiAgZGVwb3NpdFNvdXJjZUlkOiBzdHJpbmc7XG4gIHR5cGU6IG51bWJlcjtcbiAgZGlzcGxheU5hbWU6IHN0cmluZztcbiAgcHJvZHVjdE5hbWU6IHN0cmluZztcbiAgZnJpZW5kbHlBY2NvdW50TmFtZTogc3RyaW5nO1xuICBkZWVwTGluazogc3RyaW5nO1xuICBpc0ZvcmVjbG9zZWQ6IGJvb2xlYW47XG4gIGFzT2ZEYXRlOiBzdHJpbmc7XG4gIGNyZWF0ZURhdGU6IHN0cmluZztcbiAgZXhpdFBvaW50RGF0ZTogc3RyaW5nO1xuICBjdXJyZW50QmFsYW5jZTogbnVtYmVyO1xuICBpbml0aWFsQW1vdW50OiBudW1iZXIgfCBudWxsO1xuICBpbnN0YWxsbWVudHNTYXZpbmdGbGFnOiBib29sZWFuO1xuICBtYXJnaW5SYXRlOiBzdHJpbmc7XG4gIHByb2R1Y3RJbnRlcmVzdFR5cGU6IHN0cmluZyB8IG51bGw7XG4gIHByb2R1Y3RMaW5rYWdlVHlwZTogc3RyaW5nIHwgbnVsbDtcbiAgc291cmNlU3lzdGVtOiBzdHJpbmc7XG4gIGRlcG9zaXROdW1iZXI6IHN0cmluZztcbiAgcmVsYXRlZEFjY291bnROdW1iZXI6IHN0cmluZztcbiAgd2l0aGRyYXdhbFJlcXVlc3RUZXh0OiBzdHJpbmcgfCBudWxsO1xuICBXaXRoZHJhd2FsQXZhaWxhYmxlRnJlcXVlbmN5OiBzdHJpbmcgfCBudWxsO1xuICBkZXBvc2l0T3BlcmF0aW9uc0l0ZW1zOiBhbnlbXTtcbn1cblxuaW50ZXJmYWNlIFNhdmluZ3NBY2NvdW50RGF0YSB7XG4gIHRvdGFsRGVwb3NpdHNBbmRTYXZpbmdzQmFsYW5jZTogbnVtYmVyO1xuICBwcmV2aW91c0J1c2luZXNzRGF5RGF0ZTogc3RyaW5nO1xuICBkZXBvc2l0c0FuZFNhdmluZ3NJdGVtczogU2F2aW5nc0RlcG9zaXRJdGVtW107XG4gIG9wZXJhdGlvbnNJdGVtc1RvdGFsOiBzdHJpbmc7XG4gIG9wZXJhdGlvbnNMaXN0SXRlbXM6IGFueVtdO1xufVxuXG5mdW5jdGlvbiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cygpIHtcbiAgY29uc3QgdXJsczogTG9naW5PcHRpb25zWydwb3NzaWJsZVJlc3VsdHMnXSA9IHtcbiAgICBbTG9naW5SZXN1bHRzLlN1Y2Nlc3NdOiBbL2ViYW5raW5nXFwvU09cXC9TUEEuYXNweC9pXSxcbiAgICBbTG9naW5SZXN1bHRzLkludmFsaWRQYXNzd29yZF06IFtcbiAgICAgIGFzeW5jIG9wdGlvbnMgPT4ge1xuICAgICAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMucGFnZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwYWdlIG9wdGlvbnMgYXJndW1lbnQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBhd2FpdCBwYWdlRXZhbEFsbChvcHRpb25zLnBhZ2UsICdzdmcjQ2FwYV8xJywgJycsIGVsZW1lbnQgPT4ge1xuICAgICAgICAgIHJldHVybiAoZWxlbWVudFswXT8ucGFyZW50RWxlbWVudD8uY2hpbGRyZW5bMV0gYXMgSFRNTERpdkVsZW1lbnQpPy5pbm5lclRleHQ7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBlcnJvck1lc3NhZ2U/LnN0YXJ0c1dpdGgoSU5WQUxJRF9QQVNTV09SRF9NU0cpO1xuICAgICAgfSxcbiAgICBdLFxuICAgIFtMb2dpblJlc3VsdHMuQWNjb3VudEJsb2NrZWRdOiBbXG4gICAgICAvLyBOT1RJQ0UgLSBtaWdodCBub3QgYmUgcmVsZXZhbnQgc3RhcnRpbmcgdGhlIExldW1pIHJlLWRlc2lnbiBkdXJpbmcgMjAyMiBTZXBcbiAgICAgIGFzeW5jIG9wdGlvbnMgPT4ge1xuICAgICAgICBpZiAoIW9wdGlvbnMgfHwgIW9wdGlvbnMucGFnZSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbWlzc2luZyBwYWdlIG9wdGlvbnMgYXJndW1lbnQnKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBhd2FpdCBwYWdlRXZhbEFsbChvcHRpb25zLnBhZ2UsICcuZXJySGVhZGVyJywgJycsIGxhYmVsID0+IHtcbiAgICAgICAgICByZXR1cm4gKGxhYmVsWzBdIGFzIEhUTUxFbGVtZW50KT8uaW5uZXJUZXh0O1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZXJyb3JNZXNzYWdlPy5zdGFydHNXaXRoKEFDQ09VTlRfQkxPQ0tFRF9NU0cpO1xuICAgICAgfSxcbiAgICBdLFxuICAgIFtMb2dpblJlc3VsdHMuQ2hhbmdlUGFzc3dvcmRdOiBbXG4gICAgICBhc3luYyBvcHRpb25zID0+IHtcbiAgICAgICAgaWYgKCFvcHRpb25zIHx8ICFvcHRpb25zLnBhZ2UpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ21pc3NpbmcgcGFnZSBvcHRpb25zIGFyZ3VtZW50Jyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICEhKGF3YWl0IG9wdGlvbnMucGFnZS4kKENIQU5HRV9QQVNTV09SRF9NT0RBTF9TRUxFQ1RPUikpO1xuICAgICAgfSxcbiAgICBdLFxuICB9O1xuICByZXR1cm4gdXJscztcbn1cblxuZnVuY3Rpb24gY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gIHJldHVybiBbXG4gICAgeyBzZWxlY3RvcjogJ2lucHV0W3BsYWNlaG9sZGVyPVwi16nXnSDXntep16rXntepXCJdJywgdmFsdWU6IGNyZWRlbnRpYWxzLnVzZXJuYW1lIH0sXG4gICAgeyBzZWxlY3RvcjogJ2lucHV0W3BsYWNlaG9sZGVyPVwi16HXmdeh157XlFwiXScsIHZhbHVlOiBjcmVkZW50aWFscy5wYXNzd29yZCB9LFxuICBdO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0VHJhbnNhY3Rpb25zRnJvbVBhZ2UoXG4gIHRyYW5zYWN0aW9uczogYW55W10sXG4gIHN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcyxcbiAgb3B0aW9ucz86IFNjcmFwZXJPcHRpb25zLFxuKTogVHJhbnNhY3Rpb25bXSB7XG4gIGlmICh0cmFuc2FjdGlvbnMgPT09IG51bGwgfHwgdHJhbnNhY3Rpb25zLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHJlc3VsdDogVHJhbnNhY3Rpb25bXSA9IHRyYW5zYWN0aW9ucy5tYXAocmF3VHJhbnNhY3Rpb24gPT4ge1xuICAgIGNvbnN0IGRhdGUgPSBtb21lbnQocmF3VHJhbnNhY3Rpb24uRGF0ZVVUQykubWlsbGlzZWNvbmRzKDApLnRvSVNPU3RyaW5nKCk7XG4gICAgY29uc3QgbmV3VHJhbnNhY3Rpb246IFRyYW5zYWN0aW9uID0ge1xuICAgICAgc3RhdHVzLFxuICAgICAgdHlwZTogVHJhbnNhY3Rpb25UeXBlcy5Ob3JtYWwsXG4gICAgICBkYXRlLFxuICAgICAgcHJvY2Vzc2VkRGF0ZTogZGF0ZSxcbiAgICAgIGRlc2NyaXB0aW9uOiByYXdUcmFuc2FjdGlvbi5EZXNjcmlwdGlvbiB8fCAnJyxcbiAgICAgIGlkZW50aWZpZXI6IHJhd1RyYW5zYWN0aW9uLlJlZmVyZW5jZU51bWJlckxvbmcsXG4gICAgICBtZW1vOiByYXdUcmFuc2FjdGlvbi5BZGRpdGlvbmFsRGF0YSB8fCAnJyxcbiAgICAgIG9yaWdpbmFsQ3VycmVuY3k6IFNIRUtFTF9DVVJSRU5DWSxcbiAgICAgIGNoYXJnZWRBbW91bnQ6IHJhd1RyYW5zYWN0aW9uLkFtb3VudCxcbiAgICAgIG9yaWdpbmFsQW1vdW50OiByYXdUcmFuc2FjdGlvbi5BbW91bnQsXG4gICAgfTtcblxuICAgIGlmIChvcHRpb25zPy5pbmNsdWRlUmF3VHJhbnNhY3Rpb24pIHtcbiAgICAgIG5ld1RyYW5zYWN0aW9uLnJhd1RyYW5zYWN0aW9uID0gZ2V0UmF3VHJhbnNhY3Rpb24ocmF3VHJhbnNhY3Rpb24pO1xuICAgIH1cblxuICAgIHJldHVybiBuZXdUcmFuc2FjdGlvbjtcbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gaGFuZ1Byb2Nlc3ModGltZW91dDogbnVtYmVyKSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZTx2b2lkPihyZXNvbHZlID0+IHtcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHJlc29sdmUoKTtcbiAgICB9LCB0aW1lb3V0KTtcbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsaWNrQnlYUGF0aChwYWdlOiBQYWdlLCB4cGF0aDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHBhZ2Uud2FpdEZvclNlbGVjdG9yKHhwYXRoLCB7IHRpbWVvdXQ6IDMwMDAwLCB2aXNpYmxlOiB0cnVlIH0pO1xuICBjb25zdCBlbG0gPSBhd2FpdCBwYWdlLiQkKHhwYXRoKTtcbiAgYXdhaXQgZWxtWzBdLmNsaWNrKCk7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZVNwZWNpYWxDaGFyYWN0ZXJzKHN0cjogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC9bXjAtOS8tXS9nLCAnJyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoVHJhbnNhY3Rpb25zRm9yQWNjb3VudChcbiAgcGFnZTogUGFnZSxcbiAgc3RhcnREYXRlOiBNb21lbnQsXG4gIGFjY291bnRJZDogc3RyaW5nLFxuICBvcHRpb25zOiBTY3JhcGVyT3B0aW9ucyxcbik6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudD4ge1xuICAvLyBERVZFTE9QRVIgTk9USUNFIHRoZSBhY2NvdW50IG51bWJlciByZWNlaXZlZCBmcm9tIHRoZSBzZXJ2ZXIgaXMgYmVpbmcgYWx0ZXJlZCBhdFxuICAvLyBydW50aW1lIGZvciBzb21lIGFjY291bnRzIGFmdGVyIDEtMiBzZWNvbmRzIHNvIHdlIG5lZWQgdG8gaGFuZyB0aGUgcHJvY2VzcyBmb3IgYSBzaG9ydCB3aGlsZS5cbiAgYXdhaXQgaGFuZ1Byb2Nlc3MoNDAwMCk7XG5cbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdidXR0b25bdGl0bGU9XCLXl9eZ16TXldepINee16rXp9eT151cIl0nLCB0cnVlKTtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgJ2J1dHRvblt0aXRsZT1cIteX15nXpNeV16kg157Xqten15PXnVwiXScpO1xuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2JsbC1yYWRpby1idXR0b24nLCB0cnVlKTtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgJ2JsbC1yYWRpby1idXR0b246bm90KFtjaGVja2VkXSknKTtcblxuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2lucHV0W2Zvcm1jb250cm9sbmFtZT1cInR4dElucHV0RnJvbVwiXScsIHRydWUpO1xuXG4gIGF3YWl0IGZpbGxJbnB1dChwYWdlLCAnaW5wdXRbZm9ybWNvbnRyb2xuYW1lPVwidHh0SW5wdXRGcm9tXCJdJywgc3RhcnREYXRlLmZvcm1hdChEQVRFX0ZPUk1BVCkpO1xuXG4gIC8vIHdlIG11c3QgYmx1ciB0aGUgZnJvbSBjb250cm9sIG90aGVyd2lzZSB0aGUgc2VhcmNoIHdpbGwgdXNlIHRoZSBwcmV2aW91cyB2YWx1ZVxuICBhd2FpdCBwYWdlLmZvY3VzKFwiYnV0dG9uW2FyaWEtbGFiZWw9J9eh16DXnyddXCIpO1xuXG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIFwiYnV0dG9uW2FyaWEtbGFiZWw9J9eh16DXnyddXCIpO1xuICBjb25zdCBmaW5hbFJlc3BvbnNlID0gYXdhaXQgcGFnZS53YWl0Rm9yUmVzcG9uc2UocmVzcG9uc2UgPT4ge1xuICAgIHJldHVybiByZXNwb25zZS51cmwoKSA9PT0gRklMVEVSRURfVFJBTlNBQ1RJT05TX1VSTCAmJiByZXNwb25zZS5yZXF1ZXN0KCkubWV0aG9kKCkgPT09ICdQT1NUJztcbiAgfSk7XG5cbiAgY29uc3QgcmVzcG9uc2VKc29uOiBhbnkgPSBhd2FpdCBmaW5hbFJlc3BvbnNlLmpzb24oKTtcblxuICBjb25zdCBhY2NvdW50TnVtYmVyID0gYWNjb3VudElkLnJlcGxhY2UoJy8nLCAnXycpLnJlcGxhY2UoL1teXFxkLV9dL2csICcnKTtcblxuICBjb25zdCByZXNwb25zZSA9IEpTT04ucGFyc2UocmVzcG9uc2VKc29uLmpzb25SZXNwKTtcblxuICBjb25zdCBwZW5kaW5nVHJhbnNhY3Rpb25zID0gcmVzcG9uc2UuVG9kYXlUcmFuc2FjdGlvbnNJdGVtcztcbiAgY29uc3QgdHJhbnNhY3Rpb25zID0gcmVzcG9uc2UuSGlzdG9yeVRyYW5zYWN0aW9uc0l0ZW1zO1xuICBjb25zdCBiYWxhbmNlID0gcmVzcG9uc2UuQmFsYW5jZURpc3BsYXkgPyBwYXJzZUZsb2F0KHJlc3BvbnNlLkJhbGFuY2VEaXNwbGF5KSA6IHVuZGVmaW5lZDtcblxuICBjb25zdCBwZW5kaW5nVHhucyA9IGV4dHJhY3RUcmFuc2FjdGlvbnNGcm9tUGFnZShwZW5kaW5nVHJhbnNhY3Rpb25zLCBUcmFuc2FjdGlvblN0YXR1c2VzLlBlbmRpbmcsIG9wdGlvbnMpO1xuICBjb25zdCBjb21wbGV0ZWRUeG5zID0gZXh0cmFjdFRyYW5zYWN0aW9uc0Zyb21QYWdlKHRyYW5zYWN0aW9ucywgVHJhbnNhY3Rpb25TdGF0dXNlcy5Db21wbGV0ZWQsIG9wdGlvbnMpO1xuICBjb25zdCB0eG5zID0gWy4uLnBlbmRpbmdUeG5zLCAuLi5jb21wbGV0ZWRUeG5zXTtcblxuICByZXR1cm4ge1xuICAgIGFjY291bnROdW1iZXIsXG4gICAgYmFsYW5jZSxcbiAgICB0eG5zLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaFJlZ3VsYXJBY2NvdW50cyhcbiAgc2NyYXBlcjogTGV1bWlTY3JhcGVyLFxuICBwYWdlOiBQYWdlLFxuICBzdGFydERhdGU6IE1vbWVudCxcbiAgb3B0aW9uczogU2NyYXBlck9wdGlvbnMsXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBhd2FpdCBzY3JhcGVyLm5hdmlnYXRlVG8oVFJBTlNBQ1RJT05TX1VSTCk7XG4gIHJldHVybiBmZXRjaFRyYW5zYWN0aW9ucyhwYWdlLCBzdGFydERhdGUsIG9wdGlvbnMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRTYXZpbmdzQWNjb3VudHMocGFnZTogUGFnZSwgYWNjb3VudElkOiBzdHJpbmcpOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBkZWJ1ZygnPT09PT09PT09PSBGRVRDSElORyBTQVZJTkdTIEFDQ09VTlRTID09PT09PT09PT0nKTtcbiAgZGVidWcoJ0FjY291bnQ6ICVzJywgYWNjb3VudElkKTtcblxuICBjb25zdCBhY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gW107XG5cbiAgdHJ5IHtcbiAgICBkZWJ1ZygnVHJ5aW5nIHNhdmluZ3MgVVJMOiAlcycsIFNBVklOR1NfVVJMKTtcblxuICAgIGNvbnN0IHNhdmluZ3NEYXRhID0gYXdhaXQgZmV0Y2hHZXRXaXRoaW5QYWdlPFNhdmluZ3NBY2NvdW50RGF0YT4ocGFnZSwgU0FWSU5HU19VUkwpO1xuICAgIGlmICghc2F2aW5nc0RhdGEgfHwgIXNhdmluZ3NEYXRhLmRlcG9zaXRzQW5kU2F2aW5nc0l0ZW1zIHx8IHNhdmluZ3NEYXRhLmRlcG9zaXRzQW5kU2F2aW5nc0l0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgZGVidWcoJ05vIHNhdmluZ3MgYWNjb3VudHMgZm91bmQgZm9yIGFjY291bnQgJXMnLCBhY2NvdW50SWQpO1xuICAgICAgcmV0dXJuIFtdO1xuICAgIH1cbiAgICBkZWJ1Zygn4pyTIEZvdW5kICVkIHNhdmluZ3MgZGVwb3NpdHMnLCBzYXZpbmdzRGF0YS5kZXBvc2l0c0FuZFNhdmluZ3NJdGVtcy5sZW5ndGgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgYWNjb3VudCBmb3IgZWFjaCBpbmRpdmlkdWFsIGRlcG9zaXRcbiAgICBmb3IgKGNvbnN0IGRlcG9zaXQgb2Ygc2F2aW5nc0RhdGEuZGVwb3NpdHNBbmRTYXZpbmdzSXRlbXMpIHtcbiAgICAgIGNvbnN0IGJhbGFuY2UgPSBkZXBvc2l0LmN1cnJlbnRCYWxhbmNlO1xuICAgICAgY29uc3Qgc2F2aW5nc0FjY291bnROdW1iZXIgPSBgJHthY2NvdW50SWR9LSR7ZGVwb3NpdC5kZXBvc2l0SWR9YDtcblxuICAgICAgYWNjb3VudHMucHVzaCh7XG4gICAgICAgIGFjY291bnROdW1iZXI6IHNhdmluZ3NBY2NvdW50TnVtYmVyLFxuICAgICAgICBzYXZpbmdzQWNjb3VudDogdHJ1ZSxcbiAgICAgICAgYmFsYW5jZSxcbiAgICAgICAgdHhuczogW10sXG4gICAgICB9KTtcblxuICAgICAgZGVidWcoXG4gICAgICAgICdBZGRlZCBzYXZpbmdzIGFjY291bnQgJXMgd2l0aCBiYWxhbmNlICVzIChwcm9kdWN0OiAlcyknLFxuICAgICAgICBzYXZpbmdzQWNjb3VudE51bWJlcixcbiAgICAgICAgYmFsYW5jZSxcbiAgICAgICAgZGVwb3NpdC5wcm9kdWN0TmFtZSxcbiAgICAgICk7XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGRlYnVnKCcgIC0gRXJyb3IgZmV0Y2hpbmcgc2F2aW5ncyBhY2NvdW50czogJXMnLCBlcnJvcik7XG4gIH1cblxuICBkZWJ1ZygnUmV0dXJuaW5nICVkIHNhdmluZ3MgYWNjb3VudHMnLCBhY2NvdW50cy5sZW5ndGgpO1xuICByZXR1cm4gYWNjb3VudHM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoVHJhbnNhY3Rpb25zKFxuICBwYWdlOiBQYWdlLFxuICBzdGFydERhdGU6IE1vbWVudCxcbiAgb3B0aW9uczogU2NyYXBlck9wdGlvbnMsXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBjb25zdCBhY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gW107XG5cbiAgLy8gREVWRUxPUEVSIE5PVElDRSB0aGUgYWNjb3VudCBudW1iZXIgcmVjZWl2ZWQgZnJvbSB0aGUgc2VydmVyIGlzIGJlaW5nIGFsdGVyZWQgYXRcbiAgLy8gcnVudGltZSBmb3Igc29tZSBhY2NvdW50cyBhZnRlciAxLTIgc2Vjb25kcyBzbyB3ZSBuZWVkIHRvIGhhbmcgdGhlIHByb2Nlc3MgZm9yIGEgc2hvcnQgd2hpbGUuXG4gIGF3YWl0IGhhbmdQcm9jZXNzKDQwMDApO1xuXG4gIGNvbnN0IGFjY291bnRzSWRzID0gKGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT5cbiAgICBBcnJheS5mcm9tKGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ2FwcC1tYXNrZWQtbnVtYmVyLWNvbWJvIHNwYW4uZGlzcGxheS1udW1iZXItbGknKSwgZSA9PiBlLnRleHRDb250ZW50KSxcbiAgKSkgYXMgc3RyaW5nW107XG5cbiAgLy8gZHVlIHRvIGEgYnVnLCB0aGUgYWx0ZXJlZCB2YWx1ZSBtaWdodCBpbmNsdWRlIHVuZGVzaXJlZCBzaWducyBsaWtlICYgdGhhdCBzaG91bGQgYmUgcmVtb3ZlZFxuXG4gIGlmICghYWNjb3VudHNJZHMubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdGYWlsZWQgdG8gZXh0cmFjdCBvciBwYXJzZSB0aGUgYWNjb3VudCBudW1iZXInKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgYWNjb3VudElkIG9mIGFjY291bnRzSWRzKSB7XG4gICAgaWYgKGFjY291bnRzSWRzLmxlbmd0aCA+IDEpIHtcbiAgICAgIC8vIGdldCBsaXN0IG9mIGFjY291bnRzIGFuZCBjaGVjayBhY2NvdW50SWRcbiAgICAgIGF3YWl0IGNsaWNrQnlYUGF0aChwYWdlLCAneHBhdGgvLy8qW2NvbnRhaW5zKEBjbGFzcywgXCJudW1iZXJcIikgYW5kIGNvbnRhaW5zKEBjbGFzcywgXCJjb21iby1pbm5lclwiKV0nKTtcbiAgICAgIGF3YWl0IGNsaWNrQnlYUGF0aChwYWdlLCBgeHBhdGgvLy9zcGFuW2NvbnRhaW5zKHRleHQoKSwgJyR7YWNjb3VudElkfScpXWApO1xuICAgIH1cblxuICAgIGFjY291bnRzLnB1c2goYXdhaXQgZmV0Y2hUcmFuc2FjdGlvbnNGb3JBY2NvdW50KHBhZ2UsIHN0YXJ0RGF0ZSwgcmVtb3ZlU3BlY2lhbENoYXJhY3RlcnMoYWNjb3VudElkKSwgb3B0aW9ucykpO1xuICB9XG5cbiAgcmV0dXJuIGFjY291bnRzO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaFNhdmluZ3NBY2NvdW50cyhcbiAgcGFnZTogUGFnZSxcbiAgcmVndWxhckFjY291bnRzOiBUcmFuc2FjdGlvbnNBY2NvdW50W10sXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBjb25zdCBhbGxTYXZpbmdzQWNjb3VudHM6IFRyYW5zYWN0aW9uc0FjY291bnRbXSA9IFtdO1xuICBjb25zdCByZWd1bGFyQWNjb3VudENvdW50ID0gcmVndWxhckFjY291bnRzLmxlbmd0aDtcblxuICBmb3IgKGxldCBpID0gMDsgaSA8IHJlZ3VsYXJBY2NvdW50Q291bnQ7IGkrKykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCBzYXZpbmdzQWNjb3VudHMgPSBhd2FpdCBnZXRTYXZpbmdzQWNjb3VudHMocGFnZSwgcmVndWxhckFjY291bnRzW2ldLmFjY291bnROdW1iZXIpO1xuICAgICAgYWxsU2F2aW5nc0FjY291bnRzLnB1c2goLi4uc2F2aW5nc0FjY291bnRzKTtcbiAgICAgIGRlYnVnKCdBZGRlZCAlZCBzYXZpbmdzIGFjY291bnRzIHRvIHJlc3VsdHMnLCBzYXZpbmdzQWNjb3VudHMubGVuZ3RoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZGVidWcoJ0Vycm9yIGZldGNoaW5nIHNhdmluZ3MgYWNjb3VudHMgZm9yICVzOiAlcycsIHJlZ3VsYXJBY2NvdW50c1tpXS5hY2NvdW50TnVtYmVyLCBlcnJvcik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGFsbFNhdmluZ3NBY2NvdW50cztcbn1cblxuYXN5bmMgZnVuY3Rpb24gbmF2aWdhdGVUb0xvZ2luKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHZvaWQ+IHtcbiAgZGVidWcoJ25hdmlnYXRpbmcgZGlyZWN0bHkgdG8gbG9naW4gcGFnZScpO1xuICBhd2FpdCBwYWdlLmdvdG8oJ2h0dHBzOi8vaGIyLmJhbmtsZXVtaS5jby5pbC9hdXRoZW50aWNhdGUvbG9nb24nKTtcbiAgZGVidWcoJ3dhaXRpbmcgZm9yIHBhZ2UgdG8gYmUgbG9hZGVkIChuZXR3b3JraWRsZTIpJyk7XG4gIGF3YWl0IHdhaXRGb3JOYXZpZ2F0aW9uKHBhZ2UsIHsgd2FpdFVudGlsOiAnbmV0d29ya2lkbGUyJyB9KTtcbiAgZGVidWcoJ3dhaXRpbmcgZm9yIGNvbXBvbmVudHMgb2YgbG9naW4gdG8gZW50ZXIgY3JlZGVudGlhbHMnKTtcbiAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnaW5wdXRbcGxhY2Vob2xkZXI9XCLXqdedINee16nXqtee16lcIl0nLCB0cnVlKSxcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2lucHV0W3BsYWNlaG9sZGVyPVwi16HXmdeh157XlFwiXScsIHRydWUpLFxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnYnV0dG9uW3R5cGU9XCJzdWJtaXRcIl0nLCB0cnVlKSxcbiAgXSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHdhaXRGb3JQb3N0TG9naW4ocGFnZTogUGFnZSk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnYVt0aXRsZT1cIteT15zXkiDXnNeX16nXkdeV159cIl0nLCB0cnVlLCA2MDAwMCksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdkaXYubWFpbi1jb250ZW50JywgZmFsc2UsIDYwMDAwKSxcbiAgICBwYWdlLndhaXRGb3JTZWxlY3RvcihgeHBhdGgvL2Rpdltjb250YWlucyhzdHJpbmcoKSxcIiR7SU5WQUxJRF9QQVNTV09SRF9NU0d9XCIpXWApLFxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBDSEFOR0VfUEFTU1dPUkRfTU9EQUxfU0VMRUNUT1IsIHRydWUsIDYwMDAwKSxcbiAgXSk7XG59XG5cbnR5cGUgU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMgPSB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfTtcblxuY2xhc3MgTGV1bWlTY3JhcGVyIGV4dGVuZHMgQmFzZVNjcmFwZXJXaXRoQnJvd3NlcjxTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscz4ge1xuICBnZXRMb2dpbk9wdGlvbnMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxvZ2luVXJsOiBMT0dJTl9VUkwsXG4gICAgICBmaWVsZHM6IGNyZWF0ZUxvZ2luRmllbGRzKGNyZWRlbnRpYWxzKSxcbiAgICAgIHN1Ym1pdEJ1dHRvblNlbGVjdG9yOiBcImJ1dHRvblt0eXBlPSdzdWJtaXQnXVwiLFxuICAgICAgY2hlY2tSZWFkaW5lc3M6IGFzeW5jICgpID0+IG5hdmlnYXRlVG9Mb2dpbih0aGlzLnBhZ2UpLFxuICAgICAgcG9zdEFjdGlvbjogYXN5bmMgKCkgPT4gd2FpdEZvclBvc3RMb2dpbih0aGlzLnBhZ2UpLFxuICAgICAgcG9zc2libGVSZXN1bHRzOiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cygpLFxuICAgIH07XG4gIH1cblxuICBhc3luYyBmZXRjaERhdGEoKTogUHJvbWlzZTxTY3JhcGVyU2NyYXBpbmdSZXN1bHQ+IHtcbiAgICBjb25zdCBtaW5pbXVtU3RhcnRNb21lbnQgPSBtb21lbnQoKS5zdWJ0cmFjdCgzLCAneWVhcnMnKS5hZGQoMSwgJ2RheScpO1xuICAgIGNvbnN0IGRlZmF1bHRTdGFydE1vbWVudCA9IG1vbWVudCgpLnN1YnRyYWN0KDEsICd5ZWFycycpLmFkZCgxLCAnZGF5Jyk7XG4gICAgY29uc3Qgc3RhcnREYXRlID0gdGhpcy5vcHRpb25zLnN0YXJ0RGF0ZSB8fCBkZWZhdWx0U3RhcnRNb21lbnQudG9EYXRlKCk7XG4gICAgY29uc3Qgc3RhcnRNb21lbnQgPSBtb21lbnQubWF4KG1pbmltdW1TdGFydE1vbWVudCwgbW9tZW50KHN0YXJ0RGF0ZSkpO1xuXG4gICAgY29uc3QgYWNjb3VudHMgPSBhd2FpdCBmZXRjaFJlZ3VsYXJBY2NvdW50cyh0aGlzLCB0aGlzLnBhZ2UsIHN0YXJ0TW9tZW50LCB0aGlzLm9wdGlvbnMpO1xuICAgIGNvbnN0IHNhdmluZ3NBY2NvdW50cyA9IGF3YWl0IGZldGNoU2F2aW5nc0FjY291bnRzKHRoaXMucGFnZSwgYWNjb3VudHMpO1xuICAgIGFjY291bnRzLnB1c2goLi4uc2F2aW5nc0FjY291bnRzKTtcblxuICAgIHJldHVybiB7XG4gICAgICBzdWNjZXNzOiB0cnVlLFxuICAgICAgYWNjb3VudHMsXG4gICAgfTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBMZXVtaVNjcmFwZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLE9BQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUVBLElBQUFDLFVBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLHFCQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxNQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxhQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxXQUFBLEdBQUFOLE9BQUE7QUFDQSxJQUFBTyxjQUFBLEdBQUFQLE9BQUE7QUFDQSxJQUFBUSx1QkFBQSxHQUFBUixPQUFBO0FBQXNHLFNBQUFELHVCQUFBVSxDQUFBLFdBQUFBLENBQUEsSUFBQUEsQ0FBQSxDQUFBQyxVQUFBLEdBQUFELENBQUEsS0FBQUUsT0FBQSxFQUFBRixDQUFBO0FBR3RHLE1BQU1HLEtBQUssR0FBRyxJQUFBQyxlQUFRLEVBQUMsT0FBTyxDQUFDO0FBQy9CLE1BQU1DLFFBQVEsR0FBRyw2QkFBNkI7QUFDOUMsTUFBTUMsU0FBUyxHQUFHLDRCQUE0QjtBQUM5QyxNQUFNQyxnQkFBZ0IsR0FBRyxHQUFHRixRQUFRLDBEQUEwRDtBQUM5RixNQUFNRyx5QkFBeUIsR0FBRyxHQUFHSCxRQUFRLGlGQUFpRjtBQUM5SCxNQUFNSSxXQUFXLEdBQUcsR0FBR0osUUFBUSw4RUFBOEU7QUFFN0csTUFBTUssV0FBVyxHQUFHLFVBQVU7QUFDOUIsTUFBTUMsbUJBQW1CLEdBQUcsWUFBWTtBQUN4QyxNQUFNQyxvQkFBb0IsR0FBRyx3REFBd0Q7QUFDckYsTUFBTUMsOEJBQThCLEdBQUcsMkJBQTJCO0FBc0NsRSxTQUFTQyx1QkFBdUJBLENBQUEsRUFBRztFQUNqQyxNQUFNQyxJQUFxQyxHQUFHO0lBQzVDLENBQUNDLG9DQUFZLENBQUNDLE9BQU8sR0FBRyxDQUFDLHlCQUF5QixDQUFDO0lBQ25ELENBQUNELG9DQUFZLENBQUNFLGVBQWUsR0FBRyxDQUM5QixNQUFNQyxPQUFPLElBQUk7TUFDZixJQUFJLENBQUNBLE9BQU8sSUFBSSxDQUFDQSxPQUFPLENBQUNDLElBQUksRUFBRTtRQUM3QixNQUFNLElBQUlDLEtBQUssQ0FBQywrQkFBK0IsQ0FBQztNQUNsRDtNQUNBLE1BQU1DLFlBQVksR0FBRyxNQUFNLElBQUFDLGlDQUFXLEVBQUNKLE9BQU8sQ0FBQ0MsSUFBSSxFQUFFLFlBQVksRUFBRSxFQUFFLEVBQUVJLE9BQU8sSUFBSTtRQUNoRixPQUFRQSxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUVDLGFBQWEsRUFBRUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFxQkMsU0FBUztNQUM5RSxDQUFDLENBQUM7TUFFRixPQUFPTCxZQUFZLEVBQUVNLFVBQVUsQ0FBQ2hCLG9CQUFvQixDQUFDO0lBQ3ZELENBQUMsQ0FDRjtJQUNELENBQUNJLG9DQUFZLENBQUNhLGNBQWMsR0FBRztJQUM3QjtJQUNBLE1BQU1WLE9BQU8sSUFBSTtNQUNmLElBQUksQ0FBQ0EsT0FBTyxJQUFJLENBQUNBLE9BQU8sQ0FBQ0MsSUFBSSxFQUFFO1FBQzdCLE1BQU0sSUFBSUMsS0FBSyxDQUFDLCtCQUErQixDQUFDO01BQ2xEO01BQ0EsTUFBTUMsWUFBWSxHQUFHLE1BQU0sSUFBQUMsaUNBQVcsRUFBQ0osT0FBTyxDQUFDQyxJQUFJLEVBQUUsWUFBWSxFQUFFLEVBQUUsRUFBRVUsS0FBSyxJQUFJO1FBQzlFLE9BQVFBLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBa0JILFNBQVM7TUFDN0MsQ0FBQyxDQUFDO01BRUYsT0FBT0wsWUFBWSxFQUFFTSxVQUFVLENBQUNqQixtQkFBbUIsQ0FBQztJQUN0RCxDQUFDLENBQ0Y7SUFDRCxDQUFDSyxvQ0FBWSxDQUFDZSxjQUFjLEdBQUcsQ0FDN0IsTUFBTVosT0FBTyxJQUFJO01BQ2YsSUFBSSxDQUFDQSxPQUFPLElBQUksQ0FBQ0EsT0FBTyxDQUFDQyxJQUFJLEVBQUU7UUFDN0IsTUFBTSxJQUFJQyxLQUFLLENBQUMsK0JBQStCLENBQUM7TUFDbEQ7TUFDQSxPQUFPLENBQUMsRUFBRSxNQUFNRixPQUFPLENBQUNDLElBQUksQ0FBQ1ksQ0FBQyxDQUFDbkIsOEJBQThCLENBQUMsQ0FBQztJQUNqRSxDQUFDO0VBRUwsQ0FBQztFQUNELE9BQU9FLElBQUk7QUFDYjtBQUVBLFNBQVNrQixpQkFBaUJBLENBQUNDLFdBQXVDLEVBQUU7RUFDbEUsT0FBTyxDQUNMO0lBQUVDLFFBQVEsRUFBRSwrQkFBK0I7SUFBRUMsS0FBSyxFQUFFRixXQUFXLENBQUNHO0VBQVMsQ0FBQyxFQUMxRTtJQUFFRixRQUFRLEVBQUUsNEJBQTRCO0lBQUVDLEtBQUssRUFBRUYsV0FBVyxDQUFDSTtFQUFTLENBQUMsQ0FDeEU7QUFDSDtBQUVBLFNBQVNDLDJCQUEyQkEsQ0FDbENDLFlBQW1CLEVBQ25CQyxNQUEyQixFQUMzQnRCLE9BQXdCLEVBQ1Q7RUFDZixJQUFJcUIsWUFBWSxLQUFLLElBQUksSUFBSUEsWUFBWSxDQUFDRSxNQUFNLEtBQUssQ0FBQyxFQUFFO0lBQ3RELE9BQU8sRUFBRTtFQUNYO0VBRUEsTUFBTUMsTUFBcUIsR0FBR0gsWUFBWSxDQUFDSSxHQUFHLENBQUNDLGNBQWMsSUFBSTtJQUMvRCxNQUFNQyxJQUFJLEdBQUcsSUFBQUMsZUFBTSxFQUFDRixjQUFjLENBQUNHLE9BQU8sQ0FBQyxDQUFDQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUNDLFdBQVcsQ0FBQyxDQUFDO0lBQ3pFLE1BQU1DLGNBQTJCLEdBQUc7TUFDbENWLE1BQU07TUFDTlcsSUFBSSxFQUFFQywrQkFBZ0IsQ0FBQ0MsTUFBTTtNQUM3QlIsSUFBSTtNQUNKUyxhQUFhLEVBQUVULElBQUk7TUFDbkJVLFdBQVcsRUFBRVgsY0FBYyxDQUFDWSxXQUFXLElBQUksRUFBRTtNQUM3Q0MsVUFBVSxFQUFFYixjQUFjLENBQUNjLG1CQUFtQjtNQUM5Q0MsSUFBSSxFQUFFZixjQUFjLENBQUNnQixjQUFjLElBQUksRUFBRTtNQUN6Q0MsZ0JBQWdCLEVBQUVDLDBCQUFlO01BQ2pDQyxhQUFhLEVBQUVuQixjQUFjLENBQUNvQixNQUFNO01BQ3BDQyxjQUFjLEVBQUVyQixjQUFjLENBQUNvQjtJQUNqQyxDQUFDO0lBRUQsSUFBSTlDLE9BQU8sRUFBRWdELHFCQUFxQixFQUFFO01BQ2xDaEIsY0FBYyxDQUFDTixjQUFjLEdBQUcsSUFBQXVCLCtCQUFpQixFQUFDdkIsY0FBYyxDQUFDO0lBQ25FO0lBRUEsT0FBT00sY0FBYztFQUN2QixDQUFDLENBQUM7RUFFRixPQUFPUixNQUFNO0FBQ2Y7QUFFQSxTQUFTMEIsV0FBV0EsQ0FBQ0MsT0FBZSxFQUFFO0VBQ3BDLE9BQU8sSUFBSUMsT0FBTyxDQUFPQyxPQUFPLElBQUk7SUFDbENDLFVBQVUsQ0FBQyxNQUFNO01BQ2ZELE9BQU8sQ0FBQyxDQUFDO0lBQ1gsQ0FBQyxFQUFFRixPQUFPLENBQUM7RUFDYixDQUFDLENBQUM7QUFDSjtBQUVBLGVBQWVJLFlBQVlBLENBQUN0RCxJQUFVLEVBQUV1RCxLQUFhLEVBQWlCO0VBQ3BFLE1BQU12RCxJQUFJLENBQUN3RCxlQUFlLENBQUNELEtBQUssRUFBRTtJQUFFTCxPQUFPLEVBQUUsS0FBSztJQUFFTyxPQUFPLEVBQUU7RUFBSyxDQUFDLENBQUM7RUFDcEUsTUFBTUMsR0FBRyxHQUFHLE1BQU0xRCxJQUFJLENBQUMyRCxFQUFFLENBQUNKLEtBQUssQ0FBQztFQUNoQyxNQUFNRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUNFLEtBQUssQ0FBQyxDQUFDO0FBQ3RCO0FBRUEsU0FBU0MsdUJBQXVCQSxDQUFDQyxHQUFXLEVBQVU7RUFDcEQsT0FBT0EsR0FBRyxDQUFDQyxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztBQUNyQztBQUVBLGVBQWVDLDJCQUEyQkEsQ0FDeENoRSxJQUFVLEVBQ1ZpRSxTQUFpQixFQUNqQkMsU0FBaUIsRUFDakJuRSxPQUF1QixFQUNPO0VBQzlCO0VBQ0E7RUFDQSxNQUFNa0QsV0FBVyxDQUFDLElBQUksQ0FBQztFQUV2QixNQUFNLElBQUFrQiwyQ0FBcUIsRUFBQ25FLElBQUksRUFBRSw2QkFBNkIsRUFBRSxJQUFJLENBQUM7RUFDdEUsTUFBTSxJQUFBb0UsaUNBQVcsRUFBQ3BFLElBQUksRUFBRSw2QkFBNkIsQ0FBQztFQUN0RCxNQUFNLElBQUFtRSwyQ0FBcUIsRUFBQ25FLElBQUksRUFBRSxrQkFBa0IsRUFBRSxJQUFJLENBQUM7RUFDM0QsTUFBTSxJQUFBb0UsaUNBQVcsRUFBQ3BFLElBQUksRUFBRSxpQ0FBaUMsQ0FBQztFQUUxRCxNQUFNLElBQUFtRSwyQ0FBcUIsRUFBQ25FLElBQUksRUFBRSx1Q0FBdUMsRUFBRSxJQUFJLENBQUM7RUFFaEYsTUFBTSxJQUFBcUUsK0JBQVMsRUFBQ3JFLElBQUksRUFBRSx1Q0FBdUMsRUFBRWlFLFNBQVMsQ0FBQ0ssTUFBTSxDQUFDaEYsV0FBVyxDQUFDLENBQUM7O0VBRTdGO0VBQ0EsTUFBTVUsSUFBSSxDQUFDdUUsS0FBSyxDQUFDLDBCQUEwQixDQUFDO0VBRTVDLE1BQU0sSUFBQUgsaUNBQVcsRUFBQ3BFLElBQUksRUFBRSwwQkFBMEIsQ0FBQztFQUNuRCxNQUFNd0UsYUFBYSxHQUFHLE1BQU14RSxJQUFJLENBQUN5RSxlQUFlLENBQUNDLFFBQVEsSUFBSTtJQUMzRCxPQUFPQSxRQUFRLENBQUNDLEdBQUcsQ0FBQyxDQUFDLEtBQUt2Rix5QkFBeUIsSUFBSXNGLFFBQVEsQ0FBQ0UsT0FBTyxDQUFDLENBQUMsQ0FBQ0MsTUFBTSxDQUFDLENBQUMsS0FBSyxNQUFNO0VBQy9GLENBQUMsQ0FBQztFQUVGLE1BQU1DLFlBQWlCLEdBQUcsTUFBTU4sYUFBYSxDQUFDTyxJQUFJLENBQUMsQ0FBQztFQUVwRCxNQUFNQyxhQUFhLEdBQUdkLFNBQVMsQ0FBQ0gsT0FBTyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQ0EsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUM7RUFFekUsTUFBTVcsUUFBUSxHQUFHTyxJQUFJLENBQUNDLEtBQUssQ0FBQ0osWUFBWSxDQUFDSyxRQUFRLENBQUM7RUFFbEQsTUFBTUMsbUJBQW1CLEdBQUdWLFFBQVEsQ0FBQ1csc0JBQXNCO0VBQzNELE1BQU1qRSxZQUFZLEdBQUdzRCxRQUFRLENBQUNZLHdCQUF3QjtFQUN0RCxNQUFNQyxPQUFPLEdBQUdiLFFBQVEsQ0FBQ2MsY0FBYyxHQUFHQyxVQUFVLENBQUNmLFFBQVEsQ0FBQ2MsY0FBYyxDQUFDLEdBQUdFLFNBQVM7RUFFekYsTUFBTUMsV0FBVyxHQUFHeEUsMkJBQTJCLENBQUNpRSxtQkFBbUIsRUFBRVEsa0NBQW1CLENBQUNDLE9BQU8sRUFBRTlGLE9BQU8sQ0FBQztFQUMxRyxNQUFNK0YsYUFBYSxHQUFHM0UsMkJBQTJCLENBQUNDLFlBQVksRUFBRXdFLGtDQUFtQixDQUFDRyxTQUFTLEVBQUVoRyxPQUFPLENBQUM7RUFDdkcsTUFBTWlHLElBQUksR0FBRyxDQUFDLEdBQUdMLFdBQVcsRUFBRSxHQUFHRyxhQUFhLENBQUM7RUFFL0MsT0FBTztJQUNMZCxhQUFhO0lBQ2JPLE9BQU87SUFDUFM7RUFDRixDQUFDO0FBQ0g7QUFFQSxlQUFlQyxvQkFBb0JBLENBQ2pDQyxPQUFxQixFQUNyQmxHLElBQVUsRUFDVmlFLFNBQWlCLEVBQ2pCbEUsT0FBdUIsRUFDUztFQUNoQyxNQUFNbUcsT0FBTyxDQUFDQyxVQUFVLENBQUNoSCxnQkFBZ0IsQ0FBQztFQUMxQyxPQUFPaUgsaUJBQWlCLENBQUNwRyxJQUFJLEVBQUVpRSxTQUFTLEVBQUVsRSxPQUFPLENBQUM7QUFDcEQ7QUFFQSxlQUFlc0csa0JBQWtCQSxDQUFDckcsSUFBVSxFQUFFa0UsU0FBaUIsRUFBa0M7RUFDL0ZuRixLQUFLLENBQUMsaURBQWlELENBQUM7RUFDeERBLEtBQUssQ0FBQyxhQUFhLEVBQUVtRixTQUFTLENBQUM7RUFFL0IsTUFBTW9DLFFBQStCLEdBQUcsRUFBRTtFQUUxQyxJQUFJO0lBQ0Z2SCxLQUFLLENBQUMsd0JBQXdCLEVBQUVNLFdBQVcsQ0FBQztJQUU1QyxNQUFNa0gsV0FBVyxHQUFHLE1BQU0sSUFBQUMseUJBQWtCLEVBQXFCeEcsSUFBSSxFQUFFWCxXQUFXLENBQUM7SUFDbkYsSUFBSSxDQUFDa0gsV0FBVyxJQUFJLENBQUNBLFdBQVcsQ0FBQ0UsdUJBQXVCLElBQUlGLFdBQVcsQ0FBQ0UsdUJBQXVCLENBQUNuRixNQUFNLEtBQUssQ0FBQyxFQUFFO01BQzVHdkMsS0FBSyxDQUFDLDBDQUEwQyxFQUFFbUYsU0FBUyxDQUFDO01BQzVELE9BQU8sRUFBRTtJQUNYO0lBQ0FuRixLQUFLLENBQUMsNkJBQTZCLEVBQUV3SCxXQUFXLENBQUNFLHVCQUF1QixDQUFDbkYsTUFBTSxDQUFDOztJQUVoRjtJQUNBLEtBQUssTUFBTW9GLE9BQU8sSUFBSUgsV0FBVyxDQUFDRSx1QkFBdUIsRUFBRTtNQUN6RCxNQUFNbEIsT0FBTyxHQUFHbUIsT0FBTyxDQUFDQyxjQUFjO01BQ3RDLE1BQU1DLG9CQUFvQixHQUFHLEdBQUcxQyxTQUFTLElBQUl3QyxPQUFPLENBQUNHLFNBQVMsRUFBRTtNQUVoRVAsUUFBUSxDQUFDUSxJQUFJLENBQUM7UUFDWjlCLGFBQWEsRUFBRTRCLG9CQUFvQjtRQUNuQ0csY0FBYyxFQUFFLElBQUk7UUFDcEJ4QixPQUFPO1FBQ1BTLElBQUksRUFBRTtNQUNSLENBQUMsQ0FBQztNQUVGakgsS0FBSyxDQUNILHdEQUF3RCxFQUN4RDZILG9CQUFvQixFQUNwQnJCLE9BQU8sRUFDUG1CLE9BQU8sQ0FBQ00sV0FDVixDQUFDO0lBQ0g7RUFDRixDQUFDLENBQUMsT0FBT0MsS0FBSyxFQUFFO0lBQ2RsSSxLQUFLLENBQUMseUNBQXlDLEVBQUVrSSxLQUFLLENBQUM7RUFDekQ7RUFFQWxJLEtBQUssQ0FBQywrQkFBK0IsRUFBRXVILFFBQVEsQ0FBQ2hGLE1BQU0sQ0FBQztFQUN2RCxPQUFPZ0YsUUFBUTtBQUNqQjtBQUVBLGVBQWVGLGlCQUFpQkEsQ0FDOUJwRyxJQUFVLEVBQ1ZpRSxTQUFpQixFQUNqQmxFLE9BQXVCLEVBQ1M7RUFDaEMsTUFBTXVHLFFBQStCLEdBQUcsRUFBRTs7RUFFMUM7RUFDQTtFQUNBLE1BQU1yRCxXQUFXLENBQUMsSUFBSSxDQUFDO0VBRXZCLE1BQU1pRSxXQUFXLEdBQUksTUFBTWxILElBQUksQ0FBQ21ILFFBQVEsQ0FBQyxNQUN2Q0MsS0FBSyxDQUFDQyxJQUFJLENBQUNDLFFBQVEsQ0FBQ0MsZ0JBQWdCLENBQUMsZ0RBQWdELENBQUMsRUFBRTNJLENBQUMsSUFBSUEsQ0FBQyxDQUFDNEksV0FBVyxDQUM1RyxDQUFjOztFQUVkOztFQUVBLElBQUksQ0FBQ04sV0FBVyxDQUFDNUYsTUFBTSxFQUFFO0lBQ3ZCLE1BQU0sSUFBSXJCLEtBQUssQ0FBQywrQ0FBK0MsQ0FBQztFQUNsRTtFQUVBLEtBQUssTUFBTWlFLFNBQVMsSUFBSWdELFdBQVcsRUFBRTtJQUNuQyxJQUFJQSxXQUFXLENBQUM1RixNQUFNLEdBQUcsQ0FBQyxFQUFFO01BQzFCO01BQ0EsTUFBTWdDLFlBQVksQ0FBQ3RELElBQUksRUFBRSwyRUFBMkUsQ0FBQztNQUNyRyxNQUFNc0QsWUFBWSxDQUFDdEQsSUFBSSxFQUFFLGtDQUFrQ2tFLFNBQVMsS0FBSyxDQUFDO0lBQzVFO0lBRUFvQyxRQUFRLENBQUNRLElBQUksQ0FBQyxNQUFNOUMsMkJBQTJCLENBQUNoRSxJQUFJLEVBQUVpRSxTQUFTLEVBQUVKLHVCQUF1QixDQUFDSyxTQUFTLENBQUMsRUFBRW5FLE9BQU8sQ0FBQyxDQUFDO0VBQ2hIO0VBRUEsT0FBT3VHLFFBQVE7QUFDakI7QUFFQSxlQUFlbUIsb0JBQW9CQSxDQUNqQ3pILElBQVUsRUFDVjBILGVBQXNDLEVBQ047RUFDaEMsTUFBTUMsa0JBQXlDLEdBQUcsRUFBRTtFQUNwRCxNQUFNQyxtQkFBbUIsR0FBR0YsZUFBZSxDQUFDcEcsTUFBTTtFQUVsRCxLQUFLLElBQUl1RyxDQUFDLEdBQUcsQ0FBQyxFQUFFQSxDQUFDLEdBQUdELG1CQUFtQixFQUFFQyxDQUFDLEVBQUUsRUFBRTtJQUM1QyxJQUFJO01BQ0YsTUFBTUMsZUFBZSxHQUFHLE1BQU16QixrQkFBa0IsQ0FBQ3JHLElBQUksRUFBRTBILGVBQWUsQ0FBQ0csQ0FBQyxDQUFDLENBQUM3QyxhQUFhLENBQUM7TUFDeEYyQyxrQkFBa0IsQ0FBQ2IsSUFBSSxDQUFDLEdBQUdnQixlQUFlLENBQUM7TUFDM0MvSSxLQUFLLENBQUMsc0NBQXNDLEVBQUUrSSxlQUFlLENBQUN4RyxNQUFNLENBQUM7SUFDdkUsQ0FBQyxDQUFDLE9BQU8yRixLQUFLLEVBQUU7TUFDZGxJLEtBQUssQ0FBQyw0Q0FBNEMsRUFBRTJJLGVBQWUsQ0FBQ0csQ0FBQyxDQUFDLENBQUM3QyxhQUFhLEVBQUVpQyxLQUFLLENBQUM7SUFDOUY7RUFDRjtFQUVBLE9BQU9VLGtCQUFrQjtBQUMzQjtBQUVBLGVBQWVJLGVBQWVBLENBQUMvSCxJQUFVLEVBQWlCO0VBQ3hEakIsS0FBSyxDQUFDLG1DQUFtQyxDQUFDO0VBQzFDLE1BQU1pQixJQUFJLENBQUNnSSxJQUFJLENBQUMsZ0RBQWdELENBQUM7RUFDakVqSixLQUFLLENBQUMsOENBQThDLENBQUM7RUFDckQsTUFBTSxJQUFBa0osNkJBQWlCLEVBQUNqSSxJQUFJLEVBQUU7SUFBRWtJLFNBQVMsRUFBRTtFQUFlLENBQUMsQ0FBQztFQUM1RG5KLEtBQUssQ0FBQyxzREFBc0QsQ0FBQztFQUM3RCxNQUFNb0UsT0FBTyxDQUFDZ0YsR0FBRyxDQUFDLENBQ2hCLElBQUFoRSwyQ0FBcUIsRUFBQ25FLElBQUksRUFBRSwrQkFBK0IsRUFBRSxJQUFJLENBQUMsRUFDbEUsSUFBQW1FLDJDQUFxQixFQUFDbkUsSUFBSSxFQUFFLDRCQUE0QixFQUFFLElBQUksQ0FBQyxFQUMvRCxJQUFBbUUsMkNBQXFCLEVBQUNuRSxJQUFJLEVBQUUsdUJBQXVCLEVBQUUsSUFBSSxDQUFDLENBQzNELENBQUM7QUFDSjtBQUVBLGVBQWVvSSxnQkFBZ0JBLENBQUNwSSxJQUFVLEVBQWlCO0VBQ3pELE1BQU1tRCxPQUFPLENBQUNrRixJQUFJLENBQUMsQ0FDakIsSUFBQWxFLDJDQUFxQixFQUFDbkUsSUFBSSxFQUFFLHVCQUF1QixFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsRUFDakUsSUFBQW1FLDJDQUFxQixFQUFDbkUsSUFBSSxFQUFFLGtCQUFrQixFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsRUFDN0RBLElBQUksQ0FBQ3dELGVBQWUsQ0FBQyxpQ0FBaUNoRSxvQkFBb0IsS0FBSyxDQUFDLEVBQ2hGLElBQUEyRSwyQ0FBcUIsRUFBQ25FLElBQUksRUFBRVAsOEJBQThCLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUN6RSxDQUFDO0FBQ0o7QUFJQSxNQUFNNkksWUFBWSxTQUFTQyw4Q0FBc0IsQ0FBNkI7RUFDNUVDLGVBQWVBLENBQUMxSCxXQUF1QyxFQUFFO0lBQ3ZELE9BQU87TUFDTDJILFFBQVEsRUFBRXZKLFNBQVM7TUFDbkJ3SixNQUFNLEVBQUU3SCxpQkFBaUIsQ0FBQ0MsV0FBVyxDQUFDO01BQ3RDNkgsb0JBQW9CLEVBQUUsdUJBQXVCO01BQzdDQyxjQUFjLEVBQUUsTUFBQUEsQ0FBQSxLQUFZYixlQUFlLENBQUMsSUFBSSxDQUFDL0gsSUFBSSxDQUFDO01BQ3RENkksVUFBVSxFQUFFLE1BQUFBLENBQUEsS0FBWVQsZ0JBQWdCLENBQUMsSUFBSSxDQUFDcEksSUFBSSxDQUFDO01BQ25EOEksZUFBZSxFQUFFcEosdUJBQXVCLENBQUM7SUFDM0MsQ0FBQztFQUNIO0VBRUEsTUFBTXFKLFNBQVNBLENBQUEsRUFBbUM7SUFDaEQsTUFBTUMsa0JBQWtCLEdBQUcsSUFBQXJILGVBQU0sRUFBQyxDQUFDLENBQUNzSCxRQUFRLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUN0RSxNQUFNQyxrQkFBa0IsR0FBRyxJQUFBeEgsZUFBTSxFQUFDLENBQUMsQ0FBQ3NILFFBQVEsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLENBQUNDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDO0lBQ3RFLE1BQU1qRixTQUFTLEdBQUcsSUFBSSxDQUFDbEUsT0FBTyxDQUFDa0UsU0FBUyxJQUFJa0Ysa0JBQWtCLENBQUNDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZFLE1BQU1DLFdBQVcsR0FBRzFILGVBQU0sQ0FBQzJILEdBQUcsQ0FBQ04sa0JBQWtCLEVBQUUsSUFBQXJILGVBQU0sRUFBQ3NDLFNBQVMsQ0FBQyxDQUFDO0lBRXJFLE1BQU1xQyxRQUFRLEdBQUcsTUFBTUwsb0JBQW9CLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQ2pHLElBQUksRUFBRXFKLFdBQVcsRUFBRSxJQUFJLENBQUN0SixPQUFPLENBQUM7SUFDdkYsTUFBTStILGVBQWUsR0FBRyxNQUFNTCxvQkFBb0IsQ0FBQyxJQUFJLENBQUN6SCxJQUFJLEVBQUVzRyxRQUFRLENBQUM7SUFDdkVBLFFBQVEsQ0FBQ1EsSUFBSSxDQUFDLEdBQUdnQixlQUFlLENBQUM7SUFFakMsT0FBTztNQUNMeUIsT0FBTyxFQUFFLElBQUk7TUFDYmpEO0lBQ0YsQ0FBQztFQUNIO0FBQ0Y7QUFBQyxJQUFBa0QsUUFBQSxHQUFBQyxPQUFBLENBQUEzSyxPQUFBLEdBRWN3SixZQUFZIiwiaWdub3JlTGlzdCI6W119