israeli-bank-scrapers-core
Version:
Provide scrapers for all major Israeli banks and credit card companies
428 lines • 66 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.clickAccountSelectorGetAccountIds = clickAccountSelectorGetAccountIds;
exports.createLoginFields = createLoginFields;
exports.default = void 0;
exports.getPossibleLoginResults = getPossibleLoginResults;
exports.selectAccountFromDropdown = selectAccountFromDropdown;
exports.waitForPostLogin = waitForPostLogin;
var _moment = _interopRequireDefault(require("moment"));
var _constants = require("../constants");
var _elementsInteractions = require("../helpers/elements-interactions");
var _navigation = require("../helpers/navigation");
var _waiting = require("../helpers/waiting");
var _transactions = require("../transactions");
var _baseScraperWithBrowser = require("./base-scraper-with-browser");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const DATE_FORMAT = 'DD/MM/YYYY';
const NO_TRANSACTION_IN_DATE_RANGE_TEXT = 'לא נמצאו נתונים בנושא המבוקש';
const DATE_COLUMN_CLASS_COMPLETED = 'date first';
const DATE_COLUMN_CLASS_PENDING = 'first date';
const DESCRIPTION_COLUMN_CLASS_COMPLETED = 'reference wrap_normal';
const DESCRIPTION_COLUMN_CLASS_PENDING = 'details wrap_normal';
const REFERENCE_COLUMN_CLASS = 'details';
const DEBIT_COLUMN_CLASS = 'debit';
const CREDIT_COLUMN_CLASS = 'credit';
const ERROR_MESSAGE_CLASS = 'NO_DATA';
const ACCOUNTS_NUMBER = 'div.fibi_account span.acc_num';
const CLOSE_SEARCH_BY_DATES_BUTTON_CLASS = 'ui-datepicker-close';
const SHOW_SEARCH_BY_DATES_BUTTON_VALUE = 'הצג';
const COMPLETED_TRANSACTIONS_TABLE = 'table#dataTable077';
const PENDING_TRANSACTIONS_TABLE = 'table#dataTable023';
const NEXT_PAGE_LINK = 'a#Npage.paging';
const CURRENT_BALANCE = '.main_balance';
const IFRAME_NAME = 'iframe-old-pages';
const ELEMENT_RENDER_TIMEOUT_MS = 10000;
function getPossibleLoginResults() {
const urls = {};
urls[_baseScraperWithBrowser.LoginResults.Success] = [/fibi.*accountSummary/,
// New UI pattern
/Resources\/PortalNG\/shell/,
// New UI pattern
/FibiMenu\/Online/ // Old UI pattern
];
urls[_baseScraperWithBrowser.LoginResults.InvalidPassword] = [/FibiMenu\/Marketing\/Private\/Home/];
return urls;
}
function createLoginFields(credentials) {
return [{
selector: '#username',
value: credentials.username
}, {
selector: '#password',
value: credentials.password
}];
}
function getAmountData(amountStr) {
let amountStrCopy = amountStr.replace(_constants.SHEKEL_CURRENCY_SYMBOL, '');
amountStrCopy = amountStrCopy.replaceAll(',', '');
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) {
return txns.map(txn => {
const convertedDate = (0, _moment.default)(txn.date, DATE_FORMAT).toISOString();
const convertedAmount = getTxnAmount(txn);
return {
type: _transactions.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
};
});
}
function getTransactionDate(tds, transactionType, transactionsColsTypes) {
if (transactionType === 'completed') {
return (tds[transactionsColsTypes[DATE_COLUMN_CLASS_COMPLETED]] || '').trim();
}
return (tds[transactionsColsTypes[DATE_COLUMN_CLASS_PENDING]] || '').trim();
}
function getTransactionDescription(tds, transactionType, transactionsColsTypes) {
if (transactionType === 'completed') {
return (tds[transactionsColsTypes[DESCRIPTION_COLUMN_CLASS_COMPLETED]] || '').trim();
}
return (tds[transactionsColsTypes[DESCRIPTION_COLUMN_CLASS_PENDING]] || '').trim();
}
function getTransactionReference(tds, transactionsColsTypes) {
return (tds[transactionsColsTypes[REFERENCE_COLUMN_CLASS]] || '').trim();
}
function getTransactionDebit(tds, transactionsColsTypes) {
return (tds[transactionsColsTypes[DEBIT_COLUMN_CLASS]] || '').trim();
}
function getTransactionCredit(tds, transactionsColsTypes) {
return (tds[transactionsColsTypes[CREDIT_COLUMN_CLASS]] || '').trim();
}
function extractTransactionDetails(txnRow, transactionStatus, transactionsColsTypes) {
const tds = txnRow.innerTds;
const item = {
status: transactionStatus,
date: getTransactionDate(tds, transactionStatus, transactionsColsTypes),
description: getTransactionDescription(tds, transactionStatus, transactionsColsTypes),
reference: getTransactionReference(tds, transactionsColsTypes),
debit: getTransactionDebit(tds, transactionsColsTypes),
credit: getTransactionCredit(tds, transactionsColsTypes)
};
return item;
}
async function getTransactionsColsTypeClasses(page, tableLocator) {
const result = {};
const typeClassesObjs = await (0, _elementsInteractions.pageEvalAll)(page, `${tableLocator} tbody tr:first-of-type td`, null, tds => {
return tds.map((td, index) => ({
colClass: td.getAttribute('class'),
index
}));
});
for (const typeClassObj of typeClassesObjs) {
if (typeClassObj.colClass) {
result[typeClassObj.colClass] = typeClassObj.index;
}
}
return result;
}
function extractTransaction(txns, transactionStatus, txnRow, transactionsColsTypes) {
const txn = extractTransactionDetails(txnRow, transactionStatus, transactionsColsTypes);
if (txn.date !== '') {
txns.push(txn);
}
}
async function extractTransactions(page, tableLocator, transactionStatus) {
const txns = [];
const transactionsColsTypes = await getTransactionsColsTypeClasses(page, tableLocator);
const transactionsRows = await (0, _elementsInteractions.pageEvalAll)(page, `${tableLocator} tbody tr`, [], trs => {
return trs.map(tr => ({
innerTds: Array.from(tr.getElementsByTagName('td')).map(td => td.innerText)
}));
});
for (const txnRow of transactionsRows) {
extractTransaction(txns, transactionStatus, txnRow, transactionsColsTypes);
}
return txns;
}
async function isNoTransactionInDateRangeError(page) {
const hasErrorInfoElement = await (0, _elementsInteractions.elementPresentOnPage)(page, `.${ERROR_MESSAGE_CLASS}`);
if (hasErrorInfoElement) {
const errorText = await page.$eval(`.${ERROR_MESSAGE_CLASS}`, errorElement => {
return errorElement.innerText;
});
return errorText.trim() === NO_TRANSACTION_IN_DATE_RANGE_TEXT;
}
return false;
}
async function searchByDates(page, startDate) {
await (0, _elementsInteractions.clickButton)(page, 'a#tabHeader4');
await (0, _elementsInteractions.waitUntilElementFound)(page, 'div#fibi_dates');
await (0, _elementsInteractions.fillInput)(page, 'input#fromDate', startDate.format(DATE_FORMAT));
await (0, _elementsInteractions.clickButton)(page, `button[class*=${CLOSE_SEARCH_BY_DATES_BUTTON_CLASS}]`);
await (0, _elementsInteractions.clickButton)(page, `input[value=${SHOW_SEARCH_BY_DATES_BUTTON_VALUE}]`);
await (0, _navigation.waitForNavigation)(page);
}
async function getAccountNumber(page) {
// Wait until the account number element is present in the DOM
await (0, _elementsInteractions.waitUntilElementFound)(page, ACCOUNTS_NUMBER, true, ELEMENT_RENDER_TIMEOUT_MS);
const selectedSnifAccount = await page.$eval(ACCOUNTS_NUMBER, option => {
return option.innerText;
});
return selectedSnifAccount.replace('/', '_').trim();
}
async function checkIfHasNextPage(page) {
return (0, _elementsInteractions.elementPresentOnPage)(page, NEXT_PAGE_LINK);
}
async function navigateToNextPage(page) {
await (0, _elementsInteractions.clickButton)(page, NEXT_PAGE_LINK);
await (0, _navigation.waitForNavigation)(page);
}
/* Couldn't reproduce scenario with multiple pages of pending transactions - Should support if exists such case.
needToPaginate is false if scraping pending transactions */
async function scrapeTransactions(page, tableLocator, transactionStatus, needToPaginate) {
const txns = [];
let hasNextPage = false;
do {
const currentPageTxns = await extractTransactions(page, tableLocator, transactionStatus);
txns.push(...currentPageTxns);
if (needToPaginate) {
hasNextPage = await checkIfHasNextPage(page);
if (hasNextPage) {
await navigateToNextPage(page);
}
}
} while (hasNextPage);
return convertTransactions(txns);
}
async function getAccountTransactions(page) {
await Promise.race([(0, _elementsInteractions.waitUntilElementFound)(page, "div[id*='divTable']", false), (0, _elementsInteractions.waitUntilElementFound)(page, `.${ERROR_MESSAGE_CLASS}`, false)]);
const noTransactionInRangeError = await isNoTransactionInDateRangeError(page);
if (noTransactionInRangeError) {
return [];
}
const pendingTxns = await scrapeTransactions(page, PENDING_TRANSACTIONS_TABLE, _transactions.TransactionStatuses.Pending, false);
const completedTxns = await scrapeTransactions(page, COMPLETED_TRANSACTIONS_TABLE, _transactions.TransactionStatuses.Completed, true);
const txns = [...pendingTxns, ...completedTxns];
return txns;
}
async function getCurrentBalance(page) {
// Wait for the balance element to appear and be visible
await (0, _elementsInteractions.waitUntilElementFound)(page, CURRENT_BALANCE, true, ELEMENT_RENDER_TIMEOUT_MS);
// Extract text content
const balanceStr = await page.$eval(CURRENT_BALANCE, el => {
return el.innerText;
});
return getAmountData(balanceStr);
}
async function waitForPostLogin(page) {
return Promise.race([(0, _elementsInteractions.waitUntilElementFound)(page, '#card-header', true),
// New UI
(0, _elementsInteractions.waitUntilElementFound)(page, '#account_num', true),
// New UI
(0, _elementsInteractions.waitUntilElementFound)(page, '#matafLogoutLink', true),
// Old UI
(0, _elementsInteractions.waitUntilElementFound)(page, '#validationMsg', true) // Old UI
]);
}
async function fetchAccountData(page, startDate) {
const accountNumber = await getAccountNumber(page);
const balance = await getCurrentBalance(page);
await searchByDates(page, startDate);
const txns = await getAccountTransactions(page);
return {
accountNumber,
txns,
balance
};
}
async function getAccountIdsOldUI(page) {
return page.evaluate(() => {
const selectElement = document.getElementById('account_num_select');
const options = selectElement ? selectElement.querySelectorAll('option') : [];
if (!options) return [];
return Array.from(options, option => option.value);
});
}
/**
* Ensures the account dropdown is open, then returns the available account labels.
*
* This method:
* - Checks if the dropdown is already open.
* - If not open, clicks the account selector to open it.
* - Waits for the dropdown to render.
* - Extracts and returns the list of available account labels.
*
* Graceful handling:
* - If any error occurs (e.g., selectors not found, timing issues, UI version changes),
* the function returns an empty list.
*
* @param page Puppeteer Page object.
* @returns An array of available account labels (e.g., ["127 | XXXX1", "127 | XXXX2"]),
* or an empty array if something goes wrong.
*/
async function clickAccountSelectorGetAccountIds(page) {
try {
const accountSelector = 'div.current-account'; // Direct selector to clickable element
const dropdownPanelSelector = 'div.mat-mdc-autocomplete-panel.account-select-dd'; // The dropdown list box
const optionSelector = 'mat-option .mdc-list-item__primary-text'; // Account option labels
// Check if dropdown is already open
const dropdownVisible = await page.$eval(dropdownPanelSelector, el => {
return el && window.getComputedStyle(el).display !== 'none' && el.offsetParent !== null;
}).catch(() => false); // catch if dropdown is not in the DOM yet
if (!dropdownVisible) {
await (0, _elementsInteractions.waitUntilElementFound)(page, accountSelector, true, ELEMENT_RENDER_TIMEOUT_MS);
// Click the account selector to open the dropdown
await (0, _elementsInteractions.clickButton)(page, accountSelector);
// Wait for the dropdown to open
await (0, _elementsInteractions.waitUntilElementFound)(page, dropdownPanelSelector, true, ELEMENT_RENDER_TIMEOUT_MS);
}
// Extract account labels from the dropdown options
const accountLabels = await page.$$eval(optionSelector, options => {
return options.map(option => option.textContent?.trim() || '').filter(label => label !== '');
});
return accountLabels;
} catch (error) {
return []; // Graceful fallback
}
}
async function getAccountIdsBothUIs(page) {
let accountsIds = await clickAccountSelectorGetAccountIds(page);
if (accountsIds.length === 0) {
accountsIds = await getAccountIdsOldUI(page);
}
return accountsIds;
}
/**
* Selects an account from the dropdown based on the provided account label.
*
* This method:
* - Clicks the account selector button to open the dropdown.
* - Retrieves the list of available account labels.
* - Checks if the provided account label exists in the list.
* - Finds and clicks the matching account option if found.
*
* @param page Puppeteer Page object.
* @param accountLabel The text of the account to select (e.g., "127 | XXXXX").
* @returns True if the account option was found and clicked; false otherwise.
*/
async function selectAccountFromDropdown(page, accountLabel) {
// Call clickAccountSelector to get the available accounts and open the dropdown
const availableAccounts = await clickAccountSelectorGetAccountIds(page);
// Check if the account label exists in the available accounts
if (!availableAccounts.includes(accountLabel)) {
return false;
}
// Wait for the dropdown options to be rendered
const optionSelector = 'mat-option .mdc-list-item__primary-text';
await (0, _elementsInteractions.waitUntilElementFound)(page, optionSelector, true, ELEMENT_RENDER_TIMEOUT_MS);
// Query all matching options
const accountOptions = await page.$$(optionSelector);
// Find and click the option matching the accountLabel
for (const option of accountOptions) {
const text = await page.evaluate(el => el.textContent?.trim(), option);
if (text === accountLabel) {
const optionHandle = await option.evaluateHandle(el => el);
await page.evaluate(el => el.click(), optionHandle);
return true;
}
}
return false;
}
async function getTransactionsFrame(page) {
// Try a few times to find the iframe, as it might not be immediately available
for (let attempt = 0; attempt < 3; attempt++) {
await (0, _waiting.sleep)(2000);
const frames = page.frames();
const targetFrame = frames.find(f => f.name() === IFRAME_NAME);
if (targetFrame) {
return targetFrame;
}
}
return null;
}
async function selectAccountBothUIs(page, accountId) {
const accountSelected = await selectAccountFromDropdown(page, accountId);
if (!accountSelected) {
// Old UI format
await page.select('#account_num_select', accountId);
await (0, _elementsInteractions.waitUntilElementFound)(page, '#account_num_select', true);
}
}
async function fetchAccountDataBothUIs(page, startDate) {
// Try to get the iframe for the new UI
const frame = await getTransactionsFrame(page);
// Use the frame if available (new UI), otherwise use the page directly (old UI)
const targetPage = frame || page;
return fetchAccountData(targetPage, startDate);
}
async function fetchAccounts(page, startDate) {
const accountsIds = await getAccountIdsBothUIs(page);
if (accountsIds.length === 0) {
// In case accountsIds could no be parsed just return the transactions of the currently selected account
const accountData = await fetchAccountDataBothUIs(page, startDate);
return [accountData];
}
const accounts = [];
for (const accountId of accountsIds) {
await selectAccountBothUIs(page, accountId);
const accountData = await fetchAccountDataBothUIs(page, startDate);
accounts.push(accountData);
}
return accounts;
}
class BeinleumiGroupBaseScraper extends _baseScraperWithBrowser.BaseScraperWithBrowser {
BASE_URL = '';
LOGIN_URL = '';
TRANSACTIONS_URL = '';
getLoginOptions(credentials) {
return {
loginUrl: `${this.LOGIN_URL}`,
fields: createLoginFields(credentials),
submitButtonSelector: '#continueBtn',
postAction: async () => waitForPostLogin(this.page),
possibleResults: getPossibleLoginResults(),
// HACK: For some reason, though the login button (#continueBtn) is present and visible, the click action does not perform.
// Adding this delay fixes the issue.
preAction: async () => {
await (0, _waiting.sleep)(1000);
}
};
}
async fetchData() {
const defaultStartMoment = (0, _moment.default)().subtract(1, 'years').add(1, 'day');
const startMomentLimit = (0, _moment.default)({
year: 1600
});
const startDate = this.options.startDate || defaultStartMoment.toDate();
const startMoment = _moment.default.max(startMomentLimit, (0, _moment.default)(startDate));
await this.navigateTo(this.TRANSACTIONS_URL);
const accounts = await fetchAccounts(this.page, startMoment);
return {
success: true,
accounts
};
}
}
var _default = exports.default = BeinleumiGroupBaseScraper;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfd2FpdGluZyIsIl90cmFuc2FjdGlvbnMiLCJfYmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIkRBVEVfRk9STUFUIiwiTk9fVFJBTlNBQ1RJT05fSU5fREFURV9SQU5HRV9URVhUIiwiREFURV9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEIiwiREFURV9DT0xVTU5fQ0xBU1NfUEVORElORyIsIkRFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19DT01QTEVURUQiLCJERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfUEVORElORyIsIlJFRkVSRU5DRV9DT0xVTU5fQ0xBU1MiLCJERUJJVF9DT0xVTU5fQ0xBU1MiLCJDUkVESVRfQ09MVU1OX0NMQVNTIiwiRVJST1JfTUVTU0FHRV9DTEFTUyIsIkFDQ09VTlRTX05VTUJFUiIsIkNMT1NFX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fQ0xBU1MiLCJTSE9XX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fVkFMVUUiLCJDT01QTEVURURfVFJBTlNBQ1RJT05TX1RBQkxFIiwiUEVORElOR19UUkFOU0FDVElPTlNfVEFCTEUiLCJORVhUX1BBR0VfTElOSyIsIkNVUlJFTlRfQkFMQU5DRSIsIklGUkFNRV9OQU1FIiwiRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyIsImdldFBvc3NpYmxlTG9naW5SZXN1bHRzIiwidXJscyIsIkxvZ2luUmVzdWx0cyIsIlN1Y2Nlc3MiLCJJbnZhbGlkUGFzc3dvcmQiLCJjcmVhdGVMb2dpbkZpZWxkcyIsImNyZWRlbnRpYWxzIiwic2VsZWN0b3IiLCJ2YWx1ZSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJnZXRBbW91bnREYXRhIiwiYW1vdW50U3RyIiwiYW1vdW50U3RyQ29weSIsInJlcGxhY2UiLCJTSEVLRUxfQ1VSUkVOQ1lfU1lNQk9MIiwicmVwbGFjZUFsbCIsInBhcnNlRmxvYXQiLCJnZXRUeG5BbW91bnQiLCJ0eG4iLCJjcmVkaXQiLCJkZWJpdCIsIk51bWJlciIsImlzTmFOIiwiY29udmVydFRyYW5zYWN0aW9ucyIsInR4bnMiLCJtYXAiLCJjb252ZXJ0ZWREYXRlIiwibW9tZW50IiwiZGF0ZSIsInRvSVNPU3RyaW5nIiwiY29udmVydGVkQW1vdW50IiwidHlwZSIsIlRyYW5zYWN0aW9uVHlwZXMiLCJOb3JtYWwiLCJpZGVudGlmaWVyIiwicmVmZXJlbmNlIiwicGFyc2VJbnQiLCJ1bmRlZmluZWQiLCJwcm9jZXNzZWREYXRlIiwib3JpZ2luYWxBbW91bnQiLCJvcmlnaW5hbEN1cnJlbmN5IiwiU0hFS0VMX0NVUlJFTkNZIiwiY2hhcmdlZEFtb3VudCIsInN0YXR1cyIsImRlc2NyaXB0aW9uIiwibWVtbyIsImdldFRyYW5zYWN0aW9uRGF0ZSIsInRkcyIsInRyYW5zYWN0aW9uVHlwZSIsInRyYW5zYWN0aW9uc0NvbHNUeXBlcyIsInRyaW0iLCJnZXRUcmFuc2FjdGlvbkRlc2NyaXB0aW9uIiwiZ2V0VHJhbnNhY3Rpb25SZWZlcmVuY2UiLCJnZXRUcmFuc2FjdGlvbkRlYml0IiwiZ2V0VHJhbnNhY3Rpb25DcmVkaXQiLCJleHRyYWN0VHJhbnNhY3Rpb25EZXRhaWxzIiwidHhuUm93IiwidHJhbnNhY3Rpb25TdGF0dXMiLCJpbm5lclRkcyIsIml0ZW0iLCJnZXRUcmFuc2FjdGlvbnNDb2xzVHlwZUNsYXNzZXMiLCJwYWdlIiwidGFibGVMb2NhdG9yIiwicmVzdWx0IiwidHlwZUNsYXNzZXNPYmpzIiwicGFnZUV2YWxBbGwiLCJ0ZCIsImluZGV4IiwiY29sQ2xhc3MiLCJnZXRBdHRyaWJ1dGUiLCJ0eXBlQ2xhc3NPYmoiLCJleHRyYWN0VHJhbnNhY3Rpb24iLCJwdXNoIiwiZXh0cmFjdFRyYW5zYWN0aW9ucyIsInRyYW5zYWN0aW9uc1Jvd3MiLCJ0cnMiLCJ0ciIsIkFycmF5IiwiZnJvbSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwiaW5uZXJUZXh0IiwiaXNOb1RyYW5zYWN0aW9uSW5EYXRlUmFuZ2VFcnJvciIsImhhc0Vycm9ySW5mb0VsZW1lbnQiLCJlbGVtZW50UHJlc2VudE9uUGFnZSIsImVycm9yVGV4dCIsIiRldmFsIiwiZXJyb3JFbGVtZW50Iiwic2VhcmNoQnlEYXRlcyIsInN0YXJ0RGF0ZSIsImNsaWNrQnV0dG9uIiwid2FpdFVudGlsRWxlbWVudEZvdW5kIiwiZmlsbElucHV0IiwiZm9ybWF0Iiwid2FpdEZvck5hdmlnYXRpb24iLCJnZXRBY2NvdW50TnVtYmVyIiwic2VsZWN0ZWRTbmlmQWNjb3VudCIsIm9wdGlvbiIsImNoZWNrSWZIYXNOZXh0UGFnZSIsIm5hdmlnYXRlVG9OZXh0UGFnZSIsInNjcmFwZVRyYW5zYWN0aW9ucyIsIm5lZWRUb1BhZ2luYXRlIiwiaGFzTmV4dFBhZ2UiLCJjdXJyZW50UGFnZVR4bnMiLCJnZXRBY2NvdW50VHJhbnNhY3Rpb25zIiwiUHJvbWlzZSIsInJhY2UiLCJub1RyYW5zYWN0aW9uSW5SYW5nZUVycm9yIiwicGVuZGluZ1R4bnMiLCJUcmFuc2FjdGlvblN0YXR1c2VzIiwiUGVuZGluZyIsImNvbXBsZXRlZFR4bnMiLCJDb21wbGV0ZWQiLCJnZXRDdXJyZW50QmFsYW5jZSIsImJhbGFuY2VTdHIiLCJlbCIsIndhaXRGb3JQb3N0TG9naW4iLCJmZXRjaEFjY291bnREYXRhIiwiYWNjb3VudE51bWJlciIsImJhbGFuY2UiLCJnZXRBY2NvdW50SWRzT2xkVUkiLCJldmFsdWF0ZSIsInNlbGVjdEVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwib3B0aW9ucyIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJjbGlja0FjY291bnRTZWxlY3RvckdldEFjY291bnRJZHMiLCJhY2NvdW50U2VsZWN0b3IiLCJkcm9wZG93blBhbmVsU2VsZWN0b3IiLCJvcHRpb25TZWxlY3RvciIsImRyb3Bkb3duVmlzaWJsZSIsIndpbmRvdyIsImdldENvbXB1dGVkU3R5bGUiLCJkaXNwbGF5Iiwib2Zmc2V0UGFyZW50IiwiY2F0Y2giLCJhY2NvdW50TGFiZWxzIiwiJCRldmFsIiwidGV4dENvbnRlbnQiLCJmaWx0ZXIiLCJsYWJlbCIsImVycm9yIiwiZ2V0QWNjb3VudElkc0JvdGhVSXMiLCJhY2NvdW50c0lkcyIsImxlbmd0aCIsInNlbGVjdEFjY291bnRGcm9tRHJvcGRvd24iLCJhY2NvdW50TGFiZWwiLCJhdmFpbGFibGVBY2NvdW50cyIsImluY2x1ZGVzIiwiYWNjb3VudE9wdGlvbnMiLCIkJCIsInRleHQiLCJvcHRpb25IYW5kbGUiLCJldmFsdWF0ZUhhbmRsZSIsImNsaWNrIiwiZ2V0VHJhbnNhY3Rpb25zRnJhbWUiLCJhdHRlbXB0Iiwic2xlZXAiLCJmcmFtZXMiLCJ0YXJnZXRGcmFtZSIsImZpbmQiLCJmIiwibmFtZSIsInNlbGVjdEFjY291bnRCb3RoVUlzIiwiYWNjb3VudElkIiwiYWNjb3VudFNlbGVjdGVkIiwic2VsZWN0IiwiZmV0Y2hBY2NvdW50RGF0YUJvdGhVSXMiLCJmcmFtZSIsInRhcmdldFBhZ2UiLCJmZXRjaEFjY291bnRzIiwiYWNjb3VudERhdGEiLCJhY2NvdW50cyIsIkJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiQkFTRV9VUkwiLCJMT0dJTl9VUkwiLCJUUkFOU0FDVElPTlNfVVJMIiwiZ2V0TG9naW5PcHRpb25zIiwibG9naW5VcmwiLCJmaWVsZHMiLCJzdWJtaXRCdXR0b25TZWxlY3RvciIsInBvc3RBY3Rpb24iLCJwb3NzaWJsZVJlc3VsdHMiLCJwcmVBY3Rpb24iLCJmZXRjaERhdGEiLCJkZWZhdWx0U3RhcnRNb21lbnQiLCJzdWJ0cmFjdCIsImFkZCIsInN0YXJ0TW9tZW50TGltaXQiLCJ5ZWFyIiwidG9EYXRlIiwic3RhcnRNb21lbnQiLCJtYXgiLCJuYXZpZ2F0ZVRvIiwic3VjY2VzcyIsIl9kZWZhdWx0IiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLWJlaW5sZXVtaS1ncm91cC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbW9tZW50LCB7IHR5cGUgTW9tZW50IH0gZnJvbSAnbW9tZW50JztcbmltcG9ydCB7IHR5cGUgRnJhbWUsIHR5cGUgUGFnZSB9IGZyb20gJ3B1cHBldGVlci1jb3JlJztcbmltcG9ydCB7IFNIRUtFTF9DVVJSRU5DWSwgU0hFS0VMX0NVUlJFTkNZX1NZTUJPTCB9IGZyb20gJy4uL2NvbnN0YW50cyc7XG5pbXBvcnQge1xuICBjbGlja0J1dHRvbixcbiAgZWxlbWVudFByZXNlbnRPblBhZ2UsXG4gIGZpbGxJbnB1dCxcbiAgcGFnZUV2YWxBbGwsXG4gIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCxcbn0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgd2FpdEZvck5hdmlnYXRpb24gfSBmcm9tICcuLi9oZWxwZXJzL25hdmlnYXRpb24nO1xuaW1wb3J0IHsgc2xlZXAgfSBmcm9tICcuLi9oZWxwZXJzL3dhaXRpbmcnO1xuaW1wb3J0IHsgVHJhbnNhY3Rpb25TdGF0dXNlcywgVHJhbnNhY3Rpb25UeXBlcywgdHlwZSBUcmFuc2FjdGlvbiwgdHlwZSBUcmFuc2FjdGlvbnNBY2NvdW50IH0gZnJvbSAnLi4vdHJhbnNhY3Rpb25zJztcbmltcG9ydCB7IEJhc2VTY3JhcGVyV2l0aEJyb3dzZXIsIExvZ2luUmVzdWx0cywgdHlwZSBQb3NzaWJsZUxvZ2luUmVzdWx0cyB9IGZyb20gJy4vYmFzZS1zY3JhcGVyLXdpdGgtYnJvd3Nlcic7XG5cbmNvbnN0IERBVEVfRk9STUFUID0gJ0REL01NL1lZWVknO1xuY29uc3QgTk9fVFJBTlNBQ1RJT05fSU5fREFURV9SQU5HRV9URVhUID0gJ9ec15Ag16DXntem15DXlSDXoNeq15XXoNeZ150g15HXoNeV16nXkCDXlNee15HXlden16knO1xuY29uc3QgREFURV9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEID0gJ2RhdGUgZmlyc3QnO1xuY29uc3QgREFURV9DT0xVTU5fQ0xBU1NfUEVORElORyA9ICdmaXJzdCBkYXRlJztcbmNvbnN0IERFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19DT01QTEVURUQgPSAncmVmZXJlbmNlIHdyYXBfbm9ybWFsJztcbmNvbnN0IERFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19QRU5ESU5HID0gJ2RldGFpbHMgd3JhcF9ub3JtYWwnO1xuY29uc3QgUkVGRVJFTkNFX0NPTFVNTl9DTEFTUyA9ICdkZXRhaWxzJztcbmNvbnN0IERFQklUX0NPTFVNTl9DTEFTUyA9ICdkZWJpdCc7XG5jb25zdCBDUkVESVRfQ09MVU1OX0NMQVNTID0gJ2NyZWRpdCc7XG5jb25zdCBFUlJPUl9NRVNTQUdFX0NMQVNTID0gJ05PX0RBVEEnO1xuY29uc3QgQUNDT1VOVFNfTlVNQkVSID0gJ2Rpdi5maWJpX2FjY291bnQgc3Bhbi5hY2NfbnVtJztcbmNvbnN0IENMT1NFX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fQ0xBU1MgPSAndWktZGF0ZXBpY2tlci1jbG9zZSc7XG5jb25zdCBTSE9XX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fVkFMVUUgPSAn15TXpteSJztcbmNvbnN0IENPTVBMRVRFRF9UUkFOU0FDVElPTlNfVEFCTEUgPSAndGFibGUjZGF0YVRhYmxlMDc3JztcbmNvbnN0IFBFTkRJTkdfVFJBTlNBQ1RJT05TX1RBQkxFID0gJ3RhYmxlI2RhdGFUYWJsZTAyMyc7XG5jb25zdCBORVhUX1BBR0VfTElOSyA9ICdhI05wYWdlLnBhZ2luZyc7XG5jb25zdCBDVVJSRU5UX0JBTEFOQ0UgPSAnLm1haW5fYmFsYW5jZSc7XG5jb25zdCBJRlJBTUVfTkFNRSA9ICdpZnJhbWUtb2xkLXBhZ2VzJztcbmNvbnN0IEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMgPSAxMDAwMDtcblxudHlwZSBUcmFuc2FjdGlvbnNDb2xzVHlwZXMgPSBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xudHlwZSBUcmFuc2FjdGlvbnNUclRkcyA9IHN0cmluZ1tdO1xudHlwZSBUcmFuc2FjdGlvbnNUciA9IHsgaW5uZXJUZHM6IFRyYW5zYWN0aW9uc1RyVGRzIH07XG5cbmludGVyZmFjZSBTY3JhcGVkVHJhbnNhY3Rpb24ge1xuICByZWZlcmVuY2U6IHN0cmluZztcbiAgZGF0ZTogc3RyaW5nO1xuICBjcmVkaXQ6IHN0cmluZztcbiAgZGViaXQ6IHN0cmluZztcbiAgbWVtbz86IHN0cmluZztcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgc3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9zc2libGVMb2dpblJlc3VsdHMoKTogUG9zc2libGVMb2dpblJlc3VsdHMge1xuICBjb25zdCB1cmxzOiBQb3NzaWJsZUxvZ2luUmVzdWx0cyA9IHt9O1xuICB1cmxzW0xvZ2luUmVzdWx0cy5TdWNjZXNzXSA9IFtcbiAgICAvZmliaS4qYWNjb3VudFN1bW1hcnkvLCAvLyBOZXcgVUkgcGF0dGVyblxuICAgIC9SZXNvdXJjZXNcXC9Qb3J0YWxOR1xcL3NoZWxsLywgLy8gTmV3IFVJIHBhdHRlcm5cbiAgICAvRmliaU1lbnVcXC9PbmxpbmUvLCAvLyBPbGQgVUkgcGF0dGVyblxuICBdO1xuICB1cmxzW0xvZ2luUmVzdWx0cy5JbnZhbGlkUGFzc3dvcmRdID0gWy9GaWJpTWVudVxcL01hcmtldGluZ1xcL1ByaXZhdGVcXC9Ib21lL107XG4gIHJldHVybiB1cmxzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gIHJldHVybiBbXG4gICAgeyBzZWxlY3RvcjogJyN1c2VybmFtZScsIHZhbHVlOiBjcmVkZW50aWFscy51c2VybmFtZSB9LFxuICAgIHsgc2VsZWN0b3I6ICcjcGFzc3dvcmQnLCB2YWx1ZTogY3JlZGVudGlhbHMucGFzc3dvcmQgfSxcbiAgXTtcbn1cblxuZnVuY3Rpb24gZ2V0QW1vdW50RGF0YShhbW91bnRTdHI6IHN0cmluZykge1xuICBsZXQgYW1vdW50U3RyQ29weSA9IGFtb3VudFN0ci5yZXBsYWNlKFNIRUtFTF9DVVJSRU5DWV9TWU1CT0wsICcnKTtcbiAgYW1vdW50U3RyQ29weSA9IGFtb3VudFN0ckNvcHkucmVwbGFjZUFsbCgnLCcsICcnKTtcbiAgcmV0dXJuIHBhcnNlRmxvYXQoYW1vdW50U3RyQ29weSk7XG59XG5cbmZ1bmN0aW9uIGdldFR4bkFtb3VudCh0eG46IFNjcmFwZWRUcmFuc2FjdGlvbikge1xuICBjb25zdCBjcmVkaXQgPSBnZXRBbW91bnREYXRhKHR4bi5jcmVkaXQpO1xuICBjb25zdCBkZWJpdCA9IGdldEFtb3VudERhdGEodHhuLmRlYml0KTtcbiAgcmV0dXJuIChOdW1iZXIuaXNOYU4oY3JlZGl0KSA/IDAgOiBjcmVkaXQpIC0gKE51bWJlci5pc05hTihkZWJpdCkgPyAwIDogZGViaXQpO1xufVxuXG5mdW5jdGlvbiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnM6IFNjcmFwZWRUcmFuc2FjdGlvbltdKTogVHJhbnNhY3Rpb25bXSB7XG4gIHJldHVybiB0eG5zLm1hcCgodHhuKTogVHJhbnNhY3Rpb24gPT4ge1xuICAgIGNvbnN0IGNvbnZlcnRlZERhdGUgPSBtb21lbnQodHhuLmRhdGUsIERBVEVfRk9STUFUKS50b0lTT1N0cmluZygpO1xuICAgIGNvbnN0IGNvbnZlcnRlZEFtb3VudCA9IGdldFR4bkFtb3VudCh0eG4pO1xuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiBUcmFuc2FjdGlvblR5cGVzLk5vcm1hbCxcbiAgICAgIGlkZW50aWZpZXI6IHR4bi5yZWZlcmVuY2UgPyBwYXJzZUludCh0eG4ucmVmZXJlbmNlLCAxMCkgOiB1bmRlZmluZWQsXG4gICAgICBkYXRlOiBjb252ZXJ0ZWREYXRlLFxuICAgICAgcHJvY2Vzc2VkRGF0ZTogY29udmVydGVkRGF0ZSxcbiAgICAgIG9yaWdpbmFsQW1vdW50OiBjb252ZXJ0ZWRBbW91bnQsXG4gICAgICBvcmlnaW5hbEN1cnJlbmN5OiBTSEVLRUxfQ1VSUkVOQ1ksXG4gICAgICBjaGFyZ2VkQW1vdW50OiBjb252ZXJ0ZWRBbW91bnQsXG4gICAgICBzdGF0dXM6IHR4bi5zdGF0dXMsXG4gICAgICBkZXNjcmlwdGlvbjogdHhuLmRlc2NyaXB0aW9uLFxuICAgICAgbWVtbzogdHhuLm1lbW8sXG4gICAgfTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uRGF0ZShcbiAgdGRzOiBUcmFuc2FjdGlvbnNUclRkcyxcbiAgdHJhbnNhY3Rpb25UeXBlOiBzdHJpbmcsXG4gIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzLFxuKSB7XG4gIGlmICh0cmFuc2FjdGlvblR5cGUgPT09ICdjb21wbGV0ZWQnKSB7XG4gICAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0RBVEVfQ09MVU1OX0NMQVNTX0NPTVBMRVRFRF1dIHx8ICcnKS50cmltKCk7XG4gIH1cbiAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0RBVEVfQ09MVU1OX0NMQVNTX1BFTkRJTkddXSB8fCAnJykudHJpbSgpO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc2FjdGlvbkRlc2NyaXB0aW9uKFxuICB0ZHM6IFRyYW5zYWN0aW9uc1RyVGRzLFxuICB0cmFuc2FjdGlvblR5cGU6IHN0cmluZyxcbiAgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMsXG4pIHtcbiAgaWYgKHRyYW5zYWN0aW9uVHlwZSA9PT0gJ2NvbXBsZXRlZCcpIHtcbiAgICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbREVTQ1JJUFRJT05fQ09MVU1OX0NMQVNTX0NPTVBMRVRFRF1dIHx8ICcnKS50cmltKCk7XG4gIH1cbiAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0RFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19QRU5ESU5HXV0gfHwgJycpLnRyaW0oKTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25SZWZlcmVuY2UodGRzOiBUcmFuc2FjdGlvbnNUclRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMpIHtcbiAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW1JFRkVSRU5DRV9DT0xVTU5fQ0xBU1NdXSB8fCAnJykudHJpbSgpO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc2FjdGlvbkRlYml0KHRkczogVHJhbnNhY3Rpb25zVHJUZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzKSB7XG4gIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tERUJJVF9DT0xVTU5fQ0xBU1NdXSB8fCAnJykudHJpbSgpO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc2FjdGlvbkNyZWRpdCh0ZHM6IFRyYW5zYWN0aW9uc1RyVGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcykge1xuICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbQ1JFRElUX0NPTFVNTl9DTEFTU11dIHx8ICcnKS50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbkRldGFpbHMoXG4gIHR4blJvdzogVHJhbnNhY3Rpb25zVHIsXG4gIHRyYW5zYWN0aW9uU3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzLFxuICB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcyxcbik6IFNjcmFwZWRUcmFuc2FjdGlvbiB7XG4gIGNvbnN0IHRkcyA9IHR4blJvdy5pbm5lclRkcztcbiAgY29uc3QgaXRlbSA9IHtcbiAgICBzdGF0dXM6IHRyYW5zYWN0aW9uU3RhdHVzLFxuICAgIGRhdGU6IGdldFRyYW5zYWN0aW9uRGF0ZSh0ZHMsIHRyYW5zYWN0aW9uU3RhdHVzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpLFxuICAgIGRlc2NyaXB0aW9uOiBnZXRUcmFuc2FjdGlvbkRlc2NyaXB0aW9uKHRkcywgdHJhbnNhY3Rpb25TdGF0dXMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyksXG4gICAgcmVmZXJlbmNlOiBnZXRUcmFuc2FjdGlvblJlZmVyZW5jZSh0ZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyksXG4gICAgZGViaXQ6IGdldFRyYW5zYWN0aW9uRGViaXQodGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpLFxuICAgIGNyZWRpdDogZ2V0VHJhbnNhY3Rpb25DcmVkaXQodGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpLFxuICB9O1xuXG4gIHJldHVybiBpdGVtO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRUcmFuc2FjdGlvbnNDb2xzVHlwZUNsYXNzZXMoXG4gIHBhZ2U6IFBhZ2UgfCBGcmFtZSxcbiAgdGFibGVMb2NhdG9yOiBzdHJpbmcsXG4pOiBQcm9taXNlPFRyYW5zYWN0aW9uc0NvbHNUeXBlcz4ge1xuICBjb25zdCByZXN1bHQ6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcyA9IHt9O1xuICBjb25zdCB0eXBlQ2xhc3Nlc09ianMgPSBhd2FpdCBwYWdlRXZhbEFsbChwYWdlLCBgJHt0YWJsZUxvY2F0b3J9IHRib2R5IHRyOmZpcnN0LW9mLXR5cGUgdGRgLCBudWxsLCB0ZHMgPT4ge1xuICAgIHJldHVybiB0ZHMubWFwKCh0ZCwgaW5kZXgpID0+ICh7XG4gICAgICBjb2xDbGFzczogdGQuZ2V0QXR0cmlidXRlKCdjbGFzcycpLFxuICAgICAgaW5kZXgsXG4gICAgfSkpO1xuICB9KTtcblxuICBmb3IgKGNvbnN0IHR5cGVDbGFzc09iaiBvZiB0eXBlQ2xhc3Nlc09ianMpIHtcbiAgICBpZiAodHlwZUNsYXNzT2JqLmNvbENsYXNzKSB7XG4gICAgICByZXN1bHRbdHlwZUNsYXNzT2JqLmNvbENsYXNzXSA9IHR5cGVDbGFzc09iai5pbmRleDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gZXh0cmFjdFRyYW5zYWN0aW9uKFxuICB0eG5zOiBTY3JhcGVkVHJhbnNhY3Rpb25bXSxcbiAgdHJhbnNhY3Rpb25TdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMsXG4gIHR4blJvdzogVHJhbnNhY3Rpb25zVHIsXG4gIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzLFxuKSB7XG4gIGNvbnN0IHR4biA9IGV4dHJhY3RUcmFuc2FjdGlvbkRldGFpbHModHhuUm93LCB0cmFuc2FjdGlvblN0YXR1cywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKTtcbiAgaWYgKHR4bi5kYXRlICE9PSAnJykge1xuICAgIHR4bnMucHVzaCh0eG4pO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbnMocGFnZTogUGFnZSB8IEZyYW1lLCB0YWJsZUxvY2F0b3I6IHN0cmluZywgdHJhbnNhY3Rpb25TdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMpIHtcbiAgY29uc3QgdHhuczogU2NyYXBlZFRyYW5zYWN0aW9uW10gPSBbXTtcbiAgY29uc3QgdHJhbnNhY3Rpb25zQ29sc1R5cGVzID0gYXdhaXQgZ2V0VHJhbnNhY3Rpb25zQ29sc1R5cGVDbGFzc2VzKHBhZ2UsIHRhYmxlTG9jYXRvcik7XG5cbiAgY29uc3QgdHJhbnNhY3Rpb25zUm93cyA9IGF3YWl0IHBhZ2VFdmFsQWxsPFRyYW5zYWN0aW9uc1RyW10+KHBhZ2UsIGAke3RhYmxlTG9jYXRvcn0gdGJvZHkgdHJgLCBbXSwgdHJzID0+IHtcbiAgICByZXR1cm4gdHJzLm1hcCh0ciA9PiAoe1xuICAgICAgaW5uZXJUZHM6IEFycmF5LmZyb20odHIuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3RkJykpLm1hcCh0ZCA9PiB0ZC5pbm5lclRleHQpLFxuICAgIH0pKTtcbiAgfSk7XG5cbiAgZm9yIChjb25zdCB0eG5Sb3cgb2YgdHJhbnNhY3Rpb25zUm93cykge1xuICAgIGV4dHJhY3RUcmFuc2FjdGlvbih0eG5zLCB0cmFuc2FjdGlvblN0YXR1cywgdHhuUm93LCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpO1xuICB9XG4gIHJldHVybiB0eG5zO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpc05vVHJhbnNhY3Rpb25JbkRhdGVSYW5nZUVycm9yKHBhZ2U6IFBhZ2UgfCBGcmFtZSkge1xuICBjb25zdCBoYXNFcnJvckluZm9FbGVtZW50ID0gYXdhaXQgZWxlbWVudFByZXNlbnRPblBhZ2UocGFnZSwgYC4ke0VSUk9SX01FU1NBR0VfQ0xBU1N9YCk7XG4gIGlmIChoYXNFcnJvckluZm9FbGVtZW50KSB7XG4gICAgY29uc3QgZXJyb3JUZXh0ID0gYXdhaXQgcGFnZS4kZXZhbChgLiR7RVJST1JfTUVTU0FHRV9DTEFTU31gLCBlcnJvckVsZW1lbnQgPT4ge1xuICAgICAgcmV0dXJuIChlcnJvckVsZW1lbnQgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dDtcbiAgICB9KTtcbiAgICByZXR1cm4gZXJyb3JUZXh0LnRyaW0oKSA9PT0gTk9fVFJBTlNBQ1RJT05fSU5fREFURV9SQU5HRV9URVhUO1xuICB9XG4gIHJldHVybiBmYWxzZTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gc2VhcmNoQnlEYXRlcyhwYWdlOiBQYWdlIHwgRnJhbWUsIHN0YXJ0RGF0ZTogTW9tZW50KSB7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsICdhI3RhYkhlYWRlcjQnKTtcbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICdkaXYjZmliaV9kYXRlcycpO1xuICBhd2FpdCBmaWxsSW5wdXQocGFnZSwgJ2lucHV0I2Zyb21EYXRlJywgc3RhcnREYXRlLmZvcm1hdChEQVRFX0ZPUk1BVCkpO1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCBgYnV0dG9uW2NsYXNzKj0ke0NMT1NFX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fQ0xBU1N9XWApO1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCBgaW5wdXRbdmFsdWU9JHtTSE9XX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fVkFMVUV9XWApO1xuICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbihwYWdlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QWNjb3VudE51bWJlcihwYWdlOiBQYWdlIHwgRnJhbWUpOiBQcm9taXNlPHN0cmluZz4ge1xuICAvLyBXYWl0IHVudGlsIHRoZSBhY2NvdW50IG51bWJlciBlbGVtZW50IGlzIHByZXNlbnQgaW4gdGhlIERPTVxuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgQUNDT1VOVFNfTlVNQkVSLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcblxuICBjb25zdCBzZWxlY3RlZFNuaWZBY2NvdW50ID0gYXdhaXQgcGFnZS4kZXZhbChBQ0NPVU5UU19OVU1CRVIsIG9wdGlvbiA9PiB7XG4gICAgcmV0dXJuIChvcHRpb24gYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dDtcbiAgfSk7XG5cbiAgcmV0dXJuIHNlbGVjdGVkU25pZkFjY291bnQucmVwbGFjZSgnLycsICdfJykudHJpbSgpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBjaGVja0lmSGFzTmV4dFBhZ2UocGFnZTogUGFnZSB8IEZyYW1lKSB7XG4gIHJldHVybiBlbGVtZW50UHJlc2VudE9uUGFnZShwYWdlLCBORVhUX1BBR0VfTElOSyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG5hdmlnYXRlVG9OZXh0UGFnZShwYWdlOiBQYWdlIHwgRnJhbWUpIHtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgTkVYVF9QQUdFX0xJTkspO1xuICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbihwYWdlKTtcbn1cblxuLyogQ291bGRuJ3QgcmVwcm9kdWNlIHNjZW5hcmlvIHdpdGggbXVsdGlwbGUgcGFnZXMgb2YgcGVuZGluZyB0cmFuc2FjdGlvbnMgLSBTaG91bGQgc3VwcG9ydCBpZiBleGlzdHMgc3VjaCBjYXNlLlxuICAgbmVlZFRvUGFnaW5hdGUgaXMgZmFsc2UgaWYgc2NyYXBpbmcgcGVuZGluZyB0cmFuc2FjdGlvbnMgKi9cbmFzeW5jIGZ1bmN0aW9uIHNjcmFwZVRyYW5zYWN0aW9ucyhcbiAgcGFnZTogUGFnZSB8IEZyYW1lLFxuICB0YWJsZUxvY2F0b3I6IHN0cmluZyxcbiAgdHJhbnNhY3Rpb25TdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMsXG4gIG5lZWRUb1BhZ2luYXRlOiBib29sZWFuLFxuKSB7XG4gIGNvbnN0IHR4bnMgPSBbXTtcbiAgbGV0IGhhc05leHRQYWdlID0gZmFsc2U7XG5cbiAgZG8ge1xuICAgIGNvbnN0IGN1cnJlbnRQYWdlVHhucyA9IGF3YWl0IGV4dHJhY3RUcmFuc2FjdGlvbnMocGFnZSwgdGFibGVMb2NhdG9yLCB0cmFuc2FjdGlvblN0YXR1cyk7XG4gICAgdHhucy5wdXNoKC4uLmN1cnJlbnRQYWdlVHhucyk7XG4gICAgaWYgKG5lZWRUb1BhZ2luYXRlKSB7XG4gICAgICBoYXNOZXh0UGFnZSA9IGF3YWl0IGNoZWNrSWZIYXNOZXh0UGFnZShwYWdlKTtcbiAgICAgIGlmIChoYXNOZXh0UGFnZSkge1xuICAgICAgICBhd2FpdCBuYXZpZ2F0ZVRvTmV4dFBhZ2UocGFnZSk7XG4gICAgICB9XG4gICAgfVxuICB9IHdoaWxlIChoYXNOZXh0UGFnZSk7XG5cbiAgcmV0dXJuIGNvbnZlcnRUcmFuc2FjdGlvbnModHhucyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEFjY291bnRUcmFuc2FjdGlvbnMocGFnZTogUGFnZSB8IEZyYW1lKSB7XG4gIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIFwiZGl2W2lkKj0nZGl2VGFibGUnXVwiLCBmYWxzZSksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGAuJHtFUlJPUl9NRVNTQUdFX0NMQVNTfWAsIGZhbHNlKSxcbiAgXSk7XG5cbiAgY29uc3Qgbm9UcmFuc2FjdGlvbkluUmFuZ2VFcnJvciA9IGF3YWl0IGlzTm9UcmFuc2FjdGlvbkluRGF0ZVJhbmdlRXJyb3IocGFnZSk7XG4gIGlmIChub1RyYW5zYWN0aW9uSW5SYW5nZUVycm9yKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcGVuZGluZ1R4bnMgPSBhd2FpdCBzY3JhcGVUcmFuc2FjdGlvbnMocGFnZSwgUEVORElOR19UUkFOU0FDVElPTlNfVEFCTEUsIFRyYW5zYWN0aW9uU3RhdHVzZXMuUGVuZGluZywgZmFsc2UpO1xuICBjb25zdCBjb21wbGV0ZWRUeG5zID0gYXdhaXQgc2NyYXBlVHJhbnNhY3Rpb25zKFxuICAgIHBhZ2UsXG4gICAgQ09NUExFVEVEX1RSQU5TQUNUSU9OU19UQUJMRSxcbiAgICBUcmFuc2FjdGlvblN0YXR1c2VzLkNvbXBsZXRlZCxcbiAgICB0cnVlLFxuICApO1xuICBjb25zdCB0eG5zID0gWy4uLnBlbmRpbmdUeG5zLCAuLi5jb21wbGV0ZWRUeG5zXTtcbiAgcmV0dXJuIHR4bnM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEN1cnJlbnRCYWxhbmNlKHBhZ2U6IFBhZ2UgfCBGcmFtZSk6IFByb21pc2U8bnVtYmVyPiB7XG4gIC8vIFdhaXQgZm9yIHRoZSBiYWxhbmNlIGVsZW1lbnQgdG8gYXBwZWFyIGFuZCBiZSB2aXNpYmxlXG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBDVVJSRU5UX0JBTEFOQ0UsIHRydWUsIEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMpO1xuXG4gIC8vIEV4dHJhY3QgdGV4dCBjb250ZW50XG4gIGNvbnN0IGJhbGFuY2VTdHIgPSBhd2FpdCBwYWdlLiRldmFsKENVUlJFTlRfQkFMQU5DRSwgZWwgPT4ge1xuICAgIHJldHVybiAoZWwgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dDtcbiAgfSk7XG5cbiAgcmV0dXJuIGdldEFtb3VudERhdGEoYmFsYW5jZVN0cik7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3YWl0Rm9yUG9zdExvZ2luKHBhZ2U6IFBhZ2UpIHtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICcjY2FyZC1oZWFkZXInLCB0cnVlKSwgLy8gTmV3IFVJXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICcjYWNjb3VudF9udW0nLCB0cnVlKSwgLy8gTmV3IFVJXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICcjbWF0YWZMb2dvdXRMaW5rJywgdHJ1ZSksIC8vIE9sZCBVSVxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI3ZhbGlkYXRpb25Nc2cnLCB0cnVlKSwgLy8gT2xkIFVJXG4gIF0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEFjY291bnREYXRhKHBhZ2U6IFBhZ2UgfCBGcmFtZSwgc3RhcnREYXRlOiBNb21lbnQpIHtcbiAgY29uc3QgYWNjb3VudE51bWJlciA9IGF3YWl0IGdldEFjY291bnROdW1iZXIocGFnZSk7XG4gIGNvbnN0IGJhbGFuY2UgPSBhd2FpdCBnZXRDdXJyZW50QmFsYW5jZShwYWdlKTtcbiAgYXdhaXQgc2VhcmNoQnlEYXRlcyhwYWdlLCBzdGFydERhdGUpO1xuICBjb25zdCB0eG5zID0gYXdhaXQgZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyhwYWdlKTtcblxuICByZXR1cm4ge1xuICAgIGFjY291bnROdW1iZXIsXG4gICAgdHhucyxcbiAgICBiYWxhbmNlLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBY2NvdW50SWRzT2xkVUkocGFnZTogUGFnZSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgcmV0dXJuIHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgIGNvbnN0IHNlbGVjdEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYWNjb3VudF9udW1fc2VsZWN0Jyk7XG4gICAgY29uc3Qgb3B0aW9ucyA9IHNlbGVjdEVsZW1lbnQgPyBzZWxlY3RFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ29wdGlvbicpIDogW107XG4gICAgaWYgKCFvcHRpb25zKSByZXR1cm4gW107XG4gICAgcmV0dXJuIEFycmF5LmZyb20ob3B0aW9ucywgb3B0aW9uID0+IG9wdGlvbi52YWx1ZSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIEVuc3VyZXMgdGhlIGFjY291bnQgZHJvcGRvd24gaXMgb3BlbiwgdGhlbiByZXR1cm5zIHRoZSBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKlxuICogVGhpcyBtZXRob2Q6XG4gKiAtIENoZWNrcyBpZiB0aGUgZHJvcGRvd24gaXMgYWxyZWFkeSBvcGVuLlxuICogLSBJZiBub3Qgb3BlbiwgY2xpY2tzIHRoZSBhY2NvdW50IHNlbGVjdG9yIHRvIG9wZW4gaXQuXG4gKiAtIFdhaXRzIGZvciB0aGUgZHJvcGRvd24gdG8gcmVuZGVyLlxuICogLSBFeHRyYWN0cyBhbmQgcmV0dXJucyB0aGUgbGlzdCBvZiBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKlxuICogR3JhY2VmdWwgaGFuZGxpbmc6XG4gKiAtIElmIGFueSBlcnJvciBvY2N1cnMgKGUuZy4sIHNlbGVjdG9ycyBub3QgZm91bmQsIHRpbWluZyBpc3N1ZXMsIFVJIHZlcnNpb24gY2hhbmdlcyksXG4gKiAgIHRoZSBmdW5jdGlvbiByZXR1cm5zIGFuIGVtcHR5IGxpc3QuXG4gKlxuICogQHBhcmFtIHBhZ2UgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0LlxuICogQHJldHVybnMgQW4gYXJyYXkgb2YgYXZhaWxhYmxlIGFjY291bnQgbGFiZWxzIChlLmcuLCBbXCIxMjcgfCBYWFhYMVwiLCBcIjEyNyB8IFhYWFgyXCJdKSxcbiAqICAgICAgICAgIG9yIGFuIGVtcHR5IGFycmF5IGlmIHNvbWV0aGluZyBnb2VzIHdyb25nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xpY2tBY2NvdW50U2VsZWN0b3JHZXRBY2NvdW50SWRzKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgYWNjb3VudFNlbGVjdG9yID0gJ2Rpdi5jdXJyZW50LWFjY291bnQnOyAvLyBEaXJlY3Qgc2VsZWN0b3IgdG8gY2xpY2thYmxlIGVsZW1lbnRcbiAgICBjb25zdCBkcm9wZG93blBhbmVsU2VsZWN0b3IgPSAnZGl2Lm1hdC1tZGMtYXV0b2NvbXBsZXRlLXBhbmVsLmFjY291bnQtc2VsZWN0LWRkJzsgLy8gVGhlIGRyb3Bkb3duIGxpc3QgYm94XG4gICAgY29uc3Qgb3B0aW9uU2VsZWN0b3IgPSAnbWF0LW9wdGlvbiAubWRjLWxpc3QtaXRlbV9fcHJpbWFyeS10ZXh0JzsgLy8gQWNjb3VudCBvcHRpb24gbGFiZWxzXG5cbiAgICAvLyBDaGVjayBpZiBkcm9wZG93biBpcyBhbHJlYWR5IG9wZW5cbiAgICBjb25zdCBkcm9wZG93blZpc2libGUgPSBhd2FpdCBwYWdlXG4gICAgICAuJGV2YWwoZHJvcGRvd25QYW5lbFNlbGVjdG9yLCBlbCA9PiB7XG4gICAgICAgIHJldHVybiBlbCAmJiB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbCkuZGlzcGxheSAhPT0gJ25vbmUnICYmIGVsLm9mZnNldFBhcmVudCAhPT0gbnVsbDtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKCkgPT4gZmFsc2UpOyAvLyBjYXRjaCBpZiBkcm9wZG93biBpcyBub3QgaW4gdGhlIERPTSB5ZXRcblxuICAgIGlmICghZHJvcGRvd25WaXNpYmxlKSB7XG4gICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgYWNjb3VudFNlbGVjdG9yLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcblxuICAgICAgLy8gQ2xpY2sgdGhlIGFjY291bnQgc2VsZWN0b3IgdG8gb3BlbiB0aGUgZHJvcGRvd25cbiAgICAgIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGFjY291bnRTZWxlY3Rvcik7XG5cbiAgICAgIC8vIFdhaXQgZm9yIHRoZSBkcm9wZG93biB0byBvcGVuXG4gICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgZHJvcGRvd25QYW5lbFNlbGVjdG9yLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcbiAgICB9XG5cbiAgICAvLyBFeHRyYWN0IGFjY291bnQgbGFiZWxzIGZyb20gdGhlIGRyb3Bkb3duIG9wdGlvbnNcbiAgICBjb25zdCBhY2NvdW50TGFiZWxzID0gYXdhaXQgcGFnZS4kJGV2YWwob3B0aW9uU2VsZWN0b3IsIG9wdGlvbnMgPT4ge1xuICAgICAgcmV0dXJuIG9wdGlvbnMubWFwKG9wdGlvbiA9PiBvcHRpb24udGV4dENvbnRlbnQ/LnRyaW0oKSB8fCAnJykuZmlsdGVyKGxhYmVsID0+IGxhYmVsICE9PSAnJyk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gYWNjb3VudExhYmVscztcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gW107IC8vIEdyYWNlZnVsIGZhbGxiYWNrXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QWNjb3VudElkc0JvdGhVSXMocGFnZTogUGFnZSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgbGV0IGFjY291bnRzSWRzOiBzdHJpbmdbXSA9IGF3YWl0IGNsaWNrQWNjb3VudFNlbGVjdG9yR2V0QWNjb3VudElkcyhwYWdlKTtcbiAgaWYgKGFjY291bnRzSWRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGFjY291bnRzSWRzID0gYXdhaXQgZ2V0QWNjb3VudElkc09sZFVJKHBhZ2UpO1xuICB9XG4gIHJldHVybiBhY2NvdW50c0lkcztcbn1cblxuLyoqXG4gKiBTZWxlY3RzIGFuIGFjY291bnQgZnJvbSB0aGUgZHJvcGRvd24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGFjY291bnQgbGFiZWwuXG4gKlxuICogVGhpcyBtZXRob2Q6XG4gKiAtIENsaWNrcyB0aGUgYWNjb3VudCBzZWxlY3RvciBidXR0b24gdG8gb3BlbiB0aGUgZHJvcGRvd24uXG4gKiAtIFJldHJpZXZlcyB0aGUgbGlzdCBvZiBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKiAtIENoZWNrcyBpZiB0aGUgcHJvdmlkZWQgYWNjb3VudCBsYWJlbCBleGlzdHMgaW4gdGhlIGxpc3QuXG4gKiAtIEZpbmRzIGFuZCBjbGlja3MgdGhlIG1hdGNoaW5nIGFjY291bnQgb3B0aW9uIGlmIGZvdW5kLlxuICpcbiAqIEBwYXJhbSBwYWdlIFB1cHBldGVlciBQYWdlIG9iamVjdC5cbiAqIEBwYXJhbSBhY2NvdW50TGFiZWwgVGhlIHRleHQgb2YgdGhlIGFjY291bnQgdG8gc2VsZWN0IChlLmcuLCBcIjEyNyB8IFhYWFhYXCIpLlxuICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgYWNjb3VudCBvcHRpb24gd2FzIGZvdW5kIGFuZCBjbGlja2VkOyBmYWxzZSBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWxlY3RBY2NvdW50RnJvbURyb3Bkb3duKHBhZ2U6IFBhZ2UsIGFjY291bnRMYWJlbDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIC8vIENhbGwgY2xpY2tBY2NvdW50U2VsZWN0b3IgdG8gZ2V0IHRoZSBhdmFpbGFibGUgYWNjb3VudHMgYW5kIG9wZW4gdGhlIGRyb3Bkb3duXG4gIGNvbnN0IGF2YWlsYWJsZUFjY291bnRzID0gYXdhaXQgY2xpY2tBY2NvdW50U2VsZWN0b3JHZXRBY2NvdW50SWRzKHBhZ2UpO1xuXG4gIC8vIENoZWNrIGlmIHRoZSBhY2NvdW50IGxhYmVsIGV4aXN0cyBpbiB0aGUgYXZhaWxhYmxlIGFjY291bnRzXG4gIGlmICghYXZhaWxhYmxlQWNjb3VudHMuaW5jbHVkZXMoYWNjb3VudExhYmVsKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFdhaXQgZm9yIHRoZSBkcm9wZG93biBvcHRpb25zIHRvIGJlIHJlbmRlcmVkXG4gIGNvbnN0IG9wdGlvblNlbGVjdG9yID0gJ21hdC1vcHRpb24gLm1kYy1saXN0LWl0ZW1fX3ByaW1hcnktdGV4dCc7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBvcHRpb25TZWxlY3RvciwgdHJ1ZSwgRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyk7XG5cbiAgLy8gUXVlcnkgYWxsIG1hdGNoaW5nIG9wdGlvbnNcbiAgY29uc3QgYWNjb3VudE9wdGlvbnMgPSBhd2FpdCBwYWdlLiQkKG9wdGlvblNlbGVjdG9yKTtcblxuICAvLyBGaW5kIGFuZCBjbGljayB0aGUgb3B0aW9uIG1hdGNoaW5nIHRoZSBhY2NvdW50TGFiZWxcbiAgZm9yIChjb25zdCBvcHRpb24gb2YgYWNjb3VudE9wdGlvbnMpIHtcbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgcGFnZS5ldmFsdWF0ZShlbCA9PiBlbC50ZXh0Q29udGVudD8udHJpbSgpLCBvcHRpb24pO1xuXG4gICAgaWYgKHRleHQgPT09IGFjY291bnRMYWJlbCkge1xuICAgICAgY29uc3Qgb3B0aW9uSGFuZGxlID0gYXdhaXQgb3B0aW9uLmV2YWx1YXRlSGFuZGxlKGVsID0+IGVsIGFzIEhUTUxFbGVtZW50KTtcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGVsOiBIVE1MRWxlbWVudCkgPT4gZWwuY2xpY2soKSwgb3B0aW9uSGFuZGxlKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25zRnJhbWUocGFnZTogUGFnZSk6IFByb21pc2U8RnJhbWUgfCBudWxsPiB7XG4gIC8vIFRyeSBhIGZldyB0aW1lcyB0byBmaW5kIHRoZSBpZnJhbWUsIGFzIGl0IG1pZ2h0IG5vdCBiZSBpbW1lZGlhdGVseSBhdmFpbGFibGVcbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IGF0dGVtcHQgPCAzOyBhdHRlbXB0KyspIHtcbiAgICBhd2FpdCBzbGVlcCgyMDAwKTtcbiAgICBjb25zdCBmcmFtZXMgPSBwYWdlLmZyYW1lcygpO1xuICAgIGNvbnN0IHRhcmdldEZyYW1lID0gZnJhbWVzLmZpbmQoZiA9PiBmLm5hbWUoKSA9PT0gSUZSQU1FX05BTUUpO1xuXG4gICAgaWYgKHRhcmdldEZyYW1lKSB7XG4gICAgICByZXR1cm4gdGFyZ2V0RnJhbWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNlbGVjdEFjY291bnRCb3RoVUlzKHBhZ2U6IFBhZ2UsIGFjY291bnRJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGFjY291bnRTZWxlY3RlZCA9IGF3YWl0IHNlbGVjdEFjY291bnRGcm9tRHJvcGRvd24ocGFnZSwgYWNjb3VudElkKTtcbiAgaWYgKCFhY2NvdW50U2VsZWN0ZWQpIHtcbiAgICAvLyBPbGQgVUkgZm9ybWF0XG4gICAgYXdhaXQgcGFnZS5zZWxlY3QoJyNhY2NvdW50X251bV9zZWxlY3QnLCBhY2NvdW50SWQpO1xuICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI2FjY291bnRfbnVtX3NlbGVjdCcsIHRydWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoQWNjb3VudERhdGFCb3RoVUlzKHBhZ2U6IFBhZ2UsIHN0YXJ0RGF0ZTogTW9tZW50KSB7XG4gIC8vIFRyeSB0byBnZXQgdGhlIGlmcmFtZSBmb3IgdGhlIG5ldyBVSVxuICBjb25zdCBmcmFtZSA9IGF3YWl0IGdldFRyYW5zYWN0aW9uc0ZyYW1lKHBhZ2UpO1xuXG4gIC8vIFVzZSB0aGUgZnJhbWUgaWYgYXZhaWxhYmxlIChuZXcgVUkpLCBvdGhlcndpc2UgdXNlIHRoZSBwYWdlIGRpcmVjdGx5IChvbGQgVUkpXG4gIGNvbnN0IHRhcmdldFBhZ2UgPSBmcmFtZSB8fCBwYWdlO1xuICByZXR1cm4gZmV0Y2hBY2NvdW50RGF0YSh0YXJnZXRQYWdlLCBzdGFydERhdGUpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEFjY291bnRzKHBhZ2U6IFBhZ2UsIHN0YXJ0RGF0ZTogTW9tZW50KTogUHJvbWlzZTxUcmFuc2FjdGlvbnNBY2NvdW50W10+IHtcbiAgY29uc3QgYWNjb3VudHNJZHMgPSBhd2FpdCBnZXRBY2NvdW50SWRzQm90aFVJcyhwYWdlKTtcblxuICBpZiAoYWNjb3VudHNJZHMubGVuZ3RoID09PSAwKSB7XG4gICAgLy8gSW4gY2FzZSBhY2NvdW50c0lkcyBjb3VsZCBubyBiZSBwYXJzZWQganVzdCByZXR1cm4gdGhlIHRyYW5zYWN0aW9ucyBvZiB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGFjY291bnRcbiAgICBjb25zdCBhY2NvdW50RGF0YSA9IGF3YWl0IGZldGNoQWNjb3VudERhdGFCb3RoVUlzKHBhZ2UsIHN0YXJ0RGF0ZSk7XG4gICAgcmV0dXJuIFthY2NvdW50RGF0YV07XG4gIH1cblxuICBjb25zdCBhY2NvdW50czogVHJhbnNhY3Rpb25zQWNjb3VudFtdID0gW107XG4gIGZvciAoY29uc3QgYWNjb3VudElkIG9mIGFjY291bnRzSWRzKSB7XG4gICAgYXdhaXQgc2VsZWN0QWNjb3VudEJvdGhVSXMocGFnZSwgYWNjb3VudElkKTtcbiAgICBjb25zdCBhY2NvdW50RGF0YSA9IGF3YWl0IGZldGNoQWNjb3VudERhdGFCb3RoVUlzKHBhZ2UsIHN0YXJ0RGF0ZSk7XG4gICAgYWNjb3VudHMucHVzaChhY2NvdW50RGF0YSk7XG4gIH1cblxuICByZXR1cm4gYWNjb3VudHM7XG59XG5cbnR5cGUgU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMgPSB7IHVzZXJuYW1lOiBzdHJpbmc7IHBhc3N3b3JkOiBzdHJpbmcgfTtcblxuY2xhc3MgQmVpbmxldW1pR3JvdXBCYXNlU2NyYXBlciBleHRlbmRzIEJhc2VTY3JhcGVyV2l0aEJyb3dzZXI8U2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHM+IHtcbiAgQkFTRV9VUkwgPSAnJztcblxuICBMT0dJTl9VUkwgPSAnJztcblxuICBUUkFOU0FDVElPTlNfVVJMID0gJyc7XG5cbiAgZ2V0TG9naW5PcHRpb25zKGNyZWRlbnRpYWxzOiBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscykge1xuICAgIHJldHVybiB7XG4gICAgICBsb2dpblVybDogYCR7dGhpcy5MT0dJTl9VUkx9YCxcbiAgICAgIGZpZWxkczogY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHMpLFxuICAgICAgc3VibWl0QnV0dG9uU2VsZWN0b3I6ICcjY29udGludWVCdG4nLFxuICAgICAgcG9zdEFjdGlvbjogYXN5bmMgKCkgPT4gd2FpdEZvclBvc3RMb2dpbih0aGlzLnBhZ2UpLFxuICAgICAgcG9zc2libGVSZXN1bHRzOiBnZXRQb3NzaWJsZUxvZ2luUmVzdWx0cygpLFxuICAgICAgLy8gSEFDSzogRm9yIHNvbWUgcmVhc29uLCB0aG91Z2ggdGhlIGxvZ2luIGJ1dHRvbiAoI2NvbnRpbnVlQnRuKSBpcyBwcmVzZW50IGFuZCB2aXNpYmxlLCB0aGUgY2xpY2sgYWN0aW9uIGRvZXMgbm90IHBlcmZvcm0uXG4gICAgICAvLyBBZGRpbmcgdGhpcyBkZWxheSBmaXhlcyB0aGUgaXNzdWUuXG4gICAgICBwcmVBY3Rpb246IGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgc2xlZXAoMTAwMCk7XG4gICAgICB9LFxuICAgIH07XG4gIH1cblxuICBhc3luYyBmZXRjaERhdGEoKSB7XG4gICAgY29uc3QgZGVmYXVsdFN0YXJ0TW9tZW50ID0gbW9tZW50KCkuc3VidHJhY3QoMSwgJ3llYXJzJykuYWRkKDEsICdkYXknKTtcbiAgICBjb25zdCBzdGFydE1vbWVudExpbWl0ID0gbW9tZW50KHsgeWVhcjogMTYwMCB9KTtcbiAgICBjb25zdCBzdGFydERhdGUgPSB0aGlzLm9wdGlvbnMuc3RhcnREYXRlIHx8IGRlZmF1bHRTdGFydE1vbWVudC50b0RhdGUoKTtcbiAgICBjb25zdCBzdGFydE1vbWVudCA9IG1vbWVudC5tYXgoc3RhcnRNb21lbnRMaW1pdCwgbW9tZW50KHN0YXJ0RGF0ZSkpO1xuXG4gICAgYXdhaXQgdGhpcy5uYXZpZ2F0ZVRvKHRoaXMuVFJBTlNBQ1RJT05TX1VSTCk7XG5cbiAgICBjb25zdCBhY2NvdW50cyA9IGF3YWl0IGZldGNoQWNjb3VudHModGhpcy5wYWdlLCBzdGFydE1vbWVudCk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgc3VjY2VzczogdHJ1ZSxcbiAgICAgIGFjY291bnRzLFxuICAgIH07XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgQmVpbmxldW1pR3JvdXBCYXNlU2NyYXBlcjtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFBQSxJQUFBQSxPQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFFQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxxQkFBQSxHQUFBRixPQUFBO0FBT0EsSUFBQUcsV0FBQSxHQUFBSCxPQUFBO0FBQ0EsSUFBQUksUUFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssYUFBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sdUJBQUEsR0FBQU4sT0FBQTtBQUE4RyxTQUFBRCx1QkFBQVEsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUU5RyxNQUFNRyxXQUFXLEdBQUcsWUFBWTtBQUNoQyxNQUFNQyxpQ0FBaUMsR0FBRyw4QkFBOEI7QUFDeEUsTUFBTUMsMkJBQTJCLEdBQUcsWUFBWTtBQUNoRCxNQUFNQyx5QkFBeUIsR0FBRyxZQUFZO0FBQzlDLE1BQU1DLGtDQUFrQyxHQUFHLHVCQUF1QjtBQUNsRSxNQUFNQyxnQ0FBZ0MsR0FBRyxxQkFBcUI7QUFDOUQsTUFBTUMsc0JBQXNCLEdBQUcsU0FBUztBQUN4QyxNQUFNQyxrQkFBa0IsR0FBRyxPQUFPO0FBQ2xDLE1BQU1DLG1CQUFtQixHQUFHLFFBQVE7QUFDcEMsTUFBTUMsbUJBQW1CLEdBQUcsU0FBUztBQUNyQyxNQUFNQyxlQUFlLEdBQUcsK0JBQStCO0FBQ3ZELE1BQU1DLGtDQUFrQyxHQUFHLHFCQUFxQjtBQUNoRSxNQUFNQyxpQ0FBaUMsR0FBRyxLQUFLO0FBQy9DLE1BQU1DLDRCQUE0QixHQUFHLG9CQUFvQjtBQUN6RCxNQUFNQywwQkFBMEIsR0FBRyxvQkFBb0I7QUFDdkQsTUFBTUMsY0FBYyxHQUFHLGdCQUFnQjtBQUN2QyxNQUFNQyxlQUFl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QUFDakI7QUFJQSxNQUFNQyx5QkFBeUIsU0FBU0MsOENBQXNCLENBQTZCO0VBQ3pGQyxRQUFRLEdBQUcsRUFBRTtFQUViQyxTQUFTLEdBQUcsRUFBRTtFQUVkQyxnQkFBZ0IsR0FBRyxFQUFFO0VBRXJCQyxlQUFlQSxDQUFDN0ssV0FBdUMsRUFBRTtJQUN2RCxPQUFPO01BQ0w4SyxRQUFRLEVBQUUsR0FBRyxJQUFJLENBQUNILFNBQVMsRUFBRTtNQUM3QkksTUFBTSxFQUFFaEwsaUJBQWlCLENBQUNDLFdBQVcsQ0FBQztNQUN0Q2dMLG9CQUFvQixFQUFFLGNBQWM7TUFDcENDLFVBQVUsRUFBRSxNQUFBQSxDQUFBLEtBQVluRSxnQkFBZ0IsQ0FBQyxJQUFJLENBQUN0RCxJQUFJLENBQUM7TUFDbkQwSCxlQUFlLEVBQUV4TCx1QkFBdUIsQ0FBQyxDQUFDO01BQzFDO01BQ0E7TUFDQXlMLFNBQVMsRUFBRSxNQUFBQSxDQUFBLEtBQVk7UUFDckIsTUFBTSxJQUFBM0IsY0FBSyxFQUFDLElBQUksQ0FBQztNQUNuQjtJQUNGLENBQUM7RUFDSDtFQUVBLE1BQU00QixTQUFTQSxDQUFBLEVBQUc7SUFDaEIsTUFBTUMsa0JBQWtCLEdBQUcsSUFBQS9KLGVBQU0sRUFBQyxDQUFDLENBQUNnSyxRQUFRLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDQyxHQUFHLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQztJQUN0RSxNQUFNQyxnQkFBZ0IsR0FBRyxJQUFBbEssZUFBTSxFQUFDO01BQUVtSyxJQUFJLEVBQUU7SUFBSyxDQUFDLENBQUM7SUFDL0MsTUFBTXRHLFNBQVMsR0FBRyxJQUFJLENBQUNvQyxPQUFPLENBQUNwQyxTQUFTLElBQUlrRyxrQkFBa0IsQ0FBQ0ssTUFBTSxDQUFDLENBQUM7SUFDdkUsTUFBTUMsV0FBVyxHQUFHckssZUFBTSxDQUFDc0ssR0FBRyxDQUFDSixnQkFBZ0IsRUFBRSxJQUFBbEssZUFBTSxFQUFDNkQsU0FBUyxDQUFDLENBQUM7SUFFbkUsTUFBTSxJQUFJLENBQUMwRyxVQUFVLENBQUMsSUFBSSxDQUFDakIsZ0JBQWdCLENBQUM7SUFFNUMsTUFBTUwsUUFBUSxHQUFHLE1BQU1GLGFBQWEsQ0FBQyxJQUFJLENBQUM3RyxJQUFJLEVBQUVtSSxXQUFXLENBQUM7SUFFNUQsT0FBTztNQUNMRyxPQUFPLEVBQUUsSUFBSTtNQUNidkI7SUFDRixDQUFDO0VBQ0g7QUFDRjtBQUFDLElBQUF3QixRQUFBLEdBQUFDLE9BQUEsQ0FBQTFOLE9BQUEsR0FFY2tNLHlCQUF5QiIsImlnbm9yZUxpc3QiOltdfQ==