testcafe
Version:
Automated browser testing for the modern web development stack.
341 lines • 56.2 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 = require("path");
const debug_1 = __importDefault(require("debug"));
const pinkie_1 = __importDefault(require("pinkie"));
const promisify_event_1 = __importDefault(require("promisify-event"));
const map_reverse_1 = __importDefault(require("map-reverse"));
const events_1 = require("events");
const lodash_1 = require("lodash");
const bootstrapper_1 = __importDefault(require("./bootstrapper"));
const reporter_1 = __importDefault(require("../reporter"));
const task_1 = __importDefault(require("./task"));
const runtime_1 = require("../errors/runtime");
const types_1 = require("../errors/types");
const type_assertions_1 = require("../errors/runtime/type-assertions");
const utils_1 = require("../errors/test-run/utils");
const detect_ffmpeg_1 = __importDefault(require("../utils/detect-ffmpeg"));
const check_file_path_1 = __importDefault(require("../utils/check-file-path"));
const handle_errors_1 = require("../utils/handle-errors");
const option_names_1 = __importDefault(require("../configuration/option-names"));
const flag_list_1 = __importDefault(require("../utils/flag-list"));
const prepare_reporters_1 = __importDefault(require("../utils/prepare-reporters"));
const DEBUG_LOGGER = debug_1.default('testcafe:runner');
class Runner extends events_1.EventEmitter {
constructor(proxy, browserConnectionGateway, configuration) {
super();
this.proxy = proxy;
this.bootstrapper = this._createBootstrapper(browserConnectionGateway);
this.pendingTaskPromises = [];
this.configuration = configuration;
this.tsConfiguration = null;
this.isCli = false;
// NOTE: This code is necessary only for displaying marketing messages.
this.reporterPlugings = [];
this.apiMethodWasCalled = new flag_list_1.default({
initialFlagValue: false,
flags: [option_names_1.default.src, option_names_1.default.browsers, option_names_1.default.reporter]
});
}
_createBootstrapper(browserConnectionGateway) {
return new bootstrapper_1.default(browserConnectionGateway);
}
_disposeBrowserSet(browserSet) {
return browserSet.dispose().catch(e => DEBUG_LOGGER(e));
}
_disposeReporters(reporters) {
return pinkie_1.default.all(reporters.map(reporter => reporter.dispose().catch(e => DEBUG_LOGGER(e))));
}
_disposeTestedApp(testedApp) {
return testedApp ? testedApp.kill().catch(e => DEBUG_LOGGER(e)) : pinkie_1.default.resolve();
}
async _disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp) {
task.abort();
task.clearListeners();
await this._disposeAssets(browserSet, reporters, testedApp);
}
_disposeAssets(browserSet, reporters, testedApp) {
return pinkie_1.default.all([
this._disposeBrowserSet(browserSet),
this._disposeReporters(reporters),
this._disposeTestedApp(testedApp)
]);
}
_prepareArrayParameter(array) {
array = lodash_1.flattenDeep(array);
if (this.isCli)
return array.length === 0 ? void 0 : array;
return array;
}
_createCancelablePromise(taskPromise) {
const promise = taskPromise.then(({ completionPromise }) => completionPromise);
const removeFromPending = () => lodash_1.pull(this.pendingTaskPromises, promise);
promise
.then(removeFromPending)
.catch(removeFromPending);
promise.cancel = () => taskPromise
.then(({ cancelTask }) => cancelTask())
.then(removeFromPending);
this.pendingTaskPromises.push(promise);
return promise;
}
// Run task
_getFailedTestCount(task, reporter) {
let failedTestCount = reporter.testCount - reporter.passed;
if (task.opts.stopOnFirstFail && !!failedTestCount)
failedTestCount = 1;
return failedTestCount;
}
async _getTaskResult(task, browserSet, reporters, testedApp) {
task.on('browser-job-done', job => browserSet.releaseConnection(job.browserConnection));
const browserSetErrorPromise = promisify_event_1.default(browserSet, 'error');
const taskDonePromise = task.once('done')
.then(() => browserSetErrorPromise.cancel())
.then(() => {
return pinkie_1.default.all(reporters.map(reporter => reporter.pendingTaskDonePromise));
});
const promises = [
taskDonePromise,
browserSetErrorPromise
];
if (testedApp)
promises.push(testedApp.errorPromise);
try {
await pinkie_1.default.race(promises);
}
catch (err) {
await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp);
throw err;
}
await this._disposeAssets(browserSet, reporters, testedApp);
return this._getFailedTestCount(task, reporters[0]);
}
_createTask(tests, browserConnectionGroups, proxy, opts) {
return new task_1.default(tests, browserConnectionGroups, proxy, opts);
}
_runTask(reporterPlugins, browserSet, tests, testedApp) {
let completed = false;
const task = this._createTask(tests, browserSet.browserConnectionGroups, this.proxy, this.configuration.getOptions());
const reporters = reporterPlugins.map(reporter => new reporter_1.default(reporter.plugin, task, reporter.outStream));
const completionPromise = this._getTaskResult(task, browserSet, reporters, testedApp);
task.on('start', handle_errors_1.startHandlingTestErrors);
if (!this.configuration.getOption(option_names_1.default.skipUncaughtErrors)) {
task.on('test-run-start', handle_errors_1.addRunningTest);
task.on('test-run-done', handle_errors_1.removeRunningTest);
}
task.on('done', handle_errors_1.stopHandlingTestErrors);
const setCompleted = () => {
completed = true;
};
completionPromise
.then(setCompleted)
.catch(setCompleted);
const cancelTask = async () => {
if (!completed)
await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp);
};
return { completionPromise, cancelTask };
}
_registerAssets(assets) {
assets.forEach(asset => this.proxy.GET(asset.path, asset.info));
}
_validateSpeedOption() {
const speed = this.configuration.getOption(option_names_1.default.speed);
if (speed === void 0)
return;
if (typeof speed !== 'number' || isNaN(speed) || speed < 0.01 || speed > 1)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidSpeedValue);
}
_validateConcurrencyOption() {
const concurrency = this.configuration.getOption(option_names_1.default.concurrency);
if (concurrency === void 0)
return;
if (typeof concurrency !== 'number' || isNaN(concurrency) || concurrency < 1)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidConcurrencyFactor);
}
_validateProxyBypassOption() {
let proxyBypass = this.configuration.getOption(option_names_1.default.proxyBypass);
if (proxyBypass === void 0)
return;
type_assertions_1.assertType([type_assertions_1.is.string, type_assertions_1.is.array], null, '"proxyBypass" argument', proxyBypass);
if (typeof proxyBypass === 'string')
proxyBypass = [proxyBypass];
proxyBypass = proxyBypass.reduce((arr, rules) => {
type_assertions_1.assertType(type_assertions_1.is.string, null, '"proxyBypass" argument', rules);
return arr.concat(rules.split(','));
}, []);
this.configuration.mergeOptions({ proxyBypass });
}
_validateScreenshotOptions() {
const screenshotPath = this.configuration.getOption(option_names_1.default.screenshotPath);
const screenshotPathPattern = this.configuration.getOption(option_names_1.default.screenshotPathPattern);
if (screenshotPath) {
this._validateScreenshotPath(screenshotPath, 'screenshots base directory path');
this.configuration.mergeOptions({ [option_names_1.default.screenshotPath]: path_1.resolve(screenshotPath) });
}
if (screenshotPathPattern)
this._validateScreenshotPath(screenshotPathPattern, 'screenshots path pattern');
if (!screenshotPath && screenshotPathPattern)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotUseScreenshotPathPatternWithoutBaseScreenshotPathSpecified);
}
async _validateVideoOptions() {
const videoPath = this.configuration.getOption(option_names_1.default.videoPath);
const videoEncodingOptions = this.configuration.getOption(option_names_1.default.videoEncodingOptions);
let videoOptions = this.configuration.getOption(option_names_1.default.videoOptions);
if (!videoPath) {
if (videoOptions || videoEncodingOptions)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotSetVideoOptionsWithoutBaseVideoPathSpecified);
return;
}
this.configuration.mergeOptions({ [option_names_1.default.videoPath]: path_1.resolve(videoPath) });
if (!videoOptions) {
videoOptions = {};
this.configuration.mergeOptions({ [option_names_1.default.videoOptions]: videoOptions });
}
if (videoOptions.ffmpegPath)
videoOptions.ffmpegPath = path_1.resolve(videoOptions.ffmpegPath);
else
videoOptions.ffmpegPath = await detect_ffmpeg_1.default();
if (!videoOptions.ffmpegPath)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindFFMPEG);
}
async _validateRunOptions() {
this._validateScreenshotOptions();
await this._validateVideoOptions();
this._validateSpeedOption();
this._validateConcurrencyOption();
this._validateProxyBypassOption();
}
_createRunnableConfiguration() {
return this.bootstrapper
.createRunnableConfiguration()
.then(runnableConfiguration => {
this.emit('done-bootstrapping');
return runnableConfiguration;
});
}
_validateScreenshotPath(screenshotPath, pathType) {
const forbiddenCharsList = check_file_path_1.default(screenshotPath);
if (forbiddenCharsList.length)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.forbiddenCharatersInScreenshotPath, screenshotPath, pathType, utils_1.renderForbiddenCharsList(forbiddenCharsList));
}
_setBootstrapperOptions() {
this.configuration.prepare();
this.configuration.notifyAboutOverridenOptions();
this.bootstrapper.sources = this.configuration.getOption(option_names_1.default.src) || this.bootstrapper.sources;
this.bootstrapper.browsers = this.configuration.getOption(option_names_1.default.browsers) || this.bootstrapper.browsers;
this.bootstrapper.concurrency = this.configuration.getOption(option_names_1.default.concurrency);
this.bootstrapper.appCommand = this.configuration.getOption(option_names_1.default.appCommand) || this.bootstrapper.appCommand;
this.bootstrapper.appInitDelay = this.configuration.getOption(option_names_1.default.appInitDelay);
this.bootstrapper.filter = this.configuration.getOption(option_names_1.default.filter) || this.bootstrapper.filter;
this.bootstrapper.reporters = this.configuration.getOption(option_names_1.default.reporter) || this.bootstrapper.reporters;
this.bootstrapper.tsConfigPath = this.configuration.getOption(option_names_1.default.tsConfigPath);
}
// API
embeddingOptions(opts) {
const { assets, TestRunCtor } = opts;
this._registerAssets(assets);
this.configuration.mergeOptions({ TestRunCtor });
return this;
}
src(...sources) {
if (this.apiMethodWasCalled.src)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.src);
sources = this._prepareArrayParameter(sources);
this.configuration.mergeOptions({ [option_names_1.default.src]: sources });
this.apiMethodWasCalled.src = true;
return this;
}
browsers(...browsers) {
if (this.apiMethodWasCalled.browsers)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.browsers);
browsers = this._prepareArrayParameter(browsers);
this.configuration.mergeOptions({ browsers });
this.apiMethodWasCalled.browsers = true;
return this;
}
concurrency(concurrency) {
this.configuration.mergeOptions({ concurrency });
return this;
}
reporter(name, output) {
if (this.apiMethodWasCalled.reporter)
throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.reporter);
let reporters = prepare_reporters_1.default(name, output);
reporters = this._prepareArrayParameter(reporters);
this.configuration.mergeOptions({ [option_names_1.default.reporter]: reporters });
this.apiMethodWasCalled.reporter = true;
return this;
}
filter(filter) {
this.configuration.mergeOptions({ filter });
return this;
}
useProxy(proxy, proxyBypass) {
this.configuration.mergeOptions({ proxy, proxyBypass });
return this;
}
screenshots(path, takeOnFails, pattern) {
this.configuration.mergeOptions({
[option_names_1.default.screenshotPath]: path,
[option_names_1.default.takeScreenshotsOnFails]: takeOnFails,
[option_names_1.default.screenshotPathPattern]: pattern
});
return this;
}
video(path, options, encodingOptions) {
this.configuration.mergeOptions({
[option_names_1.default.videoPath]: path,
[option_names_1.default.videoOptions]: options,
[option_names_1.default.videoEncodingOptions]: encodingOptions
});
return this;
}
startApp(command, initDelay) {
this.configuration.mergeOptions({
[option_names_1.default.appCommand]: command,
[option_names_1.default.appInitDelay]: initDelay
});
return this;
}
run(options = {}) {
this.apiMethodWasCalled.reset();
const { skipJsErrors, disablePageReloads, quarantineMode, debugMode, selectorTimeout, assertionTimeout, pageLoadTimeout, speed, debugOnFail, skipUncaughtErrors, stopOnFirstFail } = options;
this.configuration.mergeOptions({
skipJsErrors: skipJsErrors,
disablePageReloads: disablePageReloads,
quarantineMode: quarantineMode,
debugMode: debugMode,
debugOnFail: debugOnFail,
selectorTimeout: selectorTimeout,
assertionTimeout: assertionTimeout,
pageLoadTimeout: pageLoadTimeout,
speed: speed,
skipUncaughtErrors: skipUncaughtErrors,
stopOnFirstFail: stopOnFirstFail
});
this._setBootstrapperOptions();
const runTaskPromise = pinkie_1.default.resolve()
.then(() => this._validateRunOptions())
.then(() => this._createRunnableConfiguration())
.then(({ reporterPlugins, browserSet, tests, testedApp }) => {
this.reporterPlugings = reporterPlugins;
return this._runTask(reporterPlugins, browserSet, tests, testedApp);
});
return this._createCancelablePromise(runTaskPromise);
}
async stop() {
// NOTE: When taskPromise is cancelled, it is removed from
// the pendingTaskPromises array, which leads to shifting indexes
// towards the beginning. So, we must copy the array in order to iterate it,
// or we can perform iteration from the end to the beginning.
const cancellationPromises = map_reverse_1.default(this.pendingTaskPromises, taskPromise => taskPromise.cancel());
await pinkie_1.default.all(cancellationPromises);
}
}
exports.default = Runner;
module.exports = exports.default;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmVyL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsK0JBQThDO0FBQzlDLGtEQUEwQjtBQUMxQixvREFBNkI7QUFDN0Isc0VBQTZDO0FBQzdDLDhEQUFxQztBQUNyQyxtQ0FBc0M7QUFDdEMsbUNBQWdFO0FBQ2hFLGtFQUEwQztBQUMxQywyREFBbUM7QUFDbkMsa0RBQTBCO0FBQzFCLCtDQUFpRDtBQUNqRCwyQ0FBaUQ7QUFDakQsdUVBQW1FO0FBQ25FLG9EQUFvRTtBQUNwRSwyRUFBa0Q7QUFDbEQsK0VBQXFEO0FBQ3JELDBEQUE0SDtBQUM1SCxpRkFBeUQ7QUFDekQsbUVBQTBDO0FBQzFDLG1GQUEwRDtBQUUxRCxNQUFNLFlBQVksR0FBRyxlQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUU5QyxNQUFxQixNQUFPLFNBQVEscUJBQVk7SUFDNUMsWUFBYSxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsYUFBYTtRQUN2RCxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxLQUFLLEdBQWlCLEtBQUssQ0FBQztRQUNqQyxJQUFJLENBQUMsWUFBWSxHQUFVLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQzlFLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLGFBQWEsR0FBUyxhQUFhLENBQUM7UUFDekMsSUFBSSxDQUFDLGVBQWUsR0FBTyxJQUFJLENBQUM7UUFDaEMsSUFBSSxDQUFDLEtBQUssR0FBaUIsS0FBSyxDQUFDO1FBRWpDLHdFQUF3RTtRQUN4RSxJQUFJLENBQUMsZ0JBQWdCLEdBQUcsRUFBRSxDQUFDO1FBRTNCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLG1CQUFRLENBQUM7WUFDbkMsZ0JBQWdCLEVBQUUsS0FBSztZQUN2QixLQUFLLEVBQWEsQ0FBQyxzQkFB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Q3hELElBQUksQ0FBQyxnQkFBZ0IsR0FBRyxlQUFlLENBQUM7WUFFeEMsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3hFLENBQUMsQ0FBQyxDQUFDO1FBRVAsT0FBTyxJQUFJLENBQUMsd0JBQXdCLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ04sMERBQTBEO1FBQzFELGlFQUFpRTtRQUNqRSw0RUFBNEU7UUFDNUUsNkRBQTZEO1FBQzdELE1BQU0sb0JBQW9CLEdBQUcscUJBQVUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUV2RyxNQUFNLGdCQUFPLENBQUMsR0FBRyxDQUFDLG9CQUFvQixDQUFDLENBQUM7SUFDNUMsQ0FBQztDQUNKO0FBbmJELHlCQW1iQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJlc29sdmUgYXMgcmVzb2x2ZVBhdGggfSBmcm9tICdwYXRoJztcbmltcG9ydCBkZWJ1ZyBmcm9tICdkZWJ1Zyc7XG5pbXBvcnQgUHJvbWlzZSBmcm9tICdwaW5raWUnO1xuaW1wb3J0IHByb21pc2lmeUV2ZW50IGZyb20gJ3Byb21pc2lmeS1ldmVudCc7XG5pbXBvcnQgbWFwUmV2ZXJzZSBmcm9tICdtYXAtcmV2ZXJzZSc7XG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdldmVudHMnO1xuaW1wb3J0IHsgZmxhdHRlbkRlZXAgYXMgZmxhdHRlbiwgcHVsbCBhcyByZW1vdmUgfSBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IEJvb3RzdHJhcHBlciBmcm9tICcuL2Jvb3RzdHJhcHBlcic7XG5pbXBvcnQgUmVwb3J0ZXIgZnJvbSAnLi4vcmVwb3J0ZXInO1xuaW1wb3J0IFRhc2sgZnJvbSAnLi90YXNrJztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCB7IGFzc2VydFR5cGUsIGlzIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUvdHlwZS1hc3NlcnRpb25zJztcbmltcG9ydCB7IHJlbmRlckZvcmJpZGRlbkNoYXJzTGlzdCB9IGZyb20gJy4uL2Vycm9ycy90ZXN0LXJ1bi91dGlscyc7XG5pbXBvcnQgZGV0ZWN0RkZNUEVHIGZyb20gJy4uL3V0aWxzL2RldGVjdC1mZm1wZWcnO1xuaW1wb3J0IGNoZWNrRmlsZVBhdGggZnJvbSAnLi4vdXRpbHMvY2hlY2stZmlsZS1wYXRoJztcbmltcG9ydCB7IGFkZFJ1bm5pbmdUZXN0LCByZW1vdmVSdW5uaW5nVGVzdCwgc3RhcnRIYW5kbGluZ1Rlc3RFcnJvcnMsIHN0b3BIYW5kbGluZ1Rlc3RFcnJvcnMgfSBmcm9tICcuLi91dGlscy9oYW5kbGUtZXJyb3JzJztcbmltcG9ydCBPUFRJT05fTkFNRVMgZnJvbSAnLi4vY29uZmlndXJhdGlvbi9vcHRpb24tbmFtZXMnO1xuaW1wb3J0IEZsYWdMaXN0IGZyb20gJy4uL3V0aWxzL2ZsYWctbGlzdCc7XG5pbXBvcnQgcHJlcGFyZVJlcG9ydGVycyBmcm9tICcuLi91dGlscy9wcmVwYXJlLXJlcG9ydGVycyc7XG5cbmNvbnN0IERFQlVHX0xPR0dFUiA9IGRlYnVnKCd0ZXN0Y2FmZTpydW5uZXInKTtcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgUnVubmVyIGV4dGVuZHMgRXZlbnRFbWl0dGVyIHtcbiAgICBjb25zdHJ1Y3RvciAocHJveHksIGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSwgY29uZmlndXJhdGlvbikge1xuICAgICAgICBzdXBlcigpO1xuXG4gICAgICAgIHRoaXMucHJveHkgICAgICAgICAgICAgICA9IHByb3h5O1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlciAgICAgICAgPSB0aGlzLl9jcmVhdGVCb290c3RyYXBwZXIoYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5KTtcbiAgICAgICAgdGhpcy5wZW5kaW5nVGFza1Byb21pc2VzID0gW107XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbiAgICAgICA9IGNvbmZpZ3VyYXRpb247XG4gICAgICAgIHRoaXMudHNDb25maWd1cmF0aW9uICAgICA9IG51bGw7XG4gICAgICAgIHRoaXMuaXNDbGkgICAgICAgICAgICAgICA9IGZhbHNlO1xuXG4gICAgICAgIC8vIE5PVEU6IFRoaXMgY29kZSBpcyBuZWNlc3Nhcnkgb25seSBmb3IgZGlzcGxheWluZyAgbWFya2V0aW5nIG1lc3NhZ2VzLlxuICAgICAgICB0aGlzLnJlcG9ydGVyUGx1Z2luZ3MgPSBbXTtcblxuICAgICAgICB0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZCA9IG5ldyBGbGFnTGlzdCh7XG4gICAgICAgICAgICBpbml0aWFsRmxhZ1ZhbHVlOiBmYWxzZSxcbiAgICAgICAgICAgIGZsYWdzOiAgICAgICAgICAgIFtPUFRJT05fTkFNRVMuc3JjLCBPUFRJT05fTkFNRVMuYnJvd3NlcnMsIE9QVElPTl9OQU1FUy5yZXBvcnRlcl1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZUJvb3RzdHJhcHBlciAoYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5KSB7XG4gICAgICAgIHJldHVybiBuZXcgQm9vdHN0cmFwcGVyKGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VCcm93c2VyU2V0IChicm93c2VyU2V0KSB7XG4gICAgICAgIHJldHVybiBicm93c2VyU2V0LmRpc3Bvc2UoKS5jYXRjaChlID0+IERFQlVHX0xPR0dFUihlKSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VSZXBvcnRlcnMgKHJlcG9ydGVycykge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwocmVwb3J0ZXJzLm1hcChyZXBvcnRlciA9PiByZXBvcnRlci5kaXNwb3NlKCkuY2F0Y2goZSA9PiBERUJVR19MT0dHRVIoZSkpKSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VUZXN0ZWRBcHAgKHRlc3RlZEFwcCkge1xuICAgICAgICByZXR1cm4gdGVzdGVkQXBwID8gdGVzdGVkQXBwLmtpbGwoKS5jYXRjaChlID0+IERFQlVHX0xPR0dFUihlKSkgOiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZGlzcG9zZVRhc2tBbmRSZWxhdGVkQXNzZXRzICh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCkge1xuICAgICAgICB0YXNrLmFib3J0KCk7XG4gICAgICAgIHRhc2suY2xlYXJMaXN0ZW5lcnMoKTtcblxuICAgICAgICBhd2FpdCB0aGlzLl9kaXNwb3NlQXNzZXRzKGJyb3dzZXJTZXQsIHJlcG9ydGVycywgdGVzdGVkQXBwKTtcbiAgICB9XG5cbiAgICBfZGlzcG9zZUFzc2V0cyAoYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIHRoaXMuX2Rpc3Bvc2VCcm93c2VyU2V0KGJyb3dzZXJTZXQpLFxuICAgICAgICAgICAgdGhpcy5fZGlzcG9zZVJlcG9ydGVycyhyZXBvcnRlcnMpLFxuICAgICAgICAgICAgdGhpcy5fZGlzcG9zZVRlc3RlZEFwcCh0ZXN0ZWRBcHApXG4gICAgICAgIF0pO1xuICAgIH1cblxuICAgIF9wcmVwYXJlQXJyYXlQYXJhbWV0ZXIgKGFycmF5KSB7XG4gICAgICAgIGFycmF5ID0gZmxhdHRlbihhcnJheSk7XG5cbiAgICAgICAgaWYgKHRoaXMuaXNDbGkpXG4gICAgICAgICAgICByZXR1cm4gYXJyYXkubGVuZ3RoID09PSAwID8gdm9pZCAwIDogYXJyYXk7XG5cbiAgICAgICAgcmV0dXJuIGFycmF5O1xuICAgIH1cblxuICAgIF9jcmVhdGVDYW5jZWxhYmxlUHJvbWlzZSAodGFza1Byb21pc2UpIHtcbiAgICAgICAgY29uc3QgcHJvbWlzZSAgICAgICAgICAgPSB0YXNrUHJvbWlzZS50aGVuKCh7IGNvbXBsZXRpb25Qcm9taXNlIH0pID0+IGNvbXBsZXRpb25Qcm9taXNlKTtcbiAgICAgICAgY29uc3QgcmVtb3ZlRnJvbVBlbmRpbmcgPSAoKSA9PiByZW1vdmUodGhpcy5wZW5kaW5nVGFza1Byb21pc2VzLCBwcm9taXNlKTtcblxuICAgICAgICBwcm9taXNlXG4gICAgICAgICAgICAudGhlbihyZW1vdmVGcm9tUGVuZGluZylcbiAgICAgICAgICAgIC5jYXRjaChyZW1vdmVGcm9tUGVuZGluZyk7XG5cbiAgICAgICAgcHJvbWlzZS5jYW5jZWwgPSAoKSA9PiB0YXNrUHJvbWlzZVxuICAgICAgICAgICAgLnRoZW4oKHsgY2FuY2VsVGFzayB9KSA9PiBjYW5jZWxUYXNrKCkpXG4gICAgICAgICAgICAudGhlbihyZW1vdmVGcm9tUGVuZGluZyk7XG5cbiAgICAgICAgdGhpcy5wZW5kaW5nVGFza1Byb21pc2VzLnB1c2gocHJvbWlzZSk7XG4gICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgIH1cblxuICAgIC8vIFJ1biB0YXNrXG4gICAgX2dldEZhaWxlZFRlc3RDb3VudCAodGFzaywgcmVwb3J0ZXIpIHtcbiAgICAgICAgbGV0IGZhaWxlZFRlc3RDb3VudCA9IHJlcG9ydGVyLnRlc3RDb3VudCAtIHJlcG9ydGVyLnBhc3NlZDtcblxuICAgICAgICBpZiAodGFzay5vcHRzLnN0b3BPbkZpcnN0RmFpbCAmJiAhIWZhaWxlZFRlc3RDb3VudClcbiAgICAgICAgICAgIGZhaWxlZFRlc3RDb3VudCA9IDE7XG5cbiAgICAgICAgcmV0dXJuIGZhaWxlZFRlc3RDb3VudDtcbiAgICB9XG5cbiAgICBhc3luYyBfZ2V0VGFza1Jlc3VsdCAodGFzaywgYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApIHtcbiAgICAgICAgdGFzay5vbignYnJvd3Nlci1qb2ItZG9uZScsIGpvYiA9PiBicm93c2VyU2V0LnJlbGVhc2VDb25uZWN0aW9uKGpvYi5icm93c2VyQ29ubmVjdGlvbikpO1xuXG4gICAgICAgIGNvbnN0IGJyb3dzZXJTZXRFcnJvclByb21pc2UgPSBwcm9taXNpZnlFdmVudChicm93c2VyU2V0LCAnZXJyb3InKTtcblxuICAgICAgICBjb25zdCB0YXNrRG9uZVByb21pc2UgPSB0YXNrLm9uY2UoJ2RvbmUnKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gYnJvd3NlclNldEVycm9yUHJvbWlzZS5jYW5jZWwoKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwocmVwb3J0ZXJzLm1hcChyZXBvcnRlciA9PiByZXBvcnRlci5wZW5kaW5nVGFza0RvbmVQcm9taXNlKSk7XG4gICAgICAgICAgICB9KTtcblxuXG4gICAgICAgIGNvbnN0IHByb21pc2VzID0gW1xuICAgICAgICAgICAgdGFza0RvbmVQcm9taXNlLFxuICAgICAgICAgICAgYnJvd3NlclNldEVycm9yUHJvbWlzZVxuICAgICAgICBdO1xuXG4gICAgICAgIGlmICh0ZXN0ZWRBcHApXG4gICAgICAgICAgICBwcm9taXNlcy5wdXNoKHRlc3RlZEFwcC5lcnJvclByb21pc2UpO1xuXG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBQcm9taXNlLnJhY2UocHJvbWlzZXMpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMuX2Rpc3Bvc2VUYXNrQW5kUmVsYXRlZEFzc2V0cyh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCk7XG5cbiAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfVxuXG4gICAgICAgIGF3YWl0IHRoaXMuX2Rpc3Bvc2VBc3NldHMoYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9nZXRGYWlsZWRUZXN0Q291bnQodGFzaywgcmVwb3J0ZXJzWzBdKTtcbiAgICB9XG5cbiAgICBfY3JlYXRlVGFzayAodGVzdHMsIGJyb3dzZXJDb25uZWN0aW9uR3JvdXBzLCBwcm94eSwgb3B0cykge1xuICAgICAgICByZXR1cm4gbmV3IFRhc2sodGVzdHMsIGJyb3dzZXJDb25uZWN0aW9uR3JvdXBzLCBwcm94eSwgb3B0cyk7XG4gICAgfVxuXG4gICAgX3J1blRhc2sgKHJlcG9ydGVyUGx1Z2lucywgYnJvd3NlclNldCwgdGVzdHMsIHRlc3RlZEFwcCkge1xuICAgICAgICBsZXQgY29tcGxldGVkICAgICAgICAgICA9IGZhbHNlO1xuICAgICAgICBjb25zdCB0YXNrICAgICAgICAgICAgICA9IHRoaXMuX2NyZWF0ZVRhc2sodGVzdHMsIGJyb3dzZXJTZXQuYnJvd3NlckNvbm5lY3Rpb25Hcm91cHMsIHRoaXMucHJveHksIHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb25zKCkpO1xuICAgICAgICBjb25zdCByZXBvcnRlcnMgICAgICAgICA9IHJlcG9ydGVyUGx1Z2lucy5tYXAocmVwb3J0ZXIgPT4gbmV3IFJlcG9ydGVyKHJlcG9ydGVyLnBsdWdpbiwgdGFzaywgcmVwb3J0ZXIub3V0U3RyZWFtKSk7XG4gICAgICAgIGNvbnN0IGNvbXBsZXRpb25Qcm9taXNlID0gdGhpcy5fZ2V0VGFza1Jlc3VsdCh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCk7XG5cbiAgICAgICAgdGFzay5vbignc3RhcnQnLCBzdGFydEhhbmRsaW5nVGVzdEVycm9ycyk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5za2lwVW5jYXVnaHRFcnJvcnMpKSB7XG4gICAgICAgICAgICB0YXNrLm9uKCd0ZXN0LXJ1bi1zdGFydCcsIGFkZFJ1bm5pbmdUZXN0KTtcbiAgICAgICAgICAgIHRhc2sub24oJ3Rlc3QtcnVuLWRvbmUnLCByZW1vdmVSdW5uaW5nVGVzdCk7XG4gICAgICAgIH1cblxuICAgICAgICB0YXNrLm9uKCdkb25lJywgc3RvcEhhbmRsaW5nVGVzdEVycm9ycyk7XG5cbiAgICAgICAgY29uc3Qgc2V0Q29tcGxldGVkID0gKCkgPT4ge1xuICAgICAgICAgICAgY29tcGxldGVkID0gdHJ1ZTtcbiAgICAgICAgfTtcblxuICAgICAgICBjb21wbGV0aW9uUHJvbWlzZVxuICAgICAgICAgICAgLnRoZW4oc2V0Q29tcGxldGVkKVxuICAgICAgICAgICAgLmNhdGNoKHNldENvbXBsZXRlZCk7XG5cbiAgICAgICAgY29uc3QgY2FuY2VsVGFzayA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICghY29tcGxldGVkKVxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuX2Rpc3Bvc2VUYXNrQW5kUmVsYXRlZEFzc2V0cyh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHsgY29tcGxldGlvblByb21pc2UsIGNhbmNlbFRhc2sgfTtcbiAgICB9XG5cbiAgICBfcmVnaXN0ZXJBc3NldHMgKGFzc2V0cykge1xuICAgICAgICBhc3NldHMuZm9yRWFjaChhc3NldCA9PiB0aGlzLnByb3h5LkdFVChhc3NldC5wYXRoLCBhc3NldC5pbmZvKSk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlU3BlZWRPcHRpb24gKCkge1xuICAgICAgICBjb25zdCBzcGVlZCA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnNwZWVkKTtcblxuICAgICAgICBpZiAoc3BlZWQgPT09IHZvaWQgMClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBpZiAodHlwZW9mIHNwZWVkICE9PSAnbnVtYmVyJyB8fCBpc05hTihzcGVlZCkgfHwgc3BlZWQgPCAwLjAxIHx8IHNwZWVkID4gMSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuaW52YWxpZFNwZWVkVmFsdWUpO1xuICAgIH1cblxuICAgIF92YWxpZGF0ZUNvbmN1cnJlbmN5T3B0aW9uICgpIHtcbiAgICAgICAgY29uc3QgY29uY3VycmVuY3kgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5jb25jdXJyZW5jeSk7XG5cbiAgICAgICAgaWYgKGNvbmN1cnJlbmN5ID09PSB2b2lkIDApXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgaWYgKHR5cGVvZiBjb25jdXJyZW5jeSAhPT0gJ251bWJlcicgfHwgaXNOYU4oY29uY3VycmVuY3kpIHx8IGNvbmN1cnJlbmN5IDwgMSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuaW52YWxpZENvbmN1cnJlbmN5RmFjdG9yKTtcbiAgICB9XG5cbiAgICBfdmFsaWRhdGVQcm94eUJ5cGFzc09wdGlvbiAoKSB7XG4gICAgICAgIGxldCBwcm94eUJ5cGFzcyA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnByb3h5QnlwYXNzKTtcblxuICAgICAgICBpZiAocHJveHlCeXBhc3MgPT09IHZvaWQgMClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBhc3NlcnRUeXBlKFsgaXMuc3RyaW5nLCBpcy5hcnJheSBdLCBudWxsLCAnXCJwcm94eUJ5cGFzc1wiIGFyZ3VtZW50JywgcHJveHlCeXBhc3MpO1xuXG4gICAgICAgIGlmICh0eXBlb2YgcHJveHlCeXBhc3MgPT09ICdzdHJpbmcnKVxuICAgICAgICAgICAgcHJveHlCeXBhc3MgPSBbcHJveHlCeXBhc3NdO1xuXG4gICAgICAgIHByb3h5QnlwYXNzID0gcHJveHlCeXBhc3MucmVkdWNlKChhcnIsIHJ1bGVzKSA9PiB7XG4gICAgICAgICAgICBhc3NlcnRUeXBlKGlzLnN0cmluZywgbnVsbCwgJ1wicHJveHlCeXBhc3NcIiBhcmd1bWVudCcsIHJ1bGVzKTtcblxuICAgICAgICAgICAgcmV0dXJuIGFyci5jb25jYXQocnVsZXMuc3BsaXQoJywnKSk7XG4gICAgICAgIH0sIFtdKTtcblxuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgcHJveHlCeXBhc3MgfSk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlU2NyZWVuc2hvdE9wdGlvbnMgKCkge1xuICAgICAgICBjb25zdCBzY3JlZW5zaG90UGF0aCAgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5zY3JlZW5zaG90UGF0aCk7XG4gICAgICAgIGNvbnN0IHNjcmVlbnNob3RQYXRoUGF0dGVybiA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnNjcmVlbnNob3RQYXRoUGF0dGVybik7XG5cbiAgICAgICAgaWYgKHNjcmVlbnNob3RQYXRoKSB7XG4gICAgICAgICAgICB0aGlzLl92YWxpZGF0ZVNjcmVlbnNob3RQYXRoKHNjcmVlbnNob3RQYXRoLCAnc2NyZWVuc2hvdHMgYmFzZSBkaXJlY3RvcnkgcGF0aCcpO1xuXG4gICAgICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgW09QVElPTl9OQU1FUy5zY3JlZW5zaG90UGF0aF06IHJlc29sdmVQYXRoKHNjcmVlbnNob3RQYXRoKSB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzY3JlZW5zaG90UGF0aFBhdHRlcm4pXG4gICAgICAgICAgICB0aGlzLl92YWxpZGF0ZVNjcmVlbnNob3RQYXRoKHNjcmVlbnNob3RQYXRoUGF0dGVybiwgJ3NjcmVlbnNob3RzIHBhdGggcGF0dGVybicpO1xuXG4gICAgICAgIGlmICghc2NyZWVuc2hvdFBhdGggJiYgc2NyZWVuc2hvdFBhdGhQYXR0ZXJuKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5jYW5ub3RVc2VTY3JlZW5zaG90UGF0aFBhdHRlcm5XaXRob3V0QmFzZVNjcmVlbnNob3RQYXRoU3BlY2lmaWVkKTtcbiAgICB9XG5cbiAgICBhc3luYyBfdmFsaWRhdGVWaWRlb09wdGlvbnMgKCkge1xuICAgICAgICBjb25zdCB2aWRlb1BhdGggICAgICAgICAgICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnZpZGVvUGF0aCk7XG4gICAgICAgIGNvbnN0IHZpZGVvRW5jb2RpbmdPcHRpb25zID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMudmlkZW9FbmNvZGluZ09wdGlvbnMpO1xuXG4gICAgICAgIGxldCB2aWRlb09wdGlvbnMgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy52aWRlb09wdGlvbnMpO1xuXG4gICAgICAgIGlmICghdmlkZW9QYXRoKSB7XG4gICAgICAgICAgICBpZiAodmlkZW9PcHRpb25zIHx8IHZpZGVvRW5jb2RpbmdPcHRpb25zKVxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90U2V0VmlkZW9PcHRpb25zV2l0aG91dEJhc2VWaWRlb1BhdGhTcGVjaWZpZWQpO1xuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgW09QVElPTl9OQU1FUy52aWRlb1BhdGhdOiByZXNvbHZlUGF0aCh2aWRlb1BhdGgpIH0pO1xuXG4gICAgICAgIGlmICghdmlkZW9PcHRpb25zKSB7XG4gICAgICAgICAgICB2aWRlb09wdGlvbnMgPSB7fTtcblxuICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7IFtPUFRJT05fTkFNRVMudmlkZW9PcHRpb25zXTogdmlkZW9PcHRpb25zIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHZpZGVvT3B0aW9ucy5mZm1wZWdQYXRoKVxuICAgICAgICAgICAgdmlkZW9PcHRpb25zLmZmbXBlZ1BhdGggPSByZXNvbHZlUGF0aCh2aWRlb09wdGlvbnMuZmZtcGVnUGF0aCk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHZpZGVvT3B0aW9ucy5mZm1wZWdQYXRoID0gYXdhaXQgZGV0ZWN0RkZNUEVHKCk7XG5cbiAgICAgICAgaWYgKCF2aWRlb09wdGlvbnMuZmZtcGVnUGF0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RmluZEZGTVBFRyk7XG4gICAgfVxuXG4gICAgYXN5bmMgX3ZhbGlkYXRlUnVuT3B0aW9ucyAoKSB7XG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlU2NyZWVuc2hvdE9wdGlvbnMoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5fdmFsaWRhdGVWaWRlb09wdGlvbnMoKTtcbiAgICAgICAgdGhpcy5fdmFsaWRhdGVTcGVlZE9wdGlvbigpO1xuICAgICAgICB0aGlzLl92YWxpZGF0ZUNvbmN1cnJlbmN5T3B0aW9uKCk7XG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlUHJveHlCeXBhc3NPcHRpb24oKTtcbiAgICB9XG5cbiAgICBfY3JlYXRlUnVubmFibGVDb25maWd1cmF0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYm9vdHN0cmFwcGVyXG4gICAgICAgICAgICAuY3JlYXRlUnVubmFibGVDb25maWd1cmF0aW9uKClcbiAgICAgICAgICAgIC50aGVuKHJ1bm5hYmxlQ29uZmlndXJhdGlvbiA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdkb25lLWJvb3RzdHJhcHBpbmcnKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBydW5uYWJsZUNvbmZpZ3VyYXRpb247XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBfdmFsaWRhdGVTY3JlZW5zaG90UGF0aCAoc2NyZWVuc2hvdFBhdGgsIHBhdGhUeXBlKSB7XG4gICAgICAgIGNvbnN0IGZvcmJpZGRlbkNoYXJzTGlzdCA9IGNoZWNrRmlsZVBhdGgoc2NyZWVuc2hvdFBhdGgpO1xuXG4gICAgICAgIGlmIChmb3JiaWRkZW5DaGFyc0xpc3QubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5mb3JiaWRkZW5DaGFyYXRlcnNJblNjcmVlbnNob3RQYXRoLCBzY3JlZW5zaG90UGF0aCwgcGF0aFR5cGUsIHJlbmRlckZvcmJpZGRlbkNoYXJzTGlzdChmb3JiaWRkZW5DaGFyc0xpc3QpKTtcbiAgICB9XG5cbiAgICBfc2V0Qm9vdHN0cmFwcGVyT3B0aW9ucyAoKSB7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5wcmVwYXJlKCk7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5ub3RpZnlBYm91dE92ZXJyaWRlbk9wdGlvbnMoKTtcblxuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5zb3VyY2VzICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5zcmMpIHx8IHRoaXMuYm9vdHN0cmFwcGVyLnNvdXJjZXM7XG4gICAgICAgIHRoaXMuYm9vdHN0cmFwcGVyLmJyb3dzZXJzICAgICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmJyb3dzZXJzKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5icm93c2VycztcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIuY29uY3VycmVuY3kgID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuY29uY3VycmVuY3kpO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5hcHBDb21tYW5kICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5hcHBDb21tYW5kKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5hcHBDb21tYW5kO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5hcHBJbml0RGVsYXkgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5hcHBJbml0RGVsYXkpO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5maWx0ZXIgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5maWx0ZXIpIHx8IHRoaXMuYm9vdHN0cmFwcGVyLmZpbHRlcjtcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIucmVwb3J0ZXJzICAgID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMucmVwb3J0ZXIpIHx8IHRoaXMuYm9vdHN0cmFwcGVyLnJlcG9ydGVycztcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIudHNDb25maWdQYXRoID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMudHNDb25maWdQYXRoKTtcbiAgICB9XG5cbiAgICAvLyBBUElcbiAgICBlbWJlZGRpbmdPcHRpb25zIChvcHRzKSB7XG4gICAgICAgIG