testcafe
Version:
Automated browser testing for the modern web development stack.
232 lines • 36.5 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const async_event_emitter_1 = __importDefault(require("../utils/async-event-emitter"));
//@ts-ignore
const testcafe_legacy_api_1 = require("testcafe-legacy-api");
const test_run_1 = __importDefault(require("../test-run"));
const session_controller_1 = __importDefault(require("../test-run/session-controller"));
const testcafe_hammerhead_1 = require("testcafe-hammerhead");
const quarantine_1 = require("../utils/get-options/quarantine");
const clientScriptsRouting = __importStar(require("../custom-client-scripts/routing"));
const types_1 = require("../errors/types");
const runtime_1 = require("../errors/runtime");
const debug_loggers_1 = require("../utils/debug-loggers");
const DISCONNECT_THRESHOLD = 3;
class TestRunController extends async_event_emitter_1.default {
constructor({ test, index, proxy, screenshots, warningLog, fixtureHookController, opts, testRunHook, messageBus, }) {
super();
this.clientScriptRoutes = [];
this.isNativeAutomation = false;
this.test = test;
this.index = index;
this._opts = opts;
this.id = (0, testcafe_hammerhead_1.generateUniqueId)();
this._proxy = proxy;
this._screenshots = screenshots;
this._warningLog = warningLog;
this._fixtureHookController = fixtureHookController;
this._testRunHook = testRunHook;
this._testRunCtor = TestRunController._getTestRunCtor(test, opts);
this.testRun = null;
this.done = false;
this._quarantine = this._opts.quarantineMode ? new quarantine_1.Quarantine() : null;
this._disconnectionCount = 0;
this._messageBus = messageBus;
}
static _getTestRunCtor(test, opts) {
if (opts.TestRunCtor)
return opts.TestRunCtor;
return test.isLegacy ? testcafe_legacy_api_1.TestRun : test_run_1.default;
}
async _createTestRun(connection, startRunExecutionTime) {
const screenshotCapturer = this._screenshots.createCapturerFor(this.test, this.index, this._quarantine, connection, this._warningLog);
const TestRunCtor = this._testRunCtor;
this.testRun = new TestRunCtor({
test: this.test,
browserConnection: connection,
globalWarningLog: this._warningLog,
opts: this._opts,
messageBus: this._messageBus,
nativeAutomation: this.isNativeAutomation,
screenshotCapturer,
startRunExecutionTime,
});
this.clientScriptRoutes = clientScriptsRouting.register({
proxy: this._proxy,
test: this.test,
nativeAutomation: this.isNativeAutomation,
folderName: this.testRun.id,
});
if (this.isNativeAutomation)
connection.resetActiveWindowId();
await this.testRun.initialize();
this._screenshots.addTestRun(this.test, this.testRun);
if (this.testRun.addQuarantineInfo)
this.testRun.addQuarantineInfo(this._quarantine);
if (this._quarantine) {
const { successThreshold, attemptLimit } = this._opts.quarantineMode;
this._quarantine.setCustomParameters(attemptLimit, successThreshold);
}
if (!this._quarantine || this._isFirstQuarantineAttempt()) {
await this.emit('test-run-create', {
testRun: this.testRun,
legacy: TestRunCtor === testcafe_legacy_api_1.TestRun,
test: this.test,
index: this.index,
quarantine: this._quarantine,
});
}
return this.testRun;
}
async _endQuarantine() {
if (this._quarantine.attempts.length > 1)
this.testRun.unstable = this._quarantine.getPassedAttempts().length > 0;
await this._emitTestRunDone();
}
_shouldKeepInQuarantine() {
const errors = this.testRun.errs;
const hasErrors = !!errors.length;
const attempts = this._quarantine.attempts;
const isFirstAttempt = this._isFirstQuarantineAttempt();
attempts.push({ testRunId: this.testRun.id, errors });
return isFirstAttempt ? hasErrors : !this._quarantine.isThresholdReached();
}
_isFirstQuarantineAttempt() {
return !!this._quarantine && !this._quarantine.attempts.length;
}
async _keepInQuarantine() {
await this._restartTest();
}
async _restartTest() {
await this.emit('test-run-restart');
}
async _testRunDoneInQuarantineMode() {
if (this._shouldKeepInQuarantine())
await this._keepInQuarantine();
else
await this._endQuarantine();
}
async _testRunDone() {
if (this._quarantine)
await this._testRunDoneInQuarantineMode();
else
await this._emitTestRunDone();
}
async _emitActionStart(args) {
await this._messageBus.emit('test-action-start', args);
}
async _emitActionDone(args) {
await this.emit('test-action-done', args);
}
async _emitTestRunDone() {
// NOTE: we should report test run completion in order they were completed in browser.
// To keep a sequence after fixture hook execution we use completion queue.
await this._fixtureHookController.runFixtureAfterHookIfNecessary(this.testRun);
await this._testRunHook.runTestRunAfterHookIfNecessary(this.testRun);
clientScriptsRouting.unRegister(this._proxy, this.clientScriptRoutes);
this.done = true;
await this.emit('test-run-done');
(0, debug_loggers_1.testRunControllerLogger)('done %s', this.id);
}
async _emitTestRunStart() {
await this._messageBus.emit('test-run-start', this.testRun);
}
async _testRunBeforeDone() {
let raiseEvent = !this._quarantine;
if (!raiseEvent) {
const isSuccessfulQuarantineFirstAttempt = this._isFirstQuarantineAttempt() && !this.testRun.errs.length;
const isAttemptsThresholdReached = this._quarantine.isThresholdReached(this.testRun.errs);
raiseEvent = isSuccessfulQuarantineFirstAttempt || isAttemptsThresholdReached;
}
if (raiseEvent)
await this.emit('test-run-before-done');
}
_testRunDisconnected(connection) {
this._disconnectionCount++;
const disconnectionThresholdExceeded = this._disconnectionCount >= DISCONNECT_THRESHOLD;
return connection
.processDisconnection(disconnectionThresholdExceeded)
.then(() => {
return this._restartTest();
});
}
_assignTestRunEvents(testRun, connection) {
testRun.on('action-start', async (args) => this._emitActionStart(Object.assign(args, { testRun })));
testRun.on('action-done', async (args) => this._emitActionDone(Object.assign(args, { testRun })));
testRun.once('start', async () => this._emitTestRunStart());
testRun.once('ready', async () => {
if (!this._quarantine || this._isFirstQuarantineAttempt())
await this.emit('test-run-ready');
});
testRun.once('before-done', () => this._testRunBeforeDone());
testRun.once('done', () => this._testRunDone());
testRun.once('disconnected', () => this._testRunDisconnected(connection));
}
get blocked() {
return this._fixtureHookController.isTestBlocked(this.test);
}
async _handleNativeAutomationMode(connection) {
this.isNativeAutomation = !this._opts.disableNativeAutomation;
const supportNativeAutomation = connection.supportNativeAutomation();
if (!this.isNativeAutomation || supportNativeAutomation)
return;
await this._messageBus.emit('before-test-run-created-error');
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.setNativeAutomationForUnsupportedBrowsers, connection.browserInfo.providerName);
}
async start(connection, startRunExecutionTime) {
(0, debug_loggers_1.testRunControllerLogger)('start %s %O %O', this.id, {
test: {
name: this.test.name,
id: this.test.id,
},
connection: {
userAgent: connection.userAgent,
id: connection.id,
},
});
await this._handleNativeAutomationMode(connection);
this._fixtureHookController.blockTestIfNecessary(this.test);
const testRun = await this._createTestRun(connection, startRunExecutionTime);
const hookOk = await this._testRunHook.runTestRunBeforeHookIfNecessary(testRun)
&& await this._fixtureHookController.runFixtureBeforeHookIfNecessary(testRun);
this._fixtureHookController.unblockTest(this.test);
if (this.test.skip || !hookOk) {
await this._emitTestRunStart();
await this.emit('test-run-before-done');
await this._emitTestRunDone();
return null;
}
this._assignTestRunEvents(testRun, connection);
testRun.start();
return session_controller_1.default.getSessionUrl(testRun, this._proxy);
}
}
exports.default = TestRunController;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC1ydW4tY29udHJvbGxlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ydW5uZXIvdGVzdC1ydW4tY29udHJvbGxlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsdUZBQTZEO0FBQzdELFlBQVk7QUFDWiw2REFBK0Q7QUFDL0QsMkRBQWtDO0FBQ2xDLHdGQUErRDtBQUUvRCw2REFBOEQ7QUFPOUQsZ0VBQTZEO0FBRzdELHVGQUF5RTtBQUN6RSwyQ0FBaUQ7QUFDakQsK0NBQWlEO0FBQ2pELDBEQUFpRTtBQUVqRSxNQUFNLG9CQUFvQixHQUFHLENBQUMsQ0FBQztBQUUvQixNQUFxQixpQkFBa0IsU0FBUSw2QkFBaUI7SUFtQjVELFlBQW9CLEVBQ2hCLElBQUksRUFDSixLQUFLLEVBQ0wsS0FBSyxFQUNMLFdBQVcsRUFDWCxVQUFVLEVBQ1YscUJBQXFCLEVBQ3JCLElBQUksRUFDSixXQUFXLEVBQ1gsVUFBVSxHQUNVO1FBQ3BCLEtBQUssRUFBRSxDQUFDO1FBZkosdUJBQWtCLEdBQWEsRUFBRSxDQUFDO1FBQ2xDLHVCQUFrQixHQUFHLEtBQUssQ0FBQztRQWdCL0IsSUFBSSxDQUFDLElBQUksR0FBSSxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFDbkIsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUM7UUFDbEIsSUFBSSxDQUFDLEVBQUUsR0FBTSxJQUFBLHNDQUFnQixHQUFFLENBQUM7UUFFaEMsSUFBSSxDQUFDLE1BQU0sR0FBbUIsS0FBSyxDQUFDO1FBQ3BDLElBQUksQ0FBQyxZQUFZLEdBQWEsV0FBVyxDQUFDO1FBQzFDLElBQUksQ0FBQyxXQUFXLEdBQWMsVUFBVSxDQUFDO1FBQ3pDLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxxQkFBcUIsQ0FBQztRQUNwRCxJQUFJLENBQUMsWUFBWSxHQUFhLFdBQVcsQ0FBQztR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QUU1RCxNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQUMsVUFBVSxFQUFFLHFCQUFxQixDQUFDLENBQUM7UUFFN0UsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsWUFBWSxDQUFDLCtCQUErQixDQUFDLE9BQU8sQ0FBQztlQUM3RCxNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQywrQkFBK0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUU3RixJQUFJLENBQUMsc0JBQXNCLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUVuRCxJQUFJLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQzNCLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7WUFDL0IsTUFBTSxJQUFJLENBQUMsSUFBSSxDQUFDLHNCQUFzQixDQUFDLENBQUM7WUFDeEMsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztZQUU5QixPQUFPLElBQUksQ0FBQztTQUNmO1FBRUQsSUFBSSxDQUFDLG9CQUFvQixDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUUvQyxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUM7UUFFaEIsT0FBTyw0QkFBaUIsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqRSxDQUFDO0NBQ0o7QUFuUkQsb0NBbVJDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEFzeW5jRXZlbnRFbWl0dGVyIGZyb20gJy4uL3V0aWxzL2FzeW5jLWV2ZW50LWVtaXR0ZXInO1xuLy9AdHMtaWdub3JlXG5pbXBvcnQgeyBUZXN0UnVuIGFzIExlZ2FjeVRlc3RSdW4gfSBmcm9tICd0ZXN0Y2FmZS1sZWdhY3ktYXBpJztcbmltcG9ydCBUZXN0UnVuIGZyb20gJy4uL3Rlc3QtcnVuJztcbmltcG9ydCBTZXNzaW9uQ29udHJvbGxlciBmcm9tICcuLi90ZXN0LXJ1bi9zZXNzaW9uLWNvbnRyb2xsZXInO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uIGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbic7XG5pbXBvcnQgeyBQcm94eSwgZ2VuZXJhdGVVbmlxdWVJZCB9IGZyb20gJ3Rlc3RjYWZlLWhhbW1lcmhlYWQnO1xuaW1wb3J0IFRlc3QgZnJvbSAnLi4vYXBpL3N0cnVjdHVyZS90ZXN0JztcbmltcG9ydCBTY3JlZW5zaG90cyBmcm9tICcuLi9zY3JlZW5zaG90cyc7XG5pbXBvcnQgV2FybmluZ0xvZyBmcm9tICcuLi9ub3RpZmljYXRpb25zL3dhcm5pbmctbG9nJztcbmltcG9ydCBGaXh0dXJlSG9va0NvbnRyb2xsZXIgZnJvbSAnLi9maXh0dXJlLWhvb2stY29udHJvbGxlcic7XG5pbXBvcnQgeyBEaWN0aW9uYXJ5IH0gZnJvbSAnLi4vY29uZmlndXJhdGlvbi9pbnRlcmZhY2VzJztcbmltcG9ydCB7IEFjdGlvbkV2ZW50QXJnLCBUZXN0UnVuQ29udHJvbGxlckluaXQgfSBmcm9tICcuL2ludGVyZmFjZXMnO1xuaW1wb3J0IHsgUXVhcmFudGluZSB9IGZyb20gJy4uL3V0aWxzL2dldC1vcHRpb25zL3F1YXJhbnRpbmUnO1xuaW1wb3J0IE1lc3NhZ2VCdXMgZnJvbSAnLi4vdXRpbHMvbWVzc2FnZS1idXMnO1xuaW1wb3J0IFRlc3RSdW5Ib29rQ29udHJvbGxlciBmcm9tICcuL3Rlc3QtcnVuLWhvb2stY29udHJvbGxlcic7XG5pbXBvcnQgKiBhcyBjbGllbnRTY3JpcHRzUm91dGluZyBmcm9tICcuLi9jdXN0b20tY2xpZW50LXNjcmlwdHMvcm91dGluZyc7XG5pbXBvcnQgeyBSVU5USU1FX0VSUk9SUyB9IGZyb20gJy4uL2Vycm9ycy90eXBlcyc7XG5pbXBvcnQgeyBHZW5lcmFsRXJyb3IgfSBmcm9tICcuLi9lcnJvcnMvcnVudGltZSc7XG5pbXBvcnQgeyB0ZXN0UnVuQ29udHJvbGxlckxvZ2dlciB9IGZyb20gJy4uL3V0aWxzL2RlYnVnLWxvZ2dlcnMnO1xuXG5jb25zdCBESVNDT05ORUNUX1RIUkVTSE9MRCA9IDM7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlc3RSdW5Db250cm9sbGVyIGV4dGVuZHMgQXN5bmNFdmVudEVtaXR0ZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3F1YXJhbnRpbmU6IG51bGwgfCBRdWFyYW50aW5lO1xuICAgIHByaXZhdGUgX2Rpc2Nvbm5lY3Rpb25Db3VudDogbnVtYmVyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Byb3h5OiBQcm94eTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgaW5kZXg6IG51bWJlcjtcbiAgICBwdWJsaWMgdGVzdDogVGVzdDtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9vcHRzOiBEaWN0aW9uYXJ5PE9wdGlvblZhbHVlPjtcbiAgICBwcml2YXRlIF9zY3JlZW5zaG90czogU2NyZWVuc2hvdHM7XG4gICAgcHJpdmF0ZSByZWFkb25seSBfd2FybmluZ0xvZzogV2FybmluZ0xvZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9maXh0dXJlSG9va0NvbnRyb2xsZXI6IEZpeHR1cmVIb29rQ29udHJvbGxlcjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF90ZXN0UnVuQ3RvcjogTGVnYWN5VGVzdFJ1blsnY29uc3RydWN0b3InXSB8IFRlc3RSdW5bJ2NvbnN0cnVjdG9yJ107XG4gICAgcHVibGljIHRlc3RSdW46IG51bGwgfCBMZWdhY3lUZXN0UnVuIHwgVGVzdFJ1bjtcbiAgICBwdWJsaWMgZG9uZTogYm9vbGVhbjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IF9tZXNzYWdlQnVzOiBNZXNzYWdlQnVzO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgX3Rlc3RSdW5Ib29rOiBUZXN0UnVuSG9va0NvbnRyb2xsZXI7XG4gICAgcHJpdmF0ZSBjbGllbnRTY3JpcHRSb3V0ZXM6IHN0cmluZ1tdID0gW107XG4gICAgcHJpdmF0ZSBpc05hdGl2ZUF1dG9tYXRpb24gPSBmYWxzZTtcbiAgICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvciAoe1xuICAgICAgICB0ZXN0LFxuICAgICAgICBpbmRleCxcbiAgICAgICAgcHJveHksXG4gICAgICAgIHNjcmVlbnNob3RzLFxuICAgICAgICB3YXJuaW5nTG9nLFxuICAgICAgICBmaXh0dXJlSG9va0NvbnRyb2xsZXIsXG4gICAgICAgIG9wdHMsXG4gICAgICAgIHRlc3RSdW5Ib29rLFxuICAgICAgICBtZXNzYWdlQnVzLFxuICAgIH06IFRlc3RSdW5Db250cm9sbGVySW5pdCkge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMudGVzdCAgPSB0ZXN0O1xuICAgICAgICB0aGlzLmluZGV4ID0gaW5kZXg7XG4gICAgICAgIHRoaXMuX29wdHMgPSBvcHRzO1xuICAgICAgICB0aGlzLmlkICAgID0gZ2VuZXJhdGVVbmlxdWVJZCgpO1xuXG4gICAgICAgIHRoaXMuX3Byb3h5ICAgICAgICAgICAgICAgICA9IHByb3h5O1xuICAgICAgICB0aGlzLl9zY3JlZW5zaG90cyAgICAgICAgICAgPSBzY3JlZW5zaG90cztcbiAgICAgICAgdGhpcy5fd2FybmluZ0xvZyAgICAgICAgICAgID0gd2FybmluZ0xvZztcbiAgICAgICAgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyID0gZml4dHVyZUhvb2tDb250cm9sbGVyO1xuICAgICAgICB0aGlzLl90ZXN0UnVuSG9vayAgICAgICAgICAgPSB0ZXN0UnVuSG9vaztcblxuICAgICAgICB0aGlzLl90ZXN0UnVuQ3RvciA9IFRlc3RSdW5Db250cm9sbGVyLl9nZXRUZXN0UnVuQ3Rvcih0ZXN0LCBvcHRzKTtcblxuICAgICAgICB0aGlzLnRlc3RSdW4gICAgICAgICAgICAgPSBudWxsO1xuICAgICAgICB0aGlzLmRvbmUgICAgICAgICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5fcXVhcmFudGluZSAgICAgICAgID0gdGhpcy5fb3B0cy5xdWFyYW50aW5lTW9kZSA/IG5ldyBRdWFyYW50aW5lKCkgOiBudWxsO1xuICAgICAgICB0aGlzLl9kaXNjb25uZWN0aW9uQ291bnQgPSAwO1xuICAgICAgICB0aGlzLl9tZXNzYWdlQnVzICAgICAgICAgPSBtZXNzYWdlQnVzO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9nZXRUZXN0UnVuQ3RvciAodGVzdDogVGVzdCwgb3B0czogRGljdGlvbmFyeTxPcHRpb25WYWx1ZT4pOiBMZWdhY3lUZXN0UnVuIHwgVGVzdFJ1biB7XG4gICAgICAgIGlmIChvcHRzLlRlc3RSdW5DdG9yKVxuICAgICAgICAgICAgcmV0dXJuIG9wdHMuVGVzdFJ1bkN0b3I7XG5cbiAgICAgICAgcmV0dXJuICh0ZXN0IGFzIExlZ2FjeVRlc3RSdW4pLmlzTGVnYWN5ID8gTGVnYWN5VGVzdFJ1biA6IFRlc3RSdW47XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY3JlYXRlVGVzdFJ1biAoY29ubmVjdGlvbjogQnJvd3NlckNvbm5lY3Rpb24sIHN0YXJ0UnVuRXhlY3V0aW9uVGltZT86IERhdGUpOiBQcm9taXNlPFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuPiB7XG4gICAgICAgIGNvbnN0IHNjcmVlbnNob3RDYXB0dXJlciA9IHRoaXMuX3NjcmVlbnNob3RzLmNyZWF0ZUNhcHR1cmVyRm9yKHRoaXMudGVzdCwgdGhpcy5pbmRleCwgdGhpcy5fcXVhcmFudGluZSwgY29ubmVjdGlvbiwgdGhpcy5fd2FybmluZ0xvZyk7XG4gICAgICAgIGNvbnN0IFRlc3RSdW5DdG9yICAgICAgICA9IHRoaXMuX3Rlc3RSdW5DdG9yO1xuXG4gICAgICAgIHRoaXMudGVzdFJ1biA9IG5ldyBUZXN0UnVuQ3Rvcih7XG4gICAgICAgICAgICB0ZXN0OiAgICAgICAgICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgYnJvd3NlckNvbm5lY3Rpb246IGNvbm5lY3Rpb24sXG4gICAgICAgICAgICBnbG9iYWxXYXJuaW5nTG9nOiAgdGhpcy5fd2FybmluZ0xvZyxcbiAgICAgICAgICAgIG9wdHM6ICAgICAgICAgICAgICB0aGlzLl9vcHRzLFxuICAgICAgICAgICAgbWVzc2FnZUJ1czogICAgICAgIHRoaXMuX21lc3NhZ2VCdXMsXG4gICAgICAgICAgICBuYXRpdmVBdXRvbWF0aW9uOiAgdGhpcy5pc05hdGl2ZUF1dG9tYXRpb24sXG4gICAgICAgICAgICBzY3JlZW5zaG90Q2FwdHVyZXIsXG4gICAgICAgICAgICBzdGFydFJ1bkV4ZWN1dGlvblRpbWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2xpZW50U2NyaXB0Um91dGVzID0gY2xpZW50U2NyaXB0c1JvdXRpbmcucmVnaXN0ZXIoe1xuICAgICAgICAgICAgcHJveHk6ICAgICAgICAgICAgdGhpcy5fcHJveHksXG4gICAgICAgICAgICB0ZXN0OiAgICAgICAgICAgICB0aGlzLnRlc3QsXG4gICAgICAgICAgICBuYXRpdmVBdXRvbWF0aW9uOiB0aGlzLmlzTmF0aXZlQXV0b21hdGlvbixcbiAgICAgICAgICAgIGZvbGRlck5hbWU6ICAgICAgIHRoaXMudGVzdFJ1bi5pZCxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHRoaXMuaXNOYXRpdmVBdXRvbWF0aW9uKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5yZXNldEFjdGl2ZVdpbmRvd0lkKCk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy50ZXN0UnVuLmluaXRpYWxpemUoKTtcblxuICAgICAgICB0aGlzLl9zY3JlZW5zaG90cy5hZGRUZXN0UnVuKHRoaXMudGVzdCwgdGhpcy50ZXN0UnVuKTtcblxuICAgICAgICBpZiAodGhpcy50ZXN0UnVuLmFkZFF1YXJhbnRpbmVJbmZvKVxuICAgICAgICAgICAgdGhpcy50ZXN0UnVuLmFkZFF1YXJhbnRpbmVJbmZvKHRoaXMuX3F1YXJhbnRpbmUpO1xuXG4gICAgICAgIGlmICh0aGlzLl9xdWFyYW50aW5lKSB7XG4gICAgICAgICAgICBjb25zdCB7IHN1Y2Nlc3NUaHJlc2hvbGQsIGF0dGVtcHRMaW1pdCB9ID0gdGhpcy5fb3B0cy5xdWFyYW50aW5lTW9kZSBhcyBRdWFyYW50aW5lT3B0aW9uVmFsdWU7XG5cbiAgICAgICAgICAgIHRoaXMuX3F1YXJhbnRpbmUuc2V0Q3VzdG9tUGFyYW1ldGVycyhhdHRlbXB0TGltaXQsIHN1Y2Nlc3NUaHJlc2hvbGQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCF0aGlzLl9xdWFyYW50aW5lIHx8IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWNyZWF0ZScsIHtcbiAgICAgICAgICAgICAgICB0ZXN0UnVuOiAgICB0aGlzLnRlc3RSdW4sXG4gICAgICAgICAgICAgICAgbGVnYWN5OiAgICAgVGVzdFJ1bkN0b3IgPT09IExlZ2FjeVRlc3RSdW4sXG4gICAgICAgICAgICAgICAgdGVzdDogICAgICAgdGhpcy50ZXN0LFxuICAgICAgICAgICAgICAgIGluZGV4OiAgICAgIHRoaXMuaW5kZXgsXG4gICAgICAgICAgICAgICAgcXVhcmFudGluZTogdGhpcy5fcXVhcmFudGluZSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRoaXMudGVzdFJ1bjtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbmRRdWFyYW50aW5lICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgaWYgKCh0aGlzLl9xdWFyYW50aW5lIGFzIFF1YXJhbnRpbmUpLmF0dGVtcHRzLmxlbmd0aCA+IDEpXG4gICAgICAgICAgICB0aGlzLnRlc3RSdW4udW5zdGFibGUgPSAodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5nZXRQYXNzZWRBdHRlbXB0cygpLmxlbmd0aCA+IDA7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fZW1pdFRlc3RSdW5Eb25lKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfc2hvdWxkS2VlcEluUXVhcmFudGluZSAoKTogYm9vbGVhbiB7XG4gICAgICAgIGNvbnN0IGVycm9ycyAgICAgICAgID0gdGhpcy50ZXN0UnVuLmVycnM7XG4gICAgICAgIGNvbnN0IGhhc0Vycm9ycyAgICAgID0gISFlcnJvcnMubGVuZ3RoO1xuICAgICAgICBjb25zdCBhdHRlbXB0cyAgICAgICA9ICh0aGlzLl9xdWFyYW50aW5lIGFzIFF1YXJhbnRpbmUpLmF0dGVtcHRzO1xuICAgICAgICBjb25zdCBpc0ZpcnN0QXR0ZW1wdCA9IHRoaXMuX2lzRmlyc3RRdWFyYW50aW5lQXR0ZW1wdCgpO1xuXG4gICAgICAgIGF0dGVtcHRzLnB1c2goeyB0ZXN0UnVuSWQ6IHRoaXMudGVzdFJ1bi5pZCwgZXJyb3JzIH0pO1xuXG4gICAgICAgIHJldHVybiBpc0ZpcnN0QXR0ZW1wdCA/IGhhc0Vycm9ycyA6ICEodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5pc1RocmVzaG9sZFJlYWNoZWQoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIF9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQgKCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gISF0aGlzLl9xdWFyYW50aW5lICYmICF0aGlzLl9xdWFyYW50aW5lLmF0dGVtcHRzLmxlbmd0aDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9rZWVwSW5RdWFyYW50aW5lICgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fcmVzdGFydFRlc3QoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9yZXN0YXJ0VGVzdCAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZW1pdCgndGVzdC1ydW4tcmVzdGFydCcpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3Rlc3RSdW5Eb25lSW5RdWFyYW50aW5lTW9kZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLl9zaG91bGRLZWVwSW5RdWFyYW50aW5lKCkpXG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9rZWVwSW5RdWFyYW50aW5lKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VuZFF1YXJhbnRpbmUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90ZXN0UnVuRG9uZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLl9xdWFyYW50aW5lKVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5fdGVzdFJ1bkRvbmVJblF1YXJhbnRpbmVNb2RlKCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2VtaXRUZXN0UnVuRG9uZSgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRBY3Rpb25TdGFydCAoYXJnczogQWN0aW9uRXZlbnRBcmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICAgICAgYXdhaXQgdGhpcy5fbWVzc2FnZUJ1cy5lbWl0KCd0ZXN0LWFjdGlvbi1zdGFydCcsIGFyZ3MpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRBY3Rpb25Eb25lIChhcmdzOiBBY3Rpb25FdmVudEFyZyk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtYWN0aW9uLWRvbmUnLCBhcmdzKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9lbWl0VGVzdFJ1bkRvbmUgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICAvLyBOT1RFOiB3ZSBzaG91bGQgcmVwb3J0IHRlc3QgcnVuIGNvbXBsZXRpb24gaW4gb3JkZXIgdGhleSB3ZXJlIGNvbXBsZXRlZCBpbiBicm93c2VyLlxuICAgICAgICAvLyBUbyBrZWVwIGEgc2VxdWVuY2UgYWZ0ZXIgZml4dHVyZSBob29rIGV4ZWN1dGlvbiB3ZSB1c2UgY29tcGxldGlvbiBxdWV1ZS5cbiAgICAgICAgYXdhaXQgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyLnJ1bkZpeHR1cmVBZnRlckhvb2tJZk5lY2Vzc2FyeSh0aGlzLnRlc3RSdW4pO1xuICAgICAgICBhd2FpdCB0aGlzLl90ZXN0UnVuSG9vay5ydW5UZXN0UnVuQWZ0ZXJIb29rSWZOZWNlc3NhcnkodGhpcy50ZXN0UnVuKTtcblxuICAgICAgICBjbGllbnRTY3JpcHRzUm91dGluZy51blJlZ2lzdGVyKHRoaXMuX3Byb3h5LCB0aGlzLmNsaWVudFNjcmlwdFJvdXRlcyk7XG5cbiAgICAgICAgdGhpcy5kb25lID0gdHJ1ZTtcblxuICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWRvbmUnKTtcblxuICAgICAgICB0ZXN0UnVuQ29udHJvbGxlckxvZ2dlcignZG9uZSAlcycsIHRoaXMuaWQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2VtaXRUZXN0UnVuU3RhcnQgKCk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBhd2FpdCB0aGlzLl9tZXNzYWdlQnVzLmVtaXQoJ3Rlc3QtcnVuLXN0YXJ0JywgdGhpcy50ZXN0UnVuKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF90ZXN0UnVuQmVmb3JlRG9uZSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGxldCByYWlzZUV2ZW50ID0gIXRoaXMuX3F1YXJhbnRpbmU7XG5cbiAgICAgICAgaWYgKCFyYWlzZUV2ZW50KSB7XG4gICAgICAgICAgICBjb25zdCBpc1N1Y2Nlc3NmdWxRdWFyYW50aW5lRmlyc3RBdHRlbXB0ID0gdGhpcy5faXNGaXJzdFF1YXJhbnRpbmVBdHRlbXB0KCkgJiYgIXRoaXMudGVzdFJ1bi5lcnJzLmxlbmd0aDtcbiAgICAgICAgICAgIGNvbnN0IGlzQXR0ZW1wdHNUaHJlc2hvbGRSZWFjaGVkICAgICAgICAgPSAodGhpcy5fcXVhcmFudGluZSBhcyBRdWFyYW50aW5lKS5pc1RocmVzaG9sZFJlYWNoZWQodGhpcy50ZXN0UnVuLmVycnMpO1xuXG4gICAgICAgICAgICByYWlzZUV2ZW50ID0gaXNTdWNjZXNzZnVsUXVhcmFudGluZUZpcnN0QXR0ZW1wdCB8fCBpc0F0dGVtcHRzVGhyZXNob2xkUmVhY2hlZDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChyYWlzZUV2ZW50KVxuICAgICAgICAgICAgYXdhaXQgdGhpcy5lbWl0KCd0ZXN0LXJ1bi1iZWZvcmUtZG9uZScpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX3Rlc3RSdW5EaXNjb25uZWN0ZWQgKGNvbm5lY3Rpb246IEJyb3dzZXJDb25uZWN0aW9uKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIHRoaXMuX2Rpc2Nvbm5lY3Rpb25Db3VudCsrO1xuXG4gICAgICAgIGNvbnN0IGRpc2Nvbm5lY3Rpb25UaHJlc2hvbGRFeGNlZWRlZCA9IHRoaXMuX2Rpc2Nvbm5lY3Rpb25Db3VudCA+PSBESVNDT05ORUNUX1RIUkVTSE9MRDtcblxuICAgICAgICByZXR1cm4gY29ubmVjdGlvblxuICAgICAgICAgICAgLnByb2Nlc3NEaXNjb25uZWN0aW9uKGRpc2Nvbm5lY3Rpb25UaHJlc2hvbGRFeGNlZWRlZClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVzdGFydFRlc3QoKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Fzc2lnblRlc3RSdW5FdmVudHMgKHRlc3RSdW46IFRlc3RSdW4gfCBMZWdhY3lUZXN0UnVuLCBjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IHZvaWQge1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tc3RhcnQnLCBhc3luYyAoYXJnczogQWN0aW9uRXZlbnRBcmcpID0+IHRoaXMuX2VtaXRBY3Rpb25TdGFydChPYmplY3QuYXNzaWduKGFyZ3MsIHsgdGVzdFJ1biB9KSkpO1xuICAgICAgICB0ZXN0UnVuLm9uKCdhY3Rpb24tZG9uZScsIGFzeW5jIChhcmdzOiBBY3Rpb25FdmVudEFyZykgPT4gdGhpcy5fZW1pdEFjdGlvbkRvbmUoT2JqZWN0LmFzc2lnbihhcmdzLCB7IHRlc3RSdW4gfSkpKTtcblxuICAgICAgICB0ZXN0UnVuLm9uY2UoJ3N0YXJ0JywgYXN5bmMgKCkgPT4gdGhpcy5fZW1pdFRlc3RSdW5TdGFydCgpKTtcbiAgICAgICAgdGVzdFJ1bi5vbmNlKCdyZWFkeScsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5fcXVhcmFudGluZSB8fCB0aGlzLl9pc0ZpcnN0UXVhcmFudGluZUF0dGVtcHQoKSlcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLXJlYWR5Jyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2JlZm9yZS1kb25lJywgKCkgPT4gdGhpcy5fdGVzdFJ1bkJlZm9yZURvbmUoKSk7XG4gICAgICAgIHRlc3RSdW4ub25jZSgnZG9uZScsICgpID0+IHRoaXMuX3Rlc3RSdW5Eb25lKCkpO1xuICAgICAgICB0ZXN0UnVuLm9uY2UoJ2Rpc2Nvbm5lY3RlZCcsICgpID0+IHRoaXMuX3Rlc3RSdW5EaXNjb25uZWN0ZWQoY29ubmVjdGlvbikpO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgYmxvY2tlZCAoKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLl9maXh0dXJlSG9va0NvbnRyb2xsZXIuaXNUZXN0QmxvY2tlZCh0aGlzLnRlc3QpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2hhbmRsZU5hdGl2ZUF1dG9tYXRpb25Nb2RlIChjb25uZWN0aW9uOiBCcm93c2VyQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICB0aGlzLmlzTmF0aXZlQXV0b21hdGlvbiA9ICF0aGlzLl9vcHRzLmRpc2FibGVOYXRpdmVBdXRvbWF0aW9uO1xuXG4gICAgICAgIGNvbnN0IHN1cHBvcnROYXRpdmVBdXRvbWF0aW9uID0gY29ubmVjdGlvbi5zdXBwb3J0TmF0aXZlQXV0b21hdGlvbigpO1xuXG4gICAgICAgIGlmICghdGhpcy5pc05hdGl2ZUF1dG9tYXRpb24gfHwgc3VwcG9ydE5hdGl2ZUF1dG9tYXRpb24pXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgYXdhaXQgdGhpcy5fbWVzc2FnZUJ1cy5lbWl0KCdiZWZvcmUtdGVzdC1ydW4tY3JlYXRlZC1lcnJvcicpO1xuXG4gICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuc2V0TmF0aXZlQXV0b21hdGlvbkZvclVuc3VwcG9ydGVkQnJvd3NlcnMsIGNvbm5lY3Rpb24uYnJvd3NlckluZm8ucHJvdmlkZXJOYW1lKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYXN5bmMgc3RhcnQgKGNvbm5lY3Rpb246IEJyb3dzZXJDb25uZWN0aW9uLCBzdGFydFJ1bkV4ZWN1dGlvblRpbWU/OiBEYXRlKTogUHJvbWlzZTxzdHJpbmcgfCBudWxsPiB7XG4gICAgICAgIHRlc3RSdW5Db250cm9sbGVyTG9nZ2VyKCdzdGFydCAlcyAlTyAlTycsIHRoaXMuaWQsIHtcbiAgICAgICAgICAgIHRlc3Q6IHtcbiAgICAgICAgICAgICAgICBuYW1lOiB0aGlzLnRlc3QubmFtZSxcbiAgICAgICAgICAgICAgICBpZDogICB0aGlzLnRlc3QuaWQsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgY29ubmVjdGlvbjoge1xuICAgICAgICAgICAgICAgIHVzZXJBZ2VudDogY29ubmVjdGlvbi51c2VyQWdlbnQsXG4gICAgICAgICAgICAgICAgaWQ6ICAgICAgICBjb25uZWN0aW9uLmlkLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgfSk7XG5cbiAgICAgICAgYXdhaXQgdGhpcy5faGFuZGxlTmF0aXZlQXV0b21hdGlvbk1vZGUoY29ubmVjdGlvbik7XG5cbiAgICAgICAgdGhpcy5fZml4dHVyZUhvb2tDb250cm9sbGVyLmJsb2NrVGVzdElmTmVjZXNzYXJ5KHRoaXMudGVzdCk7XG5cbiAgICAgICAgY29uc3QgdGVzdFJ1biA9IGF3YWl0IHRoaXMuX2NyZWF0ZVRlc3RSdW4oY29ubmVjdGlvbiwgc3RhcnRSdW5FeGVjdXRpb25UaW1lKTtcblxuICAgICAgICBjb25zdCBob29rT2sgPSBhd2FpdCB0aGlzLl90ZXN0UnVuSG9vay5ydW5UZXN0UnVuQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pXG4gICAgICAgICAgICAgICAgICAgICAgICYmIGF3YWl0IHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci5ydW5GaXh0dXJlQmVmb3JlSG9va0lmTmVjZXNzYXJ5KHRlc3RSdW4pO1xuXG4gICAgICAgIHRoaXMuX2ZpeHR1cmVIb29rQ29udHJvbGxlci51bmJsb2NrVGVzdCh0aGlzLnRlc3QpO1xuXG4gICAgICAgIGlmICh0aGlzLnRlc3Quc2tpcCB8fCAhaG9va09rKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1blN0YXJ0KCk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmVtaXQoJ3Rlc3QtcnVuLWJlZm9yZS1kb25lJyk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9lbWl0VGVzdFJ1bkRvbmUoKTtcblxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9hc3NpZ25UZXN0UnVuRXZlbnRzKHRlc3RSdW4sIGNvbm5lY3Rpb24pO1xuXG4gICAgICAgIHRlc3RSdW4uc3RhcnQoKTtcblxuICAgICAgICByZXR1cm4gU2Vzc2lvbkNvbnRyb2xsZXIuZ2V0U2Vzc2lvblVybCh0ZXN0UnVuLCB0aGlzLl9wcm94eSk7XG4gICAgfVxufVxuIl19