israeli-bank-scrapers
Version:
Provide scrapers for all major Israeli banks and credit card companies
284 lines (276 loc) • 38.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.LoginResults = exports.BaseScraperWithBrowser = void 0;
var _puppeteer = _interopRequireDefault(require("puppeteer"));
var _definitions = require("../definitions");
var _debug = require("../helpers/debug");
var _elementsInteractions = require("../helpers/elements-interactions");
var _navigation = require("../helpers/navigation");
var _baseScraper = require("./base-scraper");
var _errors = require("./errors");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const debug = (0, _debug.getDebug)('base-scraper-with-browser');
var LoginBaseResults = /*#__PURE__*/function (LoginBaseResults) {
LoginBaseResults["Success"] = "SUCCESS";
LoginBaseResults["UnknownError"] = "UNKNOWN_ERROR";
return LoginBaseResults;
}(LoginBaseResults || {});
const {
Timeout,
Generic,
General,
...rest
} = _errors.ScraperErrorTypes;
const LoginResults = exports.LoginResults = {
...rest,
...LoginBaseResults
};
// eslint-disable-next-line @typescript-eslint/no-redeclare
async function getKeyByValue(object, value, page) {
const keys = Object.keys(object);
for (const key of keys) {
// @ts-ignore
const conditions = object[key];
for (const condition of conditions) {
let result = false;
if (condition instanceof RegExp) {
result = condition.test(value);
} else if (typeof condition === 'function') {
result = await condition({
page,
value
});
} else {
result = value.toLowerCase() === condition.toLowerCase();
}
if (result) {
// @ts-ignore
return Promise.resolve(key);
}
}
}
return Promise.resolve(LoginResults.UnknownError);
}
function createGeneralError() {
return {
success: false,
errorType: _errors.ScraperErrorTypes.General
};
}
class BaseScraperWithBrowser extends _baseScraper.BaseScraper {
cleanups = [];
defaultViewportSize = {
width: 1024,
height: 768
};
// NOTICE - it is discouraged to use bang (!) in general. It is used here because
// all the classes that inherit from this base assume is it mandatory.
getViewPort() {
return this.options.viewportSize ?? this.defaultViewportSize;
}
async initialize() {
await super.initialize();
debug('initialize scraper');
this.emitProgress(_definitions.ScraperProgressTypes.Initializing);
const page = await this.initializePage();
await page.setCacheEnabled(false); // Clear cache and avoid 300's response status
if (!page) {
debug('failed to initiate a browser page, exit');
return;
}
this.page = page;
this.cleanups.push(() => page.close());
if (this.options.defaultTimeout) {
this.page.setDefaultTimeout(this.options.defaultTimeout);
}
if (this.options.preparePage) {
debug("execute 'preparePage' interceptor provided in options");
await this.options.preparePage(this.page);
}
const viewport = this.getViewPort();
debug(`set viewport to width ${viewport.width}, height ${viewport.height}`);
await this.page.setViewport({
width: viewport.width,
height: viewport.height
});
this.page.on('requestfailed', request => {
debug('Request failed: %s %s', request.failure()?.errorText, request.url());
});
}
async initializePage() {
debug('initialize browser page');
if ('browserContext' in this.options) {
debug('Using the browser context provided in options');
return this.options.browserContext.newPage();
}
if ('browser' in this.options) {
debug('Using the browser instance provided in options');
const {
browser
} = this.options;
/**
* For backward compatibility, we will close the browser even if we didn't create it
*/
if (!this.options.skipCloseBrowser) {
this.cleanups.push(async () => {
debug('closing the browser');
await browser.close();
});
}
return browser.newPage();
}
const {
timeout,
args,
executablePath,
showBrowser
} = this.options;
const headless = !showBrowser;
debug(`launch a browser with headless mode = ${headless}`);
const browser = await _puppeteer.default.launch({
env: this.options.verbose ? {
DEBUG: '*',
...process.env
} : undefined,
headless,
executablePath,
args,
timeout
});
this.cleanups.push(async () => {
debug('closing the browser');
await browser.close();
});
if (this.options.prepareBrowser) {
debug("execute 'prepareBrowser' interceptor provided in options");
await this.options.prepareBrowser(browser);
}
debug('create a new browser page');
return browser.newPage();
}
async navigateTo(url, waitUntil = 'load', retries = this.options.navigationRetryCount ?? 0) {
const response = await this.page?.goto(url, {
waitUntil
});
if (response === null) {
// note: response will be null when navigating to same url while changing the hash part.
// the condition below will always accept null as valid result.
return;
}
if (!response) {
throw new Error(`Error while trying to navigate to url ${url}, response is undefined`);
}
if (!response.ok()) {
const status = response.status();
if (retries > 0) {
debug(`Failed to navigate to url ${url}, status code: ${status}, retrying ${retries} more times`);
await this.navigateTo(url, waitUntil, retries - 1);
} else {
throw new Error(`Failed to navigate to url ${url}, status code: ${status}`);
}
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getLoginOptions(_credentials) {
throw new Error(`getLoginOptions() is not created in ${this.options.companyId}`);
}
async fillInputs(pageOrFrame, fields) {
const modified = [...fields];
const input = modified.shift();
if (!input) {
return;
}
await (0, _elementsInteractions.fillInput)(pageOrFrame, input.selector, input.value);
if (modified.length) {
await this.fillInputs(pageOrFrame, modified);
}
}
async login(credentials) {
if (!credentials || !this.page) {
return createGeneralError();
}
debug('execute login process');
const loginOptions = this.getLoginOptions(credentials);
if (loginOptions.userAgent) {
debug('set custom user agent provided in options');
await this.page.setUserAgent(loginOptions.userAgent);
}
debug('navigate to login url');
await this.navigateTo(loginOptions.loginUrl, loginOptions.waitUntil);
if (loginOptions.checkReadiness) {
debug("execute 'checkReadiness' interceptor provided in login options");
await loginOptions.checkReadiness();
} else if (typeof loginOptions.submitButtonSelector === 'string') {
debug('wait until submit button is available');
await (0, _elementsInteractions.waitUntilElementFound)(this.page, loginOptions.submitButtonSelector);
}
let loginFrameOrPage = this.page;
if (loginOptions.preAction) {
debug("execute 'preAction' interceptor provided in login options");
loginFrameOrPage = (await loginOptions.preAction()) || this.page;
}
debug('fill login components input with relevant values');
await this.fillInputs(loginFrameOrPage, loginOptions.fields);
debug('click on login submit button');
if (typeof loginOptions.submitButtonSelector === 'string') {
await (0, _elementsInteractions.clickButton)(loginFrameOrPage, loginOptions.submitButtonSelector);
} else {
await loginOptions.submitButtonSelector();
}
this.emitProgress(_definitions.ScraperProgressTypes.LoggingIn);
if (loginOptions.postAction) {
debug("execute 'postAction' interceptor provided in login options");
await loginOptions.postAction();
} else {
debug('wait for page navigation');
await (0, _navigation.waitForNavigation)(this.page);
}
debug('check login result');
const current = await (0, _navigation.getCurrentUrl)(this.page, true);
const loginResult = await getKeyByValue(loginOptions.possibleResults, current, this.page);
debug(`handle login results ${loginResult}`);
return this.handleLoginResult(loginResult);
}
async terminate(_success) {
debug(`terminating browser with success = ${_success}`);
this.emitProgress(_definitions.ScraperProgressTypes.Terminating);
if (!_success && !!this.options.storeFailureScreenShotPath) {
debug(`create a snapshot before terminated in ${this.options.storeFailureScreenShotPath}`);
await this.page.screenshot({
path: this.options.storeFailureScreenShotPath,
fullPage: true
});
}
await Promise.all(this.cleanups.reverse().map(cleanup => cleanup()));
this.cleanups = [];
}
handleLoginResult(loginResult) {
switch (loginResult) {
case LoginResults.Success:
this.emitProgress(_definitions.ScraperProgressTypes.LoginSuccess);
return {
success: true
};
case LoginResults.InvalidPassword:
case LoginResults.UnknownError:
this.emitProgress(_definitions.ScraperProgressTypes.LoginFailed);
return {
success: false,
errorType: loginResult === LoginResults.InvalidPassword ? _errors.ScraperErrorTypes.InvalidPassword : _errors.ScraperErrorTypes.General,
errorMessage: `Login failed with ${loginResult} error`
};
case LoginResults.ChangePassword:
this.emitProgress(_definitions.ScraperProgressTypes.ChangePassword);
return {
success: false,
errorType: _errors.ScraperErrorTypes.ChangePassword
};
default:
throw new Error(`unexpected login result "${loginResult}"`);
}
}
}
exports.BaseScraperWithBrowser = BaseScraperWithBrowser;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcHVwcGV0ZWVyIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZGVmaW5pdGlvbnMiLCJfZGVidWciLCJfZWxlbWVudHNJbnRlcmFjdGlvbnMiLCJfbmF2aWdhdGlvbiIsIl9iYXNlU2NyYXBlciIsIl9lcnJvcnMiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJkZWJ1ZyIsImdldERlYnVnIiwiTG9naW5CYXNlUmVzdWx0cyIsIlRpbWVvdXQiLCJHZW5lcmljIiwiR2VuZXJhbCIsInJlc3QiLCJTY3JhcGVyRXJyb3JUeXBlcyIsIkxvZ2luUmVzdWx0cyIsImV4cG9ydHMiLCJnZXRLZXlCeVZhbHVlIiwib2JqZWN0IiwidmFsdWUiLCJwYWdlIiwia2V5cyIsIk9iamVjdCIsImtleSIsImNvbmRpdGlvbnMiLCJjb25kaXRpb24iLCJyZXN1bHQiLCJSZWdFeHAiLCJ0ZXN0IiwidG9Mb3dlckNhc2UiLCJQcm9taXNlIiwicmVzb2x2ZSIsIlVua25vd25FcnJvciIsImNyZWF0ZUdlbmVyYWxFcnJvciIsInN1Y2Nlc3MiLCJlcnJvclR5cGUiLCJCYXNlU2NyYXBlcldpdGhCcm93c2VyIiwiQmFzZVNjcmFwZXIiLCJjbGVhbnVwcyIsImRlZmF1bHRWaWV3cG9ydFNpemUiLCJ3aWR0aCIsImhlaWdodCIsImdldFZpZXdQb3J0Iiwib3B0aW9ucyIsInZpZXdwb3J0U2l6ZSIsImluaXRpYWxpemUiLCJlbWl0UHJvZ3Jlc3MiLCJTY3JhcGVyUHJvZ3Jlc3NUeXBlcyIsIkluaXRpYWxpemluZyIsImluaXRpYWxpemVQYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwicHVzaCIsImNsb3NlIiwiZGVmYXVsdFRpbWVvdXQiLCJzZXREZWZhdWx0VGltZW91dCIsInByZXBhcmVQYWdlIiwidmlld3BvcnQiLCJzZXRWaWV3cG9ydCIsIm9uIiwicmVxdWVzdCIsImZhaWx1cmUiLCJlcnJvclRleHQiLCJ1cmwiLCJicm93c2VyQ29udGV4dCIsIm5ld1BhZ2UiLCJicm93c2VyIiwic2tpcENsb3NlQnJvd3NlciIsInRpbWVvdXQiLCJhcmdzIiwiZXhlY3V0YWJsZVBhdGgiLCJzaG93QnJvd3NlciIsImhlYWRsZXNzIiwicHVwcGV0ZWVyIiwibGF1bmNoIiwiZW52IiwidmVyYm9zZSIsIkRFQlVHIiwicHJvY2VzcyIsInVuZGVmaW5lZCIsInByZXBhcmVCcm93c2VyIiwibmF2aWdhdGVUbyIsIndhaXRVbnRpbCIsInJldHJpZXMiLCJuYXZpZ2F0aW9uUmV0cnlDb3VudCIsInJlc3BvbnNlIiwiZ290byIsIkVycm9yIiwib2siLCJzdGF0dXMiLCJnZXRMb2dpbk9wdGlvbnMiLCJfY3JlZGVudGlhbHMiLCJjb21wYW55SWQiLCJmaWxsSW5wdXRzIiwicGFnZU9yRnJhbWUiLCJmaWVsZHMiLCJtb2RpZmllZCIsImlucHV0Iiwic2hpZnQiLCJmaWxsSW5wdXQiLCJzZWxlY3RvciIsImxlbmd0aCIsImxvZ2luIiwiY3JlZGVudGlhbHMiLCJsb2dpbk9wdGlvbnMiLCJ1c2VyQWdlbnQiLCJzZXRVc2VyQWdlbnQiLCJsb2dpblVybCIsImNoZWNrUmVhZGluZXNzIiwic3VibWl0QnV0dG9uU2VsZWN0b3IiLCJ3YWl0VW50aWxFbGVtZW50Rm91bmQiLCJsb2dpbkZyYW1lT3JQYWdlIiwicHJlQWN0aW9uIiwiY2xpY2tCdXR0b24iLCJMb2dnaW5nSW4iLCJwb3N0QWN0aW9uIiwid2FpdEZvck5hdmlnYXRpb24iLCJjdXJyZW50IiwiZ2V0Q3VycmVudFVybCIsImxvZ2luUmVzdWx0IiwicG9zc2libGVSZXN1bHRzIiwiaGFuZGxlTG9naW5SZXN1bHQiLCJ0ZXJtaW5hdGUiLCJfc3VjY2VzcyIsIlRlcm1pbmF0aW5nIiwic3RvcmVGYWlsdXJlU2NyZWVuU2hvdFBhdGgiLCJzY3JlZW5zaG90IiwicGF0aCIsImZ1bGxQYWdlIiwiYWxsIiwicmV2ZXJzZSIsIm1hcCIsImNsZWFudXAiLCJTdWNjZXNzIiwiTG9naW5TdWNjZXNzIiwiSW52YWxpZFBhc3N3b3JkIiwiTG9naW5GYWlsZWQiLCJlcnJvck1lc3NhZ2UiLCJDaGFuZ2VQYXNzd29yZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwdXBwZXRlZXIsIHsgdHlwZSBGcmFtZSwgdHlwZSBQYWdlLCB0eXBlIFB1cHBldGVlckxpZmVDeWNsZUV2ZW50IH0gZnJvbSAncHVwcGV0ZWVyJztcbmltcG9ydCB7IFNjcmFwZXJQcm9ncmVzc1R5cGVzIH0gZnJvbSAnLi4vZGVmaW5pdGlvbnMnO1xuaW1wb3J0IHsgZ2V0RGVidWcgfSBmcm9tICcuLi9oZWxwZXJzL2RlYnVnJztcbmltcG9ydCB7IGNsaWNrQnV0dG9uLCBmaWxsSW5wdXQsIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCB9IGZyb20gJy4uL2hlbHBlcnMvZWxlbWVudHMtaW50ZXJhY3Rpb25zJztcbmltcG9ydCB7IGdldEN1cnJlbnRVcmwsIHdhaXRGb3JOYXZpZ2F0aW9uIH0gZnJvbSAnLi4vaGVscGVycy9uYXZpZ2F0aW9uJztcbmltcG9ydCB7IEJhc2VTY3JhcGVyIH0gZnJvbSAnLi9iYXNlLXNjcmFwZXInO1xuaW1wb3J0IHsgU2NyYXBlckVycm9yVHlwZXMgfSBmcm9tICcuL2Vycm9ycyc7XG5pbXBvcnQgeyB0eXBlIFNjcmFwZXJDcmVkZW50aWFscywgdHlwZSBTY3JhcGVyU2NyYXBpbmdSZXN1bHQgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoJ2Jhc2Utc2NyYXBlci13aXRoLWJyb3dzZXInKTtcblxuZW51bSBMb2dpbkJhc2VSZXN1bHRzIHtcbiAgU3VjY2VzcyA9ICdTVUNDRVNTJyxcbiAgVW5rbm93bkVycm9yID0gJ1VOS05PV05fRVJST1InLFxufVxuXG5jb25zdCB7IFRpbWVvdXQsIEdlbmVyaWMsIEdlbmVyYWwsIC4uLnJlc3QgfSA9IFNjcmFwZXJFcnJvclR5cGVzO1xuZXhwb3J0IGNvbnN0IExvZ2luUmVzdWx0cyA9IHtcbiAgLi4ucmVzdCxcbiAgLi4uTG9naW5CYXNlUmVzdWx0cyxcbn07XG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVkZWNsYXJlXG5leHBvcnQgdHlwZSBMb2dpblJlc3VsdHMgPVxuICB8IEV4Y2x1ZGU8U2NyYXBlckVycm9yVHlwZXMsIFNjcmFwZXJFcnJvclR5cGVzLlRpbWVvdXQgfCBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmljIHwgU2NyYXBlckVycm9yVHlwZXMuR2VuZXJhbD5cbiAgfCBMb2dpbkJhc2VSZXN1bHRzO1xuXG5leHBvcnQgdHlwZSBQb3NzaWJsZUxvZ2luUmVzdWx0cyA9IHtcbiAgW2tleSBpbiBMb2dpblJlc3VsdHNdPzogKHN0cmluZyB8IFJlZ0V4cCB8ICgob3B0aW9ucz86IHsgcGFnZT86IFBhZ2UgfSkgPT4gUHJvbWlzZTxib29sZWFuPikpW107XG59O1xuXG5leHBvcnQgaW50ZXJmYWNlIExvZ2luT3B0aW9ucyB7XG4gIGxvZ2luVXJsOiBzdHJpbmc7XG4gIGNoZWNrUmVhZGluZXNzPzogKCkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgZmllbGRzOiB7IHNlbGVjdG9yOiBzdHJpbmc7IHZhbHVlOiBzdHJpbmcgfVtdO1xuICBzdWJtaXRCdXR0b25TZWxlY3Rvcjogc3RyaW5nIHwgKCgpID0+IFByb21pc2U8dm9pZD4pO1xuICBwcmVBY3Rpb24/OiAoKSA9PiBQcm9taXNlPEZyYW1lIHwgdm9pZD47XG4gIHBvc3RBY3Rpb24/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBwb3NzaWJsZVJlc3VsdHM6IFBvc3NpYmxlTG9naW5SZXN1bHRzO1xuICB1c2VyQWdlbnQ/OiBzdHJpbmc7XG4gIHdhaXRVbnRpbD86IFB1cHBldGVlckxpZmVDeWNsZUV2ZW50O1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZXRLZXlCeVZhbHVlKG9iamVjdDogUG9zc2libGVMb2dpblJlc3VsdHMsIHZhbHVlOiBzdHJpbmcsIHBhZ2U6IFBhZ2UpOiBQcm9taXNlPExvZ2luUmVzdWx0cz4ge1xuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMob2JqZWN0KTtcbiAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBjb25zdCBjb25kaXRpb25zID0gb2JqZWN0W2tleV07XG5cbiAgICBmb3IgKGNvbnN0IGNvbmRpdGlvbiBvZiBjb25kaXRpb25zKSB7XG4gICAgICBsZXQgcmVzdWx0ID0gZmFsc2U7XG5cbiAgICAgIGlmIChjb25kaXRpb24gaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgcmVzdWx0ID0gY29uZGl0aW9uLnRlc3QodmFsdWUpO1xuICAgICAgfSBlbHNlIGlmICh0eXBlb2YgY29uZGl0aW9uID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IGNvbmRpdGlvbih7IHBhZ2UsIHZhbHVlIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzdWx0ID0gdmFsdWUudG9Mb3dlckNhc2UoKSA9PT0gY29uZGl0aW9uLnRvTG93ZXJDYXNlKCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChyZXN1bHQpIHtcbiAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGtleSk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShMb2dpblJlc3VsdHMuVW5rbm93bkVycm9yKTtcbn1cblxuZnVuY3Rpb24gY3JlYXRlR2VuZXJhbEVycm9yKCk6IFNjcmFwZXJTY3JhcGluZ1Jlc3VsdCB7XG4gIHJldHVybiB7XG4gICAgc3VjY2VzczogZmFsc2UsXG4gICAgZXJyb3JUeXBlOiBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmFsLFxuICB9O1xufVxuXG5jbGFzcyBCYXNlU2NyYXBlcldpdGhCcm93c2VyPFRDcmVkZW50aWFscyBleHRlbmRzIFNjcmFwZXJDcmVkZW50aWFscz4gZXh0ZW5kcyBCYXNlU2NyYXBlcjxUQ3JlZGVudGlhbHM+IHtcbiAgcHJpdmF0ZSBjbGVhbnVwczogQXJyYXk8KCkgPT4gUHJvbWlzZTx2b2lkPj4gPSBbXTtcblxuICBwcml2YXRlIGRlZmF1bHRWaWV3cG9ydFNpemUgPSB7XG4gICAgd2lkdGg6IDEwMjQsXG4gICAgaGVpZ2h0OiA3NjgsXG4gIH07XG5cbiAgLy8gTk9USUNFIC0gaXQgaXMgZGlzY291cmFnZWQgdG8gdXNlIGJhbmcgKCEpIGluIGdlbmVyYWwuIEl0IGlzIHVzZWQgaGVyZSBiZWNhdXNlXG4gIC8vIGFsbCB0aGUgY2xhc3NlcyB0aGF0IGluaGVyaXQgZnJvbSB0aGlzIGJhc2UgYXNzdW1lIGlzIGl0IG1hbmRhdG9yeS5cbiAgcHJvdGVjdGVkIHBhZ2UhOiBQYWdlO1xuXG4gIHByb3RlY3RlZCBnZXRWaWV3UG9ydCgpIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLnZpZXdwb3J0U2l6ZSA/PyB0aGlzLmRlZmF1bHRWaWV3cG9ydFNpemU7XG4gIH1cblxuICBhc3luYyBpbml0aWFsaXplKCkge1xuICAgIGF3YWl0IHN1cGVyLmluaXRpYWxpemUoKTtcbiAgICBkZWJ1ZygnaW5pdGlhbGl6ZSBzY3JhcGVyJyk7XG4gICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuSW5pdGlhbGl6aW5nKTtcblxuICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCB0aGlzLmluaXRpYWxpemVQYWdlKCk7XG4gICAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpOyAvLyBDbGVhciBjYWNoZSBhbmQgYXZvaWQgMzAwJ3MgcmVzcG9uc2Ugc3RhdHVzXG5cbiAgICBpZiAoIXBhZ2UpIHtcbiAgICAgIGRlYnVnKCdmYWlsZWQgdG8gaW5pdGlhdGUgYSBicm93c2VyIHBhZ2UsIGV4aXQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnBhZ2UgPSBwYWdlO1xuXG4gICAgdGhpcy5jbGVhbnVwcy5wdXNoKCgpID0+IHBhZ2UuY2xvc2UoKSk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLmRlZmF1bHRUaW1lb3V0KSB7XG4gICAgICB0aGlzLnBhZ2Uuc2V0RGVmYXVsdFRpbWVvdXQodGhpcy5vcHRpb25zLmRlZmF1bHRUaW1lb3V0KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnByZXBhcmVQYWdlKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ3ByZXBhcmVQYWdlJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBvcHRpb25zXCIpO1xuICAgICAgYXdhaXQgdGhpcy5vcHRpb25zLnByZXBhcmVQYWdlKHRoaXMucGFnZSk7XG4gICAgfVxuXG4gICAgY29uc3Qgdmlld3BvcnQgPSB0aGlzLmdldFZpZXdQb3J0KCk7XG4gICAgZGVidWcoYHNldCB2aWV3cG9ydCB0byB3aWR0aCAke3ZpZXdwb3J0LndpZHRofSwgaGVpZ2h0ICR7dmlld3BvcnQuaGVpZ2h0fWApO1xuICAgIGF3YWl0IHRoaXMucGFnZS5zZXRWaWV3cG9ydCh7XG4gICAgICB3aWR0aDogdmlld3BvcnQud2lkdGgsXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0LmhlaWdodCxcbiAgICB9KTtcblxuICAgIHRoaXMucGFnZS5vbigncmVxdWVzdGZhaWxlZCcsIHJlcXVlc3QgPT4ge1xuICAgICAgZGVidWcoJ1JlcXVlc3QgZmFpbGVkOiAlcyAlcycsIHJlcXVlc3QuZmFpbHVyZSgpPy5lcnJvclRleHQsIHJlcXVlc3QudXJsKCkpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBpbml0aWFsaXplUGFnZSgpIHtcbiAgICBkZWJ1ZygnaW5pdGlhbGl6ZSBicm93c2VyIHBhZ2UnKTtcbiAgICBpZiAoJ2Jyb3dzZXJDb250ZXh0JyBpbiB0aGlzLm9wdGlvbnMpIHtcbiAgICAgIGRlYnVnKCdVc2luZyB0aGUgYnJvd3NlciBjb250ZXh0IHByb3ZpZGVkIGluIG9wdGlvbnMnKTtcbiAgICAgIHJldHVybiB0aGlzLm9wdGlvbnMuYnJvd3NlckNvbnRleHQubmV3UGFnZSgpO1xuICAgIH1cblxuICAgIGlmICgnYnJvd3NlcicgaW4gdGhpcy5vcHRpb25zKSB7XG4gICAgICBkZWJ1ZygnVXNpbmcgdGhlIGJyb3dzZXIgaW5zdGFuY2UgcHJvdmlkZWQgaW4gb3B0aW9ucycpO1xuICAgICAgY29uc3QgeyBicm93c2VyIH0gPSB0aGlzLm9wdGlvbnM7XG5cbiAgICAgIC8qKlxuICAgICAgICogRm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHksIHdlIHdpbGwgY2xvc2UgdGhlIGJyb3dzZXIgZXZlbiBpZiB3ZSBkaWRuJ3QgY3JlYXRlIGl0XG4gICAgICAgKi9cbiAgICAgIGlmICghdGhpcy5vcHRpb25zLnNraXBDbG9zZUJyb3dzZXIpIHtcbiAgICAgICAgdGhpcy5jbGVhbnVwcy5wdXNoKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBkZWJ1ZygnY2xvc2luZyB0aGUgYnJvd3NlcicpO1xuICAgICAgICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBicm93c2VyLm5ld1BhZ2UoKTtcbiAgICB9XG5cbiAgICBjb25zdCB7IHRpbWVvdXQsIGFyZ3MsIGV4ZWN1dGFibGVQYXRoLCBzaG93QnJvd3NlciB9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgY29uc3QgaGVhZGxlc3MgPSAhc2hvd0Jyb3dzZXI7XG4gICAgZGVidWcoYGxhdW5jaCBhIGJyb3dzZXIgd2l0aCBoZWFkbGVzcyBtb2RlID0gJHtoZWFkbGVzc31gKTtcblxuICAgIGNvbnN0IGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKHtcbiAgICAgIGVudjogdGhpcy5vcHRpb25zLnZlcmJvc2UgPyB7IERFQlVHOiAnKicsIC4uLnByb2Nlc3MuZW52IH0gOiB1bmRlZmluZWQsXG4gICAgICBoZWFkbGVzcyxcbiAgICAgIGV4ZWN1dGFibGVQYXRoLFxuICAgICAgYXJncyxcbiAgICAgIHRpbWVvdXQsXG4gICAgfSk7XG5cbiAgICB0aGlzLmNsZWFudXBzLnB1c2goYXN5bmMgKCkgPT4ge1xuICAgICAgZGVidWcoJ2Nsb3NpbmcgdGhlIGJyb3dzZXInKTtcbiAgICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgICB9KTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucHJlcGFyZUJyb3dzZXIpIHtcbiAgICAgIGRlYnVnKFwiZXhlY3V0ZSAncHJlcGFyZUJyb3dzZXInIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCB0aGlzLm9wdGlvbnMucHJlcGFyZUJyb3dzZXIoYnJvd3Nlcik7XG4gICAgfVxuXG4gICAgZGVidWcoJ2NyZWF0ZSBhIG5ldyBicm93c2VyIHBhZ2UnKTtcbiAgICByZXR1cm4gYnJvd3Nlci5uZXdQYWdlKCk7XG4gIH1cblxuICBhc3luYyBuYXZpZ2F0ZVRvKFxuICAgIHVybDogc3RyaW5nLFxuICAgIHdhaXRVbnRpbDogUHVwcGV0ZWVyTGlmZUN5Y2xlRXZlbnQgfCB1bmRlZmluZWQgPSAnbG9hZCcsXG4gICAgcmV0cmllcyA9IHRoaXMub3B0aW9ucy5uYXZpZ2F0aW9uUmV0cnlDb3VudCA/PyAwLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMucGFnZT8uZ290byh1cmwsIHsgd2FpdFVudGlsIH0pO1xuICAgIGlmIChyZXNwb25zZSA9PT0gbnVsbCkge1xuICAgICAgLy8gbm90ZTogcmVzcG9uc2Ugd2lsbCBiZSBudWxsIHdoZW4gbmF2aWdhdGluZyB0byBzYW1lIHVybCB3aGlsZSBjaGFuZ2luZyB0aGUgaGFzaCBwYXJ0LlxuICAgICAgLy8gdGhlIGNvbmRpdGlvbiBiZWxvdyB3aWxsIGFsd2F5cyBhY2NlcHQgbnVsbCBhcyB2YWxpZCByZXN1bHQuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciB3aGlsZSB0cnlpbmcgdG8gbmF2aWdhdGUgdG8gdXJsICR7dXJsfSwgcmVzcG9uc2UgaXMgdW5kZWZpbmVkYCk7XG4gICAgfVxuXG4gICAgaWYgKCFyZXNwb25zZS5vaygpKSB7XG4gICAgICBjb25zdCBzdGF0dXMgPSByZXNwb25zZS5zdGF0dXMoKTtcbiAgICAgIGlmIChyZXRyaWVzID4gMCkge1xuICAgICAgICBkZWJ1ZyhgRmFpbGVkIHRvIG5hdmlnYXRlIHRvIHVybCAke3VybH0sIHN0YXR1cyBjb2RlOiAke3N0YXR1c30sIHJldHJ5aW5nICR7cmV0cmllc30gbW9yZSB0aW1lc2ApO1xuICAgICAgICBhd2FpdCB0aGlzLm5hdmlnYXRlVG8odXJsLCB3YWl0VW50aWwsIHJldHJpZXMgLSAxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIG5hdmlnYXRlIHRvIHVybCAke3VybH0sIHN0YXR1cyBjb2RlOiAke3N0YXR1c31gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIGdldExvZ2luT3B0aW9ucyhfY3JlZGVudGlhbHM6IFNjcmFwZXJDcmVkZW50aWFscyk6IExvZ2luT3B0aW9ucyB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBnZXRMb2dpbk9wdGlvbnMoKSBpcyBub3QgY3JlYXRlZCBpbiAke3RoaXMub3B0aW9ucy5jb21wYW55SWR9YCk7XG4gIH1cblxuICBhc3luYyBmaWxsSW5wdXRzKHBhZ2VPckZyYW1lOiBQYWdlIHwgRnJhbWUsIGZpZWxkczogeyBzZWxlY3Rvcjogc3RyaW5nOyB2YWx1ZTogc3RyaW5nIH1bXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1vZGlmaWVkID0gWy4uLmZpZWxkc107XG4gICAgY29uc3QgaW5wdXQgPSBtb2RpZmllZC5zaGlmdCgpO1xuXG4gICAgaWYgKCFpbnB1dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBmaWxsSW5wdXQocGFnZU9yRnJhbWUsIGlucHV0LnNlbGVjdG9yLCBpbnB1dC52YWx1ZSk7XG4gICAgaWYgKG1vZGlmaWVkLmxlbmd0aCkge1xuICAgICAgYXdhaXQgdGhpcy5maWxsSW5wdXRzKHBhZ2VPckZyYW1lLCBtb2RpZmllZCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgbG9naW4oY3JlZGVudGlhbHM6IFNjcmFwZXJDcmVkZW50aWFscyk6IFByb21pc2U8U2NyYXBlclNjcmFwaW5nUmVzdWx0PiB7XG4gICAgaWYgKCFjcmVkZW50aWFscyB8fCAhdGhpcy5wYWdlKSB7XG4gICAgICByZXR1cm4gY3JlYXRlR2VuZXJhbEVycm9yKCk7XG4gICAgfVxuXG4gICAgZGVidWcoJ2V4ZWN1dGUgbG9naW4gcHJvY2VzcycpO1xuICAgIGNvbnN0IGxvZ2luT3B0aW9ucyA9IHRoaXMuZ2V0TG9naW5PcHRpb25zKGNyZWRlbnRpYWxzKTtcblxuICAgIGlmIChsb2dpbk9wdGlvbnMudXNlckFnZW50KSB7XG4gICAgICBkZWJ1Zygnc2V0IGN1c3RvbSB1c2VyIGFnZW50IHByb3ZpZGVkIGluIG9wdGlvbnMnKTtcbiAgICAgIGF3YWl0IHRoaXMucGFnZS5zZXRVc2VyQWdlbnQobG9naW5PcHRpb25zLnVzZXJBZ2VudCk7XG4gICAgfVxuXG4gICAgZGVidWcoJ25hdmlnYXRlIHRvIGxvZ2luIHVybCcpO1xuICAgIGF3YWl0IHRoaXMubmF2aWdhdGVUbyhsb2dpbk9wdGlvbnMubG9naW5VcmwsIGxvZ2luT3B0aW9ucy53YWl0VW50aWwpO1xuICAgIGlmIChsb2dpbk9wdGlvbnMuY2hlY2tSZWFkaW5lc3MpIHtcbiAgICAgIGRlYnVnKFwiZXhlY3V0ZSAnY2hlY2tSZWFkaW5lc3MnIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCBsb2dpbk9wdGlvbnMuY2hlY2tSZWFkaW5lc3MoKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBsb2dpbk9wdGlvbnMuc3VibWl0QnV0dG9uU2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICBkZWJ1Zygnd2FpdCB1bnRpbCBzdWJtaXQgYnV0dG9uIGlzIGF2YWlsYWJsZScpO1xuICAgICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHRoaXMucGFnZSwgbG9naW5PcHRpb25zLnN1Ym1pdEJ1dHRvblNlbGVjdG9yKTtcbiAgICB9XG5cbiAgICBsZXQgbG9naW5GcmFtZU9yUGFnZTogUGFnZSB8IEZyYW1lIHwgbnVsbCA9IHRoaXMucGFnZTtcbiAgICBpZiAobG9naW5PcHRpb25zLnByZUFjdGlvbikge1xuICAgICAgZGVidWcoXCJleGVjdXRlICdwcmVBY3Rpb24nIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBsb2dpbkZyYW1lT3JQYWdlID0gKGF3YWl0IGxvZ2luT3B0aW9ucy5wcmVBY3Rpb24oKSkgfHwgdGhpcy5wYWdlO1xuICAgIH1cblxuICAgIGRlYnVnKCdmaWxsIGxvZ2luIGNvbXBvbmVudHMgaW5wdXQgd2l0aCByZWxldmFudCB2YWx1ZXMnKTtcbiAgICBhd2FpdCB0aGlzLmZpbGxJbnB1dHMobG9naW5GcmFtZU9yUGFnZSwgbG9naW5PcHRpb25zLmZpZWxkcyk7XG4gICAgZGVidWcoJ2NsaWNrIG9uIGxvZ2luIHN1Ym1pdCBidXR0b24nKTtcbiAgICBpZiAodHlwZW9mIGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3RvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGF3YWl0IGNsaWNrQnV0dG9uKGxvZ2luRnJhbWVPclBhZ2UsIGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3Rvcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3RvcigpO1xuICAgIH1cbiAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5Mb2dnaW5nSW4pO1xuXG4gICAgaWYgKGxvZ2luT3B0aW9ucy5wb3N0QWN0aW9uKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ3Bvc3RBY3Rpb24nIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCBsb2dpbk9wdGlvbnMucG9zdEFjdGlvbigpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1Zygnd2FpdCBmb3IgcGFnZSBuYXZpZ2F0aW9uJyk7XG4gICAgICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbih0aGlzLnBhZ2UpO1xuICAgIH1cblxuICAgIGRlYnVnKCdjaGVjayBsb2dpbiByZXN1bHQnKTtcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgZ2V0Q3VycmVudFVybCh0aGlzLnBhZ2UsIHRydWUpO1xuICAgIGNvbnN0IGxvZ2luUmVzdWx0ID0gYXdhaXQgZ2V0S2V5QnlWYWx1ZShsb2dpbk9wdGlvbnMucG9zc2libGVSZXN1bHRzLCBjdXJyZW50LCB0aGlzLnBhZ2UpO1xuICAgIGRlYnVnKGBoYW5kbGUgbG9naW4gcmVzdWx0cyAke2xvZ2luUmVzdWx0fWApO1xuICAgIHJldHVybiB0aGlzLmhhbmRsZUxvZ2luUmVzdWx0KGxvZ2luUmVzdWx0KTtcbiAgfVxuXG4gIGFzeW5jIHRlcm1pbmF0ZShfc3VjY2VzczogYm9vbGVhbikge1xuICAgIGRlYnVnKGB0ZXJtaW5hdGluZyBicm93c2VyIHdpdGggc3VjY2VzcyA9ICR7X3N1Y2Nlc3N9YCk7XG4gICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuVGVybWluYXRpbmcpO1xuXG4gICAgaWYgKCFfc3VjY2VzcyAmJiAhIXRoaXMub3B0aW9ucy5zdG9yZUZhaWx1cmVTY3JlZW5TaG90UGF0aCkge1xuICAgICAgZGVidWcoYGNyZWF0ZSBhIHNuYXBzaG90IGJlZm9yZSB0ZXJtaW5hdGVkIGluICR7dGhpcy5vcHRpb25zLnN0b3JlRmFpbHVyZVNjcmVlblNob3RQYXRofWApO1xuICAgICAgYXdhaXQgdGhpcy5wYWdlLnNjcmVlbnNob3Qoe1xuICAgICAgICBwYXRoOiB0aGlzLm9wdGlvbnMuc3RvcmVGYWlsdXJlU2NyZWVuU2hvdFBhdGgsXG4gICAgICAgIGZ1bGxQYWdlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5jbGVhbnVwcy5yZXZlcnNlKCkubWFwKGNsZWFudXAgPT4gY2xlYW51cCgpKSk7XG4gICAgdGhpcy5jbGVhbnVwcyA9IFtdO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVMb2dpblJlc3VsdChsb2dpblJlc3VsdDogTG9naW5SZXN1bHRzKSB7XG4gICAgc3dpdGNoIChsb2dpblJlc3VsdCkge1xuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuU3VjY2VzczpcbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuTG9naW5TdWNjZXNzKTtcbiAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkOlxuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuVW5rbm93bkVycm9yOlxuICAgICAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5Mb2dpbkZhaWxlZCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3JUeXBlOlxuICAgICAgICAgICAgbG9naW5SZXN1bHQgPT09IExvZ2luUmVzdWx0cy5JbnZhbGlkUGFzc3dvcmRcbiAgICAgICAgICAgICAgPyBTY3JhcGVyRXJyb3JUeXBlcy5JbnZhbGlkUGFzc3dvcmRcbiAgICAgICAgICAgICAgOiBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmFsLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogYExvZ2luIGZhaWxlZCB3aXRoICR7bG9naW5SZXN1bHR9IGVycm9yYCxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgTG9naW5SZXN1bHRzLkNoYW5nZVBhc3N3b3JkOlxuICAgICAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5DaGFuZ2VQYXNzd29yZCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3JUeXBlOiBTY3JhcGVyRXJyb3JUeXBlcy5DaGFuZ2VQYXNzd29yZCxcbiAgICAgICAgfTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBsb2dpbiByZXN1bHQgXCIke2xvZ2luUmVzdWx0fVwiYCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCB7IEJhc2VTY3JhcGVyV2l0aEJyb3dzZXIgfTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBQUEsVUFBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsWUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsTUFBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcscUJBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFdBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLFlBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLE9BQUEsR0FBQU4sT0FBQTtBQUE2QyxTQUFBRCx1QkFBQVEsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUc3QyxNQUFNRyxLQUFLLEdBQUcsSUFBQUMsZUFBUSxFQUFDLDJCQUEyQixDQUFDO0FBQUMsSUFFL0NDLGdCQUFnQiwwQkFBaEJBLGdCQUFnQjtFQUFoQkEsZ0JBQWdCO0VBQWhCQSxnQkFBZ0I7RUFBQSxPQUFoQkEsZ0JBQWdCO0FBQUEsRUFBaEJBLGdCQUFnQjtBQUtyQixNQUFNO0VBQUVDLE9BQU87RUFBRUMsT0FBTztFQUFFQyxPQUFPO0VBQUUsR0FBR0M7QUFBSyxDQUFDLEdBQUdDLHlCQUFpQjtBQUN6RCxNQUFNQyxZQUFZLEdBQUFDLE9BQUEsQ0FBQUQsWUFB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