israeli-bank-scrapers
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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfd2FpdGluZyIsIl90cmFuc2FjdGlvbnMiLCJfYmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsImUiLCJfX2VzTW9kdWxlIiwiZGVmYXVsdCIsIkRBVEVfRk9STUFUIiwiTk9fVFJBTlNBQ1RJT05fSU5fREFURV9SQU5HRV9URVhUIiwiREFURV9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEIiwiREFURV9DT0xVTU5fQ0xBU1NfUEVORElORyIsIkRFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19DT01QTEVURUQiLCJERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfUEVORElORyIsIlJFRkVSRU5DRV9DT0xVTU5fQ0xBU1MiLCJERUJJVF9DT0xVTU5fQ0xBU1MiLCJDUkVESVRfQ09MVU1OX0NMQVNTIiwiRVJST1JfTUVTU0FHRV9DTEFTUyIsIkFDQ09VTlRTX05VTUJFUiIsIkNMT1NFX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fQ0xBU1MiLCJTSE9XX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fVkFMVUUiLCJDT01QTEVURURfVFJBTlNBQ1RJT05TX1RBQkxFIiwiUEVORElOR19UUkFOU0FDVElPTlNfVEFCTEUiLCJORVhUX1BBR0VfTElOSyIsIkNVUlJFTlRfQkFMQU5DRSIsIklGUkFNRV9OQU1FIiwiRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyIsImdldFBvc3NpYmxlTG9naW5SZXN1bHRzIiwidXJscyIsIkxvZ2luUmVzdWx0cyIsIlN1Y2Nlc3MiLCJJbnZhbGlkUGFzc3dvcmQiLCJjcmVhdGVMb2dpbkZpZWxkcyIsImNyZWRlbnRpYWxzIiwic2VsZWN0b3IiLCJ2YWx1ZSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJnZXRBbW91bnREYXRhIiwiYW1vdW50U3RyIiwiYW1vdW50U3RyQ29weSIsInJlcGxhY2UiLCJTSEVLRUxfQ1VSUkVOQ1lfU1lNQk9MIiwicmVwbGFjZUFsbCIsInBhcnNlRmxvYXQiLCJnZXRUeG5BbW91bnQiLCJ0eG4iLCJjcmVkaXQiLCJkZWJpdCIsIk51bWJlciIsImlzTmFOIiwiY29udmVydFRyYW5zYWN0aW9ucyIsInR4bnMiLCJtYXAiLCJjb252ZXJ0ZWREYXRlIiwibW9tZW50IiwiZGF0ZSIsInRvSVNPU3RyaW5nIiwiY29udmVydGVkQW1vdW50IiwidHlwZSIsIlRyYW5zYWN0aW9uVHlwZXMiLCJOb3JtYWwiLCJpZGVudGlmaWVyIiwicmVmZXJlbmNlIiwicGFyc2VJbnQiLCJ1bmRlZmluZWQiLCJwcm9jZXNzZWREYXRlIiwib3JpZ2luYWxBbW91bnQiLCJvcmlnaW5hbEN1cnJlbmN5IiwiU0hFS0VMX0NVUlJFTkNZIiwiY2hhcmdlZEFtb3VudCIsInN0YXR1cyIsImRlc2NyaXB0aW9uIiwibWVtbyIsImdldFRyYW5zYWN0aW9uRGF0ZSIsInRkcyIsInRyYW5zYWN0aW9uVHlwZSIsInRyYW5zYWN0aW9uc0NvbHNUeXBlcyIsInRyaW0iLCJnZXRUcmFuc2FjdGlvbkRlc2NyaXB0aW9uIiwiZ2V0VHJhbnNhY3Rpb25SZWZlcmVuY2UiLCJnZXRUcmFuc2FjdGlvbkRlYml0IiwiZ2V0VHJhbnNhY3Rpb25DcmVkaXQiLCJleHRyYWN0VHJhbnNhY3Rpb25EZXRhaWxzIiwidHhuUm93IiwidHJhbnNhY3Rpb25TdGF0dXMiLCJpbm5lclRkcyIsIml0ZW0iLCJnZXRUcmFuc2FjdGlvbnNDb2xzVHlwZUNsYXNzZXMiLCJwYWdlIiwidGFibGVMb2NhdG9yIiwicmVzdWx0IiwidHlwZUNsYXNzZXNPYmpzIiwicGFnZUV2YWxBbGwiLCJ0ZCIsImluZGV4IiwiY29sQ2xhc3MiLCJnZXRBdHRyaWJ1dGUiLCJ0eXBlQ2xhc3NPYmoiLCJleHRyYWN0VHJhbnNhY3Rpb24iLCJwdXNoIiwiZXh0cmFjdFRyYW5zYWN0aW9ucyIsInRyYW5zYWN0aW9uc1Jvd3MiLCJ0cnMiLCJ0ciIsIkFycmF5IiwiZnJvbSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwiaW5uZXJUZXh0IiwiaXNOb1RyYW5zYWN0aW9uSW5EYXRlUmFuZ2VFcnJvciIsImhhc0Vycm9ySW5mb0VsZW1lbnQiLCJlbGVtZW50UHJlc2VudE9uUGFnZSIsImVycm9yVGV4dCIsIiRldmFsIiwiZXJyb3JFbGVtZW50Iiwic2VhcmNoQnlEYXRlcyIsInN0YXJ0RGF0ZSIsImNsaWNrQnV0dG9uIiwid2FpdFVudGlsRWxlbWVudEZvdW5kIiwiZmlsbElucHV0IiwiZm9ybWF0Iiwid2FpdEZvck5hdmlnYXRpb24iLCJnZXRBY2NvdW50TnVtYmVyIiwic2VsZWN0ZWRTbmlmQWNjb3VudCIsIm9wdGlvbiIsImNoZWNrSWZIYXNOZXh0UGFnZSIsIm5hdmlnYXRlVG9OZXh0UGFnZSIsInNjcmFwZVRyYW5zYWN0aW9ucyIsIm5lZWRUb1BhZ2luYXRlIiwiaGFzTmV4dFBhZ2UiLCJjdXJyZW50UGFnZVR4bnMiLCJnZXRBY2NvdW50VHJhbnNhY3Rpb25zIiwiUHJvbWlzZSIsInJhY2UiLCJub1RyYW5zYWN0aW9uSW5SYW5nZUVycm9yIiwicGVuZGluZ1R4bnMiLCJUcmFuc2FjdGlvblN0YXR1c2VzIiwiUGVuZGluZyIsImNvbXBsZXRlZFR4bnMiLCJDb21wbGV0ZWQiLCJnZXRDdXJyZW50QmFsYW5jZSIsImJhbGFuY2VTdHIiLCJlbCIsIndhaXRGb3JQb3N0TG9naW4iLCJmZXRjaEFjY291bnREYXRhIiwiYWNjb3VudE51bWJlciIsImJhbGFuY2UiLCJnZXRBY2NvdW50SWRzT2xkVUkiLCJldmFsdWF0ZSIsInNlbGVjdEVsZW1lbnQiLCJkb2N1bWVudCIsImdldEVsZW1lbnRCeUlkIiwib3B0aW9ucyIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJjbGlja0FjY291bnRTZWxlY3RvckdldEFjY291bnRJZHMiLCJhY2NvdW50U2VsZWN0b3IiLCJkcm9wZG93blBhbmVsU2VsZWN0b3IiLCJvcHRpb25TZWxlY3RvciIsImRyb3Bkb3duVmlzaWJsZSIsIndpbmRvdyIsImdldENvbXB1dGVkU3R5bGUiLCJkaXNwbGF5Iiwib2Zmc2V0UGFyZW50IiwiY2F0Y2giLCJhY2NvdW50TGFiZWxzIiwiJCRldmFsIiwidGV4dENvbnRlbnQiLCJmaWx0ZXIiLCJsYWJlbCIsImVycm9yIiwiZ2V0QWNjb3VudElkc0JvdGhVSXMiLCJhY2NvdW50c0lkcyIsImxlbmd0aCIsInNlbGVjdEFjY291bnRGcm9tRHJvcGRvd24iLCJhY2NvdW50TGFiZWwiLCJhdmFpbGFibGVBY2NvdW50cyIsImluY2x1ZGVzIiwiYWNjb3VudE9wdGlvbnMiLCIkJCIsInRleHQiLCJvcHRpb25IYW5kbGUiLCJldmFsdWF0ZUhhbmRsZSIsImNsaWNrIiwiZ2V0VHJhbnNhY3Rpb25zRnJhbWUiLCJhdHRlbXB0Iiwic2xlZXAiLCJmcmFtZXMiLCJ0YXJnZXRGcmFtZSIsImZpbmQiLCJmIiwibmFtZSIsInNlbGVjdEFjY291bnRCb3RoVUlzIiwiYWNjb3VudElkIiwiYWNjb3VudFNlbGVjdGVkIiwic2VsZWN0IiwiZmV0Y2hBY2NvdW50RGF0YUJvdGhVSXMiLCJmcmFtZSIsInRhcmdldFBhZ2UiLCJmZXRjaEFjY291bnRzIiwiYWNjb3VudERhdGEiLCJhY2NvdW50cyIsIkJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiQkFTRV9VUkwiLCJMT0dJTl9VUkwiLCJUUkFOU0FDVElPTlNfVVJMIiwiZ2V0TG9naW5PcHRpb25zIiwibG9naW5VcmwiLCJmaWVsZHMiLCJzdWJtaXRCdXR0b25TZWxlY3RvciIsInBvc3RBY3Rpb24iLCJwb3NzaWJsZVJlc3VsdHMiLCJwcmVBY3Rpb24iLCJmZXRjaERhdGEiLCJkZWZhdWx0U3RhcnRNb21lbnQiLCJzdWJ0cmFjdCIsImFkZCIsInN0YXJ0TW9tZW50TGltaXQiLCJ5ZWFyIiwidG9EYXRlIiwic3RhcnRNb21lbnQiLCJtYXgiLCJuYXZpZ2F0ZVRvIiwic3VjY2VzcyIsIl9kZWZhdWx0IiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLWJlaW5sZXVtaS1ncm91cC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbW9tZW50LCB7IHR5cGUgTW9tZW50IH0gZnJvbSAnbW9tZW50JztcbmltcG9ydCB7IHR5cGUgRnJhbWUsIHR5cGUgUGFnZSB9IGZyb20gJ3B1cHBldGVlcic7XG5pbXBvcnQgeyBTSEVLRUxfQ1VSUkVOQ1ksIFNIRUtFTF9DVVJSRU5DWV9TWU1CT0wgfSBmcm9tICcuLi9jb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgY2xpY2tCdXR0b24sXG4gIGVsZW1lbnRQcmVzZW50T25QYWdlLFxuICBmaWxsSW5wdXQsXG4gIHBhZ2VFdmFsQWxsLFxuICB3YWl0VW50aWxFbGVtZW50Rm91bmQsXG59IGZyb20gJy4uL2hlbHBlcnMvZWxlbWVudHMtaW50ZXJhY3Rpb25zJztcbmltcG9ydCB7IHdhaXRGb3JOYXZpZ2F0aW9uIH0gZnJvbSAnLi4vaGVscGVycy9uYXZpZ2F0aW9uJztcbmltcG9ydCB7IHNsZWVwIH0gZnJvbSAnLi4vaGVscGVycy93YWl0aW5nJztcbmltcG9ydCB7IFRyYW5zYWN0aW9uU3RhdHVzZXMsIFRyYW5zYWN0aW9uVHlwZXMsIHR5cGUgVHJhbnNhY3Rpb24sIHR5cGUgVHJhbnNhY3Rpb25zQWNjb3VudCB9IGZyb20gJy4uL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQgeyBCYXNlU2NyYXBlcldpdGhCcm93c2VyLCBMb2dpblJlc3VsdHMsIHR5cGUgUG9zc2libGVMb2dpblJlc3VsdHMgfSBmcm9tICcuL2Jhc2Utc2NyYXBlci13aXRoLWJyb3dzZXInO1xuXG5jb25zdCBEQVRFX0ZPUk1BVCA9ICdERC9NTS9ZWVlZJztcbmNvbnN0IE5PX1RSQU5TQUNUSU9OX0lOX0RBVEVfUkFOR0VfVEVYVCA9ICfXnNeQINeg157XpteQ15Ug16DXqteV16DXmdedINeR16DXldep15Ag15TXnteR15XXp9epJztcbmNvbnN0IERBVEVfQ09MVU1OX0NMQVNTX0NPTVBMRVRFRCA9ICdkYXRlIGZpcnN0JztcbmNvbnN0IERBVEVfQ09MVU1OX0NMQVNTX1BFTkRJTkcgPSAnZmlyc3QgZGF0ZSc7XG5jb25zdCBERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEID0gJ3JlZmVyZW5jZSB3cmFwX25vcm1hbCc7XG5jb25zdCBERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfUEVORElORyA9ICdkZXRhaWxzIHdyYXBfbm9ybWFsJztcbmNvbnN0IFJFRkVSRU5DRV9DT0xVTU5fQ0xBU1MgPSAnZGV0YWlscyc7XG5jb25zdCBERUJJVF9DT0xVTU5fQ0xBU1MgPSAnZGViaXQnO1xuY29uc3QgQ1JFRElUX0NPTFVNTl9DTEFTUyA9ICdjcmVkaXQnO1xuY29uc3QgRVJST1JfTUVTU0FHRV9DTEFTUyA9ICdOT19EQVRBJztcbmNvbnN0IEFDQ09VTlRTX05VTUJFUiA9ICdkaXYuZmliaV9hY2NvdW50IHNwYW4uYWNjX251bSc7XG5jb25zdCBDTE9TRV9TRUFSQ0hfQllfREFURVNfQlVUVE9OX0NMQVNTID0gJ3VpLWRhdGVwaWNrZXItY2xvc2UnO1xuY29uc3QgU0hPV19TRUFSQ0hfQllfREFURVNfQlVUVE9OX1ZBTFVFID0gJ9eU16bXkic7XG5jb25zdCBDT01QTEVURURfVFJBTlNBQ1RJT05TX1RBQkxFID0gJ3RhYmxlI2RhdGFUYWJsZTA3Nyc7XG5jb25zdCBQRU5ESU5HX1RSQU5TQUNUSU9OU19UQUJMRSA9ICd0YWJsZSNkYXRhVGFibGUwMjMnO1xuY29uc3QgTkVYVF9QQUdFX0xJTksgPSAnYSNOcGFnZS5wYWdpbmcnO1xuY29uc3QgQ1VSUkVOVF9CQUxBTkNFID0gJy5tYWluX2JhbGFuY2UnO1xuY29uc3QgSUZSQU1FX05BTUUgPSAnaWZyYW1lLW9sZC1wYWdlcyc7XG5jb25zdCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TID0gMTAwMDA7XG5cbnR5cGUgVHJhbnNhY3Rpb25zQ29sc1R5cGVzID0gUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbnR5cGUgVHJhbnNhY3Rpb25zVHJUZHMgPSBzdHJpbmdbXTtcbnR5cGUgVHJhbnNhY3Rpb25zVHIgPSB7IGlubmVyVGRzOiBUcmFuc2FjdGlvbnNUclRkcyB9O1xuXG5pbnRlcmZhY2UgU2NyYXBlZFRyYW5zYWN0aW9uIHtcbiAgcmVmZXJlbmNlOiBzdHJpbmc7XG4gIGRhdGU6IHN0cmluZztcbiAgY3JlZGl0OiBzdHJpbmc7XG4gIGRlYml0OiBzdHJpbmc7XG4gIG1lbW8/OiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uOiBzdHJpbmc7XG4gIHN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvc3NpYmxlTG9naW5SZXN1bHRzKCk6IFBvc3NpYmxlTG9naW5SZXN1bHRzIHtcbiAgY29uc3QgdXJsczogUG9zc2libGVMb2dpblJlc3VsdHMgPSB7fTtcbiAgdXJsc1tMb2dpblJlc3VsdHMuU3VjY2Vzc10gPSBbXG4gICAgL2ZpYmkuKmFjY291bnRTdW1tYXJ5LywgLy8gTmV3IFVJIHBhdHRlcm5cbiAgICAvUmVzb3VyY2VzXFwvUG9ydGFsTkdcXC9zaGVsbC8sIC8vIE5ldyBVSSBwYXR0ZXJuXG4gICAgL0ZpYmlNZW51XFwvT25saW5lLywgLy8gT2xkIFVJIHBhdHRlcm5cbiAgXTtcbiAgdXJsc1tMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkXSA9IFsvRmliaU1lbnVcXC9NYXJrZXRpbmdcXC9Qcml2YXRlXFwvSG9tZS9dO1xuICByZXR1cm4gdXJscztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZUxvZ2luRmllbGRzKGNyZWRlbnRpYWxzOiBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscykge1xuICByZXR1cm4gW1xuICAgIHsgc2VsZWN0b3I6ICcjdXNlcm5hbWUnLCB2YWx1ZTogY3JlZGVudGlhbHMudXNlcm5hbWUgfSxcbiAgICB7IHNlbGVjdG9yOiAnI3Bhc3N3b3JkJywgdmFsdWU6IGNyZWRlbnRpYWxzLnBhc3N3b3JkIH0sXG4gIF07XG59XG5cbmZ1bmN0aW9uIGdldEFtb3VudERhdGEoYW1vdW50U3RyOiBzdHJpbmcpIHtcbiAgbGV0IGFtb3VudFN0ckNvcHkgPSBhbW91bnRTdHIucmVwbGFjZShTSEVLRUxfQ1VSUkVOQ1lfU1lNQk9MLCAnJyk7XG4gIGFtb3VudFN0ckNvcHkgPSBhbW91bnRTdHJDb3B5LnJlcGxhY2VBbGwoJywnLCAnJyk7XG4gIHJldHVybiBwYXJzZUZsb2F0KGFtb3VudFN0ckNvcHkpO1xufVxuXG5mdW5jdGlvbiBnZXRUeG5BbW91bnQodHhuOiBTY3JhcGVkVHJhbnNhY3Rpb24pIHtcbiAgY29uc3QgY3JlZGl0ID0gZ2V0QW1vdW50RGF0YSh0eG4uY3JlZGl0KTtcbiAgY29uc3QgZGViaXQgPSBnZXRBbW91bnREYXRhKHR4bi5kZWJpdCk7XG4gIHJldHVybiAoTnVtYmVyLmlzTmFOKGNyZWRpdCkgPyAwIDogY3JlZGl0KSAtIChOdW1iZXIuaXNOYU4oZGViaXQpID8gMCA6IGRlYml0KTtcbn1cblxuZnVuY3Rpb24gY29udmVydFRyYW5zYWN0aW9ucyh0eG5zOiBTY3JhcGVkVHJhbnNhY3Rpb25bXSk6IFRyYW5zYWN0aW9uW10ge1xuICByZXR1cm4gdHhucy5tYXAoKHR4bik6IFRyYW5zYWN0aW9uID0+IHtcbiAgICBjb25zdCBjb252ZXJ0ZWREYXRlID0gbW9tZW50KHR4bi5kYXRlLCBEQVRFX0ZPUk1BVCkudG9JU09TdHJpbmcoKTtcbiAgICBjb25zdCBjb252ZXJ0ZWRBbW91bnQgPSBnZXRUeG5BbW91bnQodHhuKTtcbiAgICByZXR1cm4ge1xuICAgICAgdHlwZTogVHJhbnNhY3Rpb25UeXBlcy5Ob3JtYWwsXG4gICAgICBpZGVudGlmaWVyOiB0eG4ucmVmZXJlbmNlID8gcGFyc2VJbnQodHhuLnJlZmVyZW5jZSwgMTApIDogdW5kZWZpbmVkLFxuICAgICAgZGF0ZTogY29udmVydGVkRGF0ZSxcbiAgICAgIHByb2Nlc3NlZERhdGU6IGNvbnZlcnRlZERhdGUsXG4gICAgICBvcmlnaW5hbEFtb3VudDogY29udmVydGVkQW1vdW50LFxuICAgICAgb3JpZ2luYWxDdXJyZW5jeTogU0hFS0VMX0NVUlJFTkNZLFxuICAgICAgY2hhcmdlZEFtb3VudDogY29udmVydGVkQW1vdW50LFxuICAgICAgc3RhdHVzOiB0eG4uc3RhdHVzLFxuICAgICAgZGVzY3JpcHRpb246IHR4bi5kZXNjcmlwdGlvbixcbiAgICAgIG1lbW86IHR4bi5tZW1vLFxuICAgIH07XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc2FjdGlvbkRhdGUoXG4gIHRkczogVHJhbnNhY3Rpb25zVHJUZHMsXG4gIHRyYW5zYWN0aW9uVHlwZTogc3RyaW5nLFxuICB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcyxcbikge1xuICBpZiAodHJhbnNhY3Rpb25UeXBlID09PSAnY29tcGxldGVkJykge1xuICAgIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tEQVRFX0NPTFVNTl9DTEFTU19DT01QTEVURURdXSB8fCAnJykudHJpbSgpO1xuICB9XG4gIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tEQVRFX0NPTFVNTl9DTEFTU19QRU5ESU5HXV0gfHwgJycpLnRyaW0oKTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25EZXNjcmlwdGlvbihcbiAgdGRzOiBUcmFuc2FjdGlvbnNUclRkcyxcbiAgdHJhbnNhY3Rpb25UeXBlOiBzdHJpbmcsXG4gIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzLFxuKSB7XG4gIGlmICh0cmFuc2FjdGlvblR5cGUgPT09ICdjb21wbGV0ZWQnKSB7XG4gICAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0RFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19DT01QTEVURURdXSB8fCAnJykudHJpbSgpO1xuICB9XG4gIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfUEVORElOR11dIHx8ICcnKS50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uUmVmZXJlbmNlKHRkczogVHJhbnNhY3Rpb25zVHJUZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzKSB7XG4gIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tSRUZFUkVOQ0VfQ09MVU1OX0NMQVNTXV0gfHwgJycpLnRyaW0oKTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25EZWJpdCh0ZHM6IFRyYW5zYWN0aW9uc1RyVGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcykge1xuICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbREVCSVRfQ09MVU1OX0NMQVNTXV0gfHwgJycpLnRyaW0oKTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25DcmVkaXQodGRzOiBUcmFuc2FjdGlvbnNUclRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMpIHtcbiAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0NSRURJVF9DT0xVTU5fQ0xBU1NdXSB8fCAnJykudHJpbSgpO1xufVxuXG5mdW5jdGlvbiBleHRyYWN0VHJhbnNhY3Rpb25EZXRhaWxzKFxuICB0eG5Sb3c6IFRyYW5zYWN0aW9uc1RyLFxuICB0cmFuc2FjdGlvblN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcyxcbiAgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMsXG4pOiBTY3JhcGVkVHJhbnNhY3Rpb24ge1xuICBjb25zdCB0ZHMgPSB0eG5Sb3cuaW5uZXJUZHM7XG4gIGNvbnN0IGl0ZW0gPSB7XG4gICAgc3RhdHVzOiB0cmFuc2FjdGlvblN0YXR1cyxcbiAgICBkYXRlOiBnZXRUcmFuc2FjdGlvbkRhdGUodGRzLCB0cmFuc2FjdGlvblN0YXR1cywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKSxcbiAgICBkZXNjcmlwdGlvbjogZ2V0VHJhbnNhY3Rpb25EZXNjcmlwdGlvbih0ZHMsIHRyYW5zYWN0aW9uU3RhdHVzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpLFxuICAgIHJlZmVyZW5jZTogZ2V0VHJhbnNhY3Rpb25SZWZlcmVuY2UodGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpLFxuICAgIGRlYml0OiBnZXRUcmFuc2FjdGlvbkRlYml0KHRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKSxcbiAgICBjcmVkaXQ6IGdldFRyYW5zYWN0aW9uQ3JlZGl0KHRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKSxcbiAgfTtcblxuICByZXR1cm4gaXRlbTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25zQ29sc1R5cGVDbGFzc2VzKFxuICBwYWdlOiBQYWdlIHwgRnJhbWUsXG4gIHRhYmxlTG9jYXRvcjogc3RyaW5nLFxuKTogUHJvbWlzZTxUcmFuc2FjdGlvbnNDb2xzVHlwZXM+IHtcbiAgY29uc3QgcmVzdWx0OiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMgPSB7fTtcbiAgY29uc3QgdHlwZUNsYXNzZXNPYmpzID0gYXdhaXQgcGFnZUV2YWxBbGwocGFnZSwgYCR7dGFibGVMb2NhdG9yfSB0Ym9keSB0cjpmaXJzdC1vZi10eXBlIHRkYCwgbnVsbCwgdGRzID0+IHtcbiAgICByZXR1cm4gdGRzLm1hcCgodGQsIGluZGV4KSA9PiAoe1xuICAgICAgY29sQ2xhc3M6IHRkLmdldEF0dHJpYnV0ZSgnY2xhc3MnKSxcbiAgICAgIGluZGV4LFxuICAgIH0pKTtcbiAgfSk7XG5cbiAgZm9yIChjb25zdCB0eXBlQ2xhc3NPYmogb2YgdHlwZUNsYXNzZXNPYmpzKSB7XG4gICAgaWYgKHR5cGVDbGFzc09iai5jb2xDbGFzcykge1xuICAgICAgcmVzdWx0W3R5cGVDbGFzc09iai5jb2xDbGFzc10gPSB0eXBlQ2xhc3NPYmouaW5kZXg7XG4gICAgfVxuICB9XG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIGV4dHJhY3RUcmFuc2FjdGlvbihcbiAgdHhuczogU2NyYXBlZFRyYW5zYWN0aW9uW10sXG4gIHRyYW5zYWN0aW9uU3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzLFxuICB0eG5Sb3c6IFRyYW5zYWN0aW9uc1RyLFxuICB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcyxcbikge1xuICBjb25zdCB0eG4gPSBleHRyYWN0VHJhbnNhY3Rpb25EZXRhaWxzKHR4blJvdywgdHJhbnNhY3Rpb25TdGF0dXMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyk7XG4gIGlmICh0eG4uZGF0ZSAhPT0gJycpIHtcbiAgICB0eG5zLnB1c2godHhuKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBleHRyYWN0VHJhbnNhY3Rpb25zKHBhZ2U6IFBhZ2UgfCBGcmFtZSwgdGFibGVMb2NhdG9yOiBzdHJpbmcsIHRyYW5zYWN0aW9uU3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzKSB7XG4gIGNvbnN0IHR4bnM6IFNjcmFwZWRUcmFuc2FjdGlvbltdID0gW107XG4gIGNvbnN0IHRyYW5zYWN0aW9uc0NvbHNUeXBlcyA9IGF3YWl0IGdldFRyYW5zYWN0aW9uc0NvbHNUeXBlQ2xhc3NlcyhwYWdlLCB0YWJsZUxvY2F0b3IpO1xuXG4gIGNvbnN0IHRyYW5zYWN0aW9uc1Jvd3MgPSBhd2FpdCBwYWdlRXZhbEFsbDxUcmFuc2FjdGlvbnNUcltdPihwYWdlLCBgJHt0YWJsZUxvY2F0b3J9IHRib2R5IHRyYCwgW10sIHRycyA9PiB7XG4gICAgcmV0dXJuIHRycy5tYXAodHIgPT4gKHtcbiAgICAgIGlubmVyVGRzOiBBcnJheS5mcm9tKHRyLmdldEVsZW1lbnRzQnlUYWdOYW1lKCd0ZCcpKS5tYXAodGQgPT4gdGQuaW5uZXJUZXh0KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIGZvciAoY29uc3QgdHhuUm93IG9mIHRyYW5zYWN0aW9uc1Jvd3MpIHtcbiAgICBleHRyYWN0VHJhbnNhY3Rpb24odHhucywgdHJhbnNhY3Rpb25TdGF0dXMsIHR4blJvdywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKTtcbiAgfVxuICByZXR1cm4gdHhucztcbn1cblxuYXN5bmMgZnVuY3Rpb24gaXNOb1RyYW5zYWN0aW9uSW5EYXRlUmFuZ2VFcnJvcihwYWdlOiBQYWdlIHwgRnJhbWUpIHtcbiAgY29uc3QgaGFzRXJyb3JJbmZvRWxlbWVudCA9IGF3YWl0IGVsZW1lbnRQcmVzZW50T25QYWdlKHBhZ2UsIGAuJHtFUlJPUl9NRVNTQUdFX0NMQVNTfWApO1xuICBpZiAoaGFzRXJyb3JJbmZvRWxlbWVudCkge1xuICAgIGNvbnN0IGVycm9yVGV4dCA9IGF3YWl0IHBhZ2UuJGV2YWwoYC4ke0VSUk9SX01FU1NBR0VfQ0xBU1N9YCwgZXJyb3JFbGVtZW50ID0+IHtcbiAgICAgIHJldHVybiAoZXJyb3JFbGVtZW50IGFzIEhUTUxFbGVtZW50KS5pbm5lclRleHQ7XG4gICAgfSk7XG4gICAgcmV0dXJuIGVycm9yVGV4dC50cmltKCkgPT09IE5PX1RSQU5TQUNUSU9OX0lOX0RBVEVfUkFOR0VfVEVYVDtcbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNlYXJjaEJ5RGF0ZXMocGFnZTogUGFnZSB8IEZyYW1lLCBzdGFydERhdGU6IE1vbWVudCkge1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCAnYSN0YWJIZWFkZXI0Jyk7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnZGl2I2ZpYmlfZGF0ZXMnKTtcbiAgYXdhaXQgZmlsbElucHV0KHBhZ2UsICdpbnB1dCNmcm9tRGF0ZScsIHN0YXJ0RGF0ZS5mb3JtYXQoREFURV9GT1JNQVQpKTtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgYGJ1dHRvbltjbGFzcyo9JHtDTE9TRV9TRUFSQ0hfQllfREFURVNfQlVUVE9OX0NMQVNTfV1gKTtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgYGlucHV0W3ZhbHVlPSR7U0hPV19TRUFSQ0hfQllfREFURVNfQlVUVE9OX1ZBTFVFfV1gKTtcbiAgYXdhaXQgd2FpdEZvck5hdmlnYXRpb24ocGFnZSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEFjY291bnROdW1iZXIocGFnZTogUGFnZSB8IEZyYW1lKTogUHJvbWlzZTxzdHJpbmc+IHtcbiAgLy8gV2FpdCB1bnRpbCB0aGUgYWNjb3VudCBudW1iZXIgZWxlbWVudCBpcyBwcmVzZW50IGluIHRoZSBET01cbiAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIEFDQ09VTlRTX05VTUJFUiwgdHJ1ZSwgRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyk7XG5cbiAgY29uc3Qgc2VsZWN0ZWRTbmlmQWNjb3VudCA9IGF3YWl0IHBhZ2UuJGV2YWwoQUNDT1VOVFNfTlVNQkVSLCBvcHRpb24gPT4ge1xuICAgIHJldHVybiAob3B0aW9uIGFzIEhUTUxFbGVtZW50KS5pbm5lclRleHQ7XG4gIH0pO1xuXG4gIHJldHVybiBzZWxlY3RlZFNuaWZBY2NvdW50LnJlcGxhY2UoJy8nLCAnXycpLnRyaW0oKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2hlY2tJZkhhc05leHRQYWdlKHBhZ2U6IFBhZ2UgfCBGcmFtZSkge1xuICByZXR1cm4gZWxlbWVudFByZXNlbnRPblBhZ2UocGFnZSwgTkVYVF9QQUdFX0xJTkspO1xufVxuXG5hc3luYyBmdW5jdGlvbiBuYXZpZ2F0ZVRvTmV4dFBhZ2UocGFnZTogUGFnZSB8IEZyYW1lKSB7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIE5FWFRfUEFHRV9MSU5LKTtcbiAgYXdhaXQgd2FpdEZvck5hdmlnYXRpb24ocGFnZSk7XG59XG5cbi8qIENvdWxkbid0IHJlcHJvZHVjZSBzY2VuYXJpbyB3aXRoIG11bHRpcGxlIHBhZ2VzIG9mIHBlbmRpbmcgdHJhbnNhY3Rpb25zIC0gU2hvdWxkIHN1cHBvcnQgaWYgZXhpc3RzIHN1Y2ggY2FzZS5cbiAgIG5lZWRUb1BhZ2luYXRlIGlzIGZhbHNlIGlmIHNjcmFwaW5nIHBlbmRpbmcgdHJhbnNhY3Rpb25zICovXG5hc3luYyBmdW5jdGlvbiBzY3JhcGVUcmFuc2FjdGlvbnMoXG4gIHBhZ2U6IFBhZ2UgfCBGcmFtZSxcbiAgdGFibGVMb2NhdG9yOiBzdHJpbmcsXG4gIHRyYW5zYWN0aW9uU3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzLFxuICBuZWVkVG9QYWdpbmF0ZTogYm9vbGVhbixcbikge1xuICBjb25zdCB0eG5zID0gW107XG4gIGxldCBoYXNOZXh0UGFnZSA9IGZhbHNlO1xuXG4gIGRvIHtcbiAgICBjb25zdCBjdXJyZW50UGFnZVR4bnMgPSBhd2FpdCBleHRyYWN0VHJhbnNhY3Rpb25zKHBhZ2UsIHRhYmxlTG9jYXRvciwgdHJhbnNhY3Rpb25TdGF0dXMpO1xuICAgIHR4bnMucHVzaCguLi5jdXJyZW50UGFnZVR4bnMpO1xuICAgIGlmIChuZWVkVG9QYWdpbmF0ZSkge1xuICAgICAgaGFzTmV4dFBhZ2UgPSBhd2FpdCBjaGVja0lmSGFzTmV4dFBhZ2UocGFnZSk7XG4gICAgICBpZiAoaGFzTmV4dFBhZ2UpIHtcbiAgICAgICAgYXdhaXQgbmF2aWdhdGVUb05leHRQYWdlKHBhZ2UpO1xuICAgICAgfVxuICAgIH1cbiAgfSB3aGlsZSAoaGFzTmV4dFBhZ2UpO1xuXG4gIHJldHVybiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBY2NvdW50VHJhbnNhY3Rpb25zKHBhZ2U6IFBhZ2UgfCBGcmFtZSkge1xuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBcImRpdltpZCo9J2RpdlRhYmxlJ11cIiwgZmFsc2UpLFxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBgLiR7RVJST1JfTUVTU0FHRV9DTEFTU31gLCBmYWxzZSksXG4gIF0pO1xuXG4gIGNvbnN0IG5vVHJhbnNhY3Rpb25JblJhbmdlRXJyb3IgPSBhd2FpdCBpc05vVHJhbnNhY3Rpb25JbkRhdGVSYW5nZUVycm9yKHBhZ2UpO1xuICBpZiAobm9UcmFuc2FjdGlvbkluUmFuZ2VFcnJvcikge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHBlbmRpbmdUeG5zID0gYXdhaXQgc2NyYXBlVHJhbnNhY3Rpb25zKHBhZ2UsIFBFTkRJTkdfVFJBTlNBQ1RJT05TX1RBQkxFLCBUcmFuc2FjdGlvblN0YXR1c2VzLlBlbmRpbmcsIGZhbHNlKTtcbiAgY29uc3QgY29tcGxldGVkVHhucyA9IGF3YWl0IHNjcmFwZVRyYW5zYWN0aW9ucyhcbiAgICBwYWdlLFxuICAgIENPTVBMRVRFRF9UUkFOU0FDVElPTlNfVEFCTEUsXG4gICAgVHJhbnNhY3Rpb25TdGF0dXNlcy5Db21wbGV0ZWQsXG4gICAgdHJ1ZSxcbiAgKTtcbiAgY29uc3QgdHhucyA9IFsuLi5wZW5kaW5nVHhucywgLi4uY29tcGxldGVkVHhuc107XG4gIHJldHVybiB0eG5zO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRDdXJyZW50QmFsYW5jZShwYWdlOiBQYWdlIHwgRnJhbWUpOiBQcm9taXNlPG51bWJlcj4ge1xuICAvLyBXYWl0IGZvciB0aGUgYmFsYW5jZSBlbGVtZW50IHRvIGFwcGVhciBhbmQgYmUgdmlzaWJsZVxuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgQ1VSUkVOVF9CQUxBTkNFLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcblxuICAvLyBFeHRyYWN0IHRleHQgY29udGVudFxuICBjb25zdCBiYWxhbmNlU3RyID0gYXdhaXQgcGFnZS4kZXZhbChDVVJSRU5UX0JBTEFOQ0UsIGVsID0+IHtcbiAgICByZXR1cm4gKGVsIGFzIEhUTUxFbGVtZW50KS5pbm5lclRleHQ7XG4gIH0pO1xuXG4gIHJldHVybiBnZXRBbW91bnREYXRhKGJhbGFuY2VTdHIpO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gd2FpdEZvclBvc3RMb2dpbihwYWdlOiBQYWdlKSB7XG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI2NhcmQtaGVhZGVyJywgdHJ1ZSksIC8vIE5ldyBVSVxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI2FjY291bnRfbnVtJywgdHJ1ZSksIC8vIE5ldyBVSVxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI21hdGFmTG9nb3V0TGluaycsIHRydWUpLCAvLyBPbGQgVUlcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJyN2YWxpZGF0aW9uTXNnJywgdHJ1ZSksIC8vIE9sZCBVSVxuICBdKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hBY2NvdW50RGF0YShwYWdlOiBQYWdlIHwgRnJhbWUsIHN0YXJ0RGF0ZTogTW9tZW50KSB7XG4gIGNvbnN0IGFjY291bnROdW1iZXIgPSBhd2FpdCBnZXRBY2NvdW50TnVtYmVyKHBhZ2UpO1xuICBjb25zdCBiYWxhbmNlID0gYXdhaXQgZ2V0Q3VycmVudEJhbGFuY2UocGFnZSk7XG4gIGF3YWl0IHNlYXJjaEJ5RGF0ZXMocGFnZSwgc3RhcnREYXRlKTtcbiAgY29uc3QgdHhucyA9IGF3YWl0IGdldEFjY291bnRUcmFuc2FjdGlvbnMocGFnZSk7XG5cbiAgcmV0dXJuIHtcbiAgICBhY2NvdW50TnVtYmVyLFxuICAgIHR4bnMsXG4gICAgYmFsYW5jZSxcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QWNjb3VudElkc09sZFVJKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIHJldHVybiBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICBjb25zdCBzZWxlY3RFbGVtZW50ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2FjY291bnRfbnVtX3NlbGVjdCcpO1xuICAgIGNvbnN0IG9wdGlvbnMgPSBzZWxlY3RFbGVtZW50ID8gc2VsZWN0RWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCdvcHRpb24nKSA6IFtdO1xuICAgIGlmICghb3B0aW9ucykgcmV0dXJuIFtdO1xuICAgIHJldHVybiBBcnJheS5mcm9tKG9wdGlvbnMsIG9wdGlvbiA9PiBvcHRpb24udmFsdWUpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBFbnN1cmVzIHRoZSBhY2NvdW50IGRyb3Bkb3duIGlzIG9wZW4sIHRoZW4gcmV0dXJucyB0aGUgYXZhaWxhYmxlIGFjY291bnQgbGFiZWxzLlxuICpcbiAqIFRoaXMgbWV0aG9kOlxuICogLSBDaGVja3MgaWYgdGhlIGRyb3Bkb3duIGlzIGFscmVhZHkgb3Blbi5cbiAqIC0gSWYgbm90IG9wZW4sIGNsaWNrcyB0aGUgYWNjb3VudCBzZWxlY3RvciB0byBvcGVuIGl0LlxuICogLSBXYWl0cyBmb3IgdGhlIGRyb3Bkb3duIHRvIHJlbmRlci5cbiAqIC0gRXh0cmFjdHMgYW5kIHJldHVybnMgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIGFjY291bnQgbGFiZWxzLlxuICpcbiAqIEdyYWNlZnVsIGhhbmRsaW5nOlxuICogLSBJZiBhbnkgZXJyb3Igb2NjdXJzIChlLmcuLCBzZWxlY3RvcnMgbm90IGZvdW5kLCB0aW1pbmcgaXNzdWVzLCBVSSB2ZXJzaW9uIGNoYW5nZXMpLFxuICogICB0aGUgZnVuY3Rpb24gcmV0dXJucyBhbiBlbXB0eSBsaXN0LlxuICpcbiAqIEBwYXJhbSBwYWdlIFB1cHBldGVlciBQYWdlIG9iamVjdC5cbiAqIEByZXR1cm5zIEFuIGFycmF5IG9mIGF2YWlsYWJsZSBhY2NvdW50IGxhYmVscyAoZS5nLiwgW1wiMTI3IHwgWFhYWDFcIiwgXCIxMjcgfCBYWFhYMlwiXSksXG4gKiAgICAgICAgICBvciBhbiBlbXB0eSBhcnJheSBpZiBzb21ldGhpbmcgZ29lcyB3cm9uZy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsaWNrQWNjb3VudFNlbGVjdG9yR2V0QWNjb3VudElkcyhwYWdlOiBQYWdlKTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICB0cnkge1xuICAgIGNvbnN0IGFjY291bnRTZWxlY3RvciA9ICdkaXYuY3VycmVudC1hY2NvdW50JzsgLy8gRGlyZWN0IHNlbGVjdG9yIHRvIGNsaWNrYWJsZSBlbGVtZW50XG4gICAgY29uc3QgZHJvcGRvd25QYW5lbFNlbGVjdG9yID0gJ2Rpdi5tYXQtbWRjLWF1dG9jb21wbGV0ZS1wYW5lbC5hY2NvdW50LXNlbGVjdC1kZCc7IC8vIFRoZSBkcm9wZG93biBsaXN0IGJveFxuICAgIGNvbnN0IG9wdGlvblNlbGVjdG9yID0gJ21hdC1vcHRpb24gLm1kYy1saXN0LWl0ZW1fX3ByaW1hcnktdGV4dCc7IC8vIEFjY291bnQgb3B0aW9uIGxhYmVsc1xuXG4gICAgLy8gQ2hlY2sgaWYgZHJvcGRvd24gaXMgYWxyZWFkeSBvcGVuXG4gICAgY29uc3QgZHJvcGRvd25WaXNpYmxlID0gYXdhaXQgcGFnZVxuICAgICAgLiRldmFsKGRyb3Bkb3duUGFuZWxTZWxlY3RvciwgZWwgPT4ge1xuICAgICAgICByZXR1cm4gZWwgJiYgd2luZG93LmdldENvbXB1dGVkU3R5bGUoZWwpLmRpc3BsYXkgIT09ICdub25lJyAmJiBlbC5vZmZzZXRQYXJlbnQgIT09IG51bGw7XG4gICAgICB9KVxuICAgICAgLmNhdGNoKCgpID0+IGZhbHNlKTsgLy8gY2F0Y2ggaWYgZHJvcGRvd24gaXMgbm90IGluIHRoZSBET00geWV0XG5cbiAgICBpZiAoIWRyb3Bkb3duVmlzaWJsZSkge1xuICAgICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGFjY291bnRTZWxlY3RvciwgdHJ1ZSwgRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyk7XG5cbiAgICAgIC8vIENsaWNrIHRoZSBhY2NvdW50IHNlbGVjdG9yIHRvIG9wZW4gdGhlIGRyb3Bkb3duXG4gICAgICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCBhY2NvdW50U2VsZWN0b3IpO1xuXG4gICAgICAvLyBXYWl0IGZvciB0aGUgZHJvcGRvd24gdG8gb3BlblxuICAgICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGRyb3Bkb3duUGFuZWxTZWxlY3RvciwgdHJ1ZSwgRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyk7XG4gICAgfVxuXG4gICAgLy8gRXh0cmFjdCBhY2NvdW50IGxhYmVscyBmcm9tIHRoZSBkcm9wZG93biBvcHRpb25zXG4gICAgY29uc3QgYWNjb3VudExhYmVscyA9IGF3YWl0IHBhZ2UuJCRldmFsKG9wdGlvblNlbGVjdG9yLCBvcHRpb25zID0+IHtcbiAgICAgIHJldHVybiBvcHRpb25zLm1hcChvcHRpb24gPT4gb3B0aW9uLnRleHRDb250ZW50Py50cmltKCkgfHwgJycpLmZpbHRlcihsYWJlbCA9PiBsYWJlbCAhPT0gJycpO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIGFjY291bnRMYWJlbHM7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIFtdOyAvLyBHcmFjZWZ1bCBmYWxsYmFja1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEFjY291bnRJZHNCb3RoVUlzKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIGxldCBhY2NvdW50c0lkczogc3RyaW5nW10gPSBhd2FpdCBjbGlja0FjY291bnRTZWxlY3RvckdldEFjY291bnRJZHMocGFnZSk7XG4gIGlmIChhY2NvdW50c0lkcy5sZW5ndGggPT09IDApIHtcbiAgICBhY2NvdW50c0lkcyA9IGF3YWl0IGdldEFjY291bnRJZHNPbGRVSShwYWdlKTtcbiAgfVxuICByZXR1cm4gYWNjb3VudHNJZHM7XG59XG5cbi8qKlxuICogU2VsZWN0cyBhbiBhY2NvdW50IGZyb20gdGhlIGRyb3Bkb3duIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBhY2NvdW50IGxhYmVsLlxuICpcbiAqIFRoaXMgbWV0aG9kOlxuICogLSBDbGlja3MgdGhlIGFjY291bnQgc2VsZWN0b3IgYnV0dG9uIHRvIG9wZW4gdGhlIGRyb3Bkb3duLlxuICogLSBSZXRyaWV2ZXMgdGhlIGxpc3Qgb2YgYXZhaWxhYmxlIGFjY291bnQgbGFiZWxzLlxuICogLSBDaGVja3MgaWYgdGhlIHByb3ZpZGVkIGFjY291bnQgbGFiZWwgZXhpc3RzIGluIHRoZSBsaXN0LlxuICogLSBGaW5kcyBhbmQgY2xpY2tzIHRoZSBtYXRjaGluZyBhY2NvdW50IG9wdGlvbiBpZiBmb3VuZC5cbiAqXG4gKiBAcGFyYW0gcGFnZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QuXG4gKiBAcGFyYW0gYWNjb3VudExhYmVsIFRoZSB0ZXh0IG9mIHRoZSBhY2NvdW50IHRvIHNlbGVjdCAoZS5nLiwgXCIxMjcgfCBYWFhYWFwiKS5cbiAqIEByZXR1cm5zIFRydWUgaWYgdGhlIGFjY291bnQgb3B0aW9uIHdhcyBmb3VuZCBhbmQgY2xpY2tlZDsgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2VsZWN0QWNjb3VudEZyb21Ecm9wZG93bihwYWdlOiBQYWdlLCBhY2NvdW50TGFiZWw6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAvLyBDYWxsIGNsaWNrQWNjb3VudFNlbGVjdG9yIHRvIGdldCB0aGUgYXZhaWxhYmxlIGFjY291bnRzIGFuZCBvcGVuIHRoZSBkcm9wZG93blxuICBjb25zdCBhdmFpbGFibGVBY2NvdW50cyA9IGF3YWl0IGNsaWNrQWNjb3VudFNlbGVjdG9yR2V0QWNjb3VudElkcyhwYWdlKTtcblxuICAvLyBDaGVjayBpZiB0aGUgYWNjb3VudCBsYWJlbCBleGlzdHMgaW4gdGhlIGF2YWlsYWJsZSBhY2NvdW50c1xuICBpZiAoIWF2YWlsYWJsZUFjY291bnRzLmluY2x1ZGVzKGFjY291bnRMYWJlbCkpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBXYWl0IGZvciB0aGUgZHJvcGRvd24gb3B0aW9ucyB0byBiZSByZW5kZXJlZFxuICBjb25zdCBvcHRpb25TZWxlY3RvciA9ICdtYXQtb3B0aW9uIC5tZGMtbGlzdC1pdGVtX19wcmltYXJ5LXRleHQnO1xuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgb3B0aW9uU2VsZWN0b3IsIHRydWUsIEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMpO1xuXG4gIC8vIFF1ZXJ5IGFsbCBtYXRjaGluZyBvcHRpb25zXG4gIGNvbnN0IGFjY291bnRPcHRpb25zID0gYXdhaXQgcGFnZS4kJChvcHRpb25TZWxlY3Rvcik7XG5cbiAgLy8gRmluZCBhbmQgY2xpY2sgdGhlIG9wdGlvbiBtYXRjaGluZyB0aGUgYWNjb3VudExhYmVsXG4gIGZvciAoY29uc3Qgb3B0aW9uIG9mIGFjY291bnRPcHRpb25zKSB7XG4gICAgY29uc3QgdGV4dCA9IGF3YWl0IHBhZ2UuZXZhbHVhdGUoZWwgPT4gZWwudGV4dENvbnRlbnQ/LnRyaW0oKSwgb3B0aW9uKTtcblxuICAgIGlmICh0ZXh0ID09PSBhY2NvdW50TGFiZWwpIHtcbiAgICAgIGNvbnN0IG9wdGlvbkhhbmRsZSA9IGF3YWl0IG9wdGlvbi5ldmFsdWF0ZUhhbmRsZShlbCA9PiBlbCBhcyBIVE1MRWxlbWVudCk7XG4gICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKChlbDogSFRNTEVsZW1lbnQpID0+IGVsLmNsaWNrKCksIG9wdGlvbkhhbmRsZSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uc0ZyYW1lKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPEZyYW1lIHwgbnVsbD4ge1xuICAvLyBUcnkgYSBmZXcgdGltZXMgdG8gZmluZCB0aGUgaWZyYW1lLCBhcyBpdCBtaWdodCBub3QgYmUgaW1tZWRpYXRlbHkgYXZhaWxhYmxlXG4gIGZvciAobGV0IGF0dGVtcHQgPSAwOyBhdHRlbXB0IDwgMzsgYXR0ZW1wdCsrKSB7XG4gICAgYXdhaXQgc2xlZXAoMjAwMCk7XG4gICAgY29uc3QgZnJhbWVzID0gcGFnZS5mcmFtZXMoKTtcbiAgICBjb25zdCB0YXJnZXRGcmFtZSA9IGZyYW1lcy5maW5kKGYgPT4gZi5uYW1lKCkgPT09IElGUkFNRV9OQU1FKTtcblxuICAgIGlmICh0YXJnZXRGcmFtZSkge1xuICAgICAgcmV0dXJuIHRhcmdldEZyYW1lO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzZWxlY3RBY2NvdW50Qm90aFVJcyhwYWdlOiBQYWdlLCBhY2NvdW50SWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCBhY2NvdW50U2VsZWN0ZWQgPSBhd2FpdCBzZWxlY3RBY2NvdW50RnJvbURyb3Bkb3duKHBhZ2UsIGFjY291bnRJZCk7XG4gIGlmICghYWNjb3VudFNlbGVjdGVkKSB7XG4gICAgLy8gT2xkIFVJIGZvcm1hdFxuICAgIGF3YWl0IHBhZ2Uuc2VsZWN0KCcjYWNjb3VudF9udW1fc2VsZWN0JywgYWNjb3VudElkKTtcbiAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJyNhY2NvdW50X251bV9zZWxlY3QnLCB0cnVlKTtcbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEFjY291bnREYXRhQm90aFVJcyhwYWdlOiBQYWdlLCBzdGFydERhdGU6IE1vbWVudCkge1xuICAvLyBUcnkgdG8gZ2V0IHRoZSBpZnJhbWUgZm9yIHRoZSBuZXcgVUlcbiAgY29uc3QgZnJhbWUgPSBhd2FpdCBnZXRUcmFuc2FjdGlvbnNGcmFtZShwYWdlKTtcblxuICAvLyBVc2UgdGhlIGZyYW1lIGlmIGF2YWlsYWJsZSAobmV3IFVJKSwgb3RoZXJ3aXNlIHVzZSB0aGUgcGFnZSBkaXJlY3RseSAob2xkIFVJKVxuICBjb25zdCB0YXJnZXRQYWdlID0gZnJhbWUgfHwgcGFnZTtcbiAgcmV0dXJuIGZldGNoQWNjb3VudERhdGEodGFyZ2V0UGFnZSwgc3RhcnREYXRlKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hBY2NvdW50cyhwYWdlOiBQYWdlLCBzdGFydERhdGU6IE1vbWVudCk6IFByb21pc2U8VHJhbnNhY3Rpb25zQWNjb3VudFtdPiB7XG4gIGNvbnN0IGFjY291bnRzSWRzID0gYXdhaXQgZ2V0QWNjb3VudElkc0JvdGhVSXMocGFnZSk7XG5cbiAgaWYgKGFjY291bnRzSWRzLmxlbmd0aCA9PT0gMCkge1xuICAgIC8vIEluIGNhc2UgYWNjb3VudHNJZHMgY291bGQgbm8gYmUgcGFyc2VkIGp1c3QgcmV0dXJuIHRoZSB0cmFuc2FjdGlvbnMgb2YgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBhY2NvdW50XG4gICAgY29uc3QgYWNjb3VudERhdGEgPSBhd2FpdCBmZXRjaEFjY291bnREYXRhQm90aFVJcyhwYWdlLCBzdGFydERhdGUpO1xuICAgIHJldHVybiBbYWNjb3VudERhdGFdO1xuICB9XG5cbiAgY29uc3QgYWNjb3VudHM6IFRyYW5zYWN0aW9uc0FjY291bnRbXSA9IFtdO1xuICBmb3IgKGNvbnN0IGFjY291bnRJZCBvZiBhY2NvdW50c0lkcykge1xuICAgIGF3YWl0IHNlbGVjdEFjY291bnRCb3RoVUlzKHBhZ2UsIGFjY291bnRJZCk7XG4gICAgY29uc3QgYWNjb3VudERhdGEgPSBhd2FpdCBmZXRjaEFjY291bnREYXRhQm90aFVJcyhwYWdlLCBzdGFydERhdGUpO1xuICAgIGFjY291bnRzLnB1c2goYWNjb3VudERhdGEpO1xuICB9XG5cbiAgcmV0dXJuIGFjY291bnRzO1xufVxuXG50eXBlIFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzID0geyB1c2VybmFtZTogc3RyaW5nOyBwYXNzd29yZDogc3RyaW5nIH07XG5cbmNsYXNzIEJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXIgZXh0ZW5kcyBCYXNlU2NyYXBlcldpdGhCcm93c2VyPFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzPiB7XG4gIEJBU0VfVVJMID0gJyc7XG5cbiAgTE9HSU5fVVJMID0gJyc7XG5cbiAgVFJBTlNBQ1RJT05TX1VSTCA9ICcnO1xuXG4gIGdldExvZ2luT3B0aW9ucyhjcmVkZW50aWFsczogU2NyYXBlclNwZWNpZmljQ3JlZGVudGlhbHMpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbG9naW5Vcmw6IGAke3RoaXMuTE9HSU5fVVJMfWAsXG4gICAgICBmaWVsZHM6IGNyZWF0ZUxvZ2luRmllbGRzKGNyZWRlbnRpYWxzKSxcbiAgICAgIHN1Ym1pdEJ1dHRvblNlbGVjdG9yOiAnI2NvbnRpbnVlQnRuJyxcbiAgICAgIHBvc3RBY3Rpb246IGFzeW5jICgpID0+IHdhaXRGb3JQb3N0TG9naW4odGhpcy5wYWdlKSxcbiAgICAgIHBvc3NpYmxlUmVzdWx0czogZ2V0UG9zc2libGVMb2dpblJlc3VsdHMoKSxcbiAgICAgIC8vIEhBQ0s6IEZvciBzb21lIHJlYXNvbiwgdGhvdWdoIHRoZSBsb2dpbiBidXR0b24gKCNjb250aW51ZUJ0bikgaXMgcHJlc2VudCBhbmQgdmlzaWJsZSwgdGhlIGNsaWNrIGFjdGlvbiBkb2VzIG5vdCBwZXJmb3JtLlxuICAgICAgLy8gQWRkaW5nIHRoaXMgZGVsYXkgZml4ZXMgdGhlIGlzc3VlLlxuICAgICAgcHJlQWN0aW9uOiBhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHNsZWVwKDEwMDApO1xuICAgICAgfSxcbiAgICB9O1xuICB9XG5cbiAgYXN5bmMgZmV0Y2hEYXRhKCkge1xuICAgIGNvbnN0IGRlZmF1bHRTdGFydE1vbWVudCA9IG1vbWVudCgpLnN1YnRyYWN0KDEsICd5ZWFycycpLmFkZCgxLCAnZGF5Jyk7XG4gICAgY29uc3Qgc3RhcnRNb21lbnRMaW1pdCA9IG1vbWVudCh7IHllYXI6IDE2MDAgfSk7XG4gICAgY29uc3Qgc3RhcnREYXRlID0gdGhpcy5vcHRpb25zLnN0YXJ0RGF0ZSB8fCBkZWZhdWx0U3RhcnRNb21lbnQudG9EYXRlKCk7XG4gICAgY29uc3Qgc3RhcnRNb21lbnQgPSBtb21lbnQubWF4KHN0YXJ0TW9tZW50TGltaXQsIG1vbWVudChzdGFydERhdGUpKTtcblxuICAgIGF3YWl0IHRoaXMubmF2aWdhdGVUbyh0aGlzLlRSQU5TQUNUSU9OU19VUkwpO1xuXG4gICAgY29uc3QgYWNjb3VudHMgPSBhd2FpdCBmZXRjaEFjY291bnRzKHRoaXMucGFnZSwgc3RhcnRNb21lbnQpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBhY2NvdW50cyxcbiAgICB9O1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBRUEsSUFBQUMsVUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUscUJBQUEsR0FBQUYsT0FBQTtBQU9BLElBQUFHLFdBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFFBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLGFBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLHVCQUFBLEdBQUFOLE9BQUE7QUFBOEcsU0FBQUQsdUJBQUFRLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7QUFFOUcsTUFBTUcsV0FBVyxHQUFHLFlBQVk7QUFDaEMsTUFBTUMsaUNBQWlDLEdBQUcsOEJBQThCO0FBQ3hFLE1BQU1DLDJCQUEyQixHQUFHLFlBQVk7QUFDaEQsTUFBTUMseUJBQXlCLEdBQUcsWUFBWTtBQUM5QyxNQUFNQyxrQ0FBa0MsR0FBRyx1QkFBdUI7QUFDbEUsTUFBTUMsZ0NBQWdDLEdBQUcscUJBQXFCO0FBQzlELE1BQU1DLHNCQUFzQixHQUFHLFNBQVM7QUFDeEMsTUFBTUMsa0JBQWtCLEdBQUcsT0FBTztBQUNsQyxNQUFNQyxtQkFBbUIsR0FBRyxRQUFRO0FBQ3BDLE1BQU1DLG1CQUFtQixHQUFHLFNBQVM7QUFDckMsTUFBTUMsZUFBZSxHQUFHLCtCQUErQjtBQUN2RCxNQUFNQyxrQ0FBa0MsR0FBRyxxQkFBcUI7QUFDaEUsTUFBTUMsaUNBQWlDLEdBQUcsS0FBSztBQUMvQyxNQUFNQyw0QkFBNEIsR0FBRyxvQkFBb0I7QUFDekQsTUFBTUMsMEJBQTBCLEdBQUcsb0JBQW9CO0FBQ3ZELE1BQU1DLGNBQWMsR0FBRyxnQkFBZ0I7QUFDdkMsTUFBTUMsZUFBZSxHQUFH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O0FBSUEsTUFBTUMseUJBQXlCLFNBQVNDLDhDQUFzQixDQUE2QjtFQUN6RkMsUUFBUSxHQUFHLEVBQUU7RUFFYkMsU0FBUyxHQUFHLEVBQUU7RUFFZEMsZ0JBQWdCLEdBQUcsRUFBRTtFQUVyQkMsZUFBZUEsQ0FBQzdLLFdBQXVDLEVBQUU7SUFDdkQsT0FBTztNQUNMOEssUUFBUSxFQUFFLEdBQUcsSUFBSSxDQUFDSCxTQUFTLEVBQUU7TUFDN0JJLE1BQU0sRUFBRWhMLGlCQUFpQixDQUFDQyxXQUFXLENBQUM7TUFDdENnTCxvQkFBb0IsRUFBRSxjQUFjO01BQ3BDQyxVQUFVLEVBQUUsTUFBQUEsQ0FBQSxLQUFZbkUsZ0JBQWdCLENBQUMsSUFBSSxDQUFDdEQsSUFBSSxDQUFDO01BQ25EMEgsZUFBZSxFQUFFeEwsdUJBQXVCLENBQUMsQ0FBQztNQUMxQztNQUNBO01BQ0F5TCxTQUFTLEVBQUUsTUFBQUEsQ0FBQSxLQUFZO1FBQ3JCLE1BQU0sSUFBQTNCLGNBQUssRUFBQyxJQUFJLENBQUM7TUFDbkI7SUFDRixDQUFDO0VBQ0g7RUFFQSxNQUFNNEIsU0FBU0EsQ0FBQSxFQUFHO0lBQ2hCLE1BQU1DLGtCQUFrQixHQUFHLElBQUEvSixlQUFNLEVBQUMsQ0FBQyxDQUFDZ0ssUUFBUSxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsQ0FBQ0MsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUM7SUFDdEUsTUFBTUMsZ0JBQWdCLEdBQUcsSUFBQWxLLGVBQU0sRUFBQztNQUFFbUssSUFBSSxFQUFFO0lBQUssQ0FBQyxDQUFDO0lBQy9DLE1BQU10RyxTQUFTLEdBQUcsSUFBSSxDQUFDb0MsT0FBTyxDQUFDcEMsU0FBUyxJQUFJa0csa0JBQWtCLENBQUNLLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZFLE1BQU1DLFdBQVcsR0FBR3JLLGVBQU0sQ0FBQ3NLLEdBQUcsQ0FBQ0osZ0JBQWdCLEVBQUUsSUFBQWxLLGVBQU0sRUFBQzZELFNBQVMsQ0FBQyxDQUFDO0lBRW5FLE1BQU0sSUFBSSxDQUFDMEcsVUFBVSxDQUFDLElBQUksQ0FBQ2pCLGdCQUFnQixDQUFDO0lBRTVDLE1BQU1MLFFBQVEsR0FBRyxNQUFNRixhQUFhLENBQUMsSUFBSSxDQUFDN0csSUFBSSxFQUFFbUksV0FBVyxDQUFDO0lBRTVELE9BQU87TUFDTEcsT0FBTyxFQUFFLElBQUk7TUFDYnZCO0lBQ0YsQ0FBQztFQUNIO0FBQ0Y7QUFBQyxJQUFBd0IsUUFBQSxHQUFBQyxPQUFBLENBQUExTixPQUFBLEdBRWNrTSx5QkFBeUIiLCJpZ25vcmVMaXN0IjpbXX0=