UNPKG

israeli-bank-scrapers-core

Version:

Provide scrapers for all major Israeli banks and credit card companies

433 lines 67.7 kB
"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 _transactions = require("../helpers/transactions");
var _waiting = require("../helpers/waiting");
var _transactions2 = 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, options) {
  return txns.map(txn => {
    const convertedDate = (0, _moment.default)(txn.date, DATE_FORMAT).toISOString();
    const convertedAmount = getTxnAmount(txn);
    const result = {
      type: _transactions2.TransactionTypes.Normal,
      identifier: txn.reference ? parseInt(txn.reference, 10) : undefined,
      date: convertedDate,
      processedDate: convertedDate,
      originalAmount: convertedAmount,
      originalCurrency: _constants.SHEKEL_CURRENCY,
      chargedAmount: convertedAmount,
      status: txn.status,
      description: txn.description,
      memo: txn.memo
    };
    if (options?.includeRawTransaction) {
      result.rawTransaction = (0, _transactions.getRawTransaction)(txn);
    }
    return result;
  });
}
function 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, options) {
  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, options);
}
async function getAccountTransactions(page, options) {
  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, _transactions2.TransactionStatuses.Pending, false, options);
  const completedTxns = await scrapeTransactions(page, COMPLETED_TRANSACTIONS_TABLE, _transactions2.TransactionStatuses.Completed, true, options);
  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', false),
  // 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, options) {
  const accountNumber = await getAccountNumber(page);
  const balance = await getCurrentBalance(page);
  await searchByDates(page, startDate);
  const txns = await getAccountTransactions(page, options);
  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, options) {
  // 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, options);
}
async function fetchAccounts(page, startDate, options) {
  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, options);
    return [accountData];
  }
  const accounts = [];
  for (const accountId of accountsIds) {
    await selectAccountBothUIs(page, accountId);
    const accountData = await fetchAccountDataBothUIs(page, startDate, options);
    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, this.options);
    return {
      success: true,
      accounts
    };
  }
}
var _default = exports.default = BeinleumiGroupBaseScraper;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbW9tZW50IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfY29uc3RhbnRzIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfdHJhbnNhY3Rpb25zIiwiX3dhaXRpbmciLCJfdHJhbnNhY3Rpb25zMiIsIl9iYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiREFURV9GT1JNQVQiLCJOT19UUkFOU0FDVElPTl9JTl9EQVRFX1JBTkdFX1RFWFQiLCJEQVRFX0NPTFVNTl9DTEFTU19DT01QTEVURUQiLCJEQVRFX0NPTFVNTl9DTEFTU19QRU5ESU5HIiwiREVTQ1JJUFRJT05fQ09MVU1OX0NMQVNTX0NPTVBMRVRFRCIsIkRFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19QRU5ESU5HIiwiUkVGRVJFTkNFX0NPTFVNTl9DTEFTUyIsIkRFQklUX0NPTFVNTl9DTEFTUyIsIkNSRURJVF9DT0xVTU5fQ0xBU1MiLCJFUlJPUl9NRVNTQUdFX0NMQVNTIiwiQUNDT1VOVFNfTlVNQkVSIiwiQ0xPU0VfU0VBUkNIX0JZX0RBVEVTX0JVVFRPTl9DTEFTUyIsIlNIT1dfU0VBUkNIX0JZX0RBVEVTX0JVVFRPTl9WQUxVRSIsIkNPTVBMRVRFRF9UUkFOU0FDVElPTlNfVEFCTEUiLCJQRU5ESU5HX1RSQU5TQUNUSU9OU19UQUJMRSIsIk5FWFRfUEFHRV9MSU5LIiwiQ1VSUkVOVF9CQUxBTkNFIiwiSUZSQU1FX05BTUUiLCJFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TIiwiZ2V0UG9zc2libGVMb2dpblJlc3VsdHMiLCJ1cmxzIiwiTG9naW5SZXN1bHRzIiwiU3VjY2VzcyIsIkludmFsaWRQYXNzd29yZCIsImNyZWF0ZUxvZ2luRmllbGRzIiwiY3JlZGVudGlhbHMiLCJzZWxlY3RvciIsInZhbHVlIiwidXNlcm5hbWUiLCJwYXNzd29yZCIsImdldEFtb3VudERhdGEiLCJhbW91bnRTdHIiLCJhbW91bnRTdHJDb3B5IiwicmVwbGFjZSIsIlNIRUtFTF9DVVJSRU5DWV9TWU1CT0wiLCJyZXBsYWNlQWxsIiwicGFyc2VGbG9hdCIsImdldFR4bkFtb3VudCIsInR4biIsImNyZWRpdCIsImRlYml0IiwiTnVtYmVyIiwiaXNOYU4iLCJjb252ZXJ0VHJhbnNhY3Rpb25zIiwidHhucyIsIm9wdGlvbnMiLCJtYXAiLCJjb252ZXJ0ZWREYXRlIiwibW9tZW50IiwiZGF0ZSIsInRvSVNPU3RyaW5nIiwiY29udmVydGVkQW1vdW50IiwicmVzdWx0IiwidHlwZSIsIlRyYW5zYWN0aW9uVHlwZXMiLCJOb3JtYWwiLCJpZGVudGlmaWVyIiwicmVmZXJlbmNlIiwicGFyc2VJbnQiLCJ1bmRlZmluZWQiLCJwcm9jZXNzZWREYXRlIiwib3JpZ2luYWxBbW91bnQiLCJvcmlnaW5hbEN1cnJlbmN5IiwiU0hFS0VMX0NVUlJFTkNZIiwiY2hhcmdlZEFtb3VudCIsInN0YXR1cyIsImRlc2NyaXB0aW9uIiwibWVtbyIsImluY2x1ZGVSYXdUcmFuc2FjdGlvbiIsInJhd1RyYW5zYWN0aW9uIiwiZ2V0UmF3VHJhbnNhY3Rpb24iLCJnZXRUcmFuc2FjdGlvbkRhdGUiLCJ0ZHMiLCJ0cmFuc2FjdGlvblR5cGUiLCJ0cmFuc2FjdGlvbnNDb2xzVHlwZXMiLCJ0cmltIiwiZ2V0VHJhbnNhY3Rpb25EZXNjcmlwdGlvbiIsImdldFRyYW5zYWN0aW9uUmVmZXJlbmNlIiwiZ2V0VHJhbnNhY3Rpb25EZWJpdCIsImdldFRyYW5zYWN0aW9uQ3JlZGl0IiwiZXh0cmFjdFRyYW5zYWN0aW9uRGV0YWlscyIsInR4blJvdyIsInRyYW5zYWN0aW9uU3RhdHVzIiwiaW5uZXJUZHMiLCJpdGVtIiwiZ2V0VHJhbnNhY3Rpb25zQ29sc1R5cGVDbGFzc2VzIiwicGFnZSIsInRhYmxlTG9jYXRvciIsInR5cGVDbGFzc2VzT2JqcyIsInBhZ2VFdmFsQWxsIiwidGQiLCJpbmRleCIsImNvbENsYXNzIiwiZ2V0QXR0cmlidXRlIiwidHlwZUNsYXNzT2JqIiwiZXh0cmFjdFRyYW5zYWN0aW9uIiwicHVzaCIsImV4dHJhY3RUcmFuc2FjdGlvbnMiLCJ0cmFuc2FjdGlvbnNSb3dzIiwidHJzIiwidHIiLCJBcnJheSIsImZyb20iLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsImlubmVyVGV4dCIsImlzTm9UcmFuc2FjdGlvbkluRGF0ZVJhbmdlRXJyb3IiLCJoYXNFcnJvckluZm9FbGVtZW50IiwiZWxlbWVudFByZXNlbnRPblBhZ2UiLCJlcnJvclRleHQiLCIkZXZhbCIsImVycm9yRWxlbWVudCIsInNlYXJjaEJ5RGF0ZXMiLCJzdGFydERhdGUiLCJjbGlja0J1dHRvbiIsIndhaXRVbnRpbEVsZW1lbnRGb3VuZCIsImZpbGxJbnB1dCIsImZvcm1hdCIsIndhaXRGb3JOYXZpZ2F0aW9uIiwiZ2V0QWNjb3VudE51bWJlciIsInNlbGVjdGVkU25pZkFjY291bnQiLCJvcHRpb24iLCJjaGVja0lmSGFzTmV4dFBhZ2UiLCJuYXZpZ2F0ZVRvTmV4dFBhZ2UiLCJzY3JhcGVUcmFuc2FjdGlvbnMiLCJuZWVkVG9QYWdpbmF0ZSIsImhhc05leHRQYWdlIiwiY3VycmVudFBhZ2VUeG5zIiwiZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyIsIlByb21pc2UiLCJyYWNlIiwibm9UcmFuc2FjdGlvbkluUmFuZ2VFcnJvciIsInBlbmRpbmdUeG5zIiwiVHJhbnNhY3Rpb25TdGF0dXNlcyIsIlBlbmRpbmciLCJjb21wbGV0ZWRUeG5zIiwiQ29tcGxldGVkIiwiZ2V0Q3VycmVudEJhbGFuY2UiLCJiYWxhbmNlU3RyIiwiZWwiLCJ3YWl0Rm9yUG9zdExvZ2luIiwiZmV0Y2hBY2NvdW50RGF0YSIsImFjY291bnROdW1iZXIiLCJiYWxhbmNlIiwiZ2V0QWNjb3VudElkc09sZFVJIiwiZXZhbHVhdGUiLCJzZWxlY3RFbGVtZW50IiwiZG9jdW1lbnQiLCJnZXRFbGVtZW50QnlJZCIsInF1ZXJ5U2VsZWN0b3JBbGwiLCJjbGlja0FjY291bnRTZWxlY3RvckdldEFjY291bnRJZHMiLCJhY2NvdW50U2VsZWN0b3IiLCJkcm9wZG93blBhbmVsU2VsZWN0b3IiLCJvcHRpb25TZWxlY3RvciIsImRyb3Bkb3duVmlzaWJsZSIsIndpbmRvdyIsImdldENvbXB1dGVkU3R5bGUiLCJkaXNwbGF5Iiwib2Zmc2V0UGFyZW50IiwiY2F0Y2giLCJhY2NvdW50TGFiZWxzIiwiJCRldmFsIiwidGV4dENvbnRlbnQiLCJmaWx0ZXIiLCJsYWJlbCIsImVycm9yIiwiZ2V0QWNjb3VudElkc0JvdGhVSXMiLCJhY2NvdW50c0lkcyIsImxlbmd0aCIsInNlbGVjdEFjY291bnRGcm9tRHJvcGRvd24iLCJhY2NvdW50TGFiZWwiLCJhdmFpbGFibGVBY2NvdW50cyIsImluY2x1ZGVzIiwiYWNjb3VudE9wdGlvbnMiLCIkJCIsInRleHQiLCJvcHRpb25IYW5kbGUiLCJldmFsdWF0ZUhhbmRsZSIsImNsaWNrIiwiZ2V0VHJhbnNhY3Rpb25zRnJhbWUiLCJhdHRlbXB0Iiwic2xlZXAiLCJmcmFtZXMiLCJ0YXJnZXRGcmFtZSIsImZpbmQiLCJmIiwibmFtZSIsInNlbGVjdEFjY291bnRCb3RoVUlzIiwiYWNjb3VudElkIiwiYWNjb3VudFNlbGVjdGVkIiwic2VsZWN0IiwiZmV0Y2hBY2NvdW50RGF0YUJvdGhVSXMiLCJmcmFtZSIsInRhcmdldFBhZ2UiLCJmZXRjaEFjY291bnRzIiwiYWNjb3VudERhdGEiLCJhY2NvdW50cyIsIkJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXIiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiQkFTRV9VUkwiLCJMT0dJTl9VUkwiLCJUUkFOU0FDVElPTlNfVVJMIiwiZ2V0TG9naW5PcHRpb25zIiwibG9naW5VcmwiLCJmaWVsZHMiLCJzdWJtaXRCdXR0b25TZWxlY3RvciIsInBvc3RBY3Rpb24iLCJwb3NzaWJsZVJlc3VsdHMiLCJwcmVBY3Rpb24iLCJmZXRjaERhdGEiLCJkZWZhdWx0U3RhcnRNb21lbnQiLCJzdWJ0cmFjdCIsImFkZCIsInN0YXJ0TW9tZW50TGltaXQiLCJ5ZWFyIiwidG9EYXRlIiwic3RhcnRNb21lbnQiLCJtYXgiLCJuYXZpZ2F0ZVRvIiwic3VjY2VzcyIsIl9kZWZhdWx0IiwiZXhwb3J0cyJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLWJlaW5sZXVtaS1ncm91cC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgbW9tZW50LCB7IHR5cGUgTW9tZW50IH0gZnJvbSAnbW9tZW50JztcbmltcG9ydCB7IHR5cGUgRnJhbWUsIHR5cGUgUGFnZSB9IGZyb20gJ3B1cHBldGVlci1jb3JlJztcbmltcG9ydCB7IFNIRUtFTF9DVVJSRU5DWSwgU0hFS0VMX0NVUlJFTkNZX1NZTUJPTCB9IGZyb20gJy4uL2NvbnN0YW50cyc7XG5pbXBvcnQge1xuICBjbGlja0J1dHRvbixcbiAgZWxlbWVudFByZXNlbnRPblBhZ2UsXG4gIGZpbGxJbnB1dCxcbiAgcGFnZUV2YWxBbGwsXG4gIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCxcbn0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgd2FpdEZvck5hdmlnYXRpb24gfSBmcm9tICcuLi9oZWxwZXJzL25hdmlnYXRpb24nO1xuaW1wb3J0IHsgZ2V0UmF3VHJhbnNhY3Rpb24gfSBmcm9tICcuLi9oZWxwZXJzL3RyYW5zYWN0aW9ucyc7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gJy4uL2hlbHBlcnMvd2FpdGluZyc7XG5pbXBvcnQgeyBUcmFuc2FjdGlvblN0YXR1c2VzLCBUcmFuc2FjdGlvblR5cGVzLCB0eXBlIFRyYW5zYWN0aW9uLCB0eXBlIFRyYW5zYWN0aW9uc0FjY291bnQgfSBmcm9tICcuLi90cmFuc2FjdGlvbnMnO1xuaW1wb3J0IHsgQmFzZVNjcmFwZXJXaXRoQnJvd3NlciwgTG9naW5SZXN1bHRzLCB0eXBlIFBvc3NpYmxlTG9naW5SZXN1bHRzIH0gZnJvbSAnLi9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyJztcbmltcG9ydCB7IHR5cGUgU2NyYXBlck9wdGlvbnMgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5cbmNvbnN0IERBVEVfRk9STUFUID0gJ0REL01NL1lZWVknO1xuY29uc3QgTk9fVFJBTlNBQ1RJT05fSU5fREFURV9SQU5HRV9URVhUID0gJ9ec15Ag16DXntem15DXlSDXoNeq15XXoNeZ150g15HXoNeV16nXkCDXlNee15HXlden16knO1xuY29uc3QgREFURV9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEID0gJ2RhdGUgZmlyc3QnO1xuY29uc3QgREFURV9DT0xVTU5fQ0xBU1NfUEVORElORyA9ICdmaXJzdCBkYXRlJztcbmNvbnN0IERFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19DT01QTEVURUQgPSAncmVmZXJlbmNlIHdyYXBfbm9ybWFsJztcbmNvbnN0IERFU0NSSVBUSU9OX0NPTFVNTl9DTEFTU19QRU5ESU5HID0gJ2RldGFpbHMgd3JhcF9ub3JtYWwnO1xuY29uc3QgUkVGRVJFTkNFX0NPTFVNTl9DTEFTUyA9ICdkZXRhaWxzJztcbmNvbnN0IERFQklUX0NPTFVNTl9DTEFTUyA9ICdkZWJpdCc7XG5jb25zdCBDUkVESVRfQ09MVU1OX0NMQVNTID0gJ2NyZWRpdCc7XG5jb25zdCBFUlJPUl9NRVNTQUdFX0NMQVNTID0gJ05PX0RBVEEnO1xuY29uc3QgQUNDT1VOVFNfTlVNQkVSID0gJ2Rpdi5maWJpX2FjY291bnQgc3Bhbi5hY2NfbnVtJztcbmNvbnN0IENMT1NFX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fQ0xBU1MgPSAndWktZGF0ZXBpY2tlci1jbG9zZSc7XG5jb25zdCBTSE9XX1NFQVJDSF9CWV9EQVRFU19CVVRUT05fVkFMVUUgPSAn15TXpteSJztcbmNvbnN0IENPTVBMRVRFRF9UUkFOU0FDVElPTlNfVEFCTEUgPSAndGFibGUjZGF0YVRhYmxlMDc3JztcbmNvbnN0IFBFTkRJTkdfVFJBTlNBQ1RJT05TX1RBQkxFID0gJ3RhYmxlI2RhdGFUYWJsZTAyMyc7XG5jb25zdCBORVhUX1BBR0VfTElOSyA9ICdhI05wYWdlLnBhZ2luZyc7XG5jb25zdCBDVVJSRU5UX0JBTEFOQ0UgPSAnLm1haW5fYmFsYW5jZSc7XG5jb25zdCBJRlJBTUVfTkFNRSA9ICdpZnJhbWUtb2xkLXBhZ2VzJztcbmNvbnN0IEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMgPSAxMDAwMDtcblxudHlwZSBUcmFuc2FjdGlvbnNDb2xzVHlwZXMgPSBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xudHlwZSBUcmFuc2FjdGlvbnNUclRkcyA9IHN0cmluZ1tdO1xudHlwZSBUcmFuc2FjdGlvbnNUciA9IHsgaW5uZXJUZHM6IFRyYW5zYWN0aW9uc1RyVGRzIH07XG5cbmludGVyZmFjZSBTY3JhcGVkVHJhbnNhY3Rpb24ge1xuICByZWZlcmVuY2U6IHN0cmluZztcbiAgZGF0ZTogc3RyaW5nO1xuICBjcmVkaXQ6IHN0cmluZztcbiAgZGViaXQ6IHN0cmluZztcbiAgbWVtbz86IHN0cmluZztcbiAgZGVzY3JpcHRpb246IHN0cmluZztcbiAgc3RhdHVzOiBUcmFuc2FjdGlvblN0YXR1c2VzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9zc2libGVMb2dpblJlc3VsdHMoKTogUG9zc2libGVMb2dpblJlc3VsdHMge1xuICBjb25zdCB1cmxzOiBQb3NzaWJsZUxvZ2luUmVzdWx0cyA9IHt9O1xuICB1cmxzW0xvZ2luUmVzdWx0cy5TdWNjZXNzXSA9IFtcbiAgICAvZmliaS4qYWNjb3VudFN1bW1hcnkvLCAvLyBOZXcgVUkgcGF0dGVyblxuICAgIC9SZXNvdXJjZXNcXC9Qb3J0YWxOR1xcL3NoZWxsLywgLy8gTmV3IFVJIHBhdHRlcm5cbiAgICAvRmliaU1lbnVcXC9PbmxpbmUvLCAvLyBPbGQgVUkgcGF0dGVyblxuICBdO1xuICB1cmxzW0xvZ2luUmVzdWx0cy5JbnZhbGlkUGFzc3dvcmRdID0gWy9GaWJpTWVudVxcL01hcmtldGluZ1xcL1ByaXZhdGVcXC9Ib21lL107XG4gIHJldHVybiB1cmxzO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlTG9naW5GaWVsZHMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gIHJldHVybiBbXG4gICAgeyBzZWxlY3RvcjogJyN1c2VybmFtZScsIHZhbHVlOiBjcmVkZW50aWFscy51c2VybmFtZSB9LFxuICAgIHsgc2VsZWN0b3I6ICcjcGFzc3dvcmQnLCB2YWx1ZTogY3JlZGVudGlhbHMucGFzc3dvcmQgfSxcbiAgXTtcbn1cblxuZnVuY3Rpb24gZ2V0QW1vdW50RGF0YShhbW91bnRTdHI6IHN0cmluZykge1xuICBsZXQgYW1vdW50U3RyQ29weSA9IGFtb3VudFN0ci5yZXBsYWNlKFNIRUtFTF9DVVJSRU5DWV9TWU1CT0wsICcnKTtcbiAgYW1vdW50U3RyQ29weSA9IGFtb3VudFN0ckNvcHkucmVwbGFjZUFsbCgnLCcsICcnKTtcbiAgcmV0dXJuIHBhcnNlRmxvYXQoYW1vdW50U3RyQ29weSk7XG59XG5cbmZ1bmN0aW9uIGdldFR4bkFtb3VudCh0eG46IFNjcmFwZWRUcmFuc2FjdGlvbikge1xuICBjb25zdCBjcmVkaXQgPSBnZXRBbW91bnREYXRhKHR4bi5jcmVkaXQpO1xuICBjb25zdCBkZWJpdCA9IGdldEFtb3VudERhdGEodHhuLmRlYml0KTtcbiAgcmV0dXJuIChOdW1iZXIuaXNOYU4oY3JlZGl0KSA/IDAgOiBjcmVkaXQpIC0gKE51bWJlci5pc05hTihkZWJpdCkgPyAwIDogZGViaXQpO1xufVxuXG5mdW5jdGlvbiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnM6IFNjcmFwZWRUcmFuc2FjdGlvbltdLCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpOiBUcmFuc2FjdGlvbltdIHtcbiAgcmV0dXJuIHR4bnMubWFwKCh0eG4pOiBUcmFuc2FjdGlvbiA9PiB7XG4gICAgY29uc3QgY29udmVydGVkRGF0ZSA9IG1vbWVudCh0eG4uZGF0ZSwgREFURV9GT1JNQVQpLnRvSVNPU3RyaW5nKCk7XG4gICAgY29uc3QgY29udmVydGVkQW1vdW50ID0gZ2V0VHhuQW1vdW50KHR4bik7XG4gICAgY29uc3QgcmVzdWx0OiBUcmFuc2FjdGlvbiA9IHtcbiAgICAgIHR5cGU6IFRyYW5zYWN0aW9uVHlwZXMuTm9ybWFsLFxuICAgICAgaWRlbnRpZmllcjogdHhuLnJlZmVyZW5jZSA/IHBhcnNlSW50KHR4bi5yZWZlcmVuY2UsIDEwKSA6IHVuZGVmaW5lZCxcbiAgICAgIGRhdGU6IGNvbnZlcnRlZERhdGUsXG4gICAgICBwcm9jZXNzZWREYXRlOiBjb252ZXJ0ZWREYXRlLFxuICAgICAgb3JpZ2luYWxBbW91bnQ6IGNvbnZlcnRlZEFtb3VudCxcbiAgICAgIG9yaWdpbmFsQ3VycmVuY3k6IFNIRUtFTF9DVVJSRU5DWSxcbiAgICAgIGNoYXJnZWRBbW91bnQ6IGNvbnZlcnRlZEFtb3VudCxcbiAgICAgIHN0YXR1czogdHhuLnN0YXR1cyxcbiAgICAgIGRlc2NyaXB0aW9uOiB0eG4uZGVzY3JpcHRpb24sXG4gICAgICBtZW1vOiB0eG4ubWVtbyxcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnM/LmluY2x1ZGVSYXdUcmFuc2FjdGlvbikge1xuICAgICAgcmVzdWx0LnJhd1RyYW5zYWN0aW9uID0gZ2V0UmF3VHJhbnNhY3Rpb24odHhuKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9KTtcbn1cblxuZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25EYXRlKFxuICB0ZHM6IFRyYW5zYWN0aW9uc1RyVGRzLFxuICB0cmFuc2FjdGlvblR5cGU6IHN0cmluZyxcbiAgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMsXG4pIHtcbiAgaWYgKHRyYW5zYWN0aW9uVHlwZSA9PT0gJ2NvbXBsZXRlZCcpIHtcbiAgICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbREFURV9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEXV0gfHwgJycpLnRyaW0oKTtcbiAgfVxuICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbREFURV9DT0xVTU5fQ0xBU1NfUEVORElOR11dIHx8ICcnKS50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uRGVzY3JpcHRpb24oXG4gIHRkczogVHJhbnNhY3Rpb25zVHJUZHMsXG4gIHRyYW5zYWN0aW9uVHlwZTogc3RyaW5nLFxuICB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcyxcbikge1xuICBpZiAodHJhbnNhY3Rpb25UeXBlID09PSAnY29tcGxldGVkJykge1xuICAgIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tERVNDUklQVElPTl9DT0xVTU5fQ0xBU1NfQ09NUExFVEVEXV0gfHwgJycpLnRyaW0oKTtcbiAgfVxuICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbREVTQ1JJUFRJT05fQ09MVU1OX0NMQVNTX1BFTkRJTkddXSB8fCAnJykudHJpbSgpO1xufVxuXG5mdW5jdGlvbiBnZXRUcmFuc2FjdGlvblJlZmVyZW5jZSh0ZHM6IFRyYW5zYWN0aW9uc1RyVGRzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXM6IFRyYW5zYWN0aW9uc0NvbHNUeXBlcykge1xuICByZXR1cm4gKHRkc1t0cmFuc2FjdGlvbnNDb2xzVHlwZXNbUkVGRVJFTkNFX0NPTFVNTl9DTEFTU11dIHx8ICcnKS50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uRGViaXQodGRzOiBUcmFuc2FjdGlvbnNUclRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMpIHtcbiAgcmV0dXJuICh0ZHNbdHJhbnNhY3Rpb25zQ29sc1R5cGVzW0RFQklUX0NPTFVNTl9DTEFTU11dIHx8ICcnKS50cmltKCk7XG59XG5cbmZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uQ3JlZGl0KHRkczogVHJhbnNhY3Rpb25zVHJUZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzKSB7XG4gIHJldHVybiAodGRzW3RyYW5zYWN0aW9uc0NvbHNUeXBlc1tDUkVESVRfQ09MVU1OX0NMQVNTXV0gfHwgJycpLnRyaW0oKTtcbn1cblxuZnVuY3Rpb24gZXh0cmFjdFRyYW5zYWN0aW9uRGV0YWlscyhcbiAgdHhuUm93OiBUcmFuc2FjdGlvbnNUcixcbiAgdHJhbnNhY3Rpb25TdGF0dXM6IFRyYW5zYWN0aW9uU3RhdHVzZXMsXG4gIHRyYW5zYWN0aW9uc0NvbHNUeXBlczogVHJhbnNhY3Rpb25zQ29sc1R5cGVzLFxuKTogU2NyYXBlZFRyYW5zYWN0aW9uIHtcbiAgY29uc3QgdGRzID0gdHhuUm93LmlubmVyVGRzO1xuICBjb25zdCBpdGVtID0ge1xuICAgIHN0YXR1czogdHJhbnNhY3Rpb25TdGF0dXMsXG4gICAgZGF0ZTogZ2V0VHJhbnNhY3Rpb25EYXRlKHRkcywgdHJhbnNhY3Rpb25TdGF0dXMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyksXG4gICAgZGVzY3JpcHRpb246IGdldFRyYW5zYWN0aW9uRGVzY3JpcHRpb24odGRzLCB0cmFuc2FjdGlvblN0YXR1cywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKSxcbiAgICByZWZlcmVuY2U6IGdldFRyYW5zYWN0aW9uUmVmZXJlbmNlKHRkcywgdHJhbnNhY3Rpb25zQ29sc1R5cGVzKSxcbiAgICBkZWJpdDogZ2V0VHJhbnNhY3Rpb25EZWJpdCh0ZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyksXG4gICAgY3JlZGl0OiBnZXRUcmFuc2FjdGlvbkNyZWRpdCh0ZHMsIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyksXG4gIH07XG5cbiAgcmV0dXJuIGl0ZW07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldFRyYW5zYWN0aW9uc0NvbHNUeXBlQ2xhc3NlcyhcbiAgcGFnZTogUGFnZSB8IEZyYW1lLFxuICB0YWJsZUxvY2F0b3I6IHN0cmluZyxcbik6IFByb21pc2U8VHJhbnNhY3Rpb25zQ29sc1R5cGVzPiB7XG4gIGNvbnN0IHJlc3VsdDogVHJhbnNhY3Rpb25zQ29sc1R5cGVzID0ge307XG4gIGNvbnN0IHR5cGVDbGFzc2VzT2JqcyA9IGF3YWl0IHBhZ2VFdmFsQWxsKHBhZ2UsIGAke3RhYmxlTG9jYXRvcn0gdGJvZHkgdHI6Zmlyc3Qtb2YtdHlwZSB0ZGAsIG51bGwsIHRkcyA9PiB7XG4gICAgcmV0dXJuIHRkcy5tYXAoKHRkLCBpbmRleCkgPT4gKHtcbiAgICAgIGNvbENsYXNzOiB0ZC5nZXRBdHRyaWJ1dGUoJ2NsYXNzJyksXG4gICAgICBpbmRleCxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIGZvciAoY29uc3QgdHlwZUNsYXNzT2JqIG9mIHR5cGVDbGFzc2VzT2Jqcykge1xuICAgIGlmICh0eXBlQ2xhc3NPYmouY29sQ2xhc3MpIHtcbiAgICAgIHJlc3VsdFt0eXBlQ2xhc3NPYmouY29sQ2xhc3NdID0gdHlwZUNsYXNzT2JqLmluZGV4O1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBleHRyYWN0VHJhbnNhY3Rpb24oXG4gIHR4bnM6IFNjcmFwZWRUcmFuc2FjdGlvbltdLFxuICB0cmFuc2FjdGlvblN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcyxcbiAgdHhuUm93OiBUcmFuc2FjdGlvbnNUcixcbiAgdHJhbnNhY3Rpb25zQ29sc1R5cGVzOiBUcmFuc2FjdGlvbnNDb2xzVHlwZXMsXG4pIHtcbiAgY29uc3QgdHhuID0gZXh0cmFjdFRyYW5zYWN0aW9uRGV0YWlscyh0eG5Sb3csIHRyYW5zYWN0aW9uU3RhdHVzLCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMpO1xuICBpZiAodHhuLmRhdGUgIT09ICcnKSB7XG4gICAgdHhucy5wdXNoKHR4bik7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZXh0cmFjdFRyYW5zYWN0aW9ucyhwYWdlOiBQYWdlIHwgRnJhbWUsIHRhYmxlTG9jYXRvcjogc3RyaW5nLCB0cmFuc2FjdGlvblN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcykge1xuICBjb25zdCB0eG5zOiBTY3JhcGVkVHJhbnNhY3Rpb25bXSA9IFtdO1xuICBjb25zdCB0cmFuc2FjdGlvbnNDb2xzVHlwZXMgPSBhd2FpdCBnZXRUcmFuc2FjdGlvbnNDb2xzVHlwZUNsYXNzZXMocGFnZSwgdGFibGVMb2NhdG9yKTtcblxuICBjb25zdCB0cmFuc2FjdGlvbnNSb3dzID0gYXdhaXQgcGFnZUV2YWxBbGw8VHJhbnNhY3Rpb25zVHJbXT4ocGFnZSwgYCR7dGFibGVMb2NhdG9yfSB0Ym9keSB0cmAsIFtdLCB0cnMgPT4ge1xuICAgIHJldHVybiB0cnMubWFwKHRyID0+ICh7XG4gICAgICBpbm5lclRkczogQXJyYXkuZnJvbSh0ci5nZXRFbGVtZW50c0J5VGFnTmFtZSgndGQnKSkubWFwKHRkID0+IHRkLmlubmVyVGV4dCksXG4gICAgfSkpO1xuICB9KTtcblxuICBmb3IgKGNvbnN0IHR4blJvdyBvZiB0cmFuc2FjdGlvbnNSb3dzKSB7XG4gICAgZXh0cmFjdFRyYW5zYWN0aW9uKHR4bnMsIHRyYW5zYWN0aW9uU3RhdHVzLCB0eG5Sb3csIHRyYW5zYWN0aW9uc0NvbHNUeXBlcyk7XG4gIH1cbiAgcmV0dXJuIHR4bnM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGlzTm9UcmFuc2FjdGlvbkluRGF0ZVJhbmdlRXJyb3IocGFnZTogUGFnZSB8IEZyYW1lKSB7XG4gIGNvbnN0IGhhc0Vycm9ySW5mb0VsZW1lbnQgPSBhd2FpdCBlbGVtZW50UHJlc2VudE9uUGFnZShwYWdlLCBgLiR7RVJST1JfTUVTU0FHRV9DTEFTU31gKTtcbiAgaWYgKGhhc0Vycm9ySW5mb0VsZW1lbnQpIHtcbiAgICBjb25zdCBlcnJvclRleHQgPSBhd2FpdCBwYWdlLiRldmFsKGAuJHtFUlJPUl9NRVNTQUdFX0NMQVNTfWAsIGVycm9yRWxlbWVudCA9PiB7XG4gICAgICByZXR1cm4gKGVycm9yRWxlbWVudCBhcyBIVE1MRWxlbWVudCkuaW5uZXJUZXh0O1xuICAgIH0pO1xuICAgIHJldHVybiBlcnJvclRleHQudHJpbSgpID09PSBOT19UUkFOU0FDVElPTl9JTl9EQVRFX1JBTkdFX1RFWFQ7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5hc3luYyBmdW5jdGlvbiBzZWFyY2hCeURhdGVzKHBhZ2U6IFBhZ2UgfCBGcmFtZSwgc3RhcnREYXRlOiBNb21lbnQpIHtcbiAgYXdhaXQgY2xpY2tCdXR0b24ocGFnZSwgJ2EjdGFiSGVhZGVyNCcpO1xuICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJ2RpdiNmaWJpX2RhdGVzJyk7XG4gIGF3YWl0IGZpbGxJbnB1dChwYWdlLCAnaW5wdXQjZnJvbURhdGUnLCBzdGFydERhdGUuZm9ybWF0KERBVEVfRk9STUFUKSk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGBidXR0b25bY2xhc3MqPSR7Q0xPU0VfU0VBUkNIX0JZX0RBVEVTX0JVVFRPTl9DTEFTU31dYCk7XG4gIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGBpbnB1dFt2YWx1ZT0ke1NIT1dfU0VBUkNIX0JZX0RBVEVTX0JVVFRPTl9WQUxVRX1dYCk7XG4gIGF3YWl0IHdhaXRGb3JOYXZpZ2F0aW9uKHBhZ2UpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBY2NvdW50TnVtYmVyKHBhZ2U6IFBhZ2UgfCBGcmFtZSk6IFByb21pc2U8c3RyaW5nPiB7XG4gIC8vIFdhaXQgdW50aWwgdGhlIGFjY291bnQgbnVtYmVyIGVsZW1lbnQgaXMgcHJlc2VudCBpbiB0aGUgRE9NXG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBBQ0NPVU5UU19OVU1CRVIsIHRydWUsIEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMpO1xuXG4gIGNvbnN0IHNlbGVjdGVkU25pZkFjY291bnQgPSBhd2FpdCBwYWdlLiRldmFsKEFDQ09VTlRTX05VTUJFUiwgb3B0aW9uID0+IHtcbiAgICByZXR1cm4gKG9wdGlvbiBhcyBIVE1MRWxlbWVudCkuaW5uZXJUZXh0O1xuICB9KTtcblxuICByZXR1cm4gc2VsZWN0ZWRTbmlmQWNjb3VudC5yZXBsYWNlKCcvJywgJ18nKS50cmltKCk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNoZWNrSWZIYXNOZXh0UGFnZShwYWdlOiBQYWdlIHwgRnJhbWUpIHtcbiAgcmV0dXJuIGVsZW1lbnRQcmVzZW50T25QYWdlKHBhZ2UsIE5FWFRfUEFHRV9MSU5LKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gbmF2aWdhdGVUb05leHRQYWdlKHBhZ2U6IFBhZ2UgfCBGcmFtZSkge1xuICBhd2FpdCBjbGlja0J1dHRvbihwYWdlLCBORVhUX1BBR0VfTElOSyk7XG4gIGF3YWl0IHdhaXRGb3JOYXZpZ2F0aW9uKHBhZ2UpO1xufVxuXG4vKiBDb3VsZG4ndCByZXByb2R1Y2Ugc2NlbmFyaW8gd2l0aCBtdWx0aXBsZSBwYWdlcyBvZiBwZW5kaW5nIHRyYW5zYWN0aW9ucyAtIFNob3VsZCBzdXBwb3J0IGlmIGV4aXN0cyBzdWNoIGNhc2UuXG4gICBuZWVkVG9QYWdpbmF0ZSBpcyBmYWxzZSBpZiBzY3JhcGluZyBwZW5kaW5nIHRyYW5zYWN0aW9ucyAqL1xuYXN5bmMgZnVuY3Rpb24gc2NyYXBlVHJhbnNhY3Rpb25zKFxuICBwYWdlOiBQYWdlIHwgRnJhbWUsXG4gIHRhYmxlTG9jYXRvcjogc3RyaW5nLFxuICB0cmFuc2FjdGlvblN0YXR1czogVHJhbnNhY3Rpb25TdGF0dXNlcyxcbiAgbmVlZFRvUGFnaW5hdGU6IGJvb2xlYW4sXG4gIG9wdGlvbnM/OiBTY3JhcGVyT3B0aW9ucyxcbikge1xuICBjb25zdCB0eG5zID0gW107XG4gIGxldCBoYXNOZXh0UGFnZSA9IGZhbHNlO1xuXG4gIGRvIHtcbiAgICBjb25zdCBjdXJyZW50UGFnZVR4bnMgPSBhd2FpdCBleHRyYWN0VHJhbnNhY3Rpb25zKHBhZ2UsIHRhYmxlTG9jYXRvciwgdHJhbnNhY3Rpb25TdGF0dXMpO1xuICAgIHR4bnMucHVzaCguLi5jdXJyZW50UGFnZVR4bnMpO1xuICAgIGlmIChuZWVkVG9QYWdpbmF0ZSkge1xuICAgICAgaGFzTmV4dFBhZ2UgPSBhd2FpdCBjaGVja0lmSGFzTmV4dFBhZ2UocGFnZSk7XG4gICAgICBpZiAoaGFzTmV4dFBhZ2UpIHtcbiAgICAgICAgYXdhaXQgbmF2aWdhdGVUb05leHRQYWdlKHBhZ2UpO1xuICAgICAgfVxuICAgIH1cbiAgfSB3aGlsZSAoaGFzTmV4dFBhZ2UpO1xuXG4gIHJldHVybiBjb252ZXJ0VHJhbnNhY3Rpb25zKHR4bnMsIG9wdGlvbnMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBY2NvdW50VHJhbnNhY3Rpb25zKHBhZ2U6IFBhZ2UgfCBGcmFtZSwgb3B0aW9ucz86IFNjcmFwZXJPcHRpb25zKSB7XG4gIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIFwiZGl2W2lkKj0nZGl2VGFibGUnXVwiLCBmYWxzZSksXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsIGAuJHtFUlJPUl9NRVNTQUdFX0NMQVNTfWAsIGZhbHNlKSxcbiAgXSk7XG5cbiAgY29uc3Qgbm9UcmFuc2FjdGlvbkluUmFuZ2VFcnJvciA9IGF3YWl0IGlzTm9UcmFuc2FjdGlvbkluRGF0ZVJhbmdlRXJyb3IocGFnZSk7XG4gIGlmIChub1RyYW5zYWN0aW9uSW5SYW5nZUVycm9yKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG5cbiAgY29uc3QgcGVuZGluZ1R4bnMgPSBhd2FpdCBzY3JhcGVUcmFuc2FjdGlvbnMoXG4gICAgcGFnZSxcbiAgICBQRU5ESU5HX1RSQU5TQUNUSU9OU19UQUJMRSxcbiAgICBUcmFuc2FjdGlvblN0YXR1c2VzLlBlbmRpbmcsXG4gICAgZmFsc2UsXG4gICAgb3B0aW9ucyxcbiAgKTtcbiAgY29uc3QgY29tcGxldGVkVHhucyA9IGF3YWl0IHNjcmFwZVRyYW5zYWN0aW9ucyhcbiAgICBwYWdlLFxuICAgIENPTVBMRVRFRF9UUkFOU0FDVElPTlNfVEFCTEUsXG4gICAgVHJhbnNhY3Rpb25TdGF0dXNlcy5Db21wbGV0ZWQsXG4gICAgdHJ1ZSxcbiAgICBvcHRpb25zLFxuICApO1xuICBjb25zdCB0eG5zID0gWy4uLnBlbmRpbmdUeG5zLCAuLi5jb21wbGV0ZWRUeG5zXTtcbiAgcmV0dXJuIHR4bnM7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEN1cnJlbnRCYWxhbmNlKHBhZ2U6IFBhZ2UgfCBGcmFtZSk6IFByb21pc2U8bnVtYmVyPiB7XG4gIC8vIFdhaXQgZm9yIHRoZSBiYWxhbmNlIGVsZW1lbnQgdG8gYXBwZWFyIGFuZCBiZSB2aXNpYmxlXG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBDVVJSRU5UX0JBTEFOQ0UsIHRydWUsIEVMRU1FTlRfUkVOREVSX1RJTUVPVVRfTVMpO1xuXG4gIC8vIEV4dHJhY3QgdGV4dCBjb250ZW50XG4gIGNvbnN0IGJhbGFuY2VTdHIgPSBhd2FpdCBwYWdlLiRldmFsKENVUlJFTlRfQkFMQU5DRSwgZWwgPT4ge1xuICAgIHJldHVybiAoZWwgYXMgSFRNTEVsZW1lbnQpLmlubmVyVGV4dDtcbiAgfSk7XG5cbiAgcmV0dXJuIGdldEFtb3VudERhdGEoYmFsYW5jZVN0cik7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB3YWl0Rm9yUG9zdExvZ2luKHBhZ2U6IFBhZ2UpIHtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgd2FpdFVudGlsRWxlbWVudEZvdW5kKHBhZ2UsICcjY2FyZC1oZWFkZXInLCBmYWxzZSksIC8vIE5ldyBVSVxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI2FjY291bnRfbnVtJywgdHJ1ZSksIC8vIE5ldyBVSVxuICAgIHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI21hdGFmTG9nb3V0TGluaycsIHRydWUpLCAvLyBPbGQgVUlcbiAgICB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgJyN2YWxpZGF0aW9uTXNnJywgdHJ1ZSksIC8vIE9sZCBVSVxuICBdKTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZmV0Y2hBY2NvdW50RGF0YShwYWdlOiBQYWdlIHwgRnJhbWUsIHN0YXJ0RGF0ZTogTW9tZW50LCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpIHtcbiAgY29uc3QgYWNjb3VudE51bWJlciA9IGF3YWl0IGdldEFjY291bnROdW1iZXIocGFnZSk7XG4gIGNvbnN0IGJhbGFuY2UgPSBhd2FpdCBnZXRDdXJyZW50QmFsYW5jZShwYWdlKTtcbiAgYXdhaXQgc2VhcmNoQnlEYXRlcyhwYWdlLCBzdGFydERhdGUpO1xuICBjb25zdCB0eG5zID0gYXdhaXQgZ2V0QWNjb3VudFRyYW5zYWN0aW9ucyhwYWdlLCBvcHRpb25zKTtcblxuICByZXR1cm4ge1xuICAgIGFjY291bnROdW1iZXIsXG4gICAgdHhucyxcbiAgICBiYWxhbmNlLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRBY2NvdW50SWRzT2xkVUkocGFnZTogUGFnZSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgcmV0dXJuIHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgIGNvbnN0IHNlbGVjdEVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYWNjb3VudF9udW1fc2VsZWN0Jyk7XG4gICAgY29uc3Qgb3B0aW9ucyA9IHNlbGVjdEVsZW1lbnQgPyBzZWxlY3RFbGVtZW50LnF1ZXJ5U2VsZWN0b3JBbGwoJ29wdGlvbicpIDogW107XG4gICAgaWYgKCFvcHRpb25zKSByZXR1cm4gW107XG4gICAgcmV0dXJuIEFycmF5LmZyb20ob3B0aW9ucywgb3B0aW9uID0+IG9wdGlvbi52YWx1ZSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIEVuc3VyZXMgdGhlIGFjY291bnQgZHJvcGRvd24gaXMgb3BlbiwgdGhlbiByZXR1cm5zIHRoZSBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKlxuICogVGhpcyBtZXRob2Q6XG4gKiAtIENoZWNrcyBpZiB0aGUgZHJvcGRvd24gaXMgYWxyZWFkeSBvcGVuLlxuICogLSBJZiBub3Qgb3BlbiwgY2xpY2tzIHRoZSBhY2NvdW50IHNlbGVjdG9yIHRvIG9wZW4gaXQuXG4gKiAtIFdhaXRzIGZvciB0aGUgZHJvcGRvd24gdG8gcmVuZGVyLlxuICogLSBFeHRyYWN0cyBhbmQgcmV0dXJucyB0aGUgbGlzdCBvZiBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKlxuICogR3JhY2VmdWwgaGFuZGxpbmc6XG4gKiAtIElmIGFueSBlcnJvciBvY2N1cnMgKGUuZy4sIHNlbGVjdG9ycyBub3QgZm91bmQsIHRpbWluZyBpc3N1ZXMsIFVJIHZlcnNpb24gY2hhbmdlcyksXG4gKiAgIHRoZSBmdW5jdGlvbiByZXR1cm5zIGFuIGVtcHR5IGxpc3QuXG4gKlxuICogQHBhcmFtIHBhZ2UgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0LlxuICogQHJldHVybnMgQW4gYXJyYXkgb2YgYXZhaWxhYmxlIGFjY291bnQgbGFiZWxzIChlLmcuLCBbXCIxMjcgfCBYWFhYMVwiLCBcIjEyNyB8IFhYWFgyXCJdKSxcbiAqICAgICAgICAgIG9yIGFuIGVtcHR5IGFycmF5IGlmIHNvbWV0aGluZyBnb2VzIHdyb25nLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xpY2tBY2NvdW50U2VsZWN0b3JHZXRBY2NvdW50SWRzKHBhZ2U6IFBhZ2UpOiBQcm9taXNlPHN0cmluZ1tdPiB7XG4gIHRyeSB7XG4gICAgY29uc3QgYWNjb3VudFNlbGVjdG9yID0gJ2Rpdi5jdXJyZW50LWFjY291bnQnOyAvLyBEaXJlY3Qgc2VsZWN0b3IgdG8gY2xpY2thYmxlIGVsZW1lbnRcbiAgICBjb25zdCBkcm9wZG93blBhbmVsU2VsZWN0b3IgPSAnZGl2Lm1hdC1tZGMtYXV0b2NvbXBsZXRlLXBhbmVsLmFjY291bnQtc2VsZWN0LWRkJzsgLy8gVGhlIGRyb3Bkb3duIGxpc3QgYm94XG4gICAgY29uc3Qgb3B0aW9uU2VsZWN0b3IgPSAnbWF0LW9wdGlvbiAubWRjLWxpc3QtaXRlbV9fcHJpbWFyeS10ZXh0JzsgLy8gQWNjb3VudCBvcHRpb24gbGFiZWxzXG5cbiAgICAvLyBDaGVjayBpZiBkcm9wZG93biBpcyBhbHJlYWR5IG9wZW5cbiAgICBjb25zdCBkcm9wZG93blZpc2libGUgPSBhd2FpdCBwYWdlXG4gICAgICAuJGV2YWwoZHJvcGRvd25QYW5lbFNlbGVjdG9yLCBlbCA9PiB7XG4gICAgICAgIHJldHVybiBlbCAmJiB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZShlbCkuZGlzcGxheSAhPT0gJ25vbmUnICYmIGVsLm9mZnNldFBhcmVudCAhPT0gbnVsbDtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKCkgPT4gZmFsc2UpOyAvLyBjYXRjaCBpZiBkcm9wZG93biBpcyBub3QgaW4gdGhlIERPTSB5ZXRcblxuICAgIGlmICghZHJvcGRvd25WaXNpYmxlKSB7XG4gICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgYWNjb3VudFNlbGVjdG9yLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcblxuICAgICAgLy8gQ2xpY2sgdGhlIGFjY291bnQgc2VsZWN0b3IgdG8gb3BlbiB0aGUgZHJvcGRvd25cbiAgICAgIGF3YWl0IGNsaWNrQnV0dG9uKHBhZ2UsIGFjY291bnRTZWxlY3Rvcik7XG5cbiAgICAgIC8vIFdhaXQgZm9yIHRoZSBkcm9wZG93biB0byBvcGVuXG4gICAgICBhd2FpdCB3YWl0VW50aWxFbGVtZW50Rm91bmQocGFnZSwgZHJvcGRvd25QYW5lbFNlbGVjdG9yLCB0cnVlLCBFTEVNRU5UX1JFTkRFUl9USU1FT1VUX01TKTtcbiAgICB9XG5cbiAgICAvLyBFeHRyYWN0IGFjY291bnQgbGFiZWxzIGZyb20gdGhlIGRyb3Bkb3duIG9wdGlvbnNcbiAgICBjb25zdCBhY2NvdW50TGFiZWxzID0gYXdhaXQgcGFnZS4kJGV2YWwob3B0aW9uU2VsZWN0b3IsIG9wdGlvbnMgPT4ge1xuICAgICAgcmV0dXJuIG9wdGlvbnMubWFwKG9wdGlvbiA9PiBvcHRpb24udGV4dENvbnRlbnQ/LnRyaW0oKSB8fCAnJykuZmlsdGVyKGxhYmVsID0+IGxhYmVsICE9PSAnJyk7XG4gICAgfSk7XG5cbiAgICByZXR1cm4gYWNjb3VudExhYmVscztcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gW107IC8vIEdyYWNlZnVsIGZhbGxiYWNrXG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0QWNjb3VudElkc0JvdGhVSXMocGFnZTogUGFnZSk6IFByb21pc2U8c3RyaW5nW10+IHtcbiAgbGV0IGFjY291bnRzSWRzOiBzdHJpbmdbXSA9IGF3YWl0IGNsaWNrQWNjb3VudFNlbGVjdG9yR2V0QWNjb3VudElkcyhwYWdlKTtcbiAgaWYgKGFjY291bnRzSWRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGFjY291bnRzSWRzID0gYXdhaXQgZ2V0QWNjb3VudElkc09sZFVJKHBhZ2UpO1xuICB9XG4gIHJldHVybiBhY2NvdW50c0lkcztcbn1cblxuLyoqXG4gKiBTZWxlY3RzIGFuIGFjY291bnQgZnJvbSB0aGUgZHJvcGRvd24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGFjY291bnQgbGFiZWwuXG4gKlxuICogVGhpcyBtZXRob2Q6XG4gKiAtIENsaWNrcyB0aGUgYWNjb3VudCBzZWxlY3RvciBidXR0b24gdG8gb3BlbiB0aGUgZHJvcGRvd24uXG4gKiAtIFJldHJpZXZlcyB0aGUgbGlzdCBvZiBhdmFpbGFibGUgYWNjb3VudCBsYWJlbHMuXG4gKiAtIENoZWNrcyBpZiB0aGUgcHJvdmlkZWQgYWNjb3VudCBsYWJlbCBleGlzdHMgaW4gdGhlIGxpc3QuXG4gKiAtIEZpbmRzIGFuZCBjbGlja3MgdGhlIG1hdGNoaW5nIGFjY291bnQgb3B0aW9uIGlmIGZvdW5kLlxuICpcbiAqIEBwYXJhbSBwYWdlIFB1cHBldGVlciBQYWdlIG9iamVjdC5cbiAqIEBwYXJhbSBhY2NvdW50TGFiZWwgVGhlIHRleHQgb2YgdGhlIGFjY291bnQgdG8gc2VsZWN0IChlLmcuLCBcIjEyNyB8IFhYWFhYXCIpLlxuICogQHJldHVybnMgVHJ1ZSBpZiB0aGUgYWNjb3VudCBvcHRpb24gd2FzIGZvdW5kIGFuZCBjbGlja2VkOyBmYWxzZSBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzZWxlY3RBY2NvdW50RnJvbURyb3Bkb3duKHBhZ2U6IFBhZ2UsIGFjY291bnRMYWJlbDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gIC8vIENhbGwgY2xpY2tBY2NvdW50U2VsZWN0b3IgdG8gZ2V0IHRoZSBhdmFpbGFibGUgYWNjb3VudHMgYW5kIG9wZW4gdGhlIGRyb3Bkb3duXG4gIGNvbnN0IGF2YWlsYWJsZUFjY291bnRzID0gYXdhaXQgY2xpY2tBY2NvdW50U2VsZWN0b3JHZXRBY2NvdW50SWRzKHBhZ2UpO1xuXG4gIC8vIENoZWNrIGlmIHRoZSBhY2NvdW50IGxhYmVsIGV4aXN0cyBpbiB0aGUgYXZhaWxhYmxlIGFjY291bnRzXG4gIGlmICghYXZhaWxhYmxlQWNjb3VudHMuaW5jbHVkZXMoYWNjb3VudExhYmVsKSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFdhaXQgZm9yIHRoZSBkcm9wZG93biBvcHRpb25zIHRvIGJlIHJlbmRlcmVkXG4gIGNvbnN0IG9wdGlvblNlbGVjdG9yID0gJ21hdC1vcHRpb24gLm1kYy1saXN0LWl0ZW1fX3ByaW1hcnktdGV4dCc7XG4gIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCBvcHRpb25TZWxlY3RvciwgdHJ1ZSwgRUxFTUVOVF9SRU5ERVJfVElNRU9VVF9NUyk7XG5cbiAgLy8gUXVlcnkgYWxsIG1hdGNoaW5nIG9wdGlvbnNcbiAgY29uc3QgYWNjb3VudE9wdGlvbnMgPSBhd2FpdCBwYWdlLiQkKG9wdGlvblNlbGVjdG9yKTtcblxuICAvLyBGaW5kIGFuZCBjbGljayB0aGUgb3B0aW9uIG1hdGNoaW5nIHRoZSBhY2NvdW50TGFiZWxcbiAgZm9yIChjb25zdCBvcHRpb24gb2YgYWNjb3VudE9wdGlvbnMpIHtcbiAgICBjb25zdCB0ZXh0ID0gYXdhaXQgcGFnZS5ldmFsdWF0ZShlbCA9PiBlbC50ZXh0Q29udGVudD8udHJpbSgpLCBvcHRpb24pO1xuXG4gICAgaWYgKHRleHQgPT09IGFjY291bnRMYWJlbCkge1xuICAgICAgY29uc3Qgb3B0aW9uSGFuZGxlID0gYXdhaXQgb3B0aW9uLmV2YWx1YXRlSGFuZGxlKGVsID0+IGVsIGFzIEhUTUxFbGVtZW50KTtcbiAgICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGVsOiBIVE1MRWxlbWVudCkgPT4gZWwuY2xpY2soKSwgb3B0aW9uSGFuZGxlKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZ2V0VHJhbnNhY3Rpb25zRnJhbWUocGFnZTogUGFnZSk6IFByb21pc2U8RnJhbWUgfCBudWxsPiB7XG4gIC8vIFRyeSBhIGZldyB0aW1lcyB0byBmaW5kIHRoZSBpZnJhbWUsIGFzIGl0IG1pZ2h0IG5vdCBiZSBpbW1lZGlhdGVseSBhdmFpbGFibGVcbiAgZm9yIChsZXQgYXR0ZW1wdCA9IDA7IGF0dGVtcHQgPCAzOyBhdHRlbXB0KyspIHtcbiAgICBhd2FpdCBzbGVlcCgyMDAwKTtcbiAgICBjb25zdCBmcmFtZXMgPSBwYWdlLmZyYW1lcygpO1xuICAgIGNvbnN0IHRhcmdldEZyYW1lID0gZnJhbWVzLmZpbmQoZiA9PiBmLm5hbWUoKSA9PT0gSUZSQU1FX05BTUUpO1xuXG4gICAgaWYgKHRhcmdldEZyYW1lKSB7XG4gICAgICByZXR1cm4gdGFyZ2V0RnJhbWU7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNlbGVjdEFjY291bnRCb3RoVUlzKHBhZ2U6IFBhZ2UsIGFjY291bnRJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGFjY291bnRTZWxlY3RlZCA9IGF3YWl0IHNlbGVjdEFjY291bnRGcm9tRHJvcGRvd24ocGFnZSwgYWNjb3VudElkKTtcbiAgaWYgKCFhY2NvdW50U2VsZWN0ZWQpIHtcbiAgICAvLyBPbGQgVUkgZm9ybWF0XG4gICAgYXdhaXQgcGFnZS5zZWxlY3QoJyNhY2NvdW50X251bV9zZWxlY3QnLCBhY2NvdW50SWQpO1xuICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZChwYWdlLCAnI2FjY291bnRfbnVtX3NlbGVjdCcsIHRydWUpO1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGZldGNoQWNjb3VudERhdGFCb3RoVUlzKFxuICBwYWdlOiBQYWdlLFxuICBzdGFydERhdGU6IE1vbWVudCxcbiAgb3B0aW9ucz86IFNjcmFwZXJPcHRpb25zLFxuKTogUHJvbWlzZTxUcmFuc2FjdGlvbnNBY2NvdW50PiB7XG4gIC8vIFRyeSB0byBnZXQgdGhlIGlmcmFtZSBmb3IgdGhlIG5ldyBVSVxuICBjb25zdCBmcmFtZSA9IGF3YWl0IGdldFRyYW5zYWN0aW9uc0ZyYW1lKHBhZ2UpO1xuXG4gIC8vIFVzZSB0aGUgZnJhbWUgaWYgYXZhaWxhYmxlIChuZXcgVUkpLCBvdGhlcndpc2UgdXNlIHRoZSBwYWdlIGRpcmVjdGx5IChvbGQgVUkpXG4gIGNvbnN0IHRhcmdldFBhZ2UgPSBmcmFtZSB8fCBwYWdlO1xuICByZXR1cm4gZmV0Y2hBY2NvdW50RGF0YSh0YXJnZXRQYWdlLCBzdGFydERhdGUsIG9wdGlvbnMpO1xufVxuXG5hc3luYyBmdW5jdGlvbiBmZXRjaEFjY291bnRzKHBhZ2U6IFBhZ2UsIHN0YXJ0RGF0ZTogTW9tZW50LCBvcHRpb25zPzogU2NyYXBlck9wdGlvbnMpOiBQcm9taXNlPFRyYW5zYWN0aW9uc0FjY291bnRbXT4ge1xuICBjb25zdCBhY2NvdW50c0lkcyA9IGF3YWl0IGdldEFjY291bnRJZHNCb3RoVUlzKHBhZ2UpO1xuXG4gIGlmIChhY2NvdW50c0lkcy5sZW5ndGggPT09IDApIHtcbiAgICAvLyBJbiBjYXNlIGFjY291bnRzSWRzIGNvdWxkIG5vIGJlIHBhcnNlZCBqdXN0IHJldHVybiB0aGUgdHJhbnNhY3Rpb25zIG9mIHRoZSBjdXJyZW50bHkgc2VsZWN0ZWQgYWNjb3VudFxuICAgIGNvbnN0IGFjY291bnREYXRhID0gYXdhaXQgZmV0Y2hBY2NvdW50RGF0YUJvdGhVSXMocGFnZSwgc3RhcnREYXRlLCBvcHRpb25zKTtcbiAgICByZXR1cm4gW2FjY291bnREYXRhXTtcbiAgfVxuXG4gIGNvbnN0IGFjY291bnRzOiBUcmFuc2FjdGlvbnNBY2NvdW50W10gPSBbXTtcbiAgZm9yIChjb25zdCBhY2NvdW50SWQgb2YgYWNjb3VudHNJZHMpIHtcbiAgICBhd2FpdCBzZWxlY3RBY2NvdW50Qm90aFVJcyhwYWdlLCBhY2NvdW50SWQpO1xuICAgIGNvbnN0IGFjY291bnREYXRhID0gYXdhaXQgZmV0Y2hBY2NvdW50RGF0YUJvdGhVSXMocGFnZSwgc3RhcnREYXRlLCBvcHRpb25zKTtcbiAgICBhY2NvdW50cy5wdXNoKGFjY291bnREYXRhKTtcbiAgfVxuXG4gIHJldHVybiBhY2NvdW50cztcbn1cblxudHlwZSBTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscyA9IHsgdXNlcm5hbWU6IHN0cmluZzsgcGFzc3dvcmQ6IHN0cmluZyB9O1xuXG5jbGFzcyBCZWlubGV1bWlHcm91cEJhc2VTY3JhcGVyIGV4dGVuZHMgQmFzZVNjcmFwZXJXaXRoQnJvd3NlcjxTY3JhcGVyU3BlY2lmaWNDcmVkZW50aWFscz4ge1xuICBCQVNFX1VSTCA9ICcnO1xuXG4gIExPR0lOX1VSTCA9ICcnO1xuXG4gIFRSQU5TQUNUSU9OU19VUkwgPSAnJztcblxuICBnZXRMb2dpbk9wdGlvbnMoY3JlZGVudGlhbHM6IFNjcmFwZXJTcGVjaWZpY0NyZWRlbnRpYWxzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGxvZ2luVXJsOiBgJHt0aGlzLkxPR0lOX1VSTH1gLFxuICAgICAgZmllbGRzOiBjcmVhdGVMb2dpbkZpZWxkcyhjcmVkZW50aWFscyksXG4gICAgICBzdWJtaXRCdXR0b25TZWxlY3RvcjogJyNjb250aW51ZUJ0bicsXG4gICAgICBwb3N0QWN0aW9uOiBhc3luYyAoKSA9PiB3YWl0Rm9yUG9zdExvZ2luKHRoaXMucGFnZSksXG4gICAgICBwb3NzaWJsZVJlc3VsdHM6IGdldFBvc3NpYmxlTG9naW5SZXN1bHRzKCksXG4gICAgICAvLyBIQUNLOiBGb3Igc29tZSByZWFzb24sIHRob3VnaCB0aGUgbG9naW4gYnV0dG9uICgjY29udGludWVCdG4pIGlzIHByZXNlbnQgYW5kIHZpc2libGUsIHRoZSBjbGljayBhY3Rpb24gZG9lcyBub3QgcGVyZm9ybS5cbiAgICAgIC8vIEFkZGluZyB0aGlzIGRlbGF5IGZpeGVzIHRoZSBpc3N1ZS5cbiAgICAgIHByZUFjdGlvbjogYXN5bmMgKCkgPT4ge1xuICAgICAgICBhd2FpdCBzbGVlcCgxMDAwKTtcbiAgICAgIH0sXG4gICAgfTtcbiAgfVxuXG4gIGFzeW5jIGZldGNoRGF0YSgpIHtcbiAgICBjb25zdCBkZWZhdWx0U3RhcnRNb21lbnQgPSBtb21lbnQoKS5zdWJ0cmFjdCgxLCAneWVhcnMnKS5hZGQoMSwgJ2RheScpO1xuICAgIGNvbnN0IHN0YXJ0TW9tZW50TGltaXQgPSBtb21lbnQoeyB5ZWFyOiAxNjAwIH0pO1xuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IHRoaXMub3B0aW9ucy5zdGFydERhdGUgfHwgZGVmYXVsdFN0YXJ0TW9tZW50LnRvRGF0ZSgpO1xuICAgIGNvbnN0IHN0YXJ0TW9tZW50ID0gbW9tZW50Lm1heChzdGFydE1vbWVudExpbWl0LCBtb21lbnQoc3RhcnREYXRlKSk7XG5cbiAgICBhd2FpdCB0aGlzLm5hdmlnYXRlVG8odGhpcy5UUkFOU0FDVElPTlNfVVJMKTtcblxuICAgIGNvbnN0IGFjY291bnRzID0gYXdhaXQgZmV0Y2hBY2NvdW50cyh0aGlzLnBhZ2UsIHN0YXJ0TW9tZW50LCB0aGlzLm9wdGlvbnMpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IHRydWUsXG4gICAgICBhY2NvdW50cyxcbiAgICB9O1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEJlaW5sZXVtaUdyb3VwQmFzZVNjcmFwZXI7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBRUEsSUFBQUMsVUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUscUJBQUEsR0FBQUYsT0FBQTtBQU9BLElBQUFHLFdBQUEsR0FBQUgsT0FBQTtBQUNB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