Innovenergy_trunk/frontend/node_modules/testcafe/lib/api/test-controller/index.js

461 lines
80 KiB
JavaScript
Raw Normal View History

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
// TODO: Fix https://github.com/DevExpress/testcafe/issues/4139 to get rid of Pinkie
const pinkie_1 = __importDefault(require("pinkie"));
const lodash_1 = require("lodash");
const get_callsite_1 = require("../../errors/get-callsite");
const client_function_builder_1 = __importDefault(require("../../client-functions/client-function-builder"));
const assertion_1 = __importDefault(require("./assertion"));
const delegated_api_1 = require("../../utils/delegated-api");
const add_rendered_warning_1 = __importDefault(require("../../notifications/add-rendered-warning"));
const deprecated_1 = require("../../notifications/deprecated");
const actions_1 = require("../../test-run/commands/actions");
const browser_manipulation_1 = require("../../test-run/commands/browser-manipulation");
const observation_1 = require("../../test-run/commands/observation");
const execution_context_1 = require("./execution-context");
const types_1 = require("../../client-functions/types");
const test_run_proxy_1 = __importDefault(require("../../services/compiler/test-run-proxy"));
const test_run_1 = require("../../errors/test-run");
const assertion_2 = require("../../test-run/commands/assertion");
const callsite_1 = require("../../utils/callsite");
const re_executable_promise_1 = __importDefault(require("../../utils/re-executable-promise"));
const send_1 = require("../../test-run/request/send");
const runtime_1 = require("../../errors/runtime");
const types_2 = require("../../errors/types");
const custom_actions_1 = __importDefault(require("./custom-actions"));
const delegated_api_2 = __importDefault(require("./delegated-api"));
const originalThen = pinkie_1.default.resolve().then;
let inDebug = false;
class TestController {
constructor(testRun) {
var _a;
this._executionContext = null;
this.testRun = testRun;
this.executionChain = pinkie_1.default.resolve();
this.warningLog = testRun.warningLog;
this._customActions = new custom_actions_1.default(this, (_a = testRun === null || testRun === void 0 ? void 0 : testRun.opts) === null || _a === void 0 ? void 0 : _a.customActions);
this._addTestControllerToExecutionChain();
}
_addTestControllerToExecutionChain() {
this.executionChain._testController = this;
}
// NOTE: TestCafe executes actions and assertions asynchronously in the following cases:
// a) The `await` keyword that proceeds the method declaration triggers the `then` function of a Promise.
// b) The action is chained to another `awaited` method.
//
// In order to track missing `await` statements, TestCafe exposes a special Promise to the user.
// When TestCafe detects a missing `await` statement, it compares the method's callsite to the call site of the exposed Promise.
// This workaround is necessary for situations like these:
//
// var t2 = t.click('#btn1'); // <-- stores new callsiteWithoutAwait
// await t2; // <-- callsiteWithoutAwait = null
// t.click('#btn2'); // <-- stores new callsiteWithoutAwait
// await t2.click('#btn3'); // <-- without check it will set callsiteWithoutAwait = null, so we will lost tracking
_createExtendedPromise(promise, callsite) {
const extendedPromise = promise.then(lodash_1.identity);
const observedCallsites = this.testRun.observedCallsites;
const markCallsiteAwaited = () => observedCallsites.callsitesWithoutAwait.delete(callsite);
extendedPromise.then = function () {
markCallsiteAwaited();
return originalThen.apply(this, arguments);
};
(0, delegated_api_1.delegateAPI)(extendedPromise, TestController.API_LIST, {
handler: this,
proxyMethod: markCallsiteAwaited,
});
return extendedPromise;
}
_createCommand(CmdCtor, cmdArgs, callsite) {
try {
return new CmdCtor(cmdArgs, this.testRun);
}
catch (err) {
err.callsite = callsite;
throw err;
}
}
_enqueueTask(apiMethodName, createTaskExecutor, callsite) {
const executor = createTaskExecutor();
this.executionChain.then = originalThen;
this.executionChain = this.executionChain.then(executor);
this.testRun.observedCallsites.callsitesWithoutAwait.add(callsite);
this.executionChain = this._createExtendedPromise(this.executionChain, callsite);
this._addTestControllerToExecutionChain();
return this.executionChain;
}
enqueueCommand(CmdCtor, cmdArgs, validateCommandFn, callsite) {
callsite = callsite || (0, get_callsite_1.getCallsiteForMethod)(CmdCtor.methodName);
const command = this._createCommand(CmdCtor, cmdArgs, callsite);
if (typeof validateCommandFn === 'function')
validateCommandFn(this, command, callsite);
return this._enqueueTask(command.methodName, () => {
return () => {
return this.testRun.executeCommand(command, callsite)
.catch(err => {
this.executionChain = pinkie_1.default.resolve();
throw err;
});
};
}, callsite);
}
_validateMultipleWindowCommand(apiMethodName) {
const { disableMultipleWindows, activeWindowId } = this.testRun;
if (disableMultipleWindows)
throw new test_run_1.MultipleWindowsModeIsDisabledError(apiMethodName);
if (!activeWindowId)
throw new test_run_1.MultipleWindowsModeIsNotAvailableInRemoteBrowserError(apiMethodName);
}
getExecutionContext() {
if (!this._executionContext)
this._executionContext = (0, execution_context_1.createExecutionContext)(this.testRun);
return this._executionContext;
}
// API implementation
// We need implementation methods to obtain correct callsites. If we use plain API
// methods in chained wrappers then we will have callsite for the wrapped method
// in this file instead of chained method callsite in user code.
_ctx$getter() {
return this.testRun.ctx;
}
_ctx$setter(val) {
this.testRun.ctx = val;
return this.testRun.ctx;
}
_fixtureCtx$getter() {
return this.testRun.fixtureCtx;
}
_browser$getter() {
return this.testRun.browser;
}
_customActions$getter() {
return this._customActions || new custom_actions_1.default(this, this.testRun.opts.customActions);
}
[(0, delegated_api_2.default)(actions_1.DispatchEventCommand.methodName)](selector, eventName, options = {}) {
return this.enqueueCommand(actions_1.DispatchEventCommand, { selector, eventName, options, relatedTarget: options.relatedTarget });
}
_prepareCookieArguments(args, isSetCommand = false) {
const urlsArg = (0, lodash_1.castArray)(args[1]);
const urls = Array.isArray(urlsArg) && typeof urlsArg[0] === 'string' ? urlsArg : [];
const cookiesArg = urls.length ? args[0] : args;
const cookies = [];
(0, lodash_1.flattenDeep)((0, lodash_1.castArray)(cookiesArg)).forEach(cookie => {
if (isSetCommand && !cookie.name && typeof cookie === 'object')
Object.entries(cookie).forEach(([name, value]) => cookies.push({ name, value }));
else if (!isSetCommand && typeof cookie === 'string')
cookies.push({ name: cookie });
else
cookies.push(cookie);
});
return { urls, cookies };
}
[(0, delegated_api_2.default)(actions_1.GetCookiesCommand.methodName)](...args) {
return this.enqueueCommand(actions_1.GetCookiesCommand, this._prepareCookieArguments(args));
}
[(0, delegated_api_2.default)(actions_1.SetCookiesCommand.methodName)](...args) {
const { urls, cookies } = this._prepareCookieArguments(args, true);
return this.enqueueCommand(actions_1.SetCookiesCommand, { cookies, url: urls[0] });
}
[(0, delegated_api_2.default)(actions_1.DeleteCookiesCommand.methodName)](...args) {
return this.enqueueCommand(actions_1.DeleteCookiesCommand, this._prepareCookieArguments(args));
}
_prepareRequestArguments(bindOptions, ...args) {
const [url, options] = typeof args[0] === 'object' ? [args[0].url, args[0]] : args;
return {
url,
options: Object.assign({}, options, bindOptions),
};
}
_createRequestFunction(bindOptions = {}) {
const controller = this;
const callsite = (0, get_callsite_1.getCallsiteForMethod)(actions_1.RequestCommand.methodName);
if (!controller.testRun || controller.testRun instanceof test_run_proxy_1.default)
throw new runtime_1.RequestRuntimeError(callsite, types_2.RUNTIME_ERRORS.requestCannotResolveTestRun);
return function (...args) {
const cmdArgs = controller._prepareRequestArguments(bindOptions, ...args);
const command = controller._createCommand(actions_1.RequestCommand, cmdArgs, callsite);
const options = Object.assign(Object.assign({}, command.options), { url: command.url || command.options.url || '' });
const promise = re_executable_promise_1.default.fromFn(async () => {
return (0, send_1.sendRequestThroughAPI)(controller.testRun, options, callsite);
});
actions_1.RequestCommand.resultGetters.forEach(getter => {
Object.defineProperty(promise, getter, {
get: () => re_executable_promise_1.default.fromFn(async () => {
const response = await (0, send_1.sendRequestThroughAPI)(controller.testRun, options, callsite);
return response[getter];
}),
});
});
return promise;
};
}
_decorateRequestFunction(fn) {
actions_1.RequestCommand.extendedMethods.forEach(method => {
Object.defineProperty(fn, method, {
value: this._createRequestFunction({ method }),
});
});
}
[(0, delegated_api_2.default)(actions_1.RequestCommand.methodName, 'getter')]() {
const fn = this._createRequestFunction();
this._decorateRequestFunction(fn);
return fn;
}
[(0, delegated_api_2.default)(actions_1.ClickCommand.methodName)](selector, options) {
return this.enqueueCommand(actions_1.ClickCommand, { selector, options });
}
[(0, delegated_api_2.default)(actions_1.RightClickCommand.methodName)](selector, options) {
return this.enqueueCommand(actions_1.RightClickCommand, { selector, options });
}
[(0, delegated_api_2.default)(actions_1.DoubleClickCommand.methodName)](selector, options) {
return this.enqueueCommand(actions_1.DoubleClickCommand, { selector, options });
}
[(0, delegated_api_2.default)(actions_1.HoverCommand.methodName)](selector, options) {
return this.enqueueCommand(actions_1.HoverCommand, { selector, options });
}
[(0, delegated_api_2.default)(actions_1.DragCommand.methodName)](selector, dragOffsetX, dragOffsetY, options) {
return this.enqueueCommand(actions_1.DragCommand, { selector, dragOffsetX, dragOffsetY, options });
}
[(0, delegated_api_2.default)(actions_1.DragToElementCommand.methodName)](selector, destinationSelector, options) {
return this.enqueueCommand(actions_1.DragToElementCommand, { selector, destinationSelector, options });
}
_getSelectorForScroll(args) {
const selector = typeof args[0] === 'string' || (0, types_1.isSelector)(args[0]) ? args[0] : null;
if (selector)
args.shift();
else
// NOTE: here we use document.scrollingElement for old Safari versions
// document.documentElement does not work as expected on Mojave Safari 12.1/ High Sierra Safari 11.1
// eslint-disable-next-line no-undef
return () => document.scrollingElement || document.documentElement;
return selector;
}
_getPosition(args) {
const position = args.length === 1 && typeof args[0] === 'string' ? args[0] : null;
if (position)
args.shift();
return position;
}
[(0, delegated_api_2.default)(actions_1.ScrollCommand.methodName)](...args) {
let position = this._getPosition(args);
const selector = this._getSelectorForScroll(args);
let x = void 0;
let y = void 0;
let options = void 0;
if (typeof args[0] === 'string')
[position, options] = args;
if (typeof args[0] === 'number')
[x, y, options] = args;
return this.enqueueCommand(actions_1.ScrollCommand, { selector, x, y, position, options });
}
[(0, delegated_api_2.default)(actions_1.ScrollByCommand.methodName)](...args) {
const selector = this._getSelectorForScroll(args);
const [byX, byY, options] = args;
return this.enqueueCommand(actions_1.ScrollByCommand, { selector, byX, byY, options });
}
[(0, delegated_api_2.default)(actions_1.ScrollIntoViewCommand.methodName)](selector, options) {
return this.enqueueCommand(actions_1.ScrollIntoViewCommand, { selector, options });
}
[(0, delegated_api_2.default)(actions_1.TypeTextCommand.methodName)](selector, text, options) {
return this.enqueueCommand(actions_1.TypeTextCommand, { selector, text, options });
}
[(0, delegated_api_2.default)(actions_1.SelectTextCommand.methodName)](selector, startPos, endPos, options) {
return this.enqueueCommand(actions_1.SelectTextCommand, { selector, startPos, endPos, options });
}
[(0, delegated_api_2.default)(actions_1.SelectTextAreaContentCommand.methodName)](selector, startLine, startPos, endLine, endPos, options) {
return this.enqueueCommand(actions_1.SelectTextAreaContentCommand, {
selector,
startLine,
startPos,
endLine,
endPos,
options,
});
}
[(0, delegated_api_2.default)(actions_1.SelectEditableContentCommand.methodName)](startSelector, endSelector, options) {
return this.enqueueCommand(actions_1.SelectEditableContentCommand, {
startSelector,
endSelector,
options,
});
}
[(0, delegated_api_2.default)(actions_1.PressKeyCommand.methodName)](keys, options) {
return this.enqueueCommand(actions_1.PressKeyCommand, { keys, options });
}
[(0, delegated_api_2.default)(observation_1.WaitCommand.methodName)](timeout) {
return this.enqueueCommand(observation_1.WaitCommand, { timeout });
}
[(0, delegated_api_2.default)(actions_1.NavigateToCommand.methodName)](url) {
return this.enqueueCommand(actions_1.NavigateToCommand, { url });
}
[(0, delegated_api_2.default)(actions_1.SetFilesToUploadCommand.methodName)](selector, filePath) {
return this.enqueueCommand(actions_1.SetFilesToUploadCommand, { selector, filePath });
}
[(0, delegated_api_2.default)(actions_1.ClearUploadCommand.methodName)](selector) {
return this.enqueueCommand(actions_1.ClearUploadCommand, { selector });
}
[(0, delegated_api_2.default)(browser_manipulation_1.TakeScreenshotCommand.methodName)](options) {
if (options && typeof options !== 'object')
options = { path: options };
return this.enqueueCommand(browser_manipulation_1.TakeScreenshotCommand, options);
}
[(0, delegated_api_2.default)(browser_manipulation_1.TakeElementScreenshotCommand.methodName)](selector, ...args) {
const commandArgs = { selector };
if (args[1]) {
commandArgs.path = args[0];
commandArgs.options = args[1];
}
else if (typeof args[0] === 'object')
commandArgs.options = args[0];
else
commandArgs.path = args[0];
return this.enqueueCommand(browser_manipulation_1.TakeElementScreenshotCommand, commandArgs);
}
[(0, delegated_api_2.default)(browser_manipulation_1.ResizeWindowCommand.methodName)](width, height) {
return this.enqueueCommand(browser_manipulation_1.ResizeWindowCommand, { width, height });
}
[(0, delegated_api_2.default)(browser_manipulation_1.ResizeWindowToFitDeviceCommand.methodName)](device, options) {
return this.enqueueCommand(browser_manipulation_1.ResizeWindowToFitDeviceCommand, { device, options });
}
[(0, delegated_api_2.default)(browser_manipulation_1.MaximizeWindowCommand.methodName)]() {
return this.enqueueCommand(browser_manipulation_1.MaximizeWindowCommand);
}
[(0, delegated_api_2.default)(actions_1.SwitchToIframeCommand.methodName)](selector) {
return this.enqueueCommand(actions_1.SwitchToIframeCommand, { selector });
}
[(0, delegated_api_2.default)(actions_1.SwitchToMainWindowCommand.methodName)]() {
return this.enqueueCommand(actions_1.SwitchToMainWindowCommand);
}
[(0, delegated_api_2.default)(actions_1.OpenWindowCommand.methodName)](url) {
this._validateMultipleWindowCommand(actions_1.OpenWindowCommand.methodName);
return this.enqueueCommand(actions_1.OpenWindowCommand, { url });
}
[(0, delegated_api_2.default)(actions_1.CloseWindowCommand.methodName)](window) {
const windowId = (window === null || window === void 0 ? void 0 : window.id) || null;
this._validateMultipleWindowCommand(actions_1.CloseWindowCommand.methodName);
return this.enqueueCommand(actions_1.CloseWindowCommand, { windowId });
}
[(0, delegated_api_2.default)(actions_1.GetCurrentWindowCommand.methodName)]() {
this._validateMultipleWindowCommand(actions_1.GetCurrentWindowCommand.methodName);
return this.enqueueCommand(actions_1.GetCurrentWindowCommand);
}
[(0, delegated_api_2.default)(actions_1.SwitchToWindowCommand.methodName)](windowSelector) {
this._validateMultipleWindowCommand(actions_1.SwitchToWindowCommand.methodName);
let command;
let args;
if (typeof windowSelector === 'function') {
command = actions_1.SwitchToWindowByPredicateCommand;
args = { checkWindow: windowSelector };
}
else {
command = actions_1.SwitchToWindowCommand;
args = { windowId: windowSelector === null || windowSelector === void 0 ? void 0 : windowSelector.id };
}
return this.enqueueCommand(command, args);
}
[(0, delegated_api_2.default)(actions_1.SwitchToParentWindowCommand.methodName)]() {
this._validateMultipleWindowCommand(actions_1.SwitchToParentWindowCommand.methodName);
return this.enqueueCommand(actions_1.SwitchToParentWindowCommand);
}
[(0, delegated_api_2.default)(actions_1.SwitchToPreviousWindowCommand.methodName)]() {
this._validateMultipleWindowCommand(actions_1.SwitchToPreviousWindowCommand.methodName);
return this.enqueueCommand(actions_1.SwitchToPreviousWindowCommand);
}
_eval$(fn, options) {
if (!(0, lodash_1.isNil)(options))
options = (0, lodash_1.assign)({}, options, { boundTestRun: this });
const builder = new client_function_builder_1.default(fn, options, { instantiation: 'eval', execution: 'eval' });
const clientFn = builder.getFunction();
return clientFn();
}
[(0, delegated_api_2.default)(actions_1.SetNativeDialogHandlerCommand.methodName)](fn, options) {
return this.enqueueCommand(actions_1.SetNativeDialogHandlerCommand, {
dialogHandler: { fn, options },
});
}
[(0, delegated_api_2.default)(actions_1.GetNativeDialogHistoryCommand.methodName)]() {
const callsite = (0, get_callsite_1.getCallsiteForMethod)(actions_1.GetNativeDialogHistoryCommand.methodName);
const command = this._createCommand(actions_1.GetNativeDialogHistoryCommand, {}, callsite);
return this.testRun.executeCommand(command, callsite);
}
[(0, delegated_api_2.default)(actions_1.GetBrowserConsoleMessagesCommand.methodName)]() {
const callsite = (0, get_callsite_1.getCallsiteForMethod)(actions_1.GetBrowserConsoleMessagesCommand.methodName);
const command = this._createCommand(actions_1.GetBrowserConsoleMessagesCommand, {}, callsite);
return this.testRun.executeCommand(command, callsite);
}
checkForExcessiveAwaits(checkedCallsite, { actionId }) {
const snapshotPropertyCallsites = this.testRun.observedCallsites.snapshotPropertyCallsites;
const callsiteId = (0, callsite_1.getCallsiteId)(checkedCallsite);
// NOTE: If there are unasserted callsites, we should add all of them to awaitedSnapshotWarnings.
// The warnings themselves are raised after the test run in wrap-test-function
if (snapshotPropertyCallsites[callsiteId] && !snapshotPropertyCallsites[callsiteId].checked) {
for (const propertyCallsite of snapshotPropertyCallsites[callsiteId].callsites)
this.testRun.observedCallsites.awaitedSnapshotWarnings.set((0, callsite_1.getCallsiteStackFrameString)(propertyCallsite), { callsite: propertyCallsite, actionId });
delete snapshotPropertyCallsites[callsiteId];
}
else
snapshotPropertyCallsites[callsiteId] = { callsites: [], checked: true };
}
[(0, delegated_api_2.default)(assertion_2.AssertionCommand.methodName)](actual) {
const callsite = (0, get_callsite_1.getCallsiteForMethod)(assertion_2.AssertionCommand.methodName);
return new assertion_1.default(actual, this, callsite);
}
[(0, delegated_api_2.default)(observation_1.DebugCommand.methodName)]() {
// NOTE: do not need to enqueue the Debug command if we are in debugging mode.
// The Debug command will be executed by CDP.
// Also, we are forced to add empty function to the execution chain to preserve it.
return this.isCompilerServiceMode() ? this._enqueueTask(observation_1.DebugCommand.methodName, lodash_1.noop) : this.enqueueCommand(observation_1.DebugCommand);
}
[(0, delegated_api_2.default)(actions_1.SetTestSpeedCommand.methodName)](speed) {
return this.enqueueCommand(actions_1.SetTestSpeedCommand, { speed });
}
[(0, delegated_api_2.default)(actions_1.SetPageLoadTimeoutCommand.methodName)](duration) {
return this.enqueueCommand(actions_1.SetPageLoadTimeoutCommand, { duration }, (testController, command) => {
(0, add_rendered_warning_1.default)(testController.warningLog, { message: (0, deprecated_1.getDeprecationMessage)(deprecated_1.DEPRECATED.setPageLoadTimeout), actionId: command.actionId });
});
}
[(0, delegated_api_2.default)(actions_1.UseRoleCommand.methodName)](role) {
return this.enqueueCommand(actions_1.UseRoleCommand, { role });
}
[(0, delegated_api_2.default)(actions_1.SkipJsErrorsCommand.methodName)](options) {
return this.enqueueCommand(actions_1.SkipJsErrorsCommand, { options });
}
[(0, delegated_api_2.default)(actions_1.AddRequestHooksCommand.methodName)](...hooks) {
hooks = (0, lodash_1.flattenDeep)(hooks);
return this.enqueueCommand(actions_1.AddRequestHooksCommand, { hooks });
}
[(0, delegated_api_2.default)(actions_1.RemoveRequestHooksCommand.methodName)](...hooks) {
hooks = (0, lodash_1.flattenDeep)(hooks);
return this.enqueueCommand(actions_1.RemoveRequestHooksCommand, { hooks });
}
static enableDebugForNonDebugCommands() {
inDebug = true;
}
static disableDebugForNonDebugCommands() {
inDebug = false;
}
shouldStop(command) {
// NOTE: should never stop in not compliler debugging mode
if (!this.isCompilerServiceMode())
return false;
// NOTE: should always stop on Debug command
if (command === 'debug')
return true;
// NOTE: should stop on other actions after the `Next Action` button is clicked
if (inDebug) {
inDebug = false;
return true;
}
return false;
}
isCompilerServiceMode() {
return this.testRun instanceof test_run_proxy_1.default;
}
}
exports.default = TestController;
TestController.API_LIST = (0, delegated_api_1.getDelegatedAPIList)(TestController.prototype);
(0, delegated_api_1.delegateAPI)(TestController.prototype, TestController.API_LIST, { useCurrentCtxAsHandler: true });
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3Rlc3QtY29udHJvbGxlci9pbmRleC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLG9GQUFvRjtBQUNwRixvREFBNkI7QUFDN0IsbUNBT2dCO0FBRWhCLDREQUFpRTtBQUNqRSw2R0FBbUY7QUFDbkYsNERBQW9DO0FBQ3BDLDZEQUE2RTtBQUM3RSxvR0FBa0U7QUFDbEUsK0RBQW1GO0FBRW5GLDZEQXlDeUM7QUFFekMsdUZBTXNEO0FBRXRELHFFQUFnRjtBQUNoRiwyREFBOEU7QUFDOUUsd0RBQTBEO0FBQzFELDRGQUFrRTtBQUVsRSxvREFHK0I7QUFFL0IsaUVBQXFFO0FBQ3JFLG1EQUFrRjtBQUNsRiw4RkFBb0U7QUFDcEUsc0RBQW1GO0FBQ25GLGtEQUEyRDtBQUMzRCw4Q0FBb0Q7QUFDcEQsc0VBQTZDO0FBQzdDLG9FQUEyQztBQUUzQyxNQUFNLFlBQVksR0FBRyxnQkFBTyxDQUFDLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQztBQUU1QyxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7QUFFcEIsTUFBcUIsY0FBYztJQUMvQixZQUFhLE9BQU87O1FBQ2hCLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUM7UUFFOUIsSUFBSSxDQUFDLE9BQU8sR0FBVSxPQUFPLENBQUM7UUFDOUIsSUFBSSxDQUFDLGNBQWMsR0FBRyxnQkFBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ3hDLElBQUksQ0FBQyxVQUFVLEdBQU8sT0FBTyxDQUFDLFVBQVUsQ0FBQztRQUN6QyxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksd0JBQWEsQ0FBQyxJQUFJLEVBQUUsTUFBQSxPQUFPLGFBQVAsT0FBTyx1QkFBUCxPQUFPLENBQUUsSUFBSSwwQ0FBRSxhQUFhLENBQUMsQ0FBQztRQUU1RSxJQUFJLENBQUMsa0NBQWtDLEVBQUUsQ0FBQztJQUM5QyxDQUFDO0lBRUQs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