testcafe
Version:
Automated browser testing for the modern web development stack.
297 lines • 57.3 kB
JavaScript
"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 debug_1 = __importDefault(require("debug"));
const pretty_hrtime_1 = __importDefault(require("pretty-hrtime"));
const compiler_1 = __importDefault(require("../compiler"));
const connection_1 = __importDefault(require("../browser/connection"));
const browser_set_1 = __importDefault(require("./browser-set"));
const runtime_1 = require("../errors/runtime");
const types_1 = require("../errors/types");
const tested_app_1 = __importDefault(require("./tested-app"));
const parse_file_list_1 = __importDefault(require("../utils/parse-file-list"));
const load_1 = __importDefault(require("../custom-client-scripts/load"));
const string_1 = require("../utils/string");
const warning_log_1 = __importDefault(require("../notifications/warning-log"));
const warning_message_1 = __importDefault(require("../notifications/warning-message"));
const guard_time_execution_1 = __importDefault(require("../utils/guard-time-execution"));
const async_filter_1 = __importDefault(require("../utils/async-filter"));
const wrap_test_function_1 = __importDefault(require("../api/wrap-test-function"));
const type_assertions_1 = require("../errors/runtime/type-assertions");
const testcafe_hammerhead_1 = require("testcafe-hammerhead");
const assert_type_1 = __importDefault(require("../api/request-hooks/assert-type"));
const option_names_1 = __importDefault(require("../configuration/option-names"));
const status_1 = __importDefault(require("../browser/connection/gateway/status"));
const DEBUG_SCOPE = 'testcafe:bootstrapper';
function isPromiseError(value) {
return value.error !== void 0;
}
class Bootstrapper {
constructor({ browserConnectionGateway, messageBus, configuration }) {
this.browserConnectionGateway = browserConnectionGateway;
this.concurrency = 1;
this.sources = [];
this.browsers = [];
this.reporters = [];
this.filter = void 0;
this.appCommand = void 0;
this.appInitDelay = void 0;
this.tsConfigPath = void 0;
this.clientScripts = [];
this.disableMultipleWindows = false;
this.compilerOptions = void 0;
this.debugLogger = (0, debug_1.default)(DEBUG_SCOPE);
this.warningLog = new warning_log_1.default(null, warning_log_1.default.createAddWarningCallback(messageBus));
this.messageBus = messageBus;
this.configuration = configuration;
this.TESTS_COMPILATION_UPPERBOUND = 60;
}
static _getBrowserName(browser) {
if (browser instanceof connection_1.default)
return browser.browserInfo.browserName;
return browser.browserName;
}
static _splitBrowserInfo(browserInfo) {
const remotes = [];
const automated = [];
browserInfo.forEach(browser => {
if (browser instanceof connection_1.default)
remotes.push(browser);
else
automated.push(browser);
});
return { remotes, automated };
}
_createAutomatedConnections(browserInfo) {
if (!browserInfo)
return [];
return browserInfo.map(browser => (0, lodash_1.times)(this.concurrency, () => {
const options = {
disableMultipleWindows: this.disableMultipleWindows,
developmentMode: this.configuration.getOption(option_names_1.default.developmentMode),
nativeAutomation: !this.configuration.getOption(option_names_1.default.disableNativeAutomation),
};
const connection = new connection_1.default(this.browserConnectionGateway, Object.assign({}, browser), false, options, this.messageBus);
connection.initialize();
return connection;
}));
}
_getBrowserSetOptions() {
return {
concurrency: this.concurrency,
browserInitTimeout: this.browserInitTimeout,
warningLog: this.warningLog,
};
}
async _setupProxy() {
if (this.browserConnectionGateway.status === status_1.default.initialized)
return;
await this.configuration.calculateHostname({ nativeAutomation: !this.configuration.getOption(option_names_1.default.disableNativeAutomation) });
this.browserConnectionGateway.initialize(this.configuration.startOptions);
}
_hasNotSupportedBrowserInNativeAutomation(browserInfos) {
return browserInfos.some(browserInfo => {
return !browserInfo.provider.supportNativeAutomation();
});
}
getBrowsersWithUserProfileEnabled(browserInfos) {
return browserInfos.filter(browserInfo => { var _a; return (_a = browserInfo.browserOption) === null || _a === void 0 ? void 0 : _a.userProfile; });
}
_disableNativeAutomationIfNecessary(remotes, automated) {
// NOTE: CDP API allows connecting only for the local browser. So, the 'remote' browser cannot be run in the 'nativeAutomation' mode.
// However, sometimes in tests or TestCafe Studio Recorder, we use the 'remote' browser connection as a local one.
const containsNotAutomatedRemotes = remotes.some(remote => !remote.isNativeAutomationEnabled());
if (remotes.length && containsNotAutomatedRemotes || this._hasNotSupportedBrowserInNativeAutomation(automated))
this.configuration.mergeOptions({ disableNativeAutomation: true });
}
async _getBrowserConnections(browserInfo) {
const { automated, remotes } = Bootstrapper._splitBrowserInfo(browserInfo);
if (remotes && remotes.length % this.concurrency)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotDivideRemotesCountByConcurrency);
this._disableNativeAutomationIfNecessary(remotes, automated);
this._validateUserProfileOptionInNativeAutomation(automated);
await this._setupProxy();
let browserConnections = this._createAutomatedConnections(automated);
remotes.forEach(remoteConnection => {
remoteConnection.messageBus = this.messageBus;
remoteConnection.initMessageBus();
});
browserConnections = browserConnections.concat((0, lodash_1.chunk)(remotes, this.concurrency));
return browser_set_1.default.from(browserConnections, this._getBrowserSetOptions());
}
_validateUserProfileOptionInNativeAutomation(automated) {
const isNativeAutomation = !this.configuration.getOption(option_names_1.default.disableNativeAutomation);
const browsersWithUserProfile = this.getBrowsersWithUserProfileEnabled(automated);
if (isNativeAutomation && browsersWithUserProfile.length) {
const browsers = browsersWithUserProfile.map(b => b.alias).join(', ');
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.setUserProfileInNativeAutomation, browsers);
}
}
async _filterTests(tests, predicate) {
return (0, async_filter_1.default)(tests, test => {
const testFixture = test.fixture;
return predicate(test.name, testFixture.name, testFixture.path, test.meta, testFixture.meta);
});
}
async _compileTests({ sourceList, compilerOptions }) {
const baseUrl = this.configuration.getOption(option_names_1.default.baseUrl);
const esm = this.configuration.getOption(option_names_1.default.esm);
const compiler = new compiler_1.default(sourceList, compilerOptions, { baseUrl, esm });
return compiler.getTests();
}
_assertGlobalHooks() {
var _a, _b, _c, _d;
if (!this.hooks)
return;
if ((_a = this.hooks.fixture) === null || _a === void 0 ? void 0 : _a.before)
(0, type_assertions_1.assertType)(type_assertions_1.is.function, 'globalBefore', 'The fixture.globalBefore hook', this.hooks.fixture.before);
if ((_b = this.hooks.fixture) === null || _b === void 0 ? void 0 : _b.after)
(0, type_assertions_1.assertType)(type_assertions_1.is.function, 'globalAfter', 'The fixture.globalAfter hook', this.hooks.fixture.after);
if ((_c = this.hooks.test) === null || _c === void 0 ? void 0 : _c.before)
(0, type_assertions_1.assertType)(type_assertions_1.is.function, 'globalBefore', 'The test.globalBefore hook', this.hooks.test.before);
if ((_d = this.hooks.test) === null || _d === void 0 ? void 0 : _d.after)
(0, type_assertions_1.assertType)(type_assertions_1.is.function, 'globalAfter', 'The test.globalAfter hook', this.hooks.test.after);
if (this.hooks.request)
(0, assert_type_1.default)((0, lodash_1.flattenDeep)((0, lodash_1.castArray)(this.hooks.request)));
}
_setGlobalHooksToTests(tests) {
var _a, _b, _c, _d;
if (!this.hooks)
return;
this._assertGlobalHooks();
const fixtureBefore = ((_a = this.hooks.fixture) === null || _a === void 0 ? void 0 : _a.before) || null;
const fixtureAfter = ((_b = this.hooks.fixture) === null || _b === void 0 ? void 0 : _b.after) || null;
const testBefore = ((_c = this.hooks.test) === null || _c === void 0 ? void 0 : _c.before) ? (0, wrap_test_function_1.default)(this.hooks.test.before) : null;
const testAfter = ((_d = this.hooks.test) === null || _d === void 0 ? void 0 : _d.after) ? (0, wrap_test_function_1.default)(this.hooks.test.after) : null;
const request = this.hooks.request || [];
tests.forEach(item => {
if (item.fixture) {
item.fixture.globalBeforeFn = item.fixture.globalBeforeFn || fixtureBefore;
item.fixture.globalAfterFn = item.fixture.globalAfterFn || fixtureAfter;
}
item.globalBeforeFn = testBefore;
item.globalAfterFn = testAfter;
item.requestHooks = (0, lodash_1.union)((0, lodash_1.flattenDeep)((0, lodash_1.castArray)(request)), item.requestHooks);
});
}
async _getTests(id) {
const cwd = process.cwd();
const sourceList = await (0, parse_file_list_1.default)(this.sources, cwd);
if (!sourceList.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testFilesNotFound, cwd, (0, string_1.getConcatenatedValuesString)(this.sources, '\n', ''));
let tests = await (0, guard_time_execution_1.default)(async () => await this._compileTests({ sourceList, compilerOptions: this.compilerOptions, runnableConfigurationId: id }), elapsedTime => {
this.debugLogger(`tests compilation took ${(0, pretty_hrtime_1.default)(elapsedTime)}`);
const [elapsedSeconds] = elapsedTime;
if (elapsedSeconds > this.TESTS_COMPILATION_UPPERBOUND)
this.warningLog.addWarning(warning_message_1.default.testsCompilationTakesTooLong, (0, pretty_hrtime_1.default)(elapsedTime));
});
const testsWithOnlyFlag = tests.filter(test => test.only);
if (testsWithOnlyFlag.length)
tests = testsWithOnlyFlag;
if (!tests.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRun);
if (this.filter)
tests = await this._filterTests(tests, this.filter);
if (!tests.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRunDueFiltering);
this._setGlobalHooksToTests(tests);
return tests;
}
async _startTestedApp() {
if (!this.appCommand)
return void 0;
const testedApp = new tested_app_1.default();
await testedApp.start(this.appCommand, this.appInitDelay);
return testedApp;
}
async _canUseParallelBootstrapping(browserInfo) {
const isLocalPromises = browserInfo.map(browser => browser.provider.isLocalBrowser(void 0, Bootstrapper._getBrowserName(browser)));
const isLocalBrowsers = await Promise.all(isLocalPromises);
return isLocalBrowsers.every(result => result);
}
async _bootstrapSequence(browserInfo, id) {
const tests = await this._getTests(id);
const testedApp = await this._startTestedApp();
const browserSet = await this._getBrowserConnections(browserInfo);
return { tests, testedApp, browserSet };
}
_wrapBootstrappingPromise(promise) {
return promise
.then(result => ({ error: void 0, result }))
.catch(error => ({ result: void 0, error }));
}
async _getBootstrappingError(browserSetStatus, testsStatus, testedAppStatus) {
if (!isPromiseError(browserSetStatus))
await browserSetStatus.result.dispose();
if (!isPromiseError(browserSetStatus) && !isPromiseError(testedAppStatus) && testedAppStatus.result)
await testedAppStatus.result.kill();
if (isPromiseError(testsStatus))
return testsStatus.error;
if (isPromiseError(testedAppStatus))
return testedAppStatus.error;
if (isPromiseError(browserSetStatus))
return browserSetStatus.error;
return new Error('Unexpected call');
}
_getBootstrappingPromises(arg) {
const result = {};
for (const k in arg)
result[k] = this._wrapBootstrappingPromise(arg[k]);
return result;
}
async _assertNativeAutomationForLegacyTests(resources) {
var _a;
const isNativeAutomation = !this.configuration.getOption(option_names_1.default.disableNativeAutomation);
if (!isNativeAutomation)
return;
const hasLegacyTests = resources.tests.some(test => test.isLegacy);
if (!hasLegacyTests)
return;
await resources.browserSet.dispose();
await ((_a = resources.testedApp) === null || _a === void 0 ? void 0 : _a.kill());
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotRunLegacyTestsInNativeAutomationMode);
}
async _bootstrapParallel(browserInfo, id) {
const bootstrappingPromises = {
browserSet: this._getBrowserConnections(browserInfo),
tests: this._getTests(id),
app: this._startTestedApp(),
};
const bootstrappingResultPromises = this._getBootstrappingPromises(bootstrappingPromises);
const bootstrappingResults = await Promise.all([
bootstrappingResultPromises.browserSet,
bootstrappingResultPromises.tests,
bootstrappingResultPromises.app,
]);
const [browserSetResults, testResults, appResults] = bootstrappingResults;
if (isPromiseError(browserSetResults) || isPromiseError(testResults) || isPromiseError(appResults))
throw await this._getBootstrappingError(...bootstrappingResults);
const resources = {
browserSet: browserSetResults.result,
tests: testResults.result,
testedApp: appResults.result,
};
await this._assertNativeAutomationForLegacyTests(resources);
return resources;
}
// API
async createRunnableConfiguration() {
const id = (0, testcafe_hammerhead_1.generateUniqueId)();
const commonClientScripts = await (0, load_1.default)(this.clientScripts);
if (await this._canUseParallelBootstrapping(this.browsers))
return Object.assign(Object.assign({}, await this._bootstrapParallel(this.browsers, id)), { commonClientScripts, id });
return Object.assign(Object.assign({}, await this._bootstrapSequence(this.browsers, id)), { commonClientScripts, id });
}
restoreMessageBusListeners() {
const connections = this.browserConnectionGateway.getConnections();
Object.values(connections).forEach(connection => {
connection.assignTestRunStartEventListener();
});
}
}
exports.default = Bootstrapper;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bm5lci9ib290c3RyYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxtQ0FNZ0I7QUFFaEIsa0RBQTBCO0FBQzFCLGtFQUF1QztBQUN2QywyREFBbUM7QUFDbkMsdUVBQXVFO0FBQ3ZFLGdFQUF1QztBQUN2QywrQ0FBaUQ7QUFDakQsMkNBQWlEO0FBQ2pELDhEQUFxQztBQUNyQywrRUFBcUQ7QUFDckQseUVBQThEO0FBQzlELDRDQUE4RDtBQVE5RCwrRUFBc0Q7QUFDdEQsdUZBQWdFO0FBQ2hFLHlGQUErRDtBQUMvRCx5RUFBZ0Q7QUFHaEQsbUZBQXlEO0FBQ3pELHVFQUFtRTtBQUNuRSw2REFBdUQ7QUFDdkQsbUZBQXFFO0FBQ3JFLGlGQUF5RDtBQUV6RCxrRkFBa0Y7QUFFbEYsTUFBTSxXQUFXLEdBQUcsdUJBQXVCLENBQUM7QUEyQjVDLFNBQVMsY0FBYyxDQUE4QixLQUEwQjtJQUMzRSxPQUFRLEtBQXlCLENBQUMsS0FBSyxLQUFLLEtBQUssQ0FBQyxDQUFDO0FBQ3ZELENBQUM7QUFhRCxNQUFxQixZQUFZO0lBc0I3QixZQUFvQixFQUFFLHdCQUF3QixFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQW9CO1FBQ3pGLElBQUksQ0FBQyx3QkFBd0IsR0FBRyx3QkFBd0IsQ0FBQztRQUN6RCxJQUFJLENBQUMsV0FBVyxHQUFnQixDQUFDLENBQUM7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBb0IsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFrQixFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLE1BQU0sR0FBcUIsS0FBSyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLFVBQVUsR0FBaUIsS0FBSyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLFlBQVksR0FBZSxL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TSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsS0FBRSxtQkFBbUIsRUFBRSxFQUFFLElBQUc7UUFFNUYsdUNBQVksTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsS0FBRSxtQkFBbUIsRUFBRSxFQUFFLElBQUc7SUFDNUYsQ0FBQztJQUVNLDBCQUEwQjtRQUM3QixNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsY0FBYyxFQUFFLENBQUM7UUFFbkUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDNUMsVUFBVSxDQUFDLCtCQUErQixFQUFFLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0NBQ0o7QUFoWUQsK0JBZ1lDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgICBjaHVuayxcbiAgICB0aW1lcyxcbiAgICB1bmlvbixcbiAgICBjYXN0QXJyYXksXG4gICAgZmxhdHRlbkRlZXAgYXMgZmxhdHRlbixcbn0gZnJvbSAnbG9kYXNoJztcblxuaW1wb3J0IGRlYnVnIGZyb20gJ2RlYnVnJztcbmltcG9ydCBwcmV0dHlUaW1lIGZyb20gJ3ByZXR0eS1ocnRpbWUnO1xuaW1wb3J0IENvbXBpbGVyIGZyb20gJy4uL2NvbXBpbGVyJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvbiwgeyBCcm93c2VySW5mbyB9IGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbic7XG5pbXBvcnQgQnJvd3NlclNldCBmcm9tICcuL2Jyb3dzZXItc2V0JztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCBUZXN0ZWRBcHAgZnJvbSAnLi90ZXN0ZWQtYXBwJztcbmltcG9ydCBwYXJzZUZpbGVMaXN0IGZyb20gJy4uL3V0aWxzL3BhcnNlLWZpbGUtbGlzdCc7XG5pbXBvcnQgbG9hZENsaWVudFNjcmlwdHMgZnJvbSAnLi4vY3VzdG9tLWNsaWVudC1zY3JpcHRzL2xvYWQnO1xuaW1wb3J0IHsgZ2V0Q29uY2F0ZW5hdGVkVmFsdWVzU3RyaW5nIH0gZnJvbSAnLi4vdXRpbHMvc3RyaW5nJztcbmltcG9ydCB7IFJlcG9ydGVyU291cmNlIH0gZnJvbSAnLi4vcmVwb3J0ZXIvaW50ZXJmYWNlcyc7XG5pbXBvcnQgQ2xpZW50U2NyaXB0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0JztcbmltcG9ydCBDbGllbnRTY3JpcHRJbml0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0LWluaXQnO1xuaW1wb3J0IEJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSBmcm9tICcuLi9icm93c2VyL2Nvbm5lY3Rpb24vZ2F0ZXdheSc7XG5pbXBvcnQgeyBDb21waWxlckFyZ3VtZW50cyB9IGZyb20gJy4uL2NvbXBpbGVyL2ludGVyZmFjZXMnO1xuaW1wb3J0IFRlc3QgZnJvbSAnLi4vYXBpL3N0cnVjdHVyZS90ZXN0JztcbmltcG9ydCB7IEJvb3RzdHJhcHBlckluaXQsIEJyb3dzZXJTZXRPcHRpb25zIH0gZnJvbSAnLi9pbnRlcmZhY2VzJztcbmltcG9ydCBXYXJuaW5nTG9nIGZyb20gJy4uL25vdGlmaWNhdGlvbnMvd2FybmluZy1sb2cnO1xuaW1wb3J0IFdBUk5JTkdfTUVTU0FHRVMgZnJvbSAnLi4vbm90aWZpY2F0aW9ucy93YXJuaW5nLW1lc3NhZ2UnO1xuaW1wb3J0IGd1YXJkVGltZUV4ZWN1dGlvbiBmcm9tICcuLi91dGlscy9ndWFyZC10aW1lLWV4ZWN1dGlvbic7XG5pbXBvcnQgYXN5bmNGaWx0ZXIgZnJvbSAnLi4vdXRpbHMvYXN5bmMtZmlsdGVyJztcbmltcG9ydCBGaXh0dXJlIGZyb20gJy4uL2FwaS9zdHJ1Y3R1cmUvZml4dHVyZSc7XG5pbXBvcnQgTWVzc2FnZUJ1cyBmcm9tICcuLi91dGlscy9tZXNzYWdlLWJ1cyc7XG5pbXBvcnQgd3JhcFRlc3RGdW5jdGlvbiBmcm9tICcuLi9hcGkvd3JhcC10ZXN0LWZ1bmN0aW9uJztcbmltcG9ydCB7IGFzc2VydFR5cGUsIGlzIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUvdHlwZS1hc3NlcnRpb25zJztcbmltcG9ydCB7IGdlbmVyYXRlVW5pcXVlSWQgfSBmcm9tICd0ZXN0Y2FmZS1oYW1tZXJoZWFkJztcbmltcG9ydCBhc3NlcnRSZXF1ZXN0SG9va1R5cGUgZnJvbSAnLi4vYXBpL3JlcXVlc3QtaG9va3MvYXNzZXJ0LXR5cGUnO1xuaW1wb3J0IE9QVElPTl9OQU1FUyBmcm9tICcuLi9jb25maWd1cmF0aW9uL29wdGlvbi1uYW1lcyc7XG5pbXBvcnQgVGVzdENhZmVDb25maWd1cmF0aW9uIGZyb20gJy4uL2NvbmZpZ3VyYXRpb24vdGVzdGNhZmUtY29uZmlndXJhdGlvbic7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5U3RhdHVzIGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbi9nYXRld2F5L3N0YXR1cyc7XG5cbmNvbnN0IERFQlVHX1NDT1BFID0gJ3Rlc3RjYWZlOmJvb3RzdHJhcHBlcic7XG5cbnR5cGUgVGVzdFNvdXJjZSA9IHVua25vd247XG5cbnR5cGUgQnJvd3NlckluZm9Tb3VyY2UgPSBCcm93c2VySW5mbyB8IEJyb3dzZXJDb25uZWN0aW9uO1xuXG5pbnRlcmZhY2UgUHJvbWlzZVN1Y2Nlc3M8VD4ge1xuICAgIHJlc3VsdDogVDtcbn1cblxuaW50ZXJmYWNlIFByb21pc2VFcnJvcjxFIGV4dGVuZHMgRXJyb3IgPSBFcnJvcj4ge1xuICAgIGVycm9yOiBFO1xufVxuXG5pbnRlcmZhY2UgQmFzaWNSdW50aW1lUmVzb3VyY2VzIHtcbiAgICBicm93c2VyU2V0OiBCcm93c2VyU2V0O1xuICAgIHRlc3RzOiBUZXN0W107XG4gICAgdGVzdGVkQXBwPzogVGVzdGVkQXBwO1xufVxuXG5pbnRlcmZhY2UgUnVubmFibGVDb25maWd1cmF0aW9uIGV4dGVuZHMgQmFzaWNSdW50aW1lUmVzb3VyY2VzIHtcbiAgICBjb21tb25DbGllbnRTY3JpcHRzOiBDbGllbnRTY3JpcHRbXTtcbiAgICBpZDogc3RyaW5nO1xufVxuXG50eXBlIFByb21pc2VSZXN1bHQ8VCwgRSBleHRlbmRzIEVycm9yID0gRXJyb3I+ID0gUHJvbWlzZVN1Y2Nlc3M8VD4gfCBQcm9taXNlRXJyb3I8RT47XG5cbmZ1bmN0aW9uIGlzUHJvbWlzZUVycm9yPFQsIEUgZXh0ZW5kcyBFcnJvciA9IEVycm9yPiAodmFsdWU6IFByb21pc2VSZXN1bHQ8VCwgRT4pOiB2YWx1ZSBpcyBQcm9taXNlRXJyb3I8RT4ge1xuICAgIHJldHVybiAodmFsdWUgYXMgUHJvbWlzZUVycm9yPEU+KS5lcnJvciAhPT0gdm9pZCAwO1xufVxuXG5pbnRlcmZhY2UgU2VwYXJhdGVkQnJvd3NlckluZm8ge1xuICAgIHJlbW90ZXM6IEJyb3dzZXJDb25uZWN0aW9uW107XG4gICAgYXV0b21hdGVkOiBCcm93c2VySW5mb1tdO1xufVxuXG50eXBlIFByb21pc2VDb2xsZWN0aW9uPFQ+ID0ge1xuICAgIFtLIGluIGtleW9mIFRdOiBQcm9taXNlPFRbS10+XG59XG5cbnR5cGUgUmVzdWx0Q29sbGVjdGlvbjxUPiA9IHsgW1AgaW4ga2V5b2YgVF06IFByb21pc2VSZXN1bHQ8VFtQXT4gfTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQm9vdHN0cmFwcGVyIHtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5O1xuICAgIHB1YmxpYyBjb25jdXJyZW5jeTogbnVtYmVyO1xuICAgIHB1YmxpYyBzb3VyY2VzOiBUZXN0U291cmNlW107XG4gICAgcHVibGljIGJyb3dzZXJzOiBCcm93c2VySW5mb1NvdXJjZVtdO1xuICAgIHB1YmxpYyByZXBvcnRlcnM6IFJlcG9ydGVyU291cmNlW107XG4gICAgcHVibGljIGZpbHRlcj86IEZpbHRlckZ1bmN0aW9uO1xuICAgIHB1YmxpYyBhcHBDb21tYW5kPzogc3RyaW5nO1xuICAgIHB1YmxpYyBhcHBJbml0RGVsYXk/OiBudW1iZXI7XG4gICAgcHVibGljIHRzQ29uZmlnUGF0aD86IHN0cmluZztcbiAgICBwdWJsaWMgY2xpZW50U2NyaXB0czogQ2xpZW50U2NyaXB0SW5pdFtdO1xuICAgIHB1YmxpYyBkaXNhYmxlTXVsdGlwbGVXaW5kb3dzOiBib29sZWFuO1xuICAgIHB1YmxpYyBjb21waWxlck9wdGlvbnM/OiBDb21waWxlck9wdGlvbnM7XG4gICAgcHVibGljIGJyb3dzZXJJbml0VGltZW91dD86IG51bWJlcjtcbiAgICBwdWJsaWMgaG9va3M/OiBHbG9iYWxIb29rcztcbiAgICBwdWJsaWMgY29uZmlndXJhdGlvbjogVGVzdENhZmVDb25maWd1cmF0aW9uO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgZGVidWdMb2dnZXI6IGRlYnVnLkRlYnVnZ2VyO1xuICAgIHByaXZhdGUgcmVhZG9ubHkgd2FybmluZ0xvZzogV2FybmluZ0xvZztcbiAgICBwcml2YXRlIHJlYWRvbmx5IG1lc3NhZ2VCdXM6IE1lc3NhZ2VCdXM7XG5cbiAgICBwcml2YXRlIHJlYWRvbmx5IFRFU1RTX0NPTVBJTEFUSU9OX1VQUEVSQk9VTkQ6IG51bWJlcjtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvciAoeyBicm93c2VyQ29ubmVjdGlvbkdhdGV3YXksIG1lc3NhZ2VCdXMsIGNvbmZpZ3VyYXRpb24gfTogQm9vdHN0cmFwcGVySW5pdCkge1xuICAgICAgICB0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSA9IGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTtcbiAgICAgICAgdGhpcy5jb25jdXJyZW5jeSAgICAgICAgICAgICAgPSAxO1xuICAgICAgICB0aGlzLnNvdXJjZXMgICAgICAgICAgICAgICAgICA9IFtdO1xuICAgICAgICB0aGlzLmJyb3dzZXJzICAgICAgICAgICAgICAgICA9IFtdO1xuICAgICAgICB0aGlzLnJlcG9ydGVycyAgICAgICAgICAgICAgICA9IFtdO1xuICAgICAgICB0aGlzLmZpbHRlciAgICAgICAgICAgICAgICAgICA9IHZvaWQgMDtcbiAgICAgICAgdGhpcy5hcHBDb21tYW5kICAgICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuYXBwSW5pdERlbGF5ICAgICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLnRzQ29uZmlnUGF0aCAgICAgICAgICAgICA9IHZvaWQgMDtcbiAgICAgICAgdGhpcy5jbGllbnRTY3JpcHRzICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5kaXNhYmxlTXVsdGlwbGVXaW5kb3dzICAgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5jb21waWxlck9wdGlvbnMgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuZGVidWdMb2dnZXIgICAgICAgICAgICAgID0gZGVidWcoREVCVUdfU0NPUEUpO1xuICAgICAgICB0aGlzLndhcm5pbmdMb2cgICAgICAgICAgICAgICA9IG5ldyBXYXJuaW5nTG9nKG51bGwsIFdhcm5pbmdMb2cuY3JlYXRlQWRkV2FybmluZ0NhbGxiYWNrKG1lc3NhZ2VCdXMpKTtcbiAgICAgICAgdGhpcy5tZXNzYWdlQnVzICAgICAgICAgICAgICAgPSBtZXNzYWdlQnVzO1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24gICAgICAgICAgICA9IGNvbmZpZ3VyYXRpb247XG5cbiAgICAgICAgdGhpcy5URVNUU19DT01QSUxBVElPTl9VUFBFUkJPVU5EID0gNjA7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgX2dldEJyb3dzZXJOYW1lIChicm93c2VyOiBCcm93c2VySW5mb1NvdXJjZSk6IHN0cmluZyB7XG4gICAgICAgIGlmIChicm93c2VyIGluc3RhbmNlb2YgQnJvd3NlckNvbm5lY3Rpb24pXG4gICAgICAgICAgICByZXR1cm4gYnJvd3Nlci5icm93c2VySW5mby5icm93c2VyTmFtZTtcblxuICAgICAgICByZXR1cm4gYnJvd3Nlci5icm93c2VyTmFtZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBfc3BsaXRCcm93c2VySW5mbyAoYnJvd3NlckluZm86IEJyb3dzZXJJbmZvU291cmNlW10pOiBTZXBhcmF0ZWRCcm93c2VySW5mbyB7XG4gICAgICAgIGNvbnN0IHJlbW90ZXM6IEJyb3dzZXJDb25uZWN0aW9uW10gPSBbXTtcbiAgICAgICAgY29uc3QgYXV0b21hdGVkOiBCcm93c2VySW5mb1tdICAgICA9IFtdO1xuXG4gICAgICAgIGJyb3dzZXJJbmZvLmZvckVhY2goYnJvd3NlciA9PiB7XG4gICAgICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgICAgIHJlbW90ZXMucHVzaChicm93c2VyKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBhdXRvbWF0ZWQucHVzaChicm93c2VyKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHsgcmVtb3RlcywgYXV0b21hdGVkIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfY3JlYXRlQXV0b21hdGVkQ29ubmVjdGlvbnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1tdKTogQnJvd3NlckNvbm5lY3Rpb25bXVtdIHtcbiAgICAgICAgaWYgKCFicm93c2VySW5mbylcbiAgICAgICAgICAgIHJldHVybiBbXTtcblxuICAgICAgICByZXR1cm4gYnJvd3NlckluZm8ubWFwKGJyb3dzZXIgPT4gdGltZXModGhpcy5jb25jdXJyZW5jeSwgKCkgPT4ge1xuICAgICAgICAgICAgY29uc3Qgb3B0aW9ucyA9IHtcbiAgICAgICAgICAgICAgICBkaXNhYmxlTXVsdGlwbGVXaW5kb3dzOiB0aGlzLmRpc2FibGVNdWx0aXBsZVdpbmRvd3MsXG4gICAgICAgICAgICAgICAgZGV2ZWxvcG1lbnRNb2RlOiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuZGV2ZWxvcG1lbnRNb2RlKSBhcyBib29sZWFuLFxuICAgICAgICAgICAgICAgIG5hdGl2ZUF1dG9tYXRpb246ICAgICAgICF0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5kaXNhYmxlTmF0aXZlQXV0b21hdGlvbiksXG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBjb25zdCBjb25uZWN0aW9uID0gbmV3IEJyb3dzZXJDb25uZWN0aW9uKHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LCB7IC4uLmJyb3dzZXIgfSwgZmFsc2UsIG9wdGlvbnMsIHRoaXMubWVzc2FnZUJ1cyk7XG5cbiAgICAgICAgICAgIGNvbm5lY3Rpb24uaW5pdGlhbGl6ZSgpO1xuXG4gICAgICAgICAgICByZXR1cm4gY29ubmVjdGlvbjtcbiAgICAgICAgfSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2dldEJyb3dzZXJTZXRPcHRpb25zICgpOiBCcm93c2VyU2V0T3B0aW9ucyB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjb25jdXJyZW5jeTogICAgICAgIHRoaXMuY29uY3VycmVuY3ksXG4gICAgICAgICAgICBicm93c2VySW5pdFRpbWVvdXQ6IHRoaXMuYnJvd3NlckluaXRUaW1lb3V0LFxuICAgICAgICAgICAgd2FybmluZ0xvZzogICAgICAgICB0aGlzLndhcm5pbmdMb2csXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfc2V0dXBQcm94eSAoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICh0aGlzLmJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheS5zdGF0dXMgPT09IEJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheVN0YXR1cy5pbml0aWFsaXplZClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb24uY2FsY3VsYXRlSG9zdG5hbWUoeyBuYXRpdmVBdXRvbWF0aW9uOiAhdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuZGlzYWJsZU5hdGl2ZUF1dG9tYXRpb24pIH0pO1xuXG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LmluaXRpYWxpemUodGhpcy5jb25maWd1cmF0aW9uLnN0YXJ0T3B0aW9ucyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfaGFzTm90U3VwcG9ydGVkQnJvd3NlckluTmF0aXZlQXV0b21hdGlvbiAoYnJvd3NlckluZm9zOiBCcm93c2VySW5mb1tdKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiBicm93c2VySW5mb3Muc29tZShicm93c2VySW5mbyA9PiB7XG4gICAgICAgICAgICByZXR1cm4gIWJyb3dzZXJJbmZvLnByb3ZpZGVyLnN1cHBvcnROYXRpdmVBdXRvbWF0aW9uKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0QnJvd3NlcnNXaXRoVXNlclByb2ZpbGVFbmFibGVkIChicm93c2VySW5mb3M6IEJyb3dzZXJJbmZvW10pOiBCcm93c2VySW5mb1tdIHtcbiAgICAgICAgcmV0dXJuIGJyb3dzZXJJbmZvcy5maWx0ZXIoYnJvd3NlckluZm8gPT4gKGJyb3dzZXJJbmZvLmJyb3dzZXJPcHRpb24gYXMgYW55KT8udXNlclByb2ZpbGUpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Rpc2FibGVOYXRpdmVBdXRvbWF0aW9uSWZOZWNlc3NhcnkgKHJlbW90ZXM6IEJyb3dzZXJDb25uZWN0aW9uW10sIGF1dG9tYXRlZDogQnJvd3NlckluZm9bXSk6IHZvaWQge1xuICAgICAgICAvLyBOT1RFOiBDRFAgQVBJIGFsbG93cyBjb25uZWN0aW5nIG9ubHkgZm9yIHRoZSBsb2NhbCBicm93c2VyLiBTbywgdGhlICdyZW1vdGUnIGJyb3dzZXIgY2Fubm90IGJlIHJ1biBpbiB0aGUgJ25hdGl2ZUF1dG9tYXRpb24nIG1vZGUuXG4gICAgICAgIC8vIEhvd2V2ZXIsIHNvbWV0aW1lcyBpbiB0ZXN0cyBvciBUZXN0Q2FmZSBTdHVkaW8gUmVjb3JkZXIsIHdlIHVzZSB0aGUgJ3JlbW90ZScgYnJvd3NlciBjb25uZWN0aW9uIGFzIGEgbG9jYWwgb25lLlxuICAgICAgICBjb25zdCBjb250YWluc05vdEF1dG9tYXRlZFJlbW90ZXMgPSByZW1vdGVzLnNvbWUocmVtb3RlID0+ICFyZW1vdGUuaXNOYXRpdmVBdXRvbWF0aW9uRW5hYmxlZCgpKTtcblxuICAgICAgICBpZiAocmVtb3Rlcy5sZW5ndGggJiYgY29udGFpbnNOb3RBdXRvbWF0ZWRSZW1vdGVzIHx8IHRoaXMuX2hhc05vdFN1cHBvcnRlZEJyb3dzZXJJbk5hdGl2ZUF1dG9tYXRpb24oYXV0b21hdGVkKSlcbiAgICAgICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBkaXNhYmxlTmF0aXZlQXV0b21hdGlvbjogdHJ1ZSB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRCcm93c2VyQ29ubmVjdGlvbnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxCcm93c2VyU2V0PiB7XG4gICAgICAgIGNvbnN0IHsgYXV0b21hdGVkLCByZW1vdGVzIH0gPSBCb290c3RyYXBwZXIuX3NwbGl0QnJvd3NlckluZm8oYnJvd3NlckluZm8pO1xuXG4gICAgICAgIGlmIChyZW1vdGVzICYmIHJlbW90ZXMubGVuZ3RoICUgdGhpcy5jb25jdXJyZW5jeSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RGl2aWRlUmVtb3Rlc0NvdW50QnlDb25jdXJyZW5jeSk7XG5cbiAgICAgICAgdGhpcy5fZGlzYWJsZU5hdGl2ZUF1dG9tYXRpb25JZk5lY2Vzc2FyeShyZW1vdGVzLCBhdXRvbWF0ZWQpO1xuXG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlVXNlclByb2ZpbGVPcHRpb25Jbk5hdGl2ZUF1dG9tYXRpb24oYXV0b21hdGVkKTtcblxuICAgICAgICBhd2FpdCB0aGlzLl9zZXR1cFByb3h5KCk7XG5cbiAgICAgICAgbGV0IGJyb3dzZXJDb25uZWN0aW9ucyA9IHRoaXMuX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zKGF1dG9tYXRlZCk7XG5cbiAgICAgICAgcmVtb3Rlcy5mb3JFYWNoKHJlbW90ZUNvbm5lY3Rpb24gPT4ge1xuICAgICAgICAgICAgcmVtb3RlQ29ubmVjdGlvbi5tZXNzYWdlQnVzID0gdGhpcy5tZXNzYWdlQnVzO1xuXG4gICAgICAgICAgICByZW1vdGVDb25uZWN0aW9uLmluaXRNZXNzYWdlQnVzKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGJyb3dzZXJDb25uZWN0aW9ucyA9IGJyb3dzZXJDb25uZWN0aW9ucy5jb25jYXQoY2h1bmsocmVtb3RlcywgdGhpcy5jb25jdXJyZW5jeSkpO1xuXG4gICAgICAgIHJldHVybiBCcm93c2VyU2V0LmZyb20oYnJvd3NlckNvbm5lY3Rpb25zLCB0aGlzLl9nZXRCcm93c2VyU2V0T3B0aW9ucygpKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgX3ZhbGlkYXRlVXNlclByb2ZpbGVPcHRpb25Jbk5hdGl2ZUF1dG9tYXRpb24gKGF1dG9tYXRlZDogQnJvd3NlckluZm9bXSk6IHZvaWQge1xuICAgICAgICBjb25zdCBpc05hdGl2ZUF1dG9tYXRpb24gICAgICA9ICF0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5kaXNhYmxlTmF0aXZlQXV0b21hdGlvbik7XG4gICAgICAgIGNvbnN0IGJyb3dzZXJzV2l0aFVzZXJQcm9maWxlID0gdGhpcy5nZXRCcm93c2Vyc1dpdGhVc2VyUHJvZmlsZUVuYWJsZWQoYXV0b21hdGVkKTtcblxuICAgICAgICBpZiAoaXNOYXRpdmVBdXRvbWF0aW9uICYmIGJyb3dzZXJzV2l0aFVzZXJQcm9maWxlLmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc3QgYnJvd3NlcnMgPSBicm93c2Vyc1dpdGhVc2VyUHJvZmlsZS5tYXAoYiA9PiBiLmFsaWFzKS5qb2luKCcsICcpO1xuXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLnNldFVzZXJQcm9maWxlSW5OYXRpdmVBdXRvbWF0aW9uLCBicm93c2Vycyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9maWx0ZXJUZXN0cyAodGVzdHM6IFRlc3RbXSwgcHJlZGljYXRlOiBGaWx0ZXJGdW5jdGlvbik6IFByb21pc2U8VGVzdFtdPiB7XG4gICAgICAgIHJldHVybiBhc3luY0ZpbHRlcih0ZXN0cywgdGVzdCA9PiB7XG4gICAgICAgICAgICBjb25zdCB0ZXN0Rml4dHVyZSA9IHRlc3QuZml4dHVyZSBhcyBGaXh0dXJlO1xuXG4gICAgICAgICAgICByZXR1cm4gcHJlZGljYXRlKFxuICAgICAgICAgICAgICAgIHRlc3QubmFtZSBhcyBzdHJpbmcsXG4gICAgICAgICAgICAgICAgdGVzdEZpeHR1cmUubmFtZSBhcyBzdHJpbmcsXG4gICAgICAgICAgICAgICAgdGVzdEZpeHR1cmUucGF0aCxcbiAgICAgICAgICAgICAgICB0ZXN0Lm1ldGEsXG4gICAgICAgICAgICAgICAgdGVzdEZpeHR1cmUubWV0YSk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2NvbXBpbGVUZXN0cyAoeyBzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnMgfTogQ29tcGlsZXJBcmd1bWVudHMpOiBQcm9taXNlPFRlc3RbXT4ge1xuICAgICAgICBjb25zdCBiYXNlVXJsICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmJhc2VVcmwpIGFzIHN0cmluZztcbiAgICAgICAgY29uc3QgZXNtICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5lc20pO1xuICAgICAgICBjb25zdCBjb21waWxlciA9IG5ldyBDb21waWxlcihzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnMsIHsgYmFzZVVybCwgZXNtIH0pO1xuXG4gICAgICAgIHJldHVybiBjb21waWxlci5nZXRUZXN0cygpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2Fzc2VydEdsb2JhbEhvb2tzICgpOiB2b2lkIHtcbiAgICAgICAgaWYgKCF0aGlzLmhvb2tzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGlmICh0aGlzLmhvb2tzLmZpeHR1cmU/LmJlZm9yZSlcbiAgICAgICAgICAgIGFzc2VydFR5cGUoaXMuZnVuY3Rpb24sICdnbG9iYWxCZWZvcmUnLCAnVGhlIGZpeHR1cmUuZ2xvYmFsQmVmb3JlIGhvb2snLCB0aGlzLmhvb2tzLmZpeHR1cmUuYmVmb3JlKTtcblxuICAgICAgICBpZiAodGhpcy5ob29rcy5maXh0dXJlPy5hZnRlcilcbiAgICAgICAgICAgIGFzc2VydFR5cGUoaXMuZnVuY3Rpb24sICdnbG9iYWxBZnRlcicsICdUaGUgZml4dHVyZS5nbG9iYWxBZnRlciBob29rJywgdGhpcy5ob29rcy5maXh0dXJlLmFmdGVyKTtcblxuICAgICAgICBpZiAodGhpcy5ob29rcy50ZXN0Py5iZWZvcmUpXG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLmZ1bmN0aW9uLCAnZ2xvYmFsQmVmb3JlJywgJ1RoZSB0ZXN0Lmdsb2JhbEJlZm9yZSBob29rJywgdGhpcy5ob29rcy50ZXN0LmJlZm9yZSk7XG5cbiAgICAgICAgaWYgKHRoaXMuaG9va3MudGVzdD8uYWZ0ZXIpXG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLmZ1bmN0aW9uLCAnZ2xvYmFsQWZ0ZXInLCAnVGhlIHRlc3QuZ2xvYmFsQWZ0ZXIgaG9vaycsIHRoaXMuaG9va3MudGVzdC5hZnRlcik7XG5cbiAgICAgICAgaWYgKHRoaXMuaG9va3MucmVxdWVzdClcbiAgICAgICAgICAgIGFzc2VydFJlcXVlc3RIb29rVHlwZShmbGF0dGVuKGNhc3RBcnJheSh0aGlzLmhvb2tzLnJlcXVlc3QpKSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfc2V0R2xvYmFsSG9va3NUb1Rlc3RzICh0ZXN0czogVGVzdFtdKTogdm9pZCB7XG4gICAgICAgIGlmICghdGhpcy5ob29rcylcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB0aGlzLl9hc3NlcnRHbG9iYWxIb29rcygpO1xuXG4gICAgICAgIGNvbnN0IGZpeHR1cmVCZWZvcmUgPSB0aGlzLmhvb2tzLmZpeHR1cmU/LmJlZm9yZSB8fCBudWxsO1xuICAgICAgICBjb25zdCBmaXh0dXJlQWZ0ZXIgID0gdGhpcy5ob29rcy5maXh0dXJlPy5hZnRlciB8fCBudWxsO1xuICAgICAgICBjb25zdCB0ZXN0QmVmb3JlICAgID0gdGhpcy5ob29rcy50ZXN0Py5iZWZvcmUgPyB3cmFwVGVzdEZ1bmN0aW9uKHRoaXMuaG9va3MudGVzdC5iZWZvcmUpIDogbnVsbDtcbiAgICAgICAgY29uc3QgdGVzdEFmdGVyICAgICA9IHRoaXMuaG9va3MudGVzdD8uYWZ0ZXIgPyB3cmFwVGVzdEZ1bmN0aW9uKHRoaXMuaG9va3MudGVzdC5hZnRlcikgOiBudWxsO1xuICAgICAgICBjb25zdCByZXF1ZXN0ICAgICAgID0gdGhpcy5ob29rcy5yZXF1ZXN0IHx8IFtdO1xuXG4gICAgICAgIHRlc3RzLmZvckVhY2goaXRlbSA9PiB7XG4gICAgICAgICAgICBpZiAoaXRlbS5maXh0dXJlKSB7XG4gICAgICAgICAgICAgICAgaXRlbS5maXh0dXJlLmdsb2JhbEJlZm9yZUZuID0gaXRlbS5maXh0dXJlLmdsb2JhbEJlZm9yZUZuIHx8IGZpeHR1cmVCZWZvcmU7XG4gICAgICAgICAgICAgICAgaXRlbS5maXh0dXJlLmdsb2JhbEFmdGVyRm4gID0gaXRlbS5maXh0dXJlLmdsb2JhbEFmdGVyRm4gfHwgZml4dHVyZUFmdGVyO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpdGVtLmdsb2JhbEJlZm9yZUZuID0gdGVzdEJlZm9yZTtcbiAgICAgICAgICAgIGl0ZW0uZ2xvYmFsQWZ0ZXJGbiAgPSB0ZXN0QWZ0ZXI7XG4gICAgICAgICAgICBpdGVtLnJlcXVlc3RIb29rcyAgID0gdW5pb24oZmxhdHRlbihjYXN0QXJyYXkocmVxdWVzdCkpLCBpdGVtLnJlcXVlc3RIb29rcyk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldFRlc3RzIChpZDogc3RyaW5nKTogUHJvbWlzZTxUZXN0W10+IHtcbiAgICAgICAgY29uc3QgY3dkICAgICAgICA9IHByb2Nlc3MuY3dkKCk7XG4gICAgICAgIGNvbnN0IHNvdXJjZUxpc3QgPSBhd2FpdCBwYXJzZUZpbGVMaXN0KHRoaXMuc291cmNlcywgY3dkKTtcblxuICAgICAgICBpZiAoIXNvdXJjZUxpc3QubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy50ZXN0RmlsZXNOb3RGb3VuZCwgY3dkLCBnZXRDb25jYXRlbmF0ZWRWYWx1ZXNTdHJpbmcodGhpcy5zb3VyY2VzLCAnXFxuJywgJycpKTtcblxuICAgICAgICBsZXQgdGVzdHMgPSBhd2FpdCBndWFyZFRpbWVFeGVjdXRpb24oXG4gICAgICAgICAgICBhc3luYyAoKSA9PiBhd2FpdCB0aGlzLl9jb21waWxlVGVzdHMoeyBzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnM6IHRoaXMuY29tcGlsZXJPcHRpb25zLCBydW5uYWJsZUNvbmZpZ3VyYXRpb25JZDogaWQgfSksXG4gICAgICAgICAgICBlbGFwc2VkVGltZSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWJ1Z0xvZ2dlcihgdGVzdHMgY29tcGlsYXRpb24gdG9vayAke3ByZXR0eVRpbWUoZWxhcHNlZFRpbWUpfWApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgWyBlbGFwc2VkU2Vjb25kcyBdID0gZWxhcHNlZFRpbWU7XG5cbiAgICAgICAgICAgICAgICBpZiAoZWxhcHNlZFNlY29uZHMgPiB0aGlzLlRFU1RTX0NPTVBJTEFUSU9OX1VQUEVSQk9VTkQpXG4gICAgICAgICAgICAgICAgICAgIHRoaXMud2FybmluZ0xvZy5hZGRXYXJuaW5nKFdBUk5JTkdfTUVTU0FHRVMudGVzdHNDb21waWxhdGlvblRha2VzVG9vTG9uZywgcHJldHR5VGltZShlbGFwc2VkVGltZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuXG4gICAgICAgIGNvbnN0IHRlc3RzV2l0aE9ubHlGbGFnID0gdGVzdHMuZmlsdGVyKHRlc3QgPT4gdGVzdC5vbmx5KTtcblxuICAgICAgICBp