UNPKG

israeli-bank-scrapers

Version:

Provide scrapers for all major Israeli banks and credit card companies

288 lines (282 loc) 38.9 kB
"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 }; 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.message}`); } } 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(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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcHVwcGV0ZWVyIiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZGVmaW5pdGlvbnMiLCJfZGVidWciLCJfZWxlbWVudHNJbnRlcmFjdGlvbnMiLCJfbmF2aWdhdGlvbiIsIl9iYXNlU2NyYXBlciIsIl9lcnJvcnMiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJkZWJ1ZyIsImdldERlYnVnIiwiTG9naW5CYXNlUmVzdWx0cyIsIlRpbWVvdXQiLCJHZW5lcmljIiwiR2VuZXJhbCIsInJlc3QiLCJTY3JhcGVyRXJyb3JUeXBlcyIsIkxvZ2luUmVzdWx0cyIsImV4cG9ydHMiLCJnZXRLZXlCeVZhbHVlIiwib2JqZWN0IiwidmFsdWUiLCJwYWdlIiwia2V5cyIsIk9iamVjdCIsImtleSIsImNvbmRpdGlvbnMiLCJjb25kaXRpb24iLCJyZXN1bHQiLCJSZWdFeHAiLCJ0ZXN0IiwidG9Mb3dlckNhc2UiLCJQcm9taXNlIiwicmVzb2x2ZSIsIlVua25vd25FcnJvciIsImNyZWF0ZUdlbmVyYWxFcnJvciIsInN1Y2Nlc3MiLCJlcnJvclR5cGUiLCJzYWZlQ2xlYW51cCIsImNsZWFudXAiLCJtZXNzYWdlIiwiQmFzZVNjcmFwZXJXaXRoQnJvd3NlciIsIkJhc2VTY3JhcGVyIiwiY2xlYW51cHMiLCJkZWZhdWx0Vmlld3BvcnRTaXplIiwid2lkdGgiLCJoZWlnaHQiLCJnZXRWaWV3UG9ydCIsIm9wdGlvbnMiLCJ2aWV3cG9ydFNpemUiLCJpbml0aWFsaXplIiwiZW1pdFByb2dyZXNzIiwiU2NyYXBlclByb2dyZXNzVHlwZXMiLCJJbml0aWFsaXppbmciLCJpbml0aWFsaXplUGFnZSIsInNldENhY2hlRW5hYmxlZCIsInB1c2giLCJjbG9zZSIsImRlZmF1bHRUaW1lb3V0Iiwic2V0RGVmYXVsdFRpbWVvdXQiLCJwcmVwYXJlUGFnZSIsInZpZXdwb3J0Iiwic2V0Vmlld3BvcnQiLCJvbiIsInJlcXVlc3QiLCJmYWlsdXJlIiwiZXJyb3JUZXh0IiwidXJsIiwiYnJvd3NlckNvbnRleHQiLCJuZXdQYWdlIiwiYnJvd3NlciIsInNraXBDbG9zZUJyb3dzZXIiLCJ0aW1lb3V0IiwiYXJncyIsImV4ZWN1dGFibGVQYXRoIiwic2hvd0Jyb3dzZXIiLCJoZWFkbGVzcyIsInB1cHBldGVlciIsImxhdW5jaCIsImVudiIsInZlcmJvc2UiLCJERUJVRyIsInByb2Nlc3MiLCJ1bmRlZmluZWQiLCJwcmVwYXJlQnJvd3NlciIsIm5hdmlnYXRlVG8iLCJ3YWl0VW50aWwiLCJyZXRyaWVzIiwibmF2aWdhdGlvblJldHJ5Q291bnQiLCJyZXNwb25zZSIsImdvdG8iLCJFcnJvciIsIm9rIiwic3RhdHVzIiwiZ2V0TG9naW5PcHRpb25zIiwiX2NyZWRlbnRpYWxzIiwiY29tcGFueUlkIiwiZmlsbElucHV0cyIsInBhZ2VPckZyYW1lIiwiZmllbGRzIiwibW9kaWZpZWQiLCJpbnB1dCIsInNoaWZ0IiwiZmlsbElucHV0Iiwic2VsZWN0b3IiLCJsZW5ndGgiLCJsb2dpbiIsImNyZWRlbnRpYWxzIiwibG9naW5PcHRpb25zIiwidXNlckFnZW50Iiwic2V0VXNlckFnZW50IiwibG9naW5VcmwiLCJjaGVja1JlYWRpbmVzcyIsInN1Ym1pdEJ1dHRvblNlbGVjdG9yIiwid2FpdFVudGlsRWxlbWVudEZvdW5kIiwibG9naW5GcmFtZU9yUGFnZSIsInByZUFjdGlvbiIsImNsaWNrQnV0dG9uIiwiTG9nZ2luZ0luIiwicG9zdEFjdGlvbiIsIndhaXRGb3JOYXZpZ2F0aW9uIiwiY3VycmVudCIsImdldEN1cnJlbnRVcmwiLCJsb2dpblJlc3VsdCIsInBvc3NpYmxlUmVzdWx0cyIsImhhbmRsZUxvZ2luUmVzdWx0IiwidGVybWluYXRlIiwiX3N1Y2Nlc3MiLCJUZXJtaW5hdGluZyIsInN0b3JlRmFpbHVyZVNjcmVlblNob3RQYXRoIiwic2NyZWVuc2hvdCIsInBhdGgiLCJmdWxsUGFnZSIsImFsbCIsInJldmVyc2UiLCJtYXAiLCJTdWNjZXNzIiwiTG9naW5TdWNjZXNzIiwiSW52YWxpZFBhc3N3b3JkIiwiTG9naW5GYWlsZWQiLCJlcnJvck1lc3NhZ2UiLCJDaGFuZ2VQYXNzd29yZCJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zY3JhcGVycy9iYXNlLXNjcmFwZXItd2l0aC1icm93c2VyLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwdXBwZXRlZXIsIHsgdHlwZSBGcmFtZSwgdHlwZSBQYWdlLCB0eXBlIFB1cHBldGVlckxpZmVDeWNsZUV2ZW50IH0gZnJvbSAncHVwcGV0ZWVyJztcbmltcG9ydCB7IFNjcmFwZXJQcm9ncmVzc1R5cGVzIH0gZnJvbSAnLi4vZGVmaW5pdGlvbnMnO1xuaW1wb3J0IHsgZ2V0RGVidWcgfSBmcm9tICcuLi9oZWxwZXJzL2RlYnVnJztcbmltcG9ydCB7IGNsaWNrQnV0dG9uLCBmaWxsSW5wdXQsIHdhaXRVbnRpbEVsZW1lbnRGb3VuZCB9IGZyb20gJy4uL2hlbHBlcnMvZWxlbWVudHMtaW50ZXJhY3Rpb25zJztcbmltcG9ydCB7IGdldEN1cnJlbnRVcmwsIHdhaXRGb3JOYXZpZ2F0aW9uIH0gZnJvbSAnLi4vaGVscGVycy9uYXZpZ2F0aW9uJztcbmltcG9ydCB7IEJhc2VTY3JhcGVyIH0gZnJvbSAnLi9iYXNlLXNjcmFwZXInO1xuaW1wb3J0IHsgU2NyYXBlckVycm9yVHlwZXMgfSBmcm9tICcuL2Vycm9ycyc7XG5pbXBvcnQgeyB0eXBlIFNjcmFwZXJDcmVkZW50aWFscywgdHlwZSBTY3JhcGVyU2NyYXBpbmdSZXN1bHQgfSBmcm9tICcuL2ludGVyZmFjZSc7XG5cbmNvbnN0IGRlYnVnID0gZ2V0RGVidWcoJ2Jhc2Utc2NyYXBlci13aXRoLWJyb3dzZXInKTtcblxuZW51bSBMb2dpbkJhc2VSZXN1bHRzIHtcbiAgU3VjY2VzcyA9ICdTVUNDRVNTJyxcbiAgVW5rbm93bkVycm9yID0gJ1VOS05PV05fRVJST1InLFxufVxuXG5jb25zdCB7IFRpbWVvdXQsIEdlbmVyaWMsIEdlbmVyYWwsIC4uLnJlc3QgfSA9IFNjcmFwZXJFcnJvclR5cGVzO1xuZXhwb3J0IGNvbnN0IExvZ2luUmVzdWx0cyA9IHtcbiAgLi4ucmVzdCxcbiAgLi4uTG9naW5CYXNlUmVzdWx0cyxcbn07XG5cbmV4cG9ydCB0eXBlIExvZ2luUmVzdWx0cyA9XG4gIHwgRXhjbHVkZTxTY3JhcGVyRXJyb3JUeXBlcywgU2NyYXBlckVycm9yVHlwZXMuVGltZW91dCB8IFNjcmFwZXJFcnJvclR5cGVzLkdlbmVyaWMgfCBTY3JhcGVyRXJyb3JUeXBlcy5HZW5lcmFsPlxuICB8IExvZ2luQmFzZVJlc3VsdHM7XG5cbmV4cG9ydCB0eXBlIFBvc3NpYmxlTG9naW5SZXN1bHRzID0ge1xuICBba2V5IGluIExvZ2luUmVzdWx0c10/OiAoc3RyaW5nIHwgUmVnRXhwIHwgKChvcHRpb25zPzogeyBwYWdlPzogUGFnZSB9KSA9PiBQcm9taXNlPGJvb2xlYW4+KSlbXTtcbn07XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9naW5PcHRpb25zIHtcbiAgbG9naW5Vcmw6IHN0cmluZztcbiAgY2hlY2tSZWFkaW5lc3M/OiAoKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBmaWVsZHM6IHsgc2VsZWN0b3I6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W107XG4gIHN1Ym1pdEJ1dHRvblNlbGVjdG9yOiBzdHJpbmcgfCAoKCkgPT4gUHJvbWlzZTx2b2lkPik7XG4gIHByZUFjdGlvbj86ICgpID0+IFByb21pc2U8RnJhbWUgfCB2b2lkPjtcbiAgcG9zdEFjdGlvbj86ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHBvc3NpYmxlUmVzdWx0czogUG9zc2libGVMb2dpblJlc3VsdHM7XG4gIHVzZXJBZ2VudD86IHN0cmluZztcbiAgd2FpdFVudGlsPzogUHVwcGV0ZWVyTGlmZUN5Y2xlRXZlbnQ7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEtleUJ5VmFsdWUob2JqZWN0OiBQb3NzaWJsZUxvZ2luUmVzdWx0cywgdmFsdWU6IHN0cmluZywgcGFnZTogUGFnZSk6IFByb21pc2U8TG9naW5SZXN1bHRzPiB7XG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhvYmplY3QpO1xuICBmb3IgKGNvbnN0IGtleSBvZiBrZXlzKSB7XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGNvbnN0IGNvbmRpdGlvbnMgPSBvYmplY3Rba2V5XTtcblxuICAgIGZvciAoY29uc3QgY29uZGl0aW9uIG9mIGNvbmRpdGlvbnMpIHtcbiAgICAgIGxldCByZXN1bHQgPSBmYWxzZTtcblxuICAgICAgaWYgKGNvbmRpdGlvbiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICByZXN1bHQgPSBjb25kaXRpb24udGVzdCh2YWx1ZSk7XG4gICAgICB9IGVsc2UgaWYgKHR5cGVvZiBjb25kaXRpb24gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgY29uZGl0aW9uKHsgcGFnZSwgdmFsdWUgfSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQgPSB2YWx1ZS50b0xvd2VyQ2FzZSgpID09PSBjb25kaXRpb24udG9Mb3dlckNhc2UoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKExvZ2luUmVzdWx0cy5Vbmtub3duRXJyb3IpO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVHZW5lcmFsRXJyb3IoKTogU2NyYXBlclNjcmFwaW5nUmVzdWx0IHtcbiAgcmV0dXJuIHtcbiAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICBlcnJvclR5cGU6IFNjcmFwZXJFcnJvclR5cGVzLkdlbmVyYWwsXG4gIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIHNhZmVDbGVhbnVwKGNsZWFudXA6ICgpID0+IFByb21pc2U8dm9pZD4pIHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBjbGVhbnVwKCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBkZWJ1ZyhgQ2xlYW51cCBmdW5jdGlvbiBmYWlsZWQ6ICR7KGUgYXMgRXJyb3IpLm1lc3NhZ2V9YCk7XG4gIH1cbn1cblxuY2xhc3MgQmFzZVNjcmFwZXJXaXRoQnJvd3NlcjxUQ3JlZGVudGlhbHMgZXh0ZW5kcyBTY3JhcGVyQ3JlZGVudGlhbHM+IGV4dGVuZHMgQmFzZVNjcmFwZXI8VENyZWRlbnRpYWxzPiB7XG4gIHByaXZhdGUgY2xlYW51cHM6IEFycmF5PCgpID0+IFByb21pc2U8dm9pZD4+ID0gW107XG5cbiAgcHJpdmF0ZSBkZWZhdWx0Vmlld3BvcnRTaXplID0ge1xuICAgIHdpZHRoOiAxMDI0LFxuICAgIGhlaWdodDogNzY4LFxuICB9O1xuXG4gIC8vIE5PVElDRSAtIGl0IGlzIGRpc2NvdXJhZ2VkIHRvIHVzZSBiYW5nICghKSBpbiBnZW5lcmFsLiBJdCBpcyB1c2VkIGhlcmUgYmVjYXVzZVxuICAvLyBhbGwgdGhlIGNsYXNzZXMgdGhhdCBpbmhlcml0IGZyb20gdGhpcyBiYXNlIGFzc3VtZSBpcyBpdCBtYW5kYXRvcnkuXG4gIHByb3RlY3RlZCBwYWdlITogUGFnZTtcblxuICBwcm90ZWN0ZWQgZ2V0Vmlld1BvcnQoKSB7XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucy52aWV3cG9ydFNpemUgPz8gdGhpcy5kZWZhdWx0Vmlld3BvcnRTaXplO1xuICB9XG5cbiAgYXN5bmMgaW5pdGlhbGl6ZSgpIHtcbiAgICBhd2FpdCBzdXBlci5pbml0aWFsaXplKCk7XG4gICAgZGVidWcoJ2luaXRpYWxpemUgc2NyYXBlcicpO1xuICAgIHRoaXMuZW1pdFByb2dyZXNzKFNjcmFwZXJQcm9ncmVzc1R5cGVzLkluaXRpYWxpemluZyk7XG5cbiAgICBjb25zdCBwYWdlID0gYXdhaXQgdGhpcy5pbml0aWFsaXplUGFnZSgpO1xuICAgIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTsgLy8gQ2xlYXIgY2FjaGUgYW5kIGF2b2lkIDMwMCdzIHJlc3BvbnNlIHN0YXR1c1xuXG4gICAgaWYgKCFwYWdlKSB7XG4gICAgICBkZWJ1ZygnZmFpbGVkIHRvIGluaXRpYXRlIGEgYnJvd3NlciBwYWdlLCBleGl0Jyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5wYWdlID0gcGFnZTtcblxuICAgIHRoaXMuY2xlYW51cHMucHVzaCgoKSA9PiBwYWdlLmNsb3NlKCkpO1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5kZWZhdWx0VGltZW91dCkge1xuICAgICAgdGhpcy5wYWdlLnNldERlZmF1bHRUaW1lb3V0KHRoaXMub3B0aW9ucy5kZWZhdWx0VGltZW91dCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcmVwYXJlUGFnZSkge1xuICAgICAgZGVidWcoXCJleGVjdXRlICdwcmVwYXJlUGFnZScgaW50ZXJjZXB0b3IgcHJvdmlkZWQgaW4gb3B0aW9uc1wiKTtcbiAgICAgIGF3YWl0IHRoaXMub3B0aW9ucy5wcmVwYXJlUGFnZSh0aGlzLnBhZ2UpO1xuICAgIH1cblxuICAgIGNvbnN0IHZpZXdwb3J0ID0gdGhpcy5nZXRWaWV3UG9ydCgpO1xuICAgIGRlYnVnKGBzZXQgdmlld3BvcnQgdG8gd2lkdGggJHt2aWV3cG9ydC53aWR0aH0sIGhlaWdodCAke3ZpZXdwb3J0LmhlaWdodH1gKTtcbiAgICBhd2FpdCB0aGlzLnBhZ2Uuc2V0Vmlld3BvcnQoe1xuICAgICAgd2lkdGg6IHZpZXdwb3J0LndpZHRoLFxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydC5oZWlnaHQsXG4gICAgfSk7XG5cbiAgICB0aGlzLnBhZ2Uub24oJ3JlcXVlc3RmYWlsZWQnLCByZXF1ZXN0ID0+IHtcbiAgICAgIGRlYnVnKCdSZXF1ZXN0IGZhaWxlZDogJXMgJXMnLCByZXF1ZXN0LmZhaWx1cmUoKT8uZXJyb3JUZXh0LCByZXF1ZXN0LnVybCgpKTtcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgaW5pdGlhbGl6ZVBhZ2UoKSB7XG4gICAgZGVidWcoJ2luaXRpYWxpemUgYnJvd3NlciBwYWdlJyk7XG4gICAgaWYgKCdicm93c2VyQ29udGV4dCcgaW4gdGhpcy5vcHRpb25zKSB7XG4gICAgICBkZWJ1ZygnVXNpbmcgdGhlIGJyb3dzZXIgY29udGV4dCBwcm92aWRlZCBpbiBvcHRpb25zJyk7XG4gICAgICByZXR1cm4gdGhpcy5vcHRpb25zLmJyb3dzZXJDb250ZXh0Lm5ld1BhZ2UoKTtcbiAgICB9XG5cbiAgICBpZiAoJ2Jyb3dzZXInIGluIHRoaXMub3B0aW9ucykge1xuICAgICAgZGVidWcoJ1VzaW5nIHRoZSBicm93c2VyIGluc3RhbmNlIHByb3ZpZGVkIGluIG9wdGlvbnMnKTtcbiAgICAgIGNvbnN0IHsgYnJvd3NlciB9ID0gdGhpcy5vcHRpb25zO1xuXG4gICAgICAvKipcbiAgICAgICAqIEZvciBiYWNrd2FyZCBjb21wYXRpYmlsaXR5LCB3ZSB3aWxsIGNsb3NlIHRoZSBicm93c2VyIGV2ZW4gaWYgd2UgZGlkbid0IGNyZWF0ZSBpdFxuICAgICAgICovXG4gICAgICBpZiAoIXRoaXMub3B0aW9ucy5za2lwQ2xvc2VCcm93c2VyKSB7XG4gICAgICAgIHRoaXMuY2xlYW51cHMucHVzaChhc3luYyAoKSA9PiB7XG4gICAgICAgICAgZGVidWcoJ2Nsb3NpbmcgdGhlIGJyb3dzZXInKTtcbiAgICAgICAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gYnJvd3Nlci5uZXdQYWdlKCk7XG4gICAgfVxuXG4gICAgY29uc3QgeyB0aW1lb3V0LCBhcmdzLCBleGVjdXRhYmxlUGF0aCwgc2hvd0Jyb3dzZXIgfSA9IHRoaXMub3B0aW9ucztcblxuICAgIGNvbnN0IGhlYWRsZXNzID0gIXNob3dCcm93c2VyO1xuICAgIGRlYnVnKGBsYXVuY2ggYSBicm93c2VyIHdpdGggaGVhZGxlc3MgbW9kZSA9ICR7aGVhZGxlc3N9YCk7XG5cbiAgICBjb25zdCBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaCh7XG4gICAgICBlbnY6IHRoaXMub3B0aW9ucy52ZXJib3NlID8geyBERUJVRzogJyonLCAuLi5wcm9jZXNzLmVudiB9IDogdW5kZWZpbmVkLFxuICAgICAgaGVhZGxlc3MsXG4gICAgICBleGVjdXRhYmxlUGF0aCxcbiAgICAgIGFyZ3MsXG4gICAgICB0aW1lb3V0LFxuICAgIH0pO1xuXG4gICAgdGhpcy5jbGVhbnVwcy5wdXNoKGFzeW5jICgpID0+IHtcbiAgICAgIGRlYnVnKCdjbG9zaW5nIHRoZSBicm93c2VyJyk7XG4gICAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XG4gICAgfSk7XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnByZXBhcmVCcm93c2VyKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ3ByZXBhcmVCcm93c2VyJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBvcHRpb25zXCIpO1xuICAgICAgYXdhaXQgdGhpcy5vcHRpb25zLnByZXBhcmVCcm93c2VyKGJyb3dzZXIpO1xuICAgIH1cblxuICAgIGRlYnVnKCdjcmVhdGUgYSBuZXcgYnJvd3NlciBwYWdlJyk7XG4gICAgcmV0dXJuIGJyb3dzZXIubmV3UGFnZSgpO1xuICB9XG5cbiAgYXN5bmMgbmF2aWdhdGVUbyhcbiAgICB1cmw6IHN0cmluZyxcbiAgICB3YWl0VW50aWw6IFB1cHBldGVlckxpZmVDeWNsZUV2ZW50IHwgdW5kZWZpbmVkID0gJ2xvYWQnLFxuICAgIHJldHJpZXMgPSB0aGlzLm9wdGlvbnMubmF2aWdhdGlvblJldHJ5Q291bnQgPz8gMCxcbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCB0aGlzLnBhZ2U/LmdvdG8odXJsLCB7IHdhaXRVbnRpbCB9KTtcbiAgICBpZiAocmVzcG9uc2UgPT09IG51bGwpIHtcbiAgICAgIC8vIG5vdGU6IHJlc3BvbnNlIHdpbGwgYmUgbnVsbCB3aGVuIG5hdmlnYXRpbmcgdG8gc2FtZSB1cmwgd2hpbGUgY2hhbmdpbmcgdGhlIGhhc2ggcGFydC5cbiAgICAgIC8vIHRoZSBjb25kaXRpb24gYmVsb3cgd2lsbCBhbHdheXMgYWNjZXB0IG51bGwgYXMgdmFsaWQgcmVzdWx0LlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghcmVzcG9uc2UpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3Igd2hpbGUgdHJ5aW5nIHRvIG5hdmlnYXRlIHRvIHVybCAke3VybH0sIHJlc3BvbnNlIGlzIHVuZGVmaW5lZGApO1xuICAgIH1cblxuICAgIGlmICghcmVzcG9uc2Uub2soKSkge1xuICAgICAgY29uc3Qgc3RhdHVzID0gcmVzcG9uc2Uuc3RhdHVzKCk7XG4gICAgICBpZiAocmV0cmllcyA+IDApIHtcbiAgICAgICAgZGVidWcoYEZhaWxlZCB0byBuYXZpZ2F0ZSB0byB1cmwgJHt1cmx9LCBzdGF0dXMgY29kZTogJHtzdGF0dXN9LCByZXRyeWluZyAke3JldHJpZXN9IG1vcmUgdGltZXNgKTtcbiAgICAgICAgYXdhaXQgdGhpcy5uYXZpZ2F0ZVRvKHVybCwgd2FpdFVudGlsLCByZXRyaWVzIC0gMSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byBuYXZpZ2F0ZSB0byB1cmwgJHt1cmx9LCBzdGF0dXMgY29kZTogJHtzdGF0dXN9YCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFyc1xuICBnZXRMb2dpbk9wdGlvbnMoX2NyZWRlbnRpYWxzOiBTY3JhcGVyQ3JlZGVudGlhbHMpOiBMb2dpbk9wdGlvbnMge1xuICAgIHRocm93IG5ldyBFcnJvcihgZ2V0TG9naW5PcHRpb25zKCkgaXMgbm90IGNyZWF0ZWQgaW4gJHt0aGlzLm9wdGlvbnMuY29tcGFueUlkfWApO1xuICB9XG5cbiAgYXN5bmMgZmlsbElucHV0cyhwYWdlT3JGcmFtZTogUGFnZSB8IEZyYW1lLCBmaWVsZHM6IHsgc2VsZWN0b3I6IHN0cmluZzsgdmFsdWU6IHN0cmluZyB9W10pOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBtb2RpZmllZCA9IFsuLi5maWVsZHNdO1xuICAgIGNvbnN0IGlucHV0ID0gbW9kaWZpZWQuc2hpZnQoKTtcblxuICAgIGlmICghaW5wdXQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgYXdhaXQgZmlsbElucHV0KHBhZ2VPckZyYW1lLCBpbnB1dC5zZWxlY3RvciwgaW5wdXQudmFsdWUpO1xuICAgIGlmIChtb2RpZmllZC5sZW5ndGgpIHtcbiAgICAgIGF3YWl0IHRoaXMuZmlsbElucHV0cyhwYWdlT3JGcmFtZSwgbW9kaWZpZWQpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIGxvZ2luKGNyZWRlbnRpYWxzOiBTY3JhcGVyQ3JlZGVudGlhbHMpOiBQcm9taXNlPFNjcmFwZXJTY3JhcGluZ1Jlc3VsdD4ge1xuICAgIGlmICghY3JlZGVudGlhbHMgfHwgIXRoaXMucGFnZSkge1xuICAgICAgcmV0dXJuIGNyZWF0ZUdlbmVyYWxFcnJvcigpO1xuICAgIH1cblxuICAgIGRlYnVnKCdleGVjdXRlIGxvZ2luIHByb2Nlc3MnKTtcbiAgICBjb25zdCBsb2dpbk9wdGlvbnMgPSB0aGlzLmdldExvZ2luT3B0aW9ucyhjcmVkZW50aWFscyk7XG5cbiAgICBpZiAobG9naW5PcHRpb25zLnVzZXJBZ2VudCkge1xuICAgICAgZGVidWcoJ3NldCBjdXN0b20gdXNlciBhZ2VudCBwcm92aWRlZCBpbiBvcHRpb25zJyk7XG4gICAgICBhd2FpdCB0aGlzLnBhZ2Uuc2V0VXNlckFnZW50KGxvZ2luT3B0aW9ucy51c2VyQWdlbnQpO1xuICAgIH1cblxuICAgIGRlYnVnKCduYXZpZ2F0ZSB0byBsb2dpbiB1cmwnKTtcbiAgICBhd2FpdCB0aGlzLm5hdmlnYXRlVG8obG9naW5PcHRpb25zLmxvZ2luVXJsLCBsb2dpbk9wdGlvbnMud2FpdFVudGlsKTtcbiAgICBpZiAobG9naW5PcHRpb25zLmNoZWNrUmVhZGluZXNzKSB7XG4gICAgICBkZWJ1ZyhcImV4ZWN1dGUgJ2NoZWNrUmVhZGluZXNzJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBsb2dpbiBvcHRpb25zXCIpO1xuICAgICAgYXdhaXQgbG9naW5PcHRpb25zLmNoZWNrUmVhZGluZXNzKCk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgbG9naW5PcHRpb25zLnN1Ym1pdEJ1dHRvblNlbGVjdG9yID09PSAnc3RyaW5nJykge1xuICAgICAgZGVidWcoJ3dhaXQgdW50aWwgc3VibWl0IGJ1dHRvbiBpcyBhdmFpbGFibGUnKTtcbiAgICAgIGF3YWl0IHdhaXRVbnRpbEVsZW1lbnRGb3VuZCh0aGlzLnBhZ2UsIGxvZ2luT3B0aW9ucy5zdWJtaXRCdXR0b25TZWxlY3Rvcik7XG4gICAgfVxuXG4gICAgbGV0IGxvZ2luRnJhbWVPclBhZ2U6IFBhZ2UgfCBGcmFtZSB8IG51bGwgPSB0aGlzLnBhZ2U7XG4gICAgaWYgKGxvZ2luT3B0aW9ucy5wcmVBY3Rpb24pIHtcbiAgICAgIGRlYnVnKFwiZXhlY3V0ZSAncHJlQWN0aW9uJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBsb2dpbiBvcHRpb25zXCIpO1xuICAgICAgbG9naW5GcmFtZU9yUGFnZSA9IChhd2FpdCBsb2dpbk9wdGlvbnMucHJlQWN0aW9uKCkpIHx8IHRoaXMucGFnZTtcbiAgICB9XG5cbiAgICBkZWJ1ZygnZmlsbCBsb2dpbiBjb21wb25lbnRzIGlucHV0IHdpdGggcmVsZXZhbnQgdmFsdWVzJyk7XG4gICAgYXdhaXQgdGhpcy5maWxsSW5wdXRzKGxvZ2luRnJhbWVPclBhZ2UsIGxvZ2luT3B0aW9ucy5maWVsZHMpO1xuICAgIGRlYnVnKCdjbGljayBvbiBsb2dpbiBzdWJtaXQgYnV0dG9uJyk7XG4gICAgaWYgKHR5cGVvZiBsb2dpbk9wdGlvbnMuc3VibWl0QnV0dG9uU2VsZWN0b3IgPT09ICdzdHJpbmcnKSB7XG4gICAgICBhd2FpdCBjbGlja0J1dHRvbihsb2dpbkZyYW1lT3JQYWdlLCBsb2dpbk9wdGlvbnMuc3VibWl0QnV0dG9uU2VsZWN0b3IpO1xuICAgIH0gZWxzZSB7XG4gICAgICBhd2FpdCBsb2dpbk9wdGlvbnMuc3VibWl0QnV0dG9uU2VsZWN0b3IoKTtcbiAgICB9XG4gICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuTG9nZ2luZ0luKTtcblxuICAgIGlmIChsb2dpbk9wdGlvbnMucG9zdEFjdGlvbikge1xuICAgICAgZGVidWcoXCJleGVjdXRlICdwb3N0QWN0aW9uJyBpbnRlcmNlcHRvciBwcm92aWRlZCBpbiBsb2dpbiBvcHRpb25zXCIpO1xuICAgICAgYXdhaXQgbG9naW5PcHRpb25zLnBvc3RBY3Rpb24oKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZGVidWcoJ3dhaXQgZm9yIHBhZ2UgbmF2aWdhdGlvbicpO1xuICAgICAgYXdhaXQgd2FpdEZvck5hdmlnYXRpb24odGhpcy5wYWdlKTtcbiAgICB9XG5cbiAgICBkZWJ1ZygnY2hlY2sgbG9naW4gcmVzdWx0Jyk7XG4gICAgY29uc3QgY3VycmVudCA9IGF3YWl0IGdldEN1cnJlbnRVcmwodGhpcy5wYWdlLCB0cnVlKTtcbiAgICBjb25zdCBsb2dpblJlc3VsdCA9IGF3YWl0IGdldEtleUJ5VmFsdWUobG9naW5PcHRpb25zLnBvc3NpYmxlUmVzdWx0cywgY3VycmVudCwgdGhpcy5wYWdlKTtcbiAgICBkZWJ1ZyhgaGFuZGxlIGxvZ2luIHJlc3VsdHMgJHtsb2dpblJlc3VsdH1gKTtcbiAgICByZXR1cm4gdGhpcy5oYW5kbGVMb2dpblJlc3VsdChsb2dpblJlc3VsdCk7XG4gIH1cblxuICBhc3luYyB0ZXJtaW5hdGUoX3N1Y2Nlc3M6IGJvb2xlYW4pIHtcbiAgICBkZWJ1ZyhgdGVybWluYXRpbmcgYnJvd3NlciB3aXRoIHN1Y2Nlc3MgPSAke19zdWNjZXNzfWApO1xuICAgIHRoaXMuZW1pdFByb2dyZXNzKFNjcmFwZXJQcm9ncmVzc1R5cGVzLlRlcm1pbmF0aW5nKTtcblxuICAgIGlmICghX3N1Y2Nlc3MgJiYgISF0aGlzLm9wdGlvbnMuc3RvcmVGYWlsdXJlU2NyZWVuU2hvdFBhdGgpIHtcbiAgICAgIGRlYnVnKGBjcmVhdGUgYSBzbmFwc2hvdCBiZWZvcmUgdGVybWluYXRlZCBpbiAke3RoaXMub3B0aW9ucy5zdG9yZUZhaWx1cmVTY3JlZW5TaG90UGF0aH1gKTtcbiAgICAgIGF3YWl0IHRoaXMucGFnZS5zY3JlZW5zaG90KHtcbiAgICAgICAgcGF0aDogdGhpcy5vcHRpb25zLnN0b3JlRmFpbHVyZVNjcmVlblNob3RQYXRoLFxuICAgICAgICBmdWxsUGFnZTogdHJ1ZSxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGF3YWl0IFByb21pc2UuYWxsKHRoaXMuY2xlYW51cHMucmV2ZXJzZSgpLm1hcChzYWZlQ2xlYW51cCkpO1xuICAgIHRoaXMuY2xlYW51cHMgPSBbXTtcbiAgfVxuXG4gIHByaXZhdGUgaGFuZGxlTG9naW5SZXN1bHQobG9naW5SZXN1bHQ6IExvZ2luUmVzdWx0cykge1xuICAgIHN3aXRjaCAobG9naW5SZXN1bHQpIHtcbiAgICAgIGNhc2UgTG9naW5SZXN1bHRzLlN1Y2Nlc3M6XG4gICAgICAgIHRoaXMuZW1pdFByb2dyZXNzKFNjcmFwZXJQcm9ncmVzc1R5cGVzLkxvZ2luU3VjY2Vzcyk7XG4gICAgICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUgfTtcbiAgICAgIGNhc2UgTG9naW5SZXN1bHRzLkludmFsaWRQYXNzd29yZDpcbiAgICAgIGNhc2UgTG9naW5SZXN1bHRzLlVua25vd25FcnJvcjpcbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuTG9naW5GYWlsZWQpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIGVycm9yVHlwZTpcbiAgICAgICAgICAgIGxvZ2luUmVzdWx0ID09PSBMb2dpblJlc3VsdHMuSW52YWxpZFBhc3N3b3JkXG4gICAgICAgICAgICAgID8gU2NyYXBlckVycm9yVHlwZXMuSW52YWxpZFBhc3N3b3JkXG4gICAgICAgICAgICAgIDogU2NyYXBlckVycm9yVHlwZXMuR2VuZXJhbCxcbiAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBMb2dpbiBmYWlsZWQgd2l0aCAke2xvZ2luUmVzdWx0fSBlcnJvcmAsXG4gICAgICAgIH07XG4gICAgICBjYXNlIExvZ2luUmVzdWx0cy5DaGFuZ2VQYXNzd29yZDpcbiAgICAgICAgdGhpcy5lbWl0UHJvZ3Jlc3MoU2NyYXBlclByb2dyZXNzVHlwZXMuQ2hhbmdlUGFzc3dvcmQpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIGVycm9yVHlwZTogU2NyYXBlckVycm9yVHlwZXMuQ2hhbmdlUGFzc3dvcmQsXG4gICAgICAgIH07XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYHVuZXhwZWN0ZWQgbG9naW4gcmVzdWx0IFwiJHtsb2dpblJlc3VsdH1cImApO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgeyBCYXNlU2NyYXBlcldpdGhCcm93c2VyIH07XG4iXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLElBQUFBLFVBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUNBLElBQUFDLFlBQUEsR0FBQUQsT0FBQTtBQUNBLElBQUFFLE1BQUEsR0FBQUYsT0FBQTtBQUNBLElBQUFHLHFCQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxXQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxZQUFBLEdBQUFMLE9BQUE7QUFDQSxJQUFBTSxPQUFBLEdBQUFOLE9BQUE7QUFBNkMsU0FBQUQsdUJBQUFRLENBQUEsV0FBQUEsQ0FBQSxJQUFBQSxDQUFBLENBQUFDLFVBQUEsR0FBQUQsQ0FBQSxLQUFBRSxPQUFBLEVBQUFGLENBQUE7QUFHN0MsTUFBTUcsS0FBSyxHQUFHLElBQUFDLGVBQVEsRUFBQywyQkFBMkIsQ0FBQztBQUFDLElBRS9DQyxnQkFBZ0IsMEJBQWhCQSxnQkFBZ0I7RUFBaEJBLGdCQUFnQjtFQUFoQkEsZ0JBQWdCO0VBQUEsT0FBaEJBLGdCQUFn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