@browserstack/testcafe
Version:
Automated browser testing for the modern web development stack.
261 lines • 45.5 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 path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const is_ci_1 = __importDefault(require("is-ci"));
const lodash_1 = require("lodash");
const make_dir_1 = __importDefault(require("make-dir"));
const os_family_1 = __importDefault(require("os-family"));
const testcafe_browser_tools_1 = require("testcafe-browser-tools");
const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
const compiler_1 = __importDefault(require("../compiler"));
const connection_1 = __importDefault(require("../browser/connection"));
const pool_1 = __importDefault(require("../browser/provider/pool"));
const browser_set_1 = __importDefault(require("./browser-set"));
const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
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 resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd"));
const load_1 = __importDefault(require("../custom-client-scripts/load"));
const string_1 = require("../utils/string");
function isReporterPluginFactory(value) {
return typeof value === 'function';
}
function isPromiseError(value) {
return value.error !== void 0;
}
class Bootstrapper {
constructor(browserConnectionGateway, compilerService) {
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.allowMultipleWindows = false;
this.testScheduling = false;
this.compilerService = compilerService;
}
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 };
}
static async _hasLocalBrowsers(browserInfo) {
for (const browser of browserInfo) {
if (browser instanceof connection_1.default)
continue;
if (await browser.provider.isLocalBrowser(void 0, browser.browserName))
return true;
}
return false;
}
static async _checkRequiredPermissions(browserInfo) {
const hasLocalBrowsers = await Bootstrapper._hasLocalBrowsers(browserInfo);
const { error } = await authentication_helper_1.default(() => testcafe_browser_tools_1.findWindow(''), testcafe_browser_tools_1.errors.UnableToAccessScreenRecordingAPIError, {
interactive: hasLocalBrowsers && !is_ci_1.default
});
if (!error)
return;
if (hasLocalBrowsers)
throw error;
remote_1.default.canDetectLocalBrowsers = false;
}
async _getBrowserInfo() {
if (!this.browsers.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet);
const browserInfo = await Promise.all(this.browsers.map(browser => pool_1.default.getBrowserInfo(browser)));
return lodash_1.flatten(browserInfo);
}
_createAutomatedConnections(browserInfo) {
if (!browserInfo)
return [];
return browserInfo
.map(browser => lodash_1.times(this.concurrency, () => new connection_1.default(this.browserConnectionGateway, browser, false, this.allowMultipleWindows, this.testScheduling)));
}
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);
let browserConnections = this._createAutomatedConnections(automated);
browserConnections = browserConnections.concat(lodash_1.chunk(remotes, this.concurrency));
return await browser_set_1.default.from(browserConnections);
}
_filterTests(tests, predicate) {
return tests.filter(test => predicate(test.name, test.fixture.name, test.fixture.path, test.meta, test.fixture.meta));
}
async _compileTests({ sourceList, compilerOptions }) {
if (this.compilerService) {
await this.compilerService.init();
return this.compilerService.getTests({ sourceList, compilerOptions });
}
const compiler = new compiler_1.default(sourceList, compilerOptions);
return compiler.getTests();
}
async _getTests() {
const cwd = process.cwd();
const { sourceList, compilerOptions } = await this._getCompilerArguments(cwd);
if (!sourceList.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testFilesNotFound, string_1.getConcatenatedValuesString(this.sources, '\n', ''), cwd);
let tests = await this._compileTests({ sourceList, compilerOptions });
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 = this._filterTests(tests, this.filter);
if (!tests.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRunDueFiltering);
return tests;
}
async _getCompilerArguments(cwd) {
const sourceList = await parse_file_list_1.default(this.sources, cwd);
const compilerOptions = {
typeScriptOptions: {
tsConfigPath: this.tsConfigPath
}
};
return { sourceList, compilerOptions };
}
async _ensureOutStream(outStream) {
if (typeof outStream !== 'string')
return outStream;
const fullReporterOutputPath = resolve_path_relatively_cwd_1.default(outStream);
await make_dir_1.default(path_1.default.dirname(fullReporterOutputPath));
return fs_1.default.createWriteStream(fullReporterOutputPath);
}
static _addDefaultReporter(reporters) {
reporters.push({
name: 'spec',
output: process.stdout
});
}
_requireReporterPluginFactory(reporterName) {
try {
return require('testcafe-reporter-' + reporterName);
}
catch (err) {
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindReporterForAlias, reporterName);
}
}
_getPluginFactory(reporterFactorySource) {
if (!isReporterPluginFactory(reporterFactorySource))
return this._requireReporterPluginFactory(reporterFactorySource);
return reporterFactorySource;
}
async _getReporterPlugins() {
if (!this.reporters.length)
Bootstrapper._addDefaultReporter(this.reporters);
return Promise.all(this.reporters.map(async ({ name, output }) => {
const pluginFactory = this._getPluginFactory(name);
const outStream = output ? await this._ensureOutStream(output) : void 0;
return {
plugin: pluginFactory(),
outStream,
name
};
}));
}
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) {
const tests = await this._getTests();
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 _bootstrapParallel(browserInfo) {
const bootstrappingPromises = {
browserSet: this._getBrowserConnections(browserInfo),
tests: this._getTests(),
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);
return {
browserSet: browserSetResults.result,
tests: testResults.result,
testedApp: appResults.result
};
}
// API
async createRunnableConfiguration() {
const reporterPlugins = await this._getReporterPlugins();
const commonClientScripts = await load_1.default(this.clientScripts);
// NOTE: If a user forgot to specify a browser, but has specified a path to tests, the specified path will be
// considered as the browser argument, and the tests path argument will have the predefined default value.
// It's very ambiguous for the user, who might be confused by compilation errors from an unexpected test.
// So, we need to retrieve the browser aliases and paths before tests compilation.
const browserInfo = await this._getBrowserInfo();
if (os_family_1.default.mac)
await Bootstrapper._checkRequiredPermissions(browserInfo);
if (await this._canUseParallelBootstrapping(browserInfo))
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapParallel(browserInfo)), { commonClientScripts });
return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapSequence(browserInfo)), { commonClientScripts });
}
}
exports.default = Bootstrapper;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bm5lci9ib290c3RyYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxnREFBd0I7QUFDeEIsNENBQW9CO0FBQ3BCLGtEQUF5QjtBQUN6QixtQ0FBK0M7QUFDL0Msd0RBQStCO0FBQy9CLDBEQUEyQjtBQUMzQixtRUFBNEQ7QUFDNUQseUZBQWdFO0FBQ2hFLDJEQUFtQztBQUNuQyx1RUFBc0Q7QUFDdEQsb0VBQTJEO0FBQzNELGdFQUF1QztBQUN2QyxpRkFBd0U7QUFDeEUsK0NBQWlEO0FBQ2pELDJDQUFpRDtBQUNqRCw4REFBcUM7QUFDckMsK0VBQXFEO0FBQ3JELHVHQUE0RTtBQUM1RSx5RUFBOEQ7QUFDOUQsNENBQThEO0FBK0I5RCxTQUFTLHVCQUF1QixDQUFFLEtBQXdCO0lBQ3RELE9BQU8sT0FBTyxLQUFLLEtBQUssVUFBVSxDQUFDO0FBQ3ZDLENBQUM7QUFtQ0QsU0FBUyxjQUFjLENBQThCLEtBQTBCO0lBQzNFLE9BQVEsS0FBeUIsQ0FBQyxLQUFLLEtBQUssS0FBSyxDQUFDLENBQUM7QUFDdkQsQ0FBQztBQWFELE1BQXFCLFlBQVk7SUFpQjdCLFlBQW9CLHdCQUFrRCxFQUFFLGVBQWlDO1FBQ3JHLElBQUksQ0FBQyx3QkFBd0IsR0FBRyx3QkFBd0IsQ0FBQztRQUN6RCxJQUFJLENBQUMsV0FBVyxHQUFnQixDQUFDLENBQUM7UUFDbEMsSUFBSSxDQUFDLE9BQU8sR0FBb0IsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxRQUFRLEdBQW1CLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsU0FBUyxHQUFrQixFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLE1BQU0sR0FBcUIsS0FBSyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLFVBQVUsR0FBaUIsS0FBSyxDQUFDLENBQUM7UUFDdkMsSUFBSSxDQUFDLFlBQVksR0FBZSxLQUFL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LENBQUMsV0FBVyxDQUFDLEtBQUUsbUJBQW1CLElBQUc7UUFFbkcscUNBQVMsZUFBZSxJQUFLLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLFdBQVcsQ0FBQyxLQUFFLG1CQUFtQixJQUFHO0lBQ25HLENBQUM7Q0FDSjtBQXhVRCwrQkF3VUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgaXNDSSBmcm9tICdpcy1jaSc7XG5pbXBvcnQgeyBmbGF0dGVuLCBjaHVuaywgdGltZXMgfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IG1ha2VEaXIgZnJvbSAnbWFrZS1kaXInO1xuaW1wb3J0IE9TIGZyb20gJ29zLWZhbWlseSc7XG5pbXBvcnQgeyBlcnJvcnMsIGZpbmRXaW5kb3cgfSBmcm9tICd0ZXN0Y2FmZS1icm93c2VyLXRvb2xzJztcbmltcG9ydCBhdXRoZW50aWNhdGlvbkhlbHBlciBmcm9tICcuLi9jbGkvYXV0aGVudGljYXRpb24taGVscGVyJztcbmltcG9ydCBDb21waWxlciBmcm9tICcuLi9jb21waWxlcic7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb24gZnJvbSAnLi4vYnJvd3Nlci9jb25uZWN0aW9uJztcbmltcG9ydCBicm93c2VyUHJvdmlkZXJQb29sIGZyb20gJy4uL2Jyb3dzZXIvcHJvdmlkZXIvcG9vbCc7XG5pbXBvcnQgQnJvd3NlclNldCBmcm9tICcuL2Jyb3dzZXItc2V0JztcbmltcG9ydCBSZW1vdGVCcm93c2VyUHJvdmlkZXIgZnJvbSAnLi4vYnJvd3Nlci9wcm92aWRlci9idWlsdC1pbi9yZW1vdGUnO1xuaW1wb3J0IHsgR2VuZXJhbEVycm9yIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUnO1xuaW1wb3J0IHsgUlVOVElNRV9FUlJPUlMgfSBmcm9tICcuLi9lcnJvcnMvdHlwZXMnO1xuaW1wb3J0IFRlc3RlZEFwcCBmcm9tICcuL3Rlc3RlZC1hcHAnO1xuaW1wb3J0IHBhcnNlRmlsZUxpc3QgZnJvbSAnLi4vdXRpbHMvcGFyc2UtZmlsZS1saXN0JztcbmltcG9ydCByZXNvbHZlUGF0aFJlbGF0aXZlbHlDd2QgZnJvbSAnLi4vdXRpbHMvcmVzb2x2ZS1wYXRoLXJlbGF0aXZlbHktY3dkJztcbmltcG9ydCBsb2FkQ2xpZW50U2NyaXB0cyBmcm9tICcuLi9jdXN0b20tY2xpZW50LXNjcmlwdHMvbG9hZCc7XG5pbXBvcnQgeyBnZXRDb25jYXRlbmF0ZWRWYWx1ZXNTdHJpbmcgfSBmcm9tICcuLi91dGlscy9zdHJpbmcnO1xuXG5pbXBvcnQgeyBXcml0YWJsZSBhcyBXcml0YWJsZVN0cmVhbSB9IGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgQ2xpZW50U2NyaXB0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0JztcbmltcG9ydCBDbGllbnRTY3JpcHRJbml0IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9jbGllbnQtc2NyaXB0LWluaXQnO1xuaW1wb3J0IEJyb3dzZXJQcm92aWRlciBmcm9tICcuLi9icm93c2VyL3Byb3ZpZGVyJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvbkdhdGV3YXkgZnJvbSAnLi4vYnJvd3Nlci9jb25uZWN0aW9uL2dhdGV3YXknO1xuaW1wb3J0IHsgQ29tcGlsZXJBcmd1bWVudHMgfSBmcm9tICcuLi9jb21waWxlci9pbnRlcmZhY2VzJztcbmltcG9ydCBDb21waWxlclNlcnZpY2UgZnJvbSAnLi4vc2VydmljZXMvY29tcGlsZXIvaG9zdCc7XG5pbXBvcnQgeyBNZXRhZGF0YSwgVGVzdCB9IGZyb20gJy4uL2FwaS9zdHJ1Y3R1cmUvaW50ZXJmYWNlcyc7XG5cbnR5cGUgVGVzdFNvdXJjZSA9IHVua25vd247XG5cbnR5cGUgUmVwb3J0ZXJQbHVnaW4gPSB1bmtub3duO1xuXG50eXBlIEJyb3dzZXJTb3VyY2UgPSBCcm93c2VyQ29ubmVjdGlvbiB8IHN0cmluZztcblxuaW50ZXJmYWNlIFJlcG9ydGVyU291cmNlIHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgb3V0cHV0Pzogc3RyaW5nIHwgV3JpdGFibGVTdHJlYW07XG59XG5cbmludGVyZmFjZSBSZXBvcnRlclBsdWdpblNvdXJjZSB7XG4gICAgcGx1Z2luOiBSZXBvcnRlclBsdWdpbjtcbiAgICBvdXRTdHJlYW0/OiBXcml0YWJsZVN0cmVhbTtcbn1cblxuaW50ZXJmYWNlIFJlcG9ydGVyUGx1Z2luRmFjdG9yeSB7XG4gICAgKCk6IFJlcG9ydGVyUGx1Z2luO1xufVxuXG5mdW5jdGlvbiBpc1JlcG9ydGVyUGx1Z2luRmFjdG9yeSAodmFsdWU6IHN0cmluZyB8IEZ1bmN0aW9uKTogdmFsdWUgaXMgUmVwb3J0ZXJQbHVnaW5GYWN0b3J5IHtcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nO1xufVxuXG5pbnRlcmZhY2UgRmlsdGVyIHtcbiAgICAodGVzdE5hbWU6IHN0cmluZywgZml4dHVyZU5hbWU6IHN0cmluZywgZml4dHVyZVBhdGg6IHN0cmluZywgdGVzdE1ldGE6IE1ldGFkYXRhLCBmaXh0dXJlTWV0YTogTWV0YWRhdGEpOiBib29sZWFuO1xufVxuXG5pbnRlcmZhY2UgQnJvd3NlckluZm8ge1xuICAgIGJyb3dzZXJOYW1lOiBzdHJpbmc7XG4gICAgcHJvdmlkZXJOYW1lOiBzdHJpbmc7XG4gICAgcHJvdmlkZXI6IEJyb3dzZXJQcm92aWRlcjtcbn1cblxudHlwZSBCcm93c2VySW5mb1NvdXJjZSA9IEJyb3dzZXJJbmZvIHwgQnJvd3NlckNvbm5lY3Rpb247XG5cbmludGVyZmFjZSBQcm9taXNlU3VjY2VzczxUPiB7XG4gICAgcmVzdWx0OiBUO1xufVxuXG5pbnRlcmZhY2UgUHJvbWlzZUVycm9yPEUgZXh0ZW5kcyBFcnJvciA9IEVycm9yPiB7XG4gICAgZXJyb3I6IEU7XG59XG5cbmludGVyZmFjZSBCYXNpY1J1bnRpbWVSZXNvdXJjZXMge1xuICAgIGJyb3dzZXJTZXQ6IEJyb3dzZXJTZXQ7XG4gICAgdGVzdHM6IFRlc3RbXTtcbiAgICB0ZXN0ZWRBcHA/OiBUZXN0ZWRBcHA7XG59XG5cbmludGVyZmFjZSBSdW50aW1lUmVzb3VyY2VzIGV4dGVuZHMgQmFzaWNSdW50aW1lUmVzb3VyY2VzIHtcbiAgICByZXBvcnRlclBsdWdpbnM6IFJlcG9ydGVyUGx1Z2luU291cmNlW107XG4gICAgY29tbW9uQ2xpZW50U2NyaXB0czogQ2xpZW50U2NyaXB0W107XG59XG5cbnR5cGUgUHJvbWlzZVJlc3VsdDxULCBFIGV4dGVuZHMgRXJyb3IgPSBFcnJvcj4gPSBQcm9taXNlU3VjY2VzczxUPiB8IFByb21pc2VFcnJvcjxFPjtcblxuZnVuY3Rpb24gaXNQcm9taXNlRXJyb3I8VCwgRSBleHRlbmRzIEVycm9yID0gRXJyb3I+ICh2YWx1ZTogUHJvbWlzZVJlc3VsdDxULCBFPik6IHZhbHVlIGlzIFByb21pc2VFcnJvcjxFPiB7XG4gICAgcmV0dXJuICh2YWx1ZSBhcyBQcm9taXNlRXJyb3I8RT4pLmVycm9yICE9PSB2b2lkIDA7XG59XG5cbmludGVyZmFjZSBTZXBhcmF0ZWRCcm93c2VySW5mbyB7XG4gICAgcmVtb3RlczogQnJvd3NlckNvbm5lY3Rpb25bXTtcbiAgICBhdXRvbWF0ZWQ6IEJyb3dzZXJJbmZvW107XG59XG5cbnR5cGUgUHJvbWlzZUNvbGxlY3Rpb248VD4gPSB7XG4gICAgW0sgaW4ga2V5b2YgVF06IFByb21pc2U8VFtLXT5cbn1cblxudHlwZSBSZXN1bHRDb2xsZWN0aW9uPFQ+ID0geyBbUCBpbiBrZXlvZiBUXTogUHJvbWlzZVJlc3VsdDxUW1BdPiB9O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCb290c3RyYXBwZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5OiBCcm93c2VyQ29ubmVjdGlvbkdhdGV3YXk7XG5cbiAgICBwdWJsaWMgY29uY3VycmVuY3k6IG51bWJlcjtcbiAgICBwdWJsaWMgc291cmNlczogVGVzdFNvdXJjZVtdO1xuICAgIHB1YmxpYyBicm93c2VyczogQnJvd3NlclNvdXJjZVtdO1xuICAgIHB1YmxpYyByZXBvcnRlcnM6IFJlcG9ydGVyU291cmNlW107XG4gICAgcHVibGljIGZpbHRlcj86IEZpbHRlcjtcbiAgICBwdWJsaWMgYXBwQ29tbWFuZD86IHN0cmluZztcbiAgICBwdWJsaWMgYXBwSW5pdERlbGF5PzogbnVtYmVyO1xuICAgIHB1YmxpYyB0c0NvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgcHVibGljIGNsaWVudFNjcmlwdHM6IENsaWVudFNjcmlwdEluaXRbXTtcbiAgICBwdWJsaWMgYWxsb3dNdWx0aXBsZVdpbmRvd3M6IGJvb2xlYW47XG4gICAgcHVibGljIHRlc3RTY2hlZHVsaW5nOiBib29sZWFuO1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBjb21waWxlclNlcnZpY2U/OiBDb21waWxlclNlcnZpY2U7XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IgKGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LCBjb21waWxlclNlcnZpY2U/OiBDb21waWxlclNlcnZpY2UpIHtcbiAgICAgICAgdGhpcy5icm93c2VyQ29ubmVjdGlvbkdhdGV3YXkgPSBicm93c2VyQ29ubmVjdGlvbkdhdGV3YXk7XG4gICAgICAgIHRoaXMuY29uY3VycmVuY3kgICAgICAgICAgICAgID0gMTtcbiAgICAgICAgdGhpcy5zb3VyY2VzICAgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5icm93c2VycyAgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5yZXBvcnRlcnMgICAgICAgICAgICAgICAgPSBbXTtcbiAgICAgICAgdGhpcy5maWx0ZXIgICAgICAgICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuYXBwQ29tbWFuZCAgICAgICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLmFwcEluaXREZWxheSAgICAgICAgICAgICA9IHZvaWQgMDtcbiAgICAgICAgdGhpcy50c0NvbmZpZ1BhdGggICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMuY2xpZW50U2NyaXB0cyAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuYWxsb3dNdWx0aXBsZVdpbmRvd3MgICAgID0gZmFsc2U7XG5cbiAgICAgICAgdGhpcy50ZXN0U2NoZWR1bGluZyA9IGZhbHNlO1xuXG4gICAgICAgIHRoaXMuY29tcGlsZXJTZXJ2aWNlID0gY29tcGlsZXJTZXJ2aWNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9nZXRCcm93c2VyTmFtZSAoYnJvd3NlcjogQnJvd3NlckluZm9Tb3VyY2UpOiBzdHJpbmcge1xuICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXIuYnJvd3NlckluZm8uYnJvd3Nlck5hbWU7XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXIuYnJvd3Nlck5hbWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgX3NwbGl0QnJvd3NlckluZm8gKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogU2VwYXJhdGVkQnJvd3NlckluZm8ge1xuICAgICAgICBjb25zdCByZW1vdGVzOiBCcm93c2VyQ29ubmVjdGlvbltdICA9IFtdO1xuICAgICAgICBjb25zdCBhdXRvbWF0ZWQ6IEJyb3dzZXJJbmZvW10gICAgICA9IFtdO1xuXG4gICAgICAgIGJyb3dzZXJJbmZvLmZvckVhY2goYnJvd3NlciA9PiB7XG4gICAgICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgICAgIHJlbW90ZXMucHVzaChicm93c2VyKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBhdXRvbWF0ZWQucHVzaChicm93c2VyKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHsgcmVtb3RlcywgYXV0b21hdGVkIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgX2hhc0xvY2FsQnJvd3NlcnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGZvciAoY29uc3QgYnJvd3NlciBvZiBicm93c2VySW5mbykge1xuICAgICAgICAgICAgaWYgKGJyb3dzZXIgaW5zdGFuY2VvZiBCcm93c2VyQ29ubmVjdGlvbilcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgaWYgKGF3YWl0IGJyb3dzZXIucHJvdmlkZXIuaXNMb2NhbEJyb3dzZXIodm9pZCAwLCBicm93c2VyLmJyb3dzZXJOYW1lKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhc3luYyBfY2hlY2tSZXF1aXJlZFBlcm1pc3Npb25zIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBoYXNMb2NhbEJyb3dzZXJzID0gYXdhaXQgQm9vdHN0cmFwcGVyLl9oYXNMb2NhbEJyb3dzZXJzKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICBjb25zdCB7IGVycm9yIH0gPSBhd2FpdCBhdXRoZW50aWNhdGlvbkhlbHBlcihcbiAgICAgICAgICAgICgpID0+IGZpbmRXaW5kb3coJycpLFxuICAgICAgICAgICAgZXJyb3JzLlVuYWJsZVRvQWNjZXNzU2NyZWVuUmVjb3JkaW5nQVBJRXJyb3IsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU6IGhhc0xvY2FsQnJvd3NlcnMgJiYgIWlzQ0lcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIWVycm9yKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGlmIChoYXNMb2NhbEJyb3dzZXJzKVxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG5cbiAgICAgICAgUmVtb3RlQnJvd3NlclByb3ZpZGVyLmNhbkRldGVjdExvY2FsQnJvd3NlcnMgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRCcm93c2VySW5mbyAoKTogUHJvbWlzZTxCcm93c2VySW5mb1NvdXJjZVtdPiB7XG4gICAgICAgIGlmICghdGhpcy5icm93c2Vycy5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmJyb3dzZXJOb3RTZXQpO1xuXG4gICAgICAgIGNvbnN0IGJyb3dzZXJJbmZvID0gYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5icm93c2Vycy5tYXAoYnJvd3NlciA9PiBicm93c2VyUHJvdmlkZXJQb29sLmdldEJyb3dzZXJJbmZvKGJyb3dzZXIpKSk7XG5cbiAgICAgICAgcmV0dXJuIGZsYXR0ZW4oYnJvd3NlckluZm8pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zIChicm93c2VySW5mbzogQnJvd3NlckluZm9bXSk6IEJyb3dzZXJDb25uZWN0aW9uW11bXSB7XG4gICAgICAgIGlmICghYnJvd3NlckluZm8pXG4gICAgICAgICAgICByZXR1cm4gW107XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXJJbmZvXG4gICAgICAgICAgICAubWFwKGJyb3dzZXIgPT4gdGltZXModGhpcy5jb25jdXJyZW5jeSwgKCkgPT4gbmV3IEJyb3dzZXJDb25uZWN0aW9uKHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LCBicm93c2VyLCBmYWxzZSwgdGhpcy5hbGxvd011bHRpcGxlV2luZG93cywgdGhpcy50ZXN0U2NoZWR1bGluZykpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRCcm93c2VyQ29ubmVjdGlvbnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxCcm93c2VyU2V0PiB7XG4gICAgICAgIGNvbnN0IHsgYXV0b21hdGVkLCByZW1vdGVzIH0gPSBCb290c3RyYXBwZXIuX3NwbGl0QnJvd3NlckluZm8oYnJvd3NlckluZm8pO1xuXG4gICAgICAgIGlmIChyZW1vdGVzICYmIHJlbW90ZXMubGVuZ3RoICUgdGhpcy5jb25jdXJyZW5jeSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RGl2aWRlUmVtb3Rlc0NvdW50QnlDb25jdXJyZW5jeSk7XG5cbiAgICAgICAgbGV0IGJyb3dzZXJDb25uZWN0aW9ucyA9IHRoaXMuX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zKGF1dG9tYXRlZCk7XG5cbiAgICAgICAgYnJvd3NlckNvbm5lY3Rpb25zID0gYnJvd3NlckNvbm5lY3Rpb25zLmNvbmNhdChjaHVuayhyZW1vdGVzLCB0aGlzLmNvbmN1cnJlbmN5KSk7XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IEJyb3dzZXJTZXQuZnJvbShicm93c2VyQ29ubmVjdGlvbnMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2ZpbHRlclRlc3RzICh0ZXN0czogVGVzdFtdLCBwcmVkaWNhdGU6IEZpbHRlcik6IFRlc3RbXSB7XG4gICAgICAgIHJldHVybiB0ZXN0cy5maWx0ZXIodGVzdCA9PiBwcmVkaWNhdGUodGVzdC5uYW1lLCB0ZXN0LmZpeHR1cmUubmFtZSwgdGVzdC5maXh0dXJlLnBhdGgsIHRlc3QubWV0YSwgdGVzdC5maXh0dXJlLm1ldGEpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9jb21waWxlVGVzdHMgKHsgc291cmNlTGlzdCwgY29tcGlsZXJPcHRpb25zIH06IENvbXBpbGVyQXJndW1lbnRzKTogUHJvbWlzZTxUZXN0W10+IHtcbiAgICAgICAgaWYgKHRoaXMuY29tcGlsZXJTZXJ2aWNlKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmNvbXBpbGVyU2VydmljZS5pbml0KCk7XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbXBpbGVyU2VydmljZS5nZXRUZXN0cyh7IHNvdXJjZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNvbXBpbGVyID0gbmV3IENvbXBpbGVyKHNvdXJjZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyk7XG5cbiAgICAgICAgcmV0dXJuIGNvbXBpbGVyLmdldFRlc3RzKCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZ2V0VGVzdHMgKCk6IFByb21pc2U8VGVzdFtdPiB7XG4gICAgICAgIGNvbnN0IGN3ZCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgPSBwcm9jZXNzLmN3ZCgpO1xuICAgICAgICBjb25zdCB7IHNvdXJjZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyB9ID0gYXdhaXQgdGhpcy5fZ2V0Q29tcGlsZXJBcmd1bWVudHMoY3dkKTtcblxuICAgICAgICBpZiAoIXNvdXJjZUxpc3QubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy50ZXN0RmlsZXNOb3RGb3VuZCwgZ2V0Q29uY2F0ZW5hdGVkVmFsdWVzU3RyaW5nKHRoaXMuc291cmNlcywgJ1xcbicsICcnKSwgY3dkKTtcblxuICAgICAgICBsZXQgdGVzdHMgPSBhd2FpdCB0aGlzLl9jb21waWxlVGVzdHMoeyBzb3VyY2VMaXN0LCBjb21waWxlck9wdGlvbnMgfSk7XG5cbiAgICAgICAgY29uc3QgdGVzdHNXaXRoT25seUZsYWcgPSB0ZXN0cy5maWx0ZXIodGVzdCA9PiB0ZXN0Lm9ubHkpO1xuXG4gICAgICAgIGlmICh0ZXN0c1dpdGhPbmx5RmxhZy5sZW5ndGgpXG4gICAgICAgICAgICB0ZXN0cyA9IHRlc3RzV2l0aE9ubHlGbGFnO1xuXG4gICAgICAgIGlmICghdGVzdHMubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5ub1Rlc3RzVG9SdW4pO1xuXG4gICAgICAgIGlmICh0aGlzLmZpbHRlcilcbiAgICAgICAgICAgIHRlc3RzID0gdGhpcy5fZmlsdGVyVGVzdHModGVzdHMsIHRoaXMuZmlsdGVyKTtcblxuICAgICAgICBpZiAoIXRlc3RzLmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMubm9UZXN0c1RvUnVuRHVlRmlsdGVyaW5nKTtcblxuICAgICAgICByZXR1cm4gdGVzdHM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZ2V0Q29tcGlsZXJBcmd1bWVudHMgKGN3ZDogc3RyaW5nKTogUHJvbWlzZTxDb21waWxlckFyZ3VtZW50cz4ge1xuICAgICAgICBjb25zdCBzb3VyY2VMaXN0ID0gYXdhaXQgcGFyc2VGaWxlTGlzdCh0aGlzLnNvdXJjZXMsIGN3ZCk7XG5cbiAgICAgICAgY29uc3QgY29tcGlsZXJPcHRpb25zID0ge1xuICAgICAgICAgICAgdHlwZVNjcmlwdE9wdGlvbnM6IHtcbiAgICAgICAgICAgICAgICB0c0NvbmZpZ1BhdGg6IHRoaXMudHNDb25maWdQYXRoXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHsgc291cmNlTGlzdCwgY29tcGlsZXJPcHRpb25zIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW5zdXJlT3V0U3RyZWFtIChvdXRTdHJlYW06IHN0cmluZyB8IFdyaXRhYmxlU3RyZWFtKTogUHJvbWlzZTxXcml0YWJsZVN0cmVhbT4ge1xuICAgICAgICBpZiAodHlwZW9mIG91dFN0cmVhbSAhPT0gJ3N0cmluZycpXG4gICAgICAgICAgICByZXR1cm4gb3V0U3RyZWFtO1xuXG4gICAgICAgIGNvbnN0IGZ1bGxSZXBvcnRlck91dHB1dFBhdGggPSByZXNvbHZlUGF0aFJlbGF0aXZlbHlDd2Qob3V0U3RyZWFtKTtcblxuICAgICAgICBhd2FpdCBtYWtlRGlyKHBhdGguZGlybmFtZShmdWxsUmVwb3J0ZXJPdXRwdXRQYXRoKSk7XG5cbiAgICAgICAgcmV0dXJuIGZzLmNyZWF0ZVdyaXRlU3RyZWFtKGZ1bGxSZXBvcnRlck91dHB1dFBhdGgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9hZGREZWZhdWx0UmVwb3J0ZXIgKHJlcG9ydGVyczogUmVwb3J0ZXJTb3VyY2VbXSk6IHZvaWQge1xuICAgICAgICByZXBvcnRlcnMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiAgICdzcGVjJyxcbiAgICAgICAgICAgIG91dHB1dDogcHJvY2Vzcy5zdGRvdXRcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfcmVxdWlyZVJlcG9ydGVyUGx1Z2luRmFjdG9yeSAocmVwb3J0ZXJOYW1lOiBzdHJpbmcpOiBSZXBvcnRlclBsdWdpbkZhY3Rvcnkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVpcmUoJ3Rlc3RjYWZlLXJlcG9ydGVyLScgKyByZXBvcnRlck5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RmluZFJlcG9ydGVyRm9yQWxpYXMsIHJlcG9ydGVyTmFtZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRQbHVnaW5GYWN0b3J5IChyZXBvcnRlckZhY3RvcnlTb3VyY2U6IHN0cmluZyB8IFJlcG9ydGVyUGx1Z2luRmFjdG9yeSk6IFJlcG9ydGVyUGx1Z2luRmFjdG9yeSB7XG4gICAgICAgIGlmICghaXNSZXBvcnRlclBsdWdpbkZhY3RvcnkocmVwb3J0ZXJGYWN0b3J5U291cmNlKSlcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9yZXF1aXJlUmVwb3J0ZXJQbHVnaW5GYWN0b3J5KHJlcG9ydGVyRmFjdG9yeVNvdXJjZSk7XG5cbiAgICAgICAgcmV0dXJuIHJlcG9ydGVyRmFjdG9yeVNvdXJjZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRSZXBvcnRlclBsdWdpbnMgKCk6IFByb21pc2U8UmVwb3J0ZXJQbHVnaW5Tb3VyY2VbXT4ge1xuICAgICAgICBpZiAoIXRoaXMucmVwb3J0ZXJzLmxlbmd0aClcbiAgICAgICAgICAgIEJvb3RzdHJhcHBlci5fYWRkRGVmYXVsdFJlcG9ydGVyKHRoaXMucmVwb3J0ZXJzKTtcblxuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwodGhpcy5yZXBvcnRlcnMubWFwKGFzeW5jICh7IG5hbWUsIG91dHB1dCB9KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBwbHVnaW5GYWN0b3J5ID0gdGhpcy5fZ2V0UGx1Z2luRmFjdG9yeShuYW1lKTtcbiAgICAgICAgICAgIGNvbnN0IG91dFN0cmVhbSAgICAgPSBvdXRwdXQgPyBhd2FpdCB0aGlzLl9lbnN1cmVPdXRTdHJlYW0ob3V0cHV0KSA6IHZvaWQgMDtcblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBwbHVnaW46IHBsdWdpbkZhY3RvcnkoKSxcbiAgICAgICAgICAgICAgICBvdXRTdHJlYW0sXG4gICAgICAgICAgICAgICAgbmFtZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX3N0YXJ0VGVzdGVkQXBwICgpOiBQcm9taXNlPFRlc3RlZEFwcHx1bmRlZmluZWQ+IHtcbiAgICAgICAgaWYgKCF0aGlzLmFwcENvbW1hbmQpXG4gICAgICAgICAgICByZXR1cm4gdm9pZCAwO1xuXG4gICAgICAgIGNvbnN0IHRlc3RlZEFwcCA9IG5ldyBUZXN0ZWRBcHAoKTtcblxuICAgICAgICBhd2FpdCB0ZXN0ZWRBcHAuc3RhcnQodGhpcy5hcHBDb21tYW5kLCB0aGlzLmFwcEluaXREZWxheSBhcyBudW1iZXIpO1xuXG4gICAgICAgIHJldHVybiB0ZXN0ZWRBcHA7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfY2FuVXNlUGFyYWxsZWxCb290c3RyYXBwaW5nIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgICAgICBjb25zdCBpc0xvY2FsUHJvbWlzZXMgPSBicm93c2VySW5mby5tYXAoYnJvd3NlciA9PiBicm93c2VyLnByb3ZpZGVyLmlzTG9jYWxCcm93c2VyKHZvaWQgMCwgQm9vdHN0cmFwcGVyLl9nZXRCcm93c2VyTmFtZShicm93c2VyKSkpO1xuICAgICAgICBjb25zdCBpc0xvY2FsQnJvd3NlcnMgPSBhd2FpdCBQcm9taXNlLmFsbChpc0xvY2FsUHJvbWlzZXMpO1xuXG4gICAgICAgIHJldHVybiBpc0xvY2FsQnJvd3NlcnMuZXZlcnkocmVzdWx0ID0+IHJlc3VsdCk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfYm9vdHN0cmFwU2VxdWVuY2UgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxCYXNpY1J1bnRpbWVSZXNvdXJjZXM+IHtcbiAgICAgICAgY29uc3QgdGVzdHMgICAgICAgPSBhd2FpdCB0aGlzLl9nZXRUZXN0cygpO1xuICAgICAgICBjb25zdCB0ZXN0ZWRBcHAgICA9IGF3YWl0IHRoaXMuX3N0YXJ0VGVzdGVkQXBwKCk7XG4gICAgICAgIGNvbnN0IGJyb3dzZXJTZXQgID0gYXdhaXQgdGhpcy5fZ2V0QnJvd3NlckNvbm5lY3Rpb25zKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICByZXR1cm4geyB0ZXN0cywgdGVzdGVkQXBwLCBicm93c2VyU2V0IH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfd3JhcEJvb3RzdHJhcHBpbmdQcm9taXNlPFQ+IChwcm9taXNlOiBQcm9taXNlPFQ+KTogUHJvbWlzZTxQcm9taXNlUmVzdWx0PFQ+PiB7XG4gICAgICAgIHJldHVybiBwcm9taXNlXG4gICAgICAgICAgICAudGhlbihyZXN1bHQgPT4gKHsgZXJyb3I6IHZvaWQgMCwgcmVzdWx0IH0pKVxuICAgICAgICAgICAgLmNhdGNoKGVycm9yID0+ICh7IHJlc3VsdDogdm9pZCAwLCBlcnJvciB9KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZ2V0Qm9vdHN0cmFwcGluZ0Vycm9yIChicm93c2VyU2V0U3RhdHVzOiBQcm9taXNlUmVzdWx0PEJyb3dzZXJTZXQ+LCB0ZXN0c1N0YXR1czogUHJvbWlzZVJlc3VsdDxUZXN0W10+LCB0ZXN0ZWRBcHBTdGF0dXM6IFByb21pc2VSZXN1bHQ8VGVzdGVkQXBwfHVuZGVmaW5lZD4pOiBQcm9taXNlPEVycm9yPiB7XG4gICAgICAgIGlmICghaXNQcm9taXNlRXJyb3IoYnJvd3NlclNldFN0YXR1cykpXG4gICAgICAgICAgICBhd2FpdCBicm93c2VyU2V0U3RhdHVzLnJlc3VsdC5kaXNwb3NlKCk7XG5cbiAgICAgICAgaWYgKCFpc1Byb21pc2VFcnJvcihicm93c2VyU2V0U3RhdHVzKSAmJiAhaXNQcm9taXNlRXJyb3IodGVzdGVkQXBwU3RhdHVzKSAmJiB0ZXN0ZWRBcHBTdGF0dXMucmVzdWx0KVxuICAgICAgICAgICAgYXdhaXQgdGVzdGVkQXBwU3RhdHVzLnJlc3VsdC5raWxsKCk7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKHRlc3RzU3RhdHVzKSlcbiAgICAgICAgICAgIHJldHVybiB0ZXN0c1N0YXR1cy5lcnJvcjtcblxuICAgICAgICBpZiAoaXNQcm9taXNlRXJyb3IodGVzdGVkQXBwU3RhdHVzKSlcbiAgICAgICAgICAgIHJldHVybiB0ZXN0ZWRBcHBTdGF0dXMuZXJyb3I7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKGJyb3dzZXJTZXRTdGF0dXMpKVxuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXJTZXRTdGF0dXMuZXJyb3I7XG5cbiAgICAgICAgcmV0dXJuIG5ldyBFcnJvcignVW5leHBlY3RlZCBjYWxsJyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfZ2V0Qm9vdHN0cmFwcGluZ1Byb21pc2VzPFQ+IChhcmc6IFByb21pc2VDb2xsZWN0aW9uPFQ+KTogUHJvbWlzZUNvbGxlY3Rpb248UmVzdWx0Q29sbGVjdGlvbjxUPj4ge1xuICAgICAgICBjb25zdCByZXN1bHQgPSB7fSBhcyB1bmtub3duIGFzIFByb21pc2VDb2xsZWN0aW9uPFJlc3VsdENvbGxlY3Rpb248VD4+O1xuXG4gICAgICAgIGZvciAoY29uc3QgayBpbiBhcmcpXG4gICAgICAgICAgICByZXN1bHRba10gPSB0aGlzLl93cmFwQm9vdHN0cmFwcGluZ1Byb21pc2UoYXJnW2tdKTtcblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Jvb3RzdHJhcFBhcmFsbGVsIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8QmFzaWNSdW50aW1lUmVzb3VyY2VzPiB7XG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdQcm9taXNlcyA9IHtcbiAgICAgICAgICAgIGJyb3dzZXJTZXQ6IHRoaXMuX2dldEJyb3dzZXJDb25uZWN0aW9ucyhicm93c2VySW5mbyksXG4gICAgICAgICAgICB0ZXN0czogICAgICB0aGlzLl9nZXRUZXN0cygpLFxuICAgICAgICAgICAgYXBwOiAgICAgICAgdGhpcy5fc3RhcnRUZXN0ZWRBcHAoKVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdSZXN1bHRQcm9taXNlcyA9IHRoaXMuX2dldEJvb3RzdHJhcHBpbmdQcm9taXNlcyhib290c3RyYXBwaW5nUHJvbWlzZXMpO1xuXG4gICAgICAgIGNvbnN0IGJvb3RzdHJhcHBpbmdSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgYm9vdHN0cmFwcGluZ1Jlc3VsdFByb21pc2VzLmJyb3dzZXJTZXQsXG4gICAgICAgICAgICBib290c3RyYXBwaW5nUmVzdWx0UHJvbWlzZXMudGVzdHMsXG4gICAgICAgICAgICBib290c3RyYXBwaW5nUmVzdWx0UHJvbWlzZXMuYXBwXG4gICAgICAgIF0pO1xuXG4gICAgICAgIGNvbnN0IFticm93c2VyU2V0UmVzdWx0cywgdGVzdFJlc3VsdHMsIGFwcFJlc3VsdHNdID0gYm9vdHN0cmFwcGluZ1Jlc3VsdHM7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKGJyb3dzZXJTZXRSZXN1bHRzKSB8fCBpc1Byb21pc2VFcnJvcih0ZXN0UmVzdWx0cykgfHwgaXNQcm9taXNlRXJyb3IoYXBwUmVzdWx0cykpXG4gICAgICAgICAgICB0aHJvdyBhd2FpdCB0aGlzLl9nZXRCb290c3RyYXBwaW5nRXJyb3IoLi4uYm9vdHN0cmFwcGluZ1Jlc3VsdHMpO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBicm93c2VyU2V0OiBicm93c2VyU2V0UmVzdWx0cy5yZXN1bHQsXG4gICAgICAgICAgICB0ZXN0czogICAgICB0ZXN0UmVzdWx0cy5yZXN1bHQsXG4gICAgICAgICAgICB0ZXN0ZWRBcHA6ICBhcHBSZXN1bHRzLnJlc3VsdFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIEFQSVxuICAgIHB1YmxpYyBhc3luYyBjcmVhdGVSdW5uYWJsZUNvbmZpZ3VyYXRpb24gKCk6IFByb21pc2U8UnVudGltZVJlc291cmNlcz4ge1xuICAgICAgICBjb25zdCByZXBvcnRlclBsdWdpbnMgICAgID0gYXdhaXQgdGhpcy5fZ2V0UmVwb3J0ZXJQbHVnaW5zKCk7XG4gICAgICAgIGNvbnN0IGNvbW1vbkNsaWVudFNjcmlwdHMgPSBhd2FpdCBsb2FkQ2xpZW50U2NyaXB0cyh0aGlzLmNsaWVudFNjcmlwdHMpO1xuXG4gICAgICAgIC8vIE5PVEU6IElmIGEgdXNlciBmb3Jnb3QgdG8gc3BlY2lmeSBhIGJyb3dzZXIsIGJ1dCBoYXMgc3BlY2lmaWVkIGEgcGF0aCB0byB0ZXN0cywgdGhlIHNwZWNpZmllZCBwYXRoIHdpbGwgYmVcbiAgICAgICAgLy8gY29uc2lkZXJlZCBhcyB0aGUgYnJvd3NlciBhcmd1bWVudCwgYW5kIHRoZSB0ZXN0cyBwYXRoIGFyZ3VtZW50IHdpbGwgaGF2ZSB0aGUgcHJlZGVmaW5lZCBkZWZhdWx0IHZhbHVlLlxuICAgICAgICAvLyBJdCdzIHZlcnkgYW1iaWd1b3VzIGZvciB0aGUgdXNlciwgd2hvIG1pZ2h0IGJlIGNvbmZ1c2VkIGJ5IGNvbXBpbGF0aW9uIGVycm9ycyBmcm9tIGFuIHVuZXhwZWN0ZWQgdGVzdC5cbiAgICAgICAgLy8gU28sIHdlIG5lZWQgdG8gcmV0cmlldmUgdGhlIGJyb3dzZXIgYWxpYXNlcyBhbmQgcGF0aHMgYmVmb3JlIHRlc3RzIGNvbXBpbGF0aW9uLlxuICAgICAgICBjb25zdCBicm93c2VySW5mbyA9IGF3YWl0IHRoaXMuX2dldEJyb3dzZXJJbmZvKCk7XG5cbiAgICAgICAgaWYgKE9TLm1hYylcbiAgICAgICAgICAgIGF3YWl0IEJvb3RzdHJhcHBlci5fY2hlY2tSZXF1aXJlZFBlcm1pc3Npb25zKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICBpZiAoYXdhaXQgdGhpcy5fY2FuVXNlUGFyYWxsZWxCb290c3RyYXBwaW5nKGJyb3dzZXJJbmZvKSlcbiAgICAgICAgICAgIHJldHVybiB7IHJlcG9ydGVyUGx1Z2lucywgLi4uYXdhaXQgdGhpcy5fYm9vdHN0cmFwUGFyYWxsZWwoYnJvd3NlckluZm8pLCBjb21tb25DbGllbnRTY3JpcHRzIH07XG5cbiAgICAgICAgcmV0dXJuIHsgcmVwb3J0ZXJQbHVnaW5zLCAuLi5hd2FpdCB0aGlzLl9ib290c3RyYXBTZXF1ZW5jZShicm93c2VySW5mbyksIGNvbW1vbkNsaWVudFNjcmlwdHMgfTtcbiAgICB9XG59XG4iXX0=