UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

584 lines 96.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lodash_1 = require("lodash"); const read_file_relative_1 = require("read-file-relative"); const promisify_event_1 = __importDefault(require("promisify-event")); const pinkie_1 = __importDefault(require("pinkie")); const mustache_1 = __importDefault(require("mustache")); const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter")); const debug_logger_1 = __importDefault(require("../notifications/debug-logger")); const debug_log_1 = __importDefault(require("./debug-log")); const formattable_adapter_1 = __importDefault(require("../errors/test-run/formattable-adapter")); const error_list_1 = __importDefault(require("../errors/error-list")); const test_run_1 = require("../errors/test-run/"); const phase_1 = __importDefault(require("./phase")); const client_messages_1 = __importDefault(require("./client-messages")); const type_1 = __importDefault(require("./commands/type")); const delay_1 = __importDefault(require("../utils/delay")); const marker_symbol_1 = __importDefault(require("./marker-symbol")); const test_run_tracker_1 = __importDefault(require("../api/test-run-tracker")); const phase_2 = __importDefault(require("../role/phase")); const plugin_host_1 = __importDefault(require("../reporter/plugin-host")); const browser_console_messages_1 = __importDefault(require("./browser-console-messages")); const unstable_network_mode_1 = require("../browser/connection/unstable-network-mode"); const warning_log_1 = __importDefault(require("../notifications/warning-log")); const warning_message_1 = __importDefault(require("../notifications/warning-message")); const testcafe_hammerhead_1 = require("testcafe-hammerhead"); const actions_1 = require("./commands/actions"); const utils_1 = require("./commands/utils"); const types_1 = require("../errors/types"); const lazyRequire = require('import-lazy')(require); const SessionController = lazyRequire('./session-controller'); const ClientFunctionBuilder = lazyRequire('../client-functions/client-function-builder'); const executeJsExpression = lazyRequire('./execute-js-expression'); const BrowserManipulationQueue = lazyRequire('./browser-manipulation-queue'); const TestRunBookmark = lazyRequire('./bookmark'); const AssertionExecutor = lazyRequire('../assertions/executor'); const actionCommands = lazyRequire('./commands/actions'); const browserManipulationCommands = lazyRequire('./commands/browser-manipulation'); const serviceCommands = lazyRequire('./commands/service'); const TEST_RUN_TEMPLATE = read_file_relative_1.readSync('../client/test-run/index.js.mustache'); const IFRAME_TEST_RUN_TEMPLATE = read_file_relative_1.readSync('../client/test-run/iframe.js.mustache'); const TEST_DONE_CONFIRMATION_RESPONSE = 'test-done-confirmation'; const MAX_RESPONSE_DELAY = 3000; const ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT = 'all-driver-tasks-added-to-queue'; class TestRun extends async_event_emitter_1.default { constructor(test, browserConnection, screenshotCapturer, globalWarningLog, opts) { super(); this[marker_symbol_1.default] = true; this.warningLog = new warning_log_1.default(globalWarningLog); this.opts = opts; this.test = test; this.browserConnection = browserConnection; this.phase = phase_1.default.initial; this.driverTaskQueue = []; this.testDoneCommandQueued = false; this.activeDialogHandler = null; this.activeIframeSelector = null; this.speed = this.opts.speed; this.pageLoadTimeout = this.opts.pageLoadTimeout; this.disablePageReloads = test.disablePageReloads || opts.disablePageReloads && test.disablePageReloads !== false; this.session = SessionController.getSession(this); this.consoleMessages = new browser_console_messages_1.default(); this.pendingRequest = null; this.pendingPageError = null; this.controller = null; this.ctx = Object.create(null); this.fixtureCtx = null; this.currentRoleId = null; this.usedRoleStates = Object.create(null); this.errs = []; this.lastDriverStatusId = null; this.lastDriverStatusResponse = null; this.fileDownloadingHandled = false; this.resolveWaitForFileDownloadingPromise = null; this.addingDriverTasksCount = 0; this.debugging = this.opts.debugMode; this.debugOnFail = this.opts.debugOnFail; this.disableDebugBreakpoints = false; this.debugReporterPluginHost = new plugin_host_1.default({ noColors: false }); this.browserManipulationQueue = new BrowserManipulationQueue(browserConnection, screenshotCapturer, this.warningLog); this.debugLog = new debug_log_1.default(this.browserConnection.userAgent); this.quarantine = null; this.injectable.scripts.push('/testcafe-core.js'); this.injectable.scripts.push('/testcafe-ui.js'); this.injectable.scripts.push('/testcafe-automation.js'); this.injectable.scripts.push('/testcafe-driver.js'); this.injectable.styles.push('/testcafe-ui-styles.css'); this.requestHooks = Array.from(this.test.requestHooks); this._initRequestHooks(); } get id() { return this.session.id; } get injectable() { return this.session.injectable; } addQuarantineInfo(quarantine) { this.quarantine = quarantine; } addRequestHook(hook) { if (this.requestHooks.indexOf(hook) !== -1) return; this.requestHooks.push(hook); this._initRequestHook(hook); } removeRequestHook(hook) { if (this.requestHooks.indexOf(hook) === -1) return; lodash_1.pull(this.requestHooks, hook); this._disposeRequestHook(hook); } _initRequestHook(hook) { hook.warningLog = this.warningLog; hook._instantiateRequestFilterRules(); hook._instantiatedRequestFilterRules.forEach(rule => { this.session.addRequestEventListeners(rule, { onRequest: hook.onRequest.bind(hook), onConfigureResponse: hook._onConfigureResponse.bind(hook), onResponse: hook.onResponse.bind(hook) }, err => this._onRequestHookMethodError(err, hook)); }); } _onRequestHookMethodError(event, hook) { let err = event.error; const isRequestHookNotImplementedMethodError = err instanceof test_run_1.RequestHookNotImplementedMethodError; if (!isRequestHookNotImplementedMethodError) { const hookClassName = hook.constructor.name; err = new test_run_1.RequestHookUnhandledError(err, hookClassName, event.methodName); } this.addError(err); } _disposeRequestHook(hook) { hook.warningLog = null; hook._instantiatedRequestFilterRules.forEach(rule => { this.session.removeRequestEventListeners(rule); }); } _initRequestHooks() { this.requestHooks.forEach(hook => this._initRequestHook(hook)); } // Hammerhead payload _getPayloadScript() { this.fileDownloadingHandled = false; this.resolveWaitForFileDownloadingPromise = null; return mustache_1.default.render(TEST_RUN_TEMPLATE, { testRunId: JSON.stringify(this.session.id), browserId: JSON.stringify(this.browserConnection.id), browserHeartbeatRelativeUrl: JSON.stringify(this.browserConnection.heartbeatRelativeUrl), browserStatusRelativeUrl: JSON.stringify(this.browserConnection.statusRelativeUrl), browserStatusDoneRelativeUrl: JSON.stringify(this.browserConnection.statusDoneRelativeUrl), userAgent: JSON.stringify(this.browserConnection.userAgent), testName: JSON.stringify(this.test.name), fixtureName: JSON.stringify(this.test.fixture.name), selectorTimeout: this.opts.selectorTimeout, pageLoadTimeout: this.pageLoadTimeout, skipJsErrors: this.opts.skipJsErrors, retryTestPages: !!this.opts.retryTestPages, speed: this.speed, dialogHandler: JSON.stringify(this.activeDialogHandler) }); } _getIframePayloadScript() { return mustache_1.default.render(IFRAME_TEST_RUN_TEMPLATE, { testRunId: JSON.stringify(this.session.id), selectorTimeout: this.opts.selectorTimeout, pageLoadTimeout: this.pageLoadTimeout, retryTestPages: !!this.opts.retryTestPages, speed: this.speed, dialogHandler: JSON.stringify(this.activeDialogHandler) }); } // Hammerhead handlers getAuthCredentials() { return this.test.authCredentials; } handleFileDownload() { if (this.resolveWaitForFileDownloadingPromise) { this.resolveWaitForFileDownloadingPromise(true); this.resolveWaitForFileDownloadingPromise = null; } else this.fileDownloadingHandled = true; } handlePageError(ctx, err) { if (ctx.req.headers[unstable_network_mode_1.UNSTABLE_NETWORK_MODE_HEADER]) { ctx.closeWithError(500, err.toString()); return; } this.pendingPageError = new test_run_1.PageLoadError(err, ctx.reqOpts.url); ctx.redirect(ctx.toProxyUrl(testcafe_hammerhead_1.SPECIAL_ERROR_PAGE)); } // Test function execution async _executeTestFn(phase, fn) { this.phase = phase; try { await fn(this); } catch (err) { let screenshotPath = null; if (this.opts.takeScreenshotsOnFails) screenshotPath = await this.executeCommand(new browserManipulationCommands.TakeScreenshotOnFailCommand()); this.addError(err, screenshotPath); return false; } return !this._addPendingPageErrorIfAny(); } async _runBeforeHook() { if (this.test.beforeFn) return await this._executeTestFn(phase_1.default.inTestBeforeHook, this.test.beforeFn); if (this.test.fixture.beforeEachFn) return await this._executeTestFn(phase_1.default.inFixtureBeforeEachHook, this.test.fixture.beforeEachFn); return true; } async _runAfterHook() { if (this.test.afterFn) return await this._executeTestFn(phase_1.default.inTestAfterHook, this.test.afterFn); if (this.test.fixture.afterEachFn) return await this._executeTestFn(phase_1.default.inFixtureAfterEachHook, this.test.fixture.afterEachFn); return true; } async start() { test_run_tracker_1.default.activeTestRuns[this.session.id] = this; await this.emit('start'); const onDisconnected = err => this._disconnect(err); this.browserConnection.once('disconnected', onDisconnected); await this.once('connected'); await this.emit('ready'); if (await this._runBeforeHook()) { await this._executeTestFn(phase_1.default.inTest, this.test.fn); await this._runAfterHook(); } if (this.disconnected) return; this.browserConnection.removeListener('disconnected', onDisconnected); if (this.errs.length && this.debugOnFail) await this._enqueueSetBreakpointCommand(null, this.debugReporterPluginHost.formatError(this.errs[0])); await this.emit('before-done'); await this.executeCommand(new serviceCommands.TestDoneCommand()); this._addPendingPageErrorIfAny(); this.session.clearRequestEventListeners(); this.normalizeRequestHookErrors(); delete test_run_tracker_1.default.activeTestRuns[this.session.id]; await this.emit('done'); } // Errors _addPendingPageErrorIfAny() { if (this.pendingPageError) { this.addError(this.pendingPageError); this.pendingPageError = null; return true; } return false; } _createErrorAdapter(err, screenshotPath) { return new formattable_adapter_1.default(err, { userAgent: this.browserConnection.userAgent, screenshotPath: screenshotPath || '', testRunPhase: this.phase }); } addError(err, screenshotPath) { const errList = err instanceof error_list_1.default ? err.items : [err]; errList.forEach(item => { const adapter = this._createErrorAdapter(item, screenshotPath); this.errs.push(adapter); }); } normalizeRequestHookErrors() { const requestHookErrors = lodash_1.remove(this.errs, e => e.code === types_1.TEST_RUN_ERRORS.requestHookNotImplementedError || e.code === types_1.TEST_RUN_ERRORS.requestHookUnhandledError); if (!requestHookErrors.length) return; const uniqRequestHookErrors = lodash_1.chain(requestHookErrors) .uniqBy(e => e.hookClassName + e.methodName) .sortBy(['hookClassName', 'methodName']) .value(); this.errs = this.errs.concat(uniqRequestHookErrors); } // Task queue _enqueueCommand(command, callsite) { if (this.pendingRequest) this._resolvePendingRequest(command); return new pinkie_1.default(async (resolve, reject) => { this.addingDriverTasksCount--; this.driverTaskQueue.push({ command, resolve, reject, callsite }); if (!this.addingDriverTasksCount) await this.emit(ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT, this.driverTaskQueue.length); }); } get driverTaskQueueLength() { return this.addingDriverTasksCount ? promisify_event_1.default(this, ALL_DRIVER_TASKS_ADDED_TO_QUEUE_EVENT) : pinkie_1.default.resolve(this.driverTaskQueue.length); } async _enqueueBrowserConsoleMessagesCommand(command, callsite) { await this._enqueueCommand(command, callsite); return this.consoleMessages.getCopy(); } async _enqueueSetBreakpointCommand(callsite, error) { if (this.browserConnection.isHeadlessBrowser()) { this.warningLog.addWarning(warning_message_1.default.debugInHeadlessError); return; } debug_logger_1.default.showBreakpoint(this.session.id, this.browserConnection.userAgent, callsite, error); this.debugging = await this.executeCommand(new serviceCommands.SetBreakpointCommand(!!error), callsite); } _removeAllNonServiceTasks() { this.driverTaskQueue = this.driverTaskQueue.filter(driverTask => utils_1.isServiceCommand(driverTask.command)); this.browserManipulationQueue.removeAllNonServiceManipulations(); } // Current driver task get currentDriverTask() { return this.driverTaskQueue[0]; } _resolveCurrentDriverTask(result) { this.currentDriverTask.resolve(result); this.driverTaskQueue.shift(); if (this.testDoneCommandQueued) this._removeAllNonServiceTasks(); } _rejectCurrentDriverTask(err) { err.callsite = err.callsite || this.currentDriverTask.callsite; this.currentDriverTask.reject(err); this._removeAllNonServiceTasks(); } // Pending request _clearPendingRequest() { if (this.pendingRequest) { clearTimeout(this.pendingRequest.responseTimeout); this.pendingRequest = null; } } _resolvePendingRequest(command) { this.lastDriverStatusResponse = command; this.pendingRequest.resolve(command); this._clearPendingRequest(); } // Handle driver request _fulfillCurrentDriverTask(driverStatus) { if (driverStatus.executionError) this._rejectCurrentDriverTask(driverStatus.executionError); else this._resolveCurrentDriverTask(driverStatus.result); } _handlePageErrorStatus(pageError) { if (this.currentDriverTask && utils_1.isCommandRejectableByPageError(this.currentDriverTask.command)) { this._rejectCurrentDriverTask(pageError); this.pendingPageError = null; return true; } this.pendingPageError = this.pendingPageError || pageError; return false; } _handleDriverRequest(driverStatus) { const isTestDone = this.currentDriverTask && this.currentDriverTask.command.type === type_1.default.testDone; const pageError = this.pendingPageError || driverStatus.pageError; const currentTaskRejectedByError = pageError && this._handlePageErrorStatus(pageError); if (this.disconnected) return new pinkie_1.default((_, reject) => reject()); this.consoleMessages.concat(driverStatus.consoleMessages); if (!currentTaskRejectedByError && driverStatus.isCommandResult) { if (isTestDone) { this._resolveCurrentDriverTask(); return TEST_DONE_CONFIRMATION_RESPONSE; } this._fulfillCurrentDriverTask(driverStatus); } return this._getCurrentDriverTaskCommand(); } _getCurrentDriverTaskCommand() { if (!this.currentDriverTask) return null; const command = this.currentDriverTask.command; if (command.type === type_1.default.navigateTo && command.stateSnapshot) this.session.useStateSnapshot(JSON.parse(command.stateSnapshot)); return command; } // Execute command async _executeExpression(command) { const { resultVariableName, isAsyncExpression } = command; let expression = command.expression; if (isAsyncExpression) expression = `await ${expression}`; if (resultVariableName) expression = `${resultVariableName} = ${expression}, ${resultVariableName}`; if (isAsyncExpression) expression = `(async () => { return ${expression}; }).apply(this);`; const result = executeJsExpression(expression, this, { skipVisibilityCheck: false }); return isAsyncExpression ? await result : result; } async _executeAssertion(command, callsite) { const assertionTimeout = command.options.timeout === void 0 ? this.opts.assertionTimeout : command.options.timeout; const executor = new AssertionExecutor(command, assertionTimeout, callsite); executor.once('start-assertion-retries', timeout => this.executeCommand(new serviceCommands.ShowAssertionRetriesStatusCommand(timeout))); executor.once('end-assertion-retries', success => this.executeCommand(new serviceCommands.HideAssertionRetriesStatusCommand(success))); return executor.run(); } _adjustConfigurationWithCommand(command) { if (command.type === type_1.default.testDone) { this.testDoneCommandQueued = true; debug_logger_1.default.hideBreakpoint(this.session.id); } else if (command.type === type_1.default.setNativeDialogHandler) this.activeDialogHandler = command.dialogHandler; else if (command.type === type_1.default.switchToIframe) this.activeIframeSelector = command.selector; else if (command.type === type_1.default.switchToMainWindow) this.activeIframeSelector = null; else if (command.type === type_1.default.setTestSpeed) this.speed = command.speed; else if (command.type === type_1.default.setPageLoadTimeout) this.pageLoadTimeout = command.duration; else if (command.type === type_1.default.debug) this.debugging = true; } async _adjustScreenshotCommand(command) { const browserId = this.browserConnection.id; const { hasChromelessScreenshots } = await this.browserConnection.provider.hasCustomActionForBrowser(browserId); if (!hasChromelessScreenshots) command.generateScreenshotMark(); } async _setBreakpointIfNecessary(command, callsite) { if (!this.disableDebugBreakpoints && this.debugging && utils_1.canSetDebuggerBreakpointBeforeCommand(command)) await this._enqueueSetBreakpointCommand(callsite); } async executeCommand(command, callsite) { this.debugLog.command(command); if (this.pendingPageError && utils_1.isCommandRejectableByPageError(command)) return this._rejectCommandWithPageError(callsite); if (utils_1.isExecutableOnClientCommand(command)) this.addingDriverTasksCount++; this._adjustConfigurationWithCommand(command); await this._setBreakpointIfNecessary(command, callsite); if (utils_1.isScreenshotCommand(command)) await this._adjustScreenshotCommand(command); if (utils_1.isBrowserManipulationCommand(command)) { this.browserManipulationQueue.push(command); if (utils_1.isResizeWindowCommand(command) && this.opts.videoPath) this.warningLog.addWarning(warning_message_1.default.videoBrowserResizing, this.test.name); } if (command.type === type_1.default.wait) return delay_1.default(command.timeout); if (command.type === type_1.default.setPageLoadTimeout) return null; if (command.type === type_1.default.debug) return await this._enqueueSetBreakpointCommand(callsite); if (command.type === type_1.default.useRole) return await this._useRole(command.role, callsite); if (command.type === type_1.default.assertion) return this._executeAssertion(command, callsite); if (command.type === type_1.default.executeExpression) return await this._executeExpression(command, callsite); if (command.type === type_1.default.getBrowserConsoleMessages) return await this._enqueueBrowserConsoleMessagesCommand(command, callsite); return this._enqueueCommand(command, callsite); } _rejectCommandWithPageError(callsite) { const err = this.pendingPageError; err.callsite = callsite; this.pendingPageError = null; return pinkie_1.default.reject(err); } // Role management async getStateSnapshot() { const state = this.session.getStateSnapshot(); state.storages = await this.executeCommand(new serviceCommands.BackupStoragesCommand()); return state; } async switchToCleanRun(url) { this.ctx = Object.create(null); this.fixtureCtx = Object.create(null); this.consoleMessages = new browser_console_messages_1.default(); this.session.useStateSnapshot(testcafe_hammerhead_1.StateSnapshot.empty()); if (this.speed !== this.opts.speed) { const setSpeedCommand = new actionCommands.SetTestSpeedCommand({ speed: this.opts.speed }); await this.executeCommand(setSpeedCommand); } if (this.pageLoadTimeout !== this.opts.pageLoadTimeout) { const setPageLoadTimeoutCommand = new actionCommands.SetPageLoadTimeoutCommand({ duration: this.opts.pageLoadTimeout }); await this.executeCommand(setPageLoadTimeoutCommand); } await this.navigateToUrl(url, true); if (this.activeDialogHandler) { const removeDialogHandlerCommand = new actionCommands.SetNativeDialogHandlerCommand({ dialogHandler: { fn: null } }); await this.executeCommand(removeDialogHandlerCommand); } } async navigateToUrl(url, forceReload, stateSnapshot) { const navigateCommand = new actions_1.NavigateToCommand({ url, forceReload, stateSnapshot }); await this.executeCommand(navigateCommand); } async _getStateSnapshotFromRole(role) { const prevPhase = this.phase; this.phase = phase_1.default.inRoleInitializer; if (role.phase === phase_2.default.uninitialized) await role.initialize(this); else if (role.phase === phase_2.default.pendingInitialization) await promisify_event_1.default(role, 'initialized'); if (role.initErr) throw role.initErr; this.phase = prevPhase; return role.stateSnapshot; } async _useRole(role, callsite) { if (this.phase === phase_1.default.inRoleInitializer) throw new test_run_1.RoleSwitchInRoleInitializerError(callsite); this.disableDebugBreakpoints = true; const bookmark = new TestRunBookmark(this, role); await bookmark.init(); if (this.currentRoleId) this.usedRoleStates[this.currentRoleId] = await this.getStateSnapshot(); const stateSnapshot = this.usedRoleStates[role.id] || await this._getStateSnapshotFromRole(role); this.session.useStateSnapshot(stateSnapshot); this.currentRoleId = role.id; await bookmark.restore(callsite, stateSnapshot); this.disableDebugBreakpoints = false; } // Get current URL async getCurrentUrl() { const builder = new ClientFunctionBuilder(() => { /* eslint-disable no-undef */ return window.location.href; /* eslint-enable no-undef */ }, { boundTestRun: this }); const getLocation = builder.getFunction(); return await getLocation(); } _disconnect(err) { this.disconnected = true; if (this.currentDriverTask) this._rejectCurrentDriverTask(err); this.emit('disconnected', err); delete test_run_tracker_1.default.activeTestRuns[this.session.id]; } } exports.default = TestRun; // Service message handlers const ServiceMessages = TestRun.prototype; // NOTE: this function is time-critical and must return ASAP to avoid client disconnection ServiceMessages[client_messages_1.default.ready] = function (msg) { this.debugLog.driverMessage(msg); this.emit('connected'); this._clearPendingRequest(); // NOTE: the driver sends the status for the second time if it didn't get a response at the // first try. This is possible when the page was unloaded after the driver sent the status. if (msg.status.id === this.lastDriverStatusId) return this.lastDriverStatusResponse; this.lastDriverStatusId = msg.status.id; this.lastDriverStatusResponse = this._handleDriverRequest(msg.status); if (this.lastDriverStatusResponse) return this.lastDriverStatusResponse; // NOTE: we send an empty response after the MAX_RESPONSE_DELAY timeout is exceeded to keep connection // with the client and prevent the response timeout exception on the client side const responseTimeout = setTimeout(() => this._resolvePendingRequest(null), MAX_RESPONSE_DELAY); return new pinkie_1.default((resolve, reject) => { this.pendingRequest = { resolve, reject, responseTimeout }; }); }; ServiceMessages[client_messages_1.default.readyForBrowserManipulation] = async function (msg) { this.debugLog.driverMessage(msg); let result = null; let error = null; try { result = await this.browserManipulationQueue.executePendingManipulation(msg); } catch (err) { error = err; } return { result, error }; }; ServiceMessages[client_messages_1.default.waitForFileDownload] = function (msg) { this.debugLog.driverMessage(msg); return new pinkie_1.default(resolve => { if (this.fileDownloadingHandled) { this.fileDownloadingHandled = false; resolve(true); } else this.resolveWaitForFileDownloadingPromise = resolve; }); }; module.exports = exports.default; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdGVzdC1ydW4vaW5kZXguanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxtQ0FBNkM7QUFDN0MsMkRBQXNEO0FBQ3RELHNFQUE2QztBQUM3QyxvREFBNkI7QUFDN0Isd0RBQWdDO0FBQ2hDLHVGQUE2RDtBQUM3RCxpRkFBd0Q7QUFDeEQsNERBQTBDO0FBQzFDLGlHQUFvRjtBQUNwRixzRUFBcUQ7QUFDckQsa0RBSzZCO0FBQzdCLG9EQUE0QjtBQUM1Qix3RUFBZ0Q7QUFDaEQsMkRBQTJDO0FBQzNDLDJEQUFtQztBQUNuQyxvRUFBNEM7QUFDNUMsK0VBQXFEO0FBQ3JELDBEQUF1QztBQUN2QywwRUFBeUQ7QUFDekQsMEZBQWdFO0FBQ2hFLHVGQUEyRjtBQUMzRiwrRUFBc0Q7QUFDdEQsdUZBQStEO0FBQy9ELDZEQUF3RTtBQUN4RSxnREFBdUQ7QUFFdkQsNENBUTBCO0FBRTFCLDJDQUFrRDtBQUVsRCxNQUFNLFdBQVcsR0FBbUIsT0FBTyxDQUFDLGFBQWEsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3BFLE1BQU0saUJBQWlCLEdBQWEsV0FBVyxDQUFDLHNCQUFzQixDQUFDLENBQUM7QUFDeEUsTUFBTSxxQkFBcUIsR0FBUyxXQUFXLENBQUMsNkNBQTZDLENBQUMsQ0FBQztBQUMvRixNQUFNLG1CQUFtQixHQUFXLFdBQVcsQ0FBQyx5QkFBeUIsQ0FBQyxDQUFDO0FBQzNFLE1BQU0sd0JBQXdCLEdBQU0sV0FBVyxDQUFDLDhCQUE4QixDQUFDLENBQUM7QUFDaEYsTUFBTSxlQUFlLEdBQWUsV0FBVyxDQUFDLFlBQVksQ0FBQyxDQUFDO0FBQzlELE1BQU0saUJBQWlCLEdBQWEsV0FBVyxDQUFDLHdCQUF3QixDQUFDLENBQUM7QUFDMUUsTUFBTSxjQUFjLEdBQWdCLFdBQVcsQ0FBQyxvQkFBb0IsQ0FBQyxDQUFDO0FBQ3RFLE1BQU0sMkJBQTJCLEdBQUcsV0FB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