UNPKG

testcafe

Version:

Automated browser testing for the modern web development stack.

341 lines 56.2 kB
"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