UNPKG

israeli-bank-scrapers-core

Version:

Provide scrapers for all major Israeli banks and credit card companies

291 lines (283 loc) 39 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LoginResults = exports.BaseScraperWithBrowser = void 0; var _puppeteerCore = _interopRequireDefault(require("puppeteer-core")); 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 }; } async function safeCleanup(cleanup) { try { await cleanup(); } catch (e) { debug('Cleanup function failed', e); } } 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 _puppeteerCore.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(safeCleanup)); 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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcHVwcGV0ZWVyQ29yZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2RlZmluaXRpb25zIiwiX2RlYnVnIiwiX2VsZW1lbnRzSW50ZXJhY3Rpb25zIiwiX25hdmlnYXRpb24iLCJfYmFzZVNjcmFwZXIiLCJfZXJyb3JzIiwiZSIsIl9fZXNNb2R1bGUiLCJkZWZhdWx0IiwiZGVidWciLCJnZXREZWJ1ZyIsIkxvZ2luQmFzZVJlc3VsdHMiLCJUaW1lb3V0IiwiR2VuZXJpYyIsIkdlbmVyYWwiLCJyZXN0IiwiU2NyYXBlckVycm9yVHlwZXMiLCJMb2dpblJlc3VsdHMiLCJleHBvcnRzIiwiZ2V0S2V5QnlWYWx1ZSIsIm9iamVjdCIsInZhbHVlIiwicGFnZSIsImtleXMiLCJPYmplY3QiLCJrZXkiLCJjb25kaXRpb25zIiwiY29uZGl0aW9uIiwicmVzdWx0IiwiUmVnRXhwIiwidGVzdCIsInRvTG93ZXJDYXNlIiwiUHJvbWlzZSIsInJlc29sdmUiLCJVbmtub3duRXJyb3IiLCJjcmVhdGVHZW5lcmFsRXJyb3IiLCJzdWNjZXNzIiwiZXJyb3JUeXBlIiwic2FmZUNsZWFudXAiLCJjbGVhbnVwIiwiQmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsIkJhc2VTY3JhcGVyIiwiY2xlYW51cHMiLCJkZWZhdWx0Vmlld3BvcnRTaXplIiwid2lkdGgiLCJoZWlnaHQiLCJnZXRWaWV3UG9ydCIsIm9wdGlvbnMiLCJ2aWV3cG9ydFNpemUiLCJpbml0aWFsaXplIiwiZW1pdFByb2dyZXNzIiwiU2NyYXBlclByb2dyZXNzVHlwZXMiLCJJbml0aWFsaXppbmciLCJpbml0aWFsaXplUGFnZSIsInNldENhY2hlRW5hYmxlZCIsInB1c2giLCJjbG9zZSIsImRlZmF1bHRUaW1lb3V0Iiwic2V0RGVmYXVsdFRpbWVvdXQiLCJwcmVwYXJlUGFnZSIsInZpZXdwb3J0Iiwic2V0Vmlld3BvcnQiLCJvbiIsInJlcXVlc3QiLCJmYWlsdXJlIiwiZXJyb3JUZXh0IiwidXJsIiwiYnJvd3NlckNvbnRleHQiLCJuZXdQYWdlIiwiYnJvd3NlciIsInNraXBDbG9zZUJyb3dzZXIiLCJ0aW1lb3V0IiwiYXJncyIsImV4ZWN1dGFibGVQYXRoIiwic2hvd0Jyb3dzZXIiLCJoZWFkbGVzcyIsInB1cHBldGVlciIsImxhdW5jaCIsImVudiIsInZlcmJvc2UiLCJERUJVRyIsInByb2Nlc3MiLCJ1bmRlZmluZWQiLCJwcmVwYXJlQnJvd3NlciIsIm5hdmlnYXRlVG8iLCJ3YWl0VW50aWwiLCJyZXRyaWVzIiwibmF2aWdhdGlvblJldHJ5Q291bnQiLCJyZXNwb25zZSIsImdvdG8iLCJFcnJvciIsIm9rIiwic3RhdHVzIiwiZ2V0TG9naW5PcHRpb25zIiwiX2NyZWRlbnRpYWxzIiwiY29tcGFueUlkIiwiZmlsbElucHV0cyIsInBhZ2VPckZyYW1lIiwiZmllbGRzIiwibW9kaWZpZWQiLCJpbnB1dCIsInNoaWZ0IiwiZmlsbElucHV0Iiwic2VsZWN0b3IiLCJsZW5ndGgiLCJsb2dpbiIsImNyZWRlbnRpYWxzIiwibG9naW5PcHRpb25zIiwidXNlckFnZW50Iiwic2V0VXNlckFnZW50IiwibG9naW5VcmwiLCJjaGVja1JlYWRpbmVzcyIsInN1Ym1pdEJ1dHRvblNlbGVjdG9yIiwid2FpdFVudGlsRWxlbWVudEZvdW5kIiwibG9naW5GcmFtZU9yUGFnZSIsInByZUFjdGlvbiIsImNsaWNrQnV0dG9uIiwiTG9nZ2luZ0luIiwicG9zdEFjdGlvbiIsIndhaXRGb3JOYXZpZ2F0aW9uIiwiY3VycmVudCIsImdldEN1cnJlbnRVcmwiLCJsb2dpblJlc3VsdCIsInBvc3NpYmxlUmVzdWx0cyIsImhhbmRsZUxvZ2luUmVzdWx0IiwidGVybWluYXRlIiwiX3N1Y2Nlc3MiLCJUZXJtaW5hdGluZyIsInN0b3JlRmFpbHVyZVNjcmVlblNob3RQYXRoIiwic2NyZWVuc2hvdCIsInBhdGgiLCJmdWxsUGFnZSIsImFsbCIsInJldmVyc2UiLCJtYXAiLCJTdWNjZXNzIiwiTG9naW5TdWNjZXNzIiwiSW52YWxpZFBhc3N3b3JkIiwiTG9naW5GYWlsZWQiLCJlcnJvck1lc3NhZ2UiLCJDaGFuZ2VQYXNzd29yZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwdXBwZXRlZXIsIHsgdHlwZSBGcmFtZSwgdHlwZSBQYWdlLCB0eXBlIFB1cHBldGVlckxpZmVDeWNsZUV2ZW50IH0gZnJvbSAncHVwcGV0ZWVyLWNvcmUnO1xuaW1wb3J0IHsgU2NyYXBlclByb2dyZXNzVHlwZXMgfSBmcm9tICcuLi9kZWZpbml0aW9ucyc7XG5pbXBvcnQgeyBnZXREZWJ1ZyB9IGZyb20gJy4uL2hlbHBlcnMvZGVidWcnO1xuaW1wb3J0IHsgY2xpY2tCdXR0b24sIGZpbGxJbnB1dCwgd2FpdFVudGlsRWxlbWVudEZvdW5kIH0gZnJvbSAnLi4vaGVscGVycy9lbGVtZW50cy1pbnRlcmFjdGlvbnMnO1xuaW1wb3J0IHsgZ2V0Q3VycmVudFVybCwgd2FpdEZvck5hdmlnYXRpb24gfSBmcm9tICcuLi9oZWxwZXJzL25hdmlnYXRpb24nO1xuaW1wb3J0IHsgQmFzZVNjcmFwZXIgfSBmcm9tICcuL2Jhc2Utc2NyYXBlcic7XG5pbXBvcnQgeyBTY3JhcGVyRXJyb3JUeXBlcyB9IGZyb20gJy4vZXJyb3JzJztcbmltcG9ydCB7IHR5cGUgU2NyYXBlckNyZWRlbnRpYWxzLCB0eXBlIFNjcmFwZXJTY3JhcGluZ1Jlc3VsdCB9IGZyb20gJy4vaW50ZXJmYWNlJztcblxuY29uc3QgZGVidWcgPSBnZXREZWJ1ZygnYmFzZS1zY3JhcGVyLXdpdGgtYnJvd3NlcicpO1xuXG5lbnVtIExvZ2luQmFzZVJlc3VsdHMge1xuICBTdWNjZXNzID0gJ1NVQ0NFU1MnLFxuICBVbmtub3duRXJyb3IgPSAnVU5LTk9XTl9FUlJPUicsXG59XG5cbmNvbnN0IHsgVGltZW91dCwgR2VuZXJpYywgR2VuZXJhbCwgLi4ucmVzdCB9ID0gU2NyYXBlckVycm9yVHlwZXM7XG5leHBvcnQgY29uc3QgTG9naW5SZXN1bHRzID0ge1xuICAuLi5yZXN0LFxuICAuLi5Mb2dpbkJhc2VSZXN1bHRzLFxufTtcblxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1yZWRlY2xhcmVcbmV4cG9ydCB0eXBlIExvZ2luUmVzdWx0cyA9XG4gIHwgRXhjbHVkZTxTY3JhcGVyRXJyb3JUeXBlcywgU2NyYXBlckVycm9yVHlwZXMuVGltZW91dCB8IFNjcmFwZXJFcnJvclR5cGVzLkdlbmVyaWMgfCBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmFsPlxuICB8IExvZ2luQmFzZVJlc3VsdHM7XG5cbmV4cG9ydCB0eXBlIFBvc3NpYmxlTG9naW5SZXN1bHRzID0ge1xuICBba2V5IGluIExvZ2luUmVzdWx0c10/OiAoc3RyaW5nIHwgUmVnRXhwIHwgKChvcHRpb25zPzogeyBwYWdlPzogUGFnZSB9KSA9PiBQcm9taXNlPGJvb2xlYW4+KSlbXTtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5PcHRpb25zIHtcbiAgbG9naW5Vcmw6IHN0cmluZztcbiAgY2hlY2tSZWFkaW5lc3M/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBmaWVsZHM6IHsgc2VsZWN0b3I6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W107XG4gIHN1Ym1pdEJ1dHRvblNlbGVjdG9yOiBzdHJpbmcgfCAoKCkgPT4gUHJvbWlzZTx2b2lkPik7XG4gIHByZUFjdGlvbj86ICgpID0+IFByb21pc2U8RnJhbWUgfCB2b2lkPjtcbiAgcG9zdEFjdGlvbj86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHBvc3NpYmxlUmVzdWx0czogUG9zc2libGVMb2dpblJlc3VsdHM7XG4gIHVzZXJBZ2VudD86IHN0cmluZztcbiAgd2FpdFVudGlsPzogUHVwcGV0ZWVyTGlmZUN5Y2xlRXZlbnQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEtleUJ5VmFsdWUob2JqZWN0OiBQb3NzaWJsZUxvZ2luUmVzdWx0cywgdmFsdWU6IHN0cmluZywgcGFnZTogUGFnZSk6IFByb21pc2U8TG9naW5SZXN1bHRzPiB7XG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhvYmplY3QpO1xuICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSBvYmplY3Rba2V5XTtcblxuICAgIGZvciAoY29uc3QgY29uZGl0aW9uIG9mIGNvbmRpdGlvbnMpIHtcbiAgICAgIGxldCByZXN1bHQgPSBmYWxzZTtcblxuICAgICAgaWYgKGNvbmRpdGlvbiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICByZXN1bHQgPSBjb25kaXRpb24udGVzdCh2YWx1ZSk7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBjb25kaXRpb24gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgY29uZGl0aW9uKHsgcGFnZSwgdmFsdWUgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgPSB2YWx1ZS50b0xvd2VyQ2FzZSgpID09PSBjb25kaXRpb24udG9Mb3dlckNhc2UoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKExvZ2luUmVzdWx0cy5Vbmtub3duRXJyb3IpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVHZW5lcmFsRXJyb3IoKTogU2NyYXBlclNjcmFwaW5nUmVzdWx0IHtcbiAgcmV0dXJuIHtcbiAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICBlcnJvclR5cGU6IFNjcmFwZXJFcnJvclR5cGVzLkdlbmVyYWwsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNhZmVDbGVhbnVwKGNsZWFudXA6ICgpID0+IFByb21pc2U8dm9pZD4pIHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBjbGVhbnVwKCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBkZWJ1ZygnQ2xlYW51cCBmdW5jdGlvbiBmYWlsZWQnLCBlKTtcbiAgfVxufVxuXG5jbGFzcyBCYXNlU2NyYXBlcldpdGhCcm93c2VyPFRDcmVkZW50aWFscyBleHRlbmRzIFNjcmFwZXJDcmVkZW50aWFscz4gZXh0ZW5kcyBCYXNlU2NyYXBlcjxUQ3JlZGVudGlhbHM+IHtcbiAgcHJpdmF0ZSBjbGVhbnVwczogQXJyYXk8KCkgPT4gUHJvbWlzZTx2b2lkPj4gPSBbXTtcblxuICBwcml2YXRlIGRlZmF1bHRWaWV3cG9ydFNpemUgPSB7XG4gICAgd2lkdGg6IDEwMjQsXG4gICAgaGVpZ2h0OiA3NjgsXG4gIH07XG5cbiAgLy8gTk9USUNFIC0gaXQgaXMgZGlzY291cmFnZWQgdG8gdXNlIGJhbmcgKCEpIGluIGdlbmVyYWwuIEl0IGlzIHVzZWQgaGVyZSBiZWNhdXNlXG4gIC8vIGFsbCB0aGUgY2xhc3NlcyB0aGF0IGluaGVyaXQgZnJvbSB0aGlzIGJhc2UgYXNzdW1lIGlzIGl0IG1hbmRhdG9yeS5cbiAgcHJvdGVjdGVkIHBhZ2UhOiBQYWdlO1xuXG4gIHByb3RlY3RlZCBnZXRWaWV3UG9ydCgpIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLnZpZXdwb3J0U2l6ZSA/PyB0aGlzLmRlZmF1bHRWaWV3cG9ydFNpemU7XG4gIH1cblxuICBhc3luYyBpbml0aWFsaXplKCkge1xuICAgIGF3YWl0IHN1cGVyLmluaXRpYWxpemUoKTtcbiAgICBkZWJ1ZygnaW5pdGlhbGl6ZSBzY3JhcGVyJyk7XG4gICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuSW5pdGlhbGl6aW5nKTtcblxuICAgIGNvbnN0IHBhZ2UgPSBhd2FpdCB0aGlzLmluaXRpYWxpemVQYWdlKCk7XG4gICAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpOyAvLyBDbGVhciBjYWNoZSBhbmQgYXZvaWQgMzAwJ3MgcmVzcG9uc2Ugc3RhdHVzXG5cbiAgICBpZiAoIXBhZ2UpIHtcbiAgICAgIGRlYnVnKCdmYWlsZWQgdG8gaW5pdGlhdGUgYSBicm93c2VyIHBhZ2UsIGV4aXQnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnBhZ2UgPSBwYWdlO1xuXG4gICAgdGhpcy5jbGVhbnVwcy5wdXNoKCgpID0+IHBhZ2UuY2xvc2UoKSk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLmRlZmF1bHRUaW1lb3V0KSB7XG4gICAgICB0aGlzLnBhZ2Uuc2V0RGVmYXVsdFRpbWVvdXQodGhpcy5vcHRpb25zLmRlZmF1bHRUaW1lb3V0KTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnByZXBhcmVQYWdlKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ3ByZXBhcmVQYWdlJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBvcHRpb25zXCIpO1xuICAgICAgYXdhaXQgdGhpcy5vcHRpb25zLnByZXBhcmVQYWdlKHRoaXMucGFnZSk7XG4gICAgfVxuXG4gICAgY29uc3Qgdmlld3BvcnQgPSB0aGlzLmdldFZpZXdQb3J0KCk7XG4gICAgZGVidWcoYHNldCB2aWV3cG9ydCB0byB3aWR0aCAke3ZpZXdwb3J0LndpZHRofSwgaGVpZ2h0ICR7dmlld3BvcnQuaGVpZ2h0fWApO1xuICAgIGF3YWl0IHRoaXMucGFnZS5zZXRWaWV3cG9ydCh7XG4gICAgICB3aWR0aDogdmlld3BvcnQud2lkdGgsXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0LmhlaWdodCxcbiAgICB9KTtcblxuICAgIHRoaXMucGFnZS5vbigncmVxdWVzdGZhaWxlZCcsIHJlcXVlc3QgPT4ge1xuICAgICAgZGVidWcoJ1JlcXVlc3QgZmFpbGVkOiAlcyAlcycsIHJlcXVlc3QuZmFpbHVyZSgpPy5lcnJvclRleHQsIHJlcXVlc3QudXJsKCkpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBpbml0aWFsaXplUGFnZSgpIHtcbiAgICBkZWJ1ZygnaW5pdGlhbGl6ZSBicm93c2VyIHBhZ2UnKTtcbiAgICBpZiAoJ2Jyb3dzZXJDb250ZXh0JyBpbiB0aGlzLm9wdGlvbnMpIHtcbiAgICAgIGRlYnVnKCdVc2luZyB0aGUgYnJvd3NlciBjb250ZXh0IHByb3ZpZGVkIGluIG9wdGlvbnMnKTtcbiAgICAgIHJldHVybiB0aGlzLm9wdGlvbnMuYnJvd3NlckNvbnRleHQubmV3UGFnZSgpO1xuICAgIH1cblxuICAgIGlmICgnYnJvd3NlcicgaW4gdGhpcy5vcHRpb25zKSB7XG4gICAgICBkZWJ1ZygnVXNpbmcgdGhlIGJyb3dzZXIgaW5zdGFuY2UgcHJvdmlkZWQgaW4gb3B0aW9ucycpO1xuICAgICAgY29uc3QgeyBicm93c2VyIH0gPSB0aGlzLm9wdGlvbnM7XG5cbiAgICAgIC8qKlxuICAgICAgICogRm9yIGJhY2t3YXJkIGNvbXBhdGliaWxpdHksIHdlIHdpbGwgY2xvc2UgdGhlIGJyb3dzZXIgZXZlbiBpZiB3ZSBkaWRuJ3QgY3JlYXRlIGl0XG4gICAgICAgKi9cbiAgICAgIGlmICghdGhpcy5vcHRpb25zLnNraXBDbG9zZUJyb3dzZXIpIHtcbiAgICAgICAgdGhpcy5jbGVhbnVwcy5wdXNoKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBkZWJ1ZygnY2xvc2luZyB0aGUgYnJvd3NlcicpO1xuICAgICAgICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBicm93c2VyLm5ld1BhZ2UoKTtcbiAgICB9XG5cbiAgICBjb25zdCB7IHRpbWVvdXQsIGFyZ3MsIGV4ZWN1dGFibGVQYXRoLCBzaG93QnJvd3NlciB9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgY29uc3QgaGVhZGxlc3MgPSAhc2hvd0Jyb3dzZXI7XG4gICAgZGVidWcoYGxhdW5jaCBhIGJyb3dzZXIgd2l0aCBoZWFkbGVzcyBtb2RlID0gJHtoZWFkbGVzc31gKTtcblxuICAgIGNvbnN0IGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKHtcbiAgICAgIGVudjogdGhpcy5vcHRpb25zLnZlcmJvc2UgPyB7IERFQlVHOiAnKicsIC4uLnByb2Nlc3MuZW52IH0gOiB1bmRlZmluZWQsXG4gICAgICBoZWFkbGVzcyxcbiAgICAgIGV4ZWN1dGFibGVQYXRoLFxuICAgICAgYXJncyxcbiAgICAgIHRpbWVvdXQsXG4gICAgfSk7XG5cbiAgICB0aGlzLmNsZWFudXBzLnB1c2goYXN5bmMgKCkgPT4ge1xuICAgICAgZGVidWcoJ2Nsb3NpbmcgdGhlIGJyb3dzZXInKTtcbiAgICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgICB9KTtcblxuICAgIGlmICh0aGlzLm9wdGlvbnMucHJlcGFyZUJyb3dzZXIpIHtcbiAgICAgIGRlYnVnKFwiZXhlY3V0ZSAncHJlcGFyZUJyb3dzZXInIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCB0aGlzLm9wdGlvbnMucHJlcGFyZUJyb3dzZXIoYnJvd3Nlcik7XG4gICAgfVxuXG4gICAgZGVidWcoJ2NyZWF0ZSBhIG5ldyBicm93c2VyIHBhZ2UnKTtcbiAgICByZXR1cm4gYnJvd3Nlci5uZXdQYWdlKCk7XG4gIH1cblxuICBhc3luYyBuYXZpZ2F0ZVRvKFxuICAgIHVybDogc3RyaW5nLFxuICAgIHdhaXRVbnRpbDogUHVwcGV0ZWVyTGlmZUN5Y2xlRXZlbnQgfCB1bmRlZmluZWQgPSAnbG9hZCcsXG4gICAgcmV0cmllcyA9IHRoaXMub3B0aW9ucy5uYXZpZ2F0aW9uUmV0cnlDb3VudCA/PyAwLFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMucGFnZT8uZ290byh1cmwsIHsgd2FpdFVudGlsIH0pO1xuICAgIGlmIChyZXNwb25zZSA9PT0gbnVsbCkge1xuICAgICAgLy8gbm90ZTogcmVzcG9uc2Ugd2lsbCBiZSBudWxsIHdoZW4gbmF2aWdhdGluZyB0byBzYW1lIHVybCB3aGlsZSBjaGFuZ2luZyB0aGUgaGFzaCBwYXJ0LlxuICAgICAgLy8gdGhlIGNvbmRpdGlvbiBiZWxvdyB3aWxsIGFsd2F5cyBhY2NlcHQgbnVsbCBhcyB2YWxpZCByZXN1bHQuXG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciB3aGlsZSB0cnlpbmcgdG8gbmF2aWdhdGUgdG8gdXJsICR7dXJsfSwgcmVzcG9uc2UgaXMgdW5kZWZpbmVkYCk7XG4gICAgfVxuXG4gICAgaWYgKCFyZXNwb25zZS5vaygpKSB7XG4gICAgICBjb25zdCBzdGF0dXMgPSByZXNwb25zZS5zdGF0dXMoKTtcbiAgICAgIGlmIChyZXRyaWVzID4gMCkge1xuICAgICAgICBkZWJ1ZyhgRmFpbGVkIHRvIG5hdmlnYXRlIHRvIHVybCAke3VybH0sIHN0YXR1cyBjb2RlOiAke3N0YXR1c30sIHJldHJ5aW5nICR7cmV0cmllc30gbW9yZSB0aW1lc2ApO1xuICAgICAgICBhd2FpdCB0aGlzLm5hdmlnYXRlVG8odXJsLCB3YWl0VW50aWwsIHJldHJpZXMgLSAxKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIG5hdmlnYXRlIHRvIHVybCAke3VybH0sIHN0YXR1cyBjb2RlOiAke3N0YXR1c31gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzXG4gIGdldExvZ2luT3B0aW9ucyhfY3JlZGVudGlhbHM6IFNjcmFwZXJDcmVkZW50aWFscyk6IExvZ2luT3B0aW9ucyB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGBnZXRMb2dpbk9wdGlvbnMoKSBpcyBub3QgY3JlYXRlZCBpbiAke3RoaXMub3B0aW9ucy5jb21wYW55SWR9YCk7XG4gIH1cblxuICBhc3luYyBmaWxsSW5wdXRzKHBhZ2VPckZyYW1lOiBQYWdlIHwgRnJhbWUsIGZpZWxkczogeyBzZWxlY3Rvcjogc3RyaW5nOyB2YWx1ZTogc3RyaW5nIH1bXSk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IG1vZGlmaWVkID0gWy4uLmZpZWxkc107XG4gICAgY29uc3QgaW5wdXQgPSBtb2RpZmllZC5zaGlmdCgpO1xuXG4gICAgaWYgKCFpbnB1dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBhd2FpdCBmaWxsSW5wdXQocGFnZU9yRnJhbWUsIGlucHV0LnNlbGVjdG9yLCBpbnB1dC52YWx1ZSk7XG4gICAgaWYgKG1vZGlmaWVkLmxlbmd0aCkge1xuICAgICAgYXdhaXQgdGhpcy5maWxsSW5wdXRzKHBhZ2VPckZyYW1lLCBtb2RpZmllZCk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgbG9naW4oY3JlZGVudGlhbHM6IFNjcmFwZXJDcmVkZW50aWFscyk6IFByb21pc2U8U2NyYXBlclNjcmFwaW5nUmVzdWx0PiB7XG4gICAgaWYgKCFjcmVkZW50aWFscyB8fCAhdGhpcy5wYWdlKSB7XG4gICAgICByZXR1cm4gY3JlYXRlR2VuZXJhbEVycm9yKCk7XG4gICAgfVxuXG4gICAgZGVidWcoJ2V4ZWN1dGUgbG9naW4gcHJvY2VzcycpO1xuICAgIGNvbnN0IGxvZ2luT3B0aW9ucyA9IHRoaXMuZ2V0TG9naW5PcHRpb25zKGNyZWRlbnRpYWxzKTtcblxuICAgIGlmIChsb2dpbk9wdGlvbnMudXNlckFnZW50KSB7XG4gICAgICBkZWJ1Zygnc2V0IGN1c3RvbSB1c2VyIGFnZW50IHByb3ZpZGVkIGluIG9wdGlvbnMnKTtcbiAgICAgIGF3YWl0IHRoaXMucGFnZS5zZXRVc2VyQWdlbnQobG9naW5PcHRpb25zLnVzZXJBZ2VudCk7XG4gICAgfVxuXG4gICAgZGVidWcoJ25hdmlnYXRlIHRvIGxvZ2luIHVybCcpO1xuICAgIGF3YWl0IHRoaXMubmF2aWdhdGVUbyhsb2dpbk9wdGlvbnMubG9naW5VcmwsIGxvZ2luT3B0aW9ucy53YWl0VW50aWwpO1xuICAgIGlmIChsb2dpbk9wdGlvbnMuY2hlY2tSZWFkaW5lc3MpIHtcbiAgICAgIGRlYnVnKFwiZXhlY3V0ZSAnY2hlY2tSZWFkaW5lc3MnIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCBsb2dpbk9wdGlvbnMuY2hlY2tSZWFkaW5lc3MoKTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBsb2dpbk9wdGlvbnMuc3VibWl0QnV0dG9uU2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICBkZWJ1Zygnd2FpdCB1bnRpbCBzdWJtaXQgYnV0dG9uIGlzIGF2YWlsYWJsZScpO1xuICAgICAgYXdhaXQgd2FpdFVudGlsRWxlbWVudEZvdW5kKHRoaXMucGFnZSwgbG9naW5PcHRpb25zLnN1Ym1pdEJ1dHRvblNlbGVjdG9yKTtcbiAgICB9XG5cbiAgICBsZXQgbG9naW5GcmFtZU9yUGFnZTogUGFnZSB8IEZyYW1lIHwgbnVsbCA9IHRoaXMucGFnZTtcbiAgICBpZiAobG9naW5PcHRpb25zLnByZUFjdGlvbikge1xuICAgICAgZGVidWcoXCJleGVjdXRlICdwcmVBY3Rpb24nIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBsb2dpbkZyYW1lT3JQYWdlID0gKGF3YWl0IGxvZ2luT3B0aW9ucy5wcmVBY3Rpb24oKSkgfHwgdGhpcy5wYWdlO1xuICAgIH1cblxuICAgIGRlYnVnKCdmaWxsIGxvZ2luIGNvbXBvbmVudHMgaW5wdXQgd2l0aCByZWxldmFudCB2YWx1ZXMnKTtcbiAgICBhd2FpdCB0aGlzLmZpbGxJbnB1dHMobG9naW5GcmFtZU9yUGFnZSwgbG9naW5PcHRpb25zLmZpZWxkcyk7XG4gICAgZGVidWcoJ2NsaWNrIG9uIGxvZ2luIHN1Ym1pdCBidXR0b24nKTtcbiAgICBpZiAodHlwZW9mIGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3RvciA9PT0gJ3N0cmluZycpIHtcbiAgICAgIGF3YWl0IGNsaWNrQnV0dG9uKGxvZ2luRnJhbWVPclBhZ2UsIGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3Rvcik7XG4gICAgfSBlbHNlIHtcbiAgICAgIGF3YWl0IGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3RvcigpO1xuICAgIH1cbiAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5Mb2dnaW5nSW4pO1xuXG4gICAgaWYgKGxvZ2luT3B0aW9ucy5wb3N0QWN0aW9uKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ3Bvc3RBY3Rpb24nIGludGVyY2VwdG9yIHByb3ZpZGVkIGluIGxvZ2luIG9wdGlvbnNcIik7XG4gICAgICBhd2FpdCBsb2dpbk9wdGlvbnMucG9zdEFjdGlvbigpO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1Zygnd2FpdCBmb3IgcGFnZSBuYXZpZ2F0aW9uJyk7XG4gICAgICBhd2FpdCB3YWl0Rm9yTmF2aWdhdGlvbih0aGlzLnBhZ2UpO1xuICAgIH1cblxuICAgIGRlYnVnKCdjaGVjayBsb2dpbiByZXN1bHQnKTtcbiAgICBjb25zdCBjdXJyZW50ID0gYXdhaXQgZ2V0Q3VycmVudFVybCh0aGlzLnBhZ2UsIHRydWUpO1xuICAgIGNvbnN0IGxvZ2luUmVzdWx0ID0gYXdhaXQgZ2V0S2V5QnlWYWx1ZShsb2dpbk9wdGlvbnMucG9zc2libGVSZXN1bHRzLCBjdXJyZW50LCB0aGlzLnBhZ2UpO1xuICAgIGRlYnVnKGBoYW5kbGUgbG9naW4gcmVzdWx0cyAke2xvZ2luUmVzdWx0fWApO1xuICAgIHJldHVybiB0aGlzLmhhbmRsZUxvZ2luUmVzdWx0KGxvZ2luUmVzdWx0KTtcbiAgfVxuXG4gIGFzeW5jIHRlcm1pbmF0ZShfc3VjY2VzczogYm9vbGVhbikge1xuICAgIGRlYnVnKGB0ZXJtaW5hdGluZyBicm93c2VyIHdpdGggc3VjY2VzcyA9ICR7X3N1Y2Nlc3N9YCk7XG4gICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuVGVybWluYXRpbmcpO1xuXG4gICAgaWYgKCFfc3VjY2VzcyAmJiAhIXRoaXMub3B0aW9ucy5zdG9yZUZhaWx1cmVTY3JlZW5TaG90UGF0aCkge1xuICAgICAgZGVidWcoYGNyZWF0ZSBhIHNuYXBzaG90IGJlZm9yZSB0ZXJtaW5hdGVkIGluICR7dGhpcy5vcHRpb25zLnN0b3JlRmFpbHVyZVNjcmVlblNob3RQYXRofWApO1xuICAgICAgYXdhaXQgdGhpcy5wYWdlLnNjcmVlbnNob3Qoe1xuICAgICAgICBwYXRoOiB0aGlzLm9wdGlvbnMuc3RvcmVGYWlsdXJlU2NyZWVuU2hvdFBhdGgsXG4gICAgICAgIGZ1bGxQYWdlOiB0cnVlLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5jbGVhbnVwcy5yZXZlcnNlKCkubWFwKHNhZmVDbGVhbnVwKSk7XG4gICAgdGhpcy5jbGVhbnVwcyA9IFtdO1xuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVMb2dpblJlc3VsdChsb2dpblJlc3VsdDogTG9naW5SZXN1bHRzKSB7XG4gICAgc3dpdGNoIChsb2dpblJlc3VsdCkge1xuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuU3VjY2VzczpcbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuTG9naW5TdWNjZXNzKTtcbiAgICAgICAgcmV0dXJuIHsgc3VjY2VzczogdHJ1ZSB9O1xuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkOlxuICAgICAgY2FzZSBMb2dpblJlc3VsdHMuVW5rbm93bkVycm9yOlxuICAgICAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5Mb2dpbkZhaWxlZCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3JUeXBlOlxuICAgICAgICAgICAgbG9naW5SZXN1bHQgPT09IExvZ2luUmVzdWx0cy5JbnZhbGlkUGFzc3dvcmRcbiAgICAgICAgICAgICAgPyBTY3JhcGVyRXJyb3JUeXBlcy5JbnZhbGlkUGFzc3dvcmRcbiAgICAgICAgICAgICAgOiBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmFsLFxuICAgICAgICAgIGVycm9yTWVzc2FnZTogYExvZ2luIGZhaWxlZCB3aXRoICR7bG9naW5SZXN1bHR9IGVycm9yYCxcbiAgICAgICAgfTtcbiAgICAgIGNhc2UgTG9naW5SZXN1bHRzLkNoYW5nZVBhc3N3b3JkOlxuICAgICAgICB0aGlzLmVtaXRQcm9ncmVzcyhTY3JhcGVyUHJvZ3Jlc3NUeXBlcy5DaGFuZ2VQYXNzd29yZCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgc3VjY2VzczogZmFsc2UsXG4gICAgICAgICAgZXJyb3JUeXBlOiBTY3JhcGVyRXJyb3JUeXBlcy5DaGFuZ2VQYXNzd29yZCxcbiAgICAgICAgfTtcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgdW5leHBlY3RlZCBsb2dpbiByZXN1bHQgXCIke2xvZ2luUmVzdWx0fVwiYCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCB7IEJhc2VTY3JhcGVyV2l0aEJyb3dzZXIgfTtcbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsSUFBQUEsY0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsWUFBQSxHQUFBRCxPQUFBO0FBQ0EsSUFBQUUsTUFBQSxHQUFBRixPQUFBO0FBQ0EsSUFBQUcscUJBQUEsR0FBQUgsT0FBQTtBQUNBLElBQUFJLFdBQUEsR0FBQUosT0FBQTtBQUNBLElBQUFLLFlBQUEsR0FBQUwsT0FBQTtBQUNBLElBQUFNLE9BQUEsR0FBQU4sT0FBQTtBQUE2QyxTQUFBRCx1QkFBQVEsQ0FBQSxXQUFBQSxDQUFBLElBQUFBLENBQUEsQ0FBQUMsVUFBQSxHQUFBRCxDQUFBLEtBQUFFLE9BQUEsRUFBQUYsQ0FBQTtBQUc3QyxNQUFNRyxLQUFLLEdBQUcsSUFBQUMsZUFBUSxFQUFDLDJCQUEyQixDQUFDO0FBQUMsSUFFL0NDLGdCQUFnQiwwQkFBaEJBLGdCQUFnQjtFQUFoQkEs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