UNPKG

68.1 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6const path_1 = require("path");
7const debug_1 = __importDefault(require("debug"));
8const promisify_event_1 = __importDefault(require("promisify-event"));
9const map_reverse_1 = __importDefault(require("map-reverse"));
10const events_1 = require("events");
11const lodash_1 = require("lodash");
12const bootstrapper_1 = __importDefault(require("./bootstrapper"));
13const reporter_1 = __importDefault(require("../reporter"));
14const task_1 = __importDefault(require("./task"));
15const debug_logger_1 = __importDefault(require("../notifications/debug-logger"));
16const runtime_1 = require("../errors/runtime");
17const types_1 = require("../errors/types");
18const type_assertions_1 = require("../errors/runtime/type-assertions");
19const utils_1 = require("../errors/test-run/utils");
20const detect_ffmpeg_1 = __importDefault(require("../utils/detect-ffmpeg"));
21const check_file_path_1 = __importDefault(require("../utils/check-file-path"));
22const handle_errors_1 = require("../utils/handle-errors");
23const option_names_1 = __importDefault(require("../configuration/option-names"));
24const flag_list_1 = __importDefault(require("../utils/flag-list"));
25const prepare_reporters_1 = __importDefault(require("../utils/prepare-reporters"));
26const load_1 = __importDefault(require("../custom-client-scripts/load"));
27const utils_2 = require("../custom-client-scripts/utils");
28const string_1 = require("../utils/string");
29const DEBUG_LOGGER = debug_1.default('testcafe:runner');
30class Runner extends events_1.EventEmitter {
31 constructor(proxy, browserConnectionGateway, configuration) {
32 super();
33 this.proxy = proxy;
34 this.bootstrapper = this._createBootstrapper(browserConnectionGateway);
35 this.pendingTaskPromises = [];
36 this.configuration = configuration;
37 this.isCli = false;
38 this.apiMethodWasCalled = new flag_list_1.default([
39 option_names_1.default.src,
40 option_names_1.default.browsers,
41 option_names_1.default.reporter,
42 option_names_1.default.clientScripts
43 ]);
44 }
45 _createBootstrapper(browserConnectionGateway) {
46 return new bootstrapper_1.default(browserConnectionGateway);
47 }
48 _disposeBrowserSet(browserSet) {
49 return browserSet.dispose().catch(e => DEBUG_LOGGER(e));
50 }
51 _disposeReporters(reporters) {
52 return Promise.all(reporters.map(reporter => reporter.dispose().catch(e => DEBUG_LOGGER(e))));
53 }
54 _disposeTestedApp(testedApp) {
55 return testedApp ? testedApp.kill().catch(e => DEBUG_LOGGER(e)) : Promise.resolve();
56 }
57 async _disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp) {
58 task.abort();
59 task.unRegisterClientScriptRouting();
60 task.clearListeners();
61 await this._disposeAssets(browserSet, reporters, testedApp);
62 }
63 _disposeAssets(browserSet, reporters, testedApp) {
64 return Promise.all([
65 this._disposeBrowserSet(browserSet),
66 this._disposeReporters(reporters),
67 this._disposeTestedApp(testedApp)
68 ]);
69 }
70 _prepareArrayParameter(array) {
71 array = lodash_1.flattenDeep(array);
72 if (this.isCli)
73 return array.length === 0 ? void 0 : array;
74 return array;
75 }
76 _createCancelablePromise(taskPromise) {
77 const promise = taskPromise.then(({ completionPromise }) => completionPromise);
78 const removeFromPending = () => lodash_1.pull(this.pendingTaskPromises, promise);
79 promise
80 .then(removeFromPending)
81 .catch(removeFromPending);
82 promise.cancel = () => taskPromise
83 .then(({ cancelTask }) => cancelTask())
84 .then(removeFromPending);
85 this.pendingTaskPromises.push(promise);
86 return promise;
87 }
88 // Run task
89 _getFailedTestCount(task, reporter) {
90 let failedTestCount = reporter.testCount - reporter.passed;
91 if (task.opts.stopOnFirstFail && !!failedTestCount)
92 failedTestCount = 1;
93 return failedTestCount;
94 }
95 async _getTaskResult(task, browserSet, reporters, testedApp) {
96 task.on('browser-job-done', job => browserSet.releaseConnection(job.browserConnection));
97 const browserSetErrorPromise = promisify_event_1.default(browserSet, 'error');
98 const taskDonePromise = task.once('done')
99 .then(() => browserSetErrorPromise.cancel())
100 .then(() => {
101 return Promise.all(reporters.map(reporter => reporter.pendingTaskDonePromise));
102 });
103 const promises = [
104 taskDonePromise,
105 browserSetErrorPromise
106 ];
107 if (testedApp)
108 promises.push(testedApp.errorPromise);
109 try {
110 await Promise.race(promises);
111 }
112 catch (err) {
113 await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp);
114 throw err;
115 }
116 await this._disposeAssets(browserSet, reporters, testedApp);
117 return this._getFailedTestCount(task, reporters[0]);
118 }
119 _createTask(tests, browserConnectionGroups, proxy, opts) {
120 return new task_1.default(tests, browserConnectionGroups, proxy, opts);
121 }
122 _runTask(reporterPlugins, browserSet, tests, testedApp) {
123 let completed = false;
124 const task = this._createTask(tests, browserSet.browserConnectionGroups, this.proxy, this.configuration.getOptions());
125 const reporters = reporterPlugins.map(reporter => new reporter_1.default(reporter.plugin, task, reporter.outStream));
126 const completionPromise = this._getTaskResult(task, browserSet, reporters, testedApp);
127 task.on('start', handle_errors_1.startHandlingTestErrors);
128 if (!this.configuration.getOption(option_names_1.default.skipUncaughtErrors)) {
129 task.on('test-run-start', handle_errors_1.addRunningTest);
130 task.on('test-run-done', handle_errors_1.removeRunningTest);
131 }
132 task.on('done', handle_errors_1.stopHandlingTestErrors);
133 const onTaskCompleted = () => {
134 task.unRegisterClientScriptRouting();
135 completed = true;
136 };
137 completionPromise
138 .then(onTaskCompleted)
139 .catch(onTaskCompleted);
140 const cancelTask = async () => {
141 if (!completed)
142 await this._disposeTaskAndRelatedAssets(task, browserSet, reporters, testedApp);
143 };
144 return { completionPromise, cancelTask };
145 }
146 _registerAssets(assets) {
147 assets.forEach(asset => this.proxy.GET(asset.path, asset.info));
148 }
149 _validateDebugLogger() {
150 const debugLogger = this.configuration.getOption(option_names_1.default.debugLogger);
151 const debugLoggerDefinedCorrectly = debugLogger === null || !!debugLogger &&
152 ['showBreakpoint', 'hideBreakpoint'].every(method => method in debugLogger && lodash_1.isFunction(debugLogger[method]));
153 if (!debugLoggerDefinedCorrectly) {
154 this.configuration.mergeOptions({
155 [option_names_1.default.debugLogger]: debug_logger_1.default
156 });
157 }
158 }
159 _validateSpeedOption() {
160 const speed = this.configuration.getOption(option_names_1.default.speed);
161 if (speed === void 0)
162 return;
163 if (typeof speed !== 'number' || isNaN(speed) || speed < 0.01 || speed > 1)
164 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidSpeedValue);
165 }
166 _validateConcurrencyOption() {
167 const concurrency = this.configuration.getOption(option_names_1.default.concurrency);
168 if (concurrency === void 0)
169 return;
170 if (typeof concurrency !== 'number' || isNaN(concurrency) || concurrency < 1)
171 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.invalidConcurrencyFactor);
172 }
173 _validateProxyBypassOption() {
174 let proxyBypass = this.configuration.getOption(option_names_1.default.proxyBypass);
175 if (proxyBypass === void 0)
176 return;
177 type_assertions_1.assertType([type_assertions_1.is.string, type_assertions_1.is.array], null, '"proxyBypass" argument', proxyBypass);
178 if (typeof proxyBypass === 'string')
179 proxyBypass = [proxyBypass];
180 proxyBypass = proxyBypass.reduce((arr, rules) => {
181 type_assertions_1.assertType(type_assertions_1.is.string, null, '"proxyBypass" argument', rules);
182 return arr.concat(rules.split(','));
183 }, []);
184 this.configuration.mergeOptions({ proxyBypass });
185 }
186 _getScreenshotOptions() {
187 let { path, pathPattern } = this.configuration.getOption(option_names_1.default.screenshots) || {};
188 if (!path)
189 path = this.configuration.getOption(option_names_1.default.screenshotPath);
190 if (!pathPattern)
191 pathPattern = this.configuration.getOption(option_names_1.default.screenshotPathPattern);
192 return { path, pathPattern };
193 }
194 _validateScreenshotOptions() {
195 const { path, pathPattern } = this._getScreenshotOptions();
196 const disableScreenshots = this.configuration.getOption(option_names_1.default.disableScreenshots) || !path;
197 this.configuration.mergeOptions({ [option_names_1.default.disableScreenshots]: disableScreenshots });
198 if (disableScreenshots)
199 return;
200 if (path) {
201 this._validateScreenshotPath(path, 'screenshots base directory path');
202 this.configuration.mergeOptions({ [option_names_1.default.screenshots]: { path: path_1.resolve(path) } });
203 }
204 if (pathPattern) {
205 this._validateScreenshotPath(pathPattern, 'screenshots path pattern');
206 this.configuration.mergeOptions({ [option_names_1.default.screenshots]: { pathPattern } });
207 }
208 }
209 async _validateVideoOptions() {
210 const videoPath = this.configuration.getOption(option_names_1.default.videoPath);
211 const videoEncodingOptions = this.configuration.getOption(option_names_1.default.videoEncodingOptions);
212 let videoOptions = this.configuration.getOption(option_names_1.default.videoOptions);
213 if (!videoPath) {
214 if (videoOptions || videoEncodingOptions)
215 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotSetVideoOptionsWithoutBaseVideoPathSpecified);
216 return;
217 }
218 this.configuration.mergeOptions({ [option_names_1.default.videoPath]: path_1.resolve(videoPath) });
219 if (!videoOptions) {
220 videoOptions = {};
221 this.configuration.mergeOptions({ [option_names_1.default.videoOptions]: videoOptions });
222 }
223 if (videoOptions.ffmpegPath)
224 videoOptions.ffmpegPath = path_1.resolve(videoOptions.ffmpegPath);
225 else
226 videoOptions.ffmpegPath = await detect_ffmpeg_1.default();
227 if (!videoOptions.ffmpegPath)
228 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindFFMPEG);
229 }
230 async _validateRunOptions() {
231 this._validateDebugLogger();
232 this._validateScreenshotOptions();
233 await this._validateVideoOptions();
234 this._validateSpeedOption();
235 this._validateConcurrencyOption();
236 this._validateProxyBypassOption();
237 }
238 _validateTestForAllowMultipleWindowsOption(tests) {
239 if (tests.some(test => test.isLegacy))
240 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotUseAllowMultipleWindowsOptionForLegacyTests);
241 }
242 _validateBrowsersForAllowMultipleWindowsOption(browserSet) {
243 const browserConnections = browserSet.browserConnectionGroups.map(browserConnectionGroup => browserConnectionGroup[0]);
244 const unsupportedBrowserConnections = browserConnections.filter(browserConnection => !browserConnection.activeWindowId);
245 if (!unsupportedBrowserConnections.length)
246 return;
247 const unsupportedBrowserAliases = unsupportedBrowserConnections.map(browserConnection => browserConnection.browserInfo.alias);
248 const browserAliases = string_1.getConcatenatedValuesString(unsupportedBrowserAliases);
249 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotUseAllowMultipleWindowsOptionForSomeBrowsers, browserAliases);
250 }
251 _validateAllowMultipleWindowsOption(tests, browserSet) {
252 const allowMultipleWindows = this.configuration.getOption(option_names_1.default.allowMultipleWindows);
253 if (!allowMultipleWindows)
254 return;
255 this._validateTestForAllowMultipleWindowsOption(tests);
256 this._validateBrowsersForAllowMultipleWindowsOption(browserSet);
257 }
258 _createRunnableConfiguration() {
259 return this.bootstrapper
260 .createRunnableConfiguration()
261 .then(runnableConfiguration => {
262 this.emit('done-bootstrapping');
263 return runnableConfiguration;
264 });
265 }
266 _validateScreenshotPath(screenshotPath, pathType) {
267 const forbiddenCharsList = check_file_path_1.default(screenshotPath);
268 if (forbiddenCharsList.length)
269 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.forbiddenCharatersInScreenshotPath, screenshotPath, pathType, utils_1.renderForbiddenCharsList(forbiddenCharsList));
270 }
271 _setBootstrapperOptions() {
272 this.configuration.prepare();
273 this.configuration.notifyAboutOverriddenOptions();
274 this.bootstrapper.sources = this.configuration.getOption(option_names_1.default.src) || this.bootstrapper.sources;
275 this.bootstrapper.browsers = this.configuration.getOption(option_names_1.default.browsers) || this.bootstrapper.browsers;
276 this.bootstrapper.concurrency = this.configuration.getOption(option_names_1.default.concurrency);
277 this.bootstrapper.appCommand = this.configuration.getOption(option_names_1.default.appCommand) || this.bootstrapper.appCommand;
278 this.bootstrapper.appInitDelay = this.configuration.getOption(option_names_1.default.appInitDelay);
279 this.bootstrapper.filter = this.configuration.getOption(option_names_1.default.filter) || this.bootstrapper.filter;
280 this.bootstrapper.reporters = this.configuration.getOption(option_names_1.default.reporter) || this.bootstrapper.reporters;
281 this.bootstrapper.tsConfigPath = this.configuration.getOption(option_names_1.default.tsConfigPath);
282 this.bootstrapper.clientScripts = this.configuration.getOption(option_names_1.default.clientScripts) || this.bootstrapper.clientScripts;
283 this.bootstrapper.allowMultipleWindows = this.configuration.getOption(option_names_1.default.allowMultipleWindows) || this.bootstrapper.allowMultipleWindows;
284 }
285 // API
286 embeddingOptions(opts) {
287 const { assets, TestRunCtor } = opts;
288 this._registerAssets(assets);
289 this.configuration.mergeOptions({ TestRunCtor });
290 return this;
291 }
292 src(...sources) {
293 if (this.apiMethodWasCalled.src)
294 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.src);
295 sources = this._prepareArrayParameter(sources);
296 this.configuration.mergeOptions({ [option_names_1.default.src]: sources });
297 this.apiMethodWasCalled.src = true;
298 return this;
299 }
300 browsers(...browsers) {
301 if (this.apiMethodWasCalled.browsers)
302 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.browsers);
303 browsers = this._prepareArrayParameter(browsers);
304 this.configuration.mergeOptions({ browsers });
305 this.apiMethodWasCalled.browsers = true;
306 return this;
307 }
308 concurrency(concurrency) {
309 this.configuration.mergeOptions({ concurrency });
310 return this;
311 }
312 reporter(name, output) {
313 if (this.apiMethodWasCalled.reporter)
314 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.reporter);
315 let reporters = prepare_reporters_1.default(name, output);
316 reporters = this._prepareArrayParameter(reporters);
317 this.configuration.mergeOptions({ [option_names_1.default.reporter]: reporters });
318 this.apiMethodWasCalled.reporter = true;
319 return this;
320 }
321 filter(filter) {
322 this.configuration.mergeOptions({ filter });
323 return this;
324 }
325 useProxy(proxy, proxyBypass) {
326 this.configuration.mergeOptions({ proxy, proxyBypass });
327 return this;
328 }
329 screenshots(...options) {
330 let fullPage;
331 let [path, takeOnFails, pathPattern] = options;
332 if (options.length === 1 && options[0] && typeof options[0] === 'object')
333 ({ path, takeOnFails, pathPattern, fullPage } = options[0]);
334 this.configuration.mergeOptions({ screenshots: { path, takeOnFails, pathPattern, fullPage } });
335 return this;
336 }
337 video(path, options, encodingOptions) {
338 this.configuration.mergeOptions({
339 [option_names_1.default.videoPath]: path,
340 [option_names_1.default.videoOptions]: options,
341 [option_names_1.default.videoEncodingOptions]: encodingOptions
342 });
343 return this;
344 }
345 startApp(command, initDelay) {
346 this.configuration.mergeOptions({
347 [option_names_1.default.appCommand]: command,
348 [option_names_1.default.appInitDelay]: initDelay
349 });
350 return this;
351 }
352 tsConfigPath(path) {
353 this.configuration.mergeOptions({
354 [option_names_1.default.tsConfigPath]: path
355 });
356 return this;
357 }
358 clientScripts(...scripts) {
359 if (this.apiMethodWasCalled.clientScripts)
360 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleAPIMethodCallForbidden, option_names_1.default.clientScripts);
361 scripts = this._prepareArrayParameter(scripts);
362 this.configuration.mergeOptions({ [option_names_1.default.clientScripts]: scripts });
363 this.apiMethodWasCalled.clientScripts = true;
364 return this;
365 }
366 async _prepareClientScripts(tests, clientScripts) {
367 return Promise.all(tests.map(async (test) => {
368 if (test.isLegacy)
369 return;
370 let loadedTestClientScripts = await load_1.default(test.clientScripts, path_1.dirname(test.testFile.filename));
371 loadedTestClientScripts = clientScripts.concat(loadedTestClientScripts);
372 test.clientScripts = utils_2.setUniqueUrls(loadedTestClientScripts);
373 }));
374 }
375 run(options = {}) {
376 this.apiMethodWasCalled.reset();
377 this.configuration.mergeOptions(options);
378 this._setBootstrapperOptions();
379 const runTaskPromise = Promise.resolve()
380 .then(() => this._validateRunOptions())
381 .then(() => this._createRunnableConfiguration())
382 .then(async ({ reporterPlugins, browserSet, tests, testedApp, commonClientScripts }) => {
383 await this._prepareClientScripts(tests, commonClientScripts);
384 this._validateAllowMultipleWindowsOption(tests, browserSet);
385 return this._runTask(reporterPlugins, browserSet, tests, testedApp);
386 });
387 return this._createCancelablePromise(runTaskPromise);
388 }
389 async stop() {
390 // NOTE: When taskPromise is cancelled, it is removed from
391 // the pendingTaskPromises array, which leads to shifting indexes
392 // towards the beginning. So, we must copy the array in order to iterate it,
393 // or we can perform iteration from the end to the beginning.
394 const cancellationPromises = map_reverse_1.default(this.pendingTaskPromises, taskPromise => taskPromise.cancel());
395 await Promise.all(cancellationPromises);
396 }
397}
398exports.default = Runner;
399module.exports = exports.default;
400//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcnVubmVyL2luZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsK0JBQXVEO0FBQ3ZELGtEQUEwQjtBQUMxQixzRUFBNkM7QUFDN0MsOERBQXFDO0FBQ3JDLG1DQUFzQztBQUN0QyxtQ0FBNEU7QUFDNUUsa0VBQTBDO0FBQzFDLDJEQUFtQztBQUNuQyxrREFBMEI7QUFDMUIsaUZBQStEO0FBQy9ELCtDQUFpRDtBQUNqRCwyQ0FBaUQ7QUFDakQsdUVBQW1FO0FBQ25FLG9EQUFvRTtBQUNwRSwyRUFBa0Q7QUFDbEQsK0VBQXFEO0FBQ3JELDBEQUE0SDtBQUM1SCxpRkFBeUQ7QUFDekQsbUVBQTBDO0FBQzFDLG1GQUEwRDtBQUMxRCx5RUFBOEQ7QUFDOUQsMERBQStEO0FBQy9ELDRDQUE4RDtBQUU5RCxNQUFNLFlBQVksR0FBRyxlQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztBQUU5QyxNQUFxQixNQUFPLFNBQVEscUJBQVk7SUFDNUMsWUFBYSxLQUFLLEVBQUUsd0JBQXdCLEVBQUUsYUFBYTtRQUN2RCxLQUFLLEVBQUUsQ0FBQztRQUVSLElBQUksQ0FBQyxLQUFLLEdBQWlCLEtBQUssQ0FBQztRQUNqQyxJQUFJLENBQUMsWUFBWSxHQUFVLElBQUksQ0FBQyxtQkFBbUIsQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDO1FBQzlFLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLGFBQWEsR0FBUyxhQUFhLENBQUM7UUFDekMsSUFBSSxDQUFDLEtBQUssR0FBaUIsS0FBSyxDQUFDO1FBRWpDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLG1CQUFRLENBQUM7WUFDbkMsc0JBQVksQ0FBQyxHQUFHO1lBQ2hCLHNCQUFZLENBQUMsUUFBUTtZQUNyQixzQkFBWSxDQUFDLFFBQVE7WUFDckIsc0JBQVksQ0FBQyxhQUFhO1NBQzdCLENB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LENBQUM7YUFDdEMsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO2FBQy9DLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxlQUFlLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsbUJBQW1CLEVBQUUsRUFBRSxFQUFFO1lBQ25GLE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLEtBQUssRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO1lBRTdELElBQUksQ0FBQyxtQ0FBbUMsQ0FBQyxLQUFLLEVBQUUsVUFBVSxDQUFDLENBQUM7WUFFNUQsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLGVBQWUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ3hFLENBQUMsQ0FBQyxDQUFDO1FBRVAsT0FBTyxJQUFJLENBQUMsd0JBQXdCLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDekQsQ0FBQztJQUVELEtBQUssQ0FBQyxJQUFJO1FBQ04sMERBQTBEO1FBQzFELGlFQUFpRTtRQUNqRSw0RUFBNEU7UUFDNUUsNkRBQTZEO1FBQzdELE1BQU0sb0JBQW9CLEdBQUcscUJBQVUsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsV0FBVyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUV2RyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUMsQ0FBQztJQUM1QyxDQUFDO0NBQ0o7QUE3ZkQseUJBNmZDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmVzb2x2ZSBhcyByZXNvbHZlUGF0aCwgZGlybmFtZSB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IGRlYnVnIGZyb20gJ2RlYnVnJztcbmltcG9ydCBwcm9taXNpZnlFdmVudCBmcm9tICdwcm9taXNpZnktZXZlbnQnO1xuaW1wb3J0IG1hcFJldmVyc2UgZnJvbSAnbWFwLXJldmVyc2UnO1xuaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcbmltcG9ydCB7IGZsYXR0ZW5EZWVwIGFzIGZsYXR0ZW4sIHB1bGwgYXMgcmVtb3ZlLCBpc0Z1bmN0aW9uIH0gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBCb290c3RyYXBwZXIgZnJvbSAnLi9ib290c3RyYXBwZXInO1xuaW1wb3J0IFJlcG9ydGVyIGZyb20gJy4uL3JlcG9ydGVyJztcbmltcG9ydCBUYXNrIGZyb20gJy4vdGFzayc7XG5pbXBvcnQgZGVmYXVsdERlYnVnTG9nZ2VyIGZyb20gJy4uL25vdGlmaWNhdGlvbnMvZGVidWctbG9nZ2VyJztcbmltcG9ydCB7IEdlbmVyYWxFcnJvciB9IGZyb20gJy4uL2Vycm9ycy9ydW50aW1lJztcbmltcG9ydCB7IFJVTlRJTUVfRVJST1JTIH0gZnJvbSAnLi4vZXJyb3JzL3R5cGVzJztcbmltcG9ydCB7IGFzc2VydFR5cGUsIGlzIH0gZnJvbSAnLi4vZXJyb3JzL3J1bnRpbWUvdHlwZS1hc3NlcnRpb25zJztcbmltcG9ydCB7IHJlbmRlckZvcmJpZGRlbkNoYXJzTGlzdCB9IGZyb20gJy4uL2Vycm9ycy90ZXN0LXJ1bi91dGlscyc7XG5pbXBvcnQgZGV0ZWN0RkZNUEVHIGZyb20gJy4uL3V0aWxzL2RldGVjdC1mZm1wZWcnO1xuaW1wb3J0IGNoZWNrRmlsZVBhdGggZnJvbSAnLi4vdXRpbHMvY2hlY2stZmlsZS1wYXRoJztcbmltcG9ydCB7IGFkZFJ1bm5pbmdUZXN0LCByZW1vdmVSdW5uaW5nVGVzdCwgc3RhcnRIYW5kbGluZ1Rlc3RFcnJvcnMsIHN0b3BIYW5kbGluZ1Rlc3RFcnJvcnMgfSBmcm9tICcuLi91dGlscy9oYW5kbGUtZXJyb3JzJztcbmltcG9ydCBPUFRJT05fTkFNRVMgZnJvbSAnLi4vY29uZmlndXJhdGlvbi9vcHRpb24tbmFtZXMnO1xuaW1wb3J0IEZsYWdMaXN0IGZyb20gJy4uL3V0aWxzL2ZsYWctbGlzdCc7XG5pbXBvcnQgcHJlcGFyZVJlcG9ydGVycyBmcm9tICcuLi91dGlscy9wcmVwYXJlLXJlcG9ydGVycyc7XG5pbXBvcnQgbG9hZENsaWVudFNjcmlwdHMgZnJvbSAnLi4vY3VzdG9tLWNsaWVudC1zY3JpcHRzL2xvYWQnO1xuaW1wb3J0IHsgc2V0VW5pcXVlVXJscyB9IGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy91dGlscyc7XG5pbXBvcnQgeyBnZXRDb25jYXRlbmF0ZWRWYWx1ZXNTdHJpbmcgfSBmcm9tICcuLi91dGlscy9zdHJpbmcnO1xuXG5jb25zdCBERUJVR19MT0dHRVIgPSBkZWJ1ZygndGVzdGNhZmU6cnVubmVyJyk7XG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFJ1bm5lciBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gICAgY29uc3RydWN0b3IgKHByb3h5LCBicm93c2VyQ29ubmVjdGlvbkdhdGV3YXksIGNvbmZpZ3VyYXRpb24pIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICB0aGlzLnByb3h5ICAgICAgICAgICAgICAgPSBwcm94eTtcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIgICAgICAgID0gdGhpcy5fY3JlYXRlQm9vdHN0cmFwcGVyKGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSk7XG4gICAgICAgIHRoaXMucGVuZGluZ1Rhc2tQcm9taXNlcyA9IFtdO1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24gICAgICAgPSBjb25maWd1cmF0aW9uO1xuICAgICAgICB0aGlzLmlzQ2xpICAgICAgICAgICAgICAgPSBmYWxzZTtcblxuICAgICAgICB0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZCA9IG5ldyBGbGFnTGlzdChbXG4gICAgICAgICAgICBPUFRJT05fTkFNRVMuc3JjLFxuICAgICAgICAgICAgT1BUSU9OX05BTUVTLmJyb3dzZXJzLFxuICAgICAgICAgICAgT1BUSU9OX05BTUVTLnJlcG9ydGVyLFxuICAgICAgICAgICAgT1BUSU9OX05BTUVTLmNsaWVudFNjcmlwdHNcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZUJvb3RzdHJhcHBlciAoYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5KSB7XG4gICAgICAgIHJldHVybiBuZXcgQm9vdHN0cmFwcGVyKGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VCcm93c2VyU2V0IChicm93c2VyU2V0KSB7XG4gICAgICAgIHJldHVybiBicm93c2VyU2V0LmRpc3Bvc2UoKS5jYXRjaChlID0+IERFQlVHX0xPR0dFUihlKSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VSZXBvcnRlcnMgKHJlcG9ydGVycykge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwocmVwb3J0ZXJzLm1hcChyZXBvcnRlciA9PiByZXBvcnRlci5kaXNwb3NlKCkuY2F0Y2goZSA9PiBERUJVR19MT0dHRVIoZSkpKSk7XG4gICAgfVxuXG4gICAgX2Rpc3Bvc2VUZXN0ZWRBcHAgKHRlc3RlZEFwcCkge1xuICAgICAgICByZXR1cm4gdGVzdGVkQXBwID8gdGVzdGVkQXBwLmtpbGwoKS5jYXRjaChlID0+IERFQlVHX0xPR0dFUihlKSkgOiBQcm9taXNlLnJlc29sdmUoKTtcbiAgICB9XG5cbiAgICBhc3luYyBfZGlzcG9zZVRhc2tBbmRSZWxhdGVkQXNzZXRzICh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCkge1xuICAgICAgICB0YXNrLmFib3J0KCk7XG4gICAgICAgIHRhc2sudW5SZWdpc3RlckNsaWVudFNjcmlwdFJvdXRpbmcoKTtcbiAgICAgICAgdGFzay5jbGVhckxpc3RlbmVycygpO1xuXG4gICAgICAgIGF3YWl0IHRoaXMuX2Rpc3Bvc2VBc3NldHMoYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApO1xuICAgIH1cblxuICAgIF9kaXNwb3NlQXNzZXRzIChicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCkge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwoW1xuICAgICAgICAgICAgdGhpcy5fZGlzcG9zZUJyb3dzZXJTZXQoYnJvd3NlclNldCksXG4gICAgICAgICAgICB0aGlzLl9kaXNwb3NlUmVwb3J0ZXJzKHJlcG9ydGVycyksXG4gICAgICAgICAgICB0aGlzLl9kaXNwb3NlVGVzdGVkQXBwKHRlc3RlZEFwcClcbiAgICAgICAgXSk7XG4gICAgfVxuXG4gICAgX3ByZXBhcmVBcnJheVBhcmFtZXRlciAoYXJyYXkpIHtcbiAgICAgICAgYXJyYXkgPSBmbGF0dGVuKGFycmF5KTtcblxuICAgICAgICBpZiAodGhpcy5pc0NsaSlcbiAgICAgICAgICAgIHJldHVybiBhcnJheS5sZW5ndGggPT09IDAgPyB2b2lkIDAgOiBhcnJheTtcblxuICAgICAgICByZXR1cm4gYXJyYXk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZUNhbmNlbGFibGVQcm9taXNlICh0YXNrUHJvbWlzZSkge1xuICAgICAgICBjb25zdCBwcm9taXNlICAgICAgICAgICA9IHRhc2tQcm9taXNlLnRoZW4oKHsgY29tcGxldGlvblByb21pc2UgfSkgPT4gY29tcGxldGlvblByb21pc2UpO1xuICAgICAgICBjb25zdCByZW1vdmVGcm9tUGVuZGluZyA9ICgpID0+IHJlbW92ZSh0aGlzLnBlbmRpbmdUYXNrUHJvbWlzZXMsIHByb21pc2UpO1xuXG4gICAgICAgIHByb21pc2VcbiAgICAgICAgICAgIC50aGVuKHJlbW92ZUZyb21QZW5kaW5nKVxuICAgICAgICAgICAgLmNhdGNoKHJlbW92ZUZyb21QZW5kaW5nKTtcblxuICAgICAgICBwcm9taXNlLmNhbmNlbCA9ICgpID0+IHRhc2tQcm9taXNlXG4gICAgICAgICAgICAudGhlbigoeyBjYW5jZWxUYXNrIH0pID0+IGNhbmNlbFRhc2soKSlcbiAgICAgICAgICAgIC50aGVuKHJlbW92ZUZyb21QZW5kaW5nKTtcblxuICAgICAgICB0aGlzLnBlbmRpbmdUYXNrUHJvbWlzZXMucHVzaChwcm9taXNlKTtcblxuICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICB9XG5cbiAgICAvLyBSdW4gdGFza1xuICAgIF9nZXRGYWlsZWRUZXN0Q291bnQgKHRhc2ssIHJlcG9ydGVyKSB7XG4gICAgICAgIGxldCBmYWlsZWRUZXN0Q291bnQgPSByZXBvcnRlci50ZXN0Q291bnQgLSByZXBvcnRlci5wYXNzZWQ7XG5cbiAgICAgICAgaWYgKHRhc2sub3B0cy5zdG9wT25GaXJzdEZhaWwgJiYgISFmYWlsZWRUZXN0Q291bnQpXG4gICAgICAgICAgICBmYWlsZWRUZXN0Q291bnQgPSAxO1xuXG4gICAgICAgIHJldHVybiBmYWlsZWRUZXN0Q291bnQ7XG4gICAgfVxuXG4gICAgYXN5bmMgX2dldFRhc2tSZXN1bHQgKHRhc2ssIGJyb3dzZXJTZXQsIHJlcG9ydGVycywgdGVzdGVkQXBwKSB7XG4gICAgICAgIHRhc2sub24oJ2Jyb3dzZXItam9iLWRvbmUnLCBqb2IgPT4gYnJvd3NlclNldC5yZWxlYXNlQ29ubmVjdGlvbihqb2IuYnJvd3NlckNvbm5lY3Rpb24pKTtcblxuICAgICAgICBjb25zdCBicm93c2VyU2V0RXJyb3JQcm9taXNlID0gcHJvbWlzaWZ5RXZlbnQoYnJvd3NlclNldCwgJ2Vycm9yJyk7XG5cbiAgICAgICAgY29uc3QgdGFza0RvbmVQcm9taXNlID0gdGFzay5vbmNlKCdkb25lJylcbiAgICAgICAgICAgIC50aGVuKCgpID0+IGJyb3dzZXJTZXRFcnJvclByb21pc2UuY2FuY2VsKCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHJlcG9ydGVycy5tYXAocmVwb3J0ZXIgPT4gcmVwb3J0ZXIucGVuZGluZ1Rhc2tEb25lUHJvbWlzZSkpO1xuICAgICAgICAgICAgfSk7XG5cblxuICAgICAgICBjb25zdCBwcm9taXNlcyA9IFtcbiAgICAgICAgICAgIHRhc2tEb25lUHJvbWlzZSxcbiAgICAgICAgICAgIGJyb3dzZXJTZXRFcnJvclByb21pc2VcbiAgICAgICAgXTtcblxuICAgICAgICBpZiAodGVzdGVkQXBwKVxuICAgICAgICAgICAgcHJvbWlzZXMucHVzaCh0ZXN0ZWRBcHAuZXJyb3JQcm9taXNlKTtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5yYWNlKHByb21pc2VzKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLl9kaXNwb3NlVGFza0FuZFJlbGF0ZWRBc3NldHModGFzaywgYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApO1xuXG4gICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgIH1cblxuICAgICAgICBhd2FpdCB0aGlzLl9kaXNwb3NlQXNzZXRzKGJyb3dzZXJTZXQsIHJlcG9ydGVycywgdGVzdGVkQXBwKTtcblxuICAgICAgICByZXR1cm4gdGhpcy5fZ2V0RmFpbGVkVGVzdENvdW50KHRhc2ssIHJlcG9ydGVyc1swXSk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZVRhc2sgKHRlc3RzLCBicm93c2VyQ29ubmVjdGlvbkdyb3VwcywgcHJveHksIG9wdHMpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBUYXNrKHRlc3RzLCBicm93c2VyQ29ubmVjdGlvbkdyb3VwcywgcHJveHksIG9wdHMpO1xuICAgIH1cblxuICAgIF9ydW5UYXNrIChyZXBvcnRlclBsdWdpbnMsIGJyb3dzZXJTZXQsIHRlc3RzLCB0ZXN0ZWRBcHApIHtcbiAgICAgICAgbGV0IGNvbXBsZXRlZCAgICAgICAgICAgPSBmYWxzZTtcbiAgICAgICAgY29uc3QgdGFzayAgICAgICAgICAgICAgPSB0aGlzLl9jcmVhdGVUYXNrKHRlc3RzLCBicm93c2VyU2V0LmJyb3dzZXJDb25uZWN0aW9uR3JvdXBzLCB0aGlzLnByb3h5LCB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9ucygpKTtcbiAgICAgICAgY29uc3QgcmVwb3J0ZXJzICAgICAgICAgPSByZXBvcnRlclBsdWdpbnMubWFwKHJlcG9ydGVyID0+IG5ldyBSZXBvcnRlcihyZXBvcnRlci5wbHVnaW4sIHRhc2ssIHJlcG9ydGVyLm91dFN0cmVhbSkpO1xuICAgICAgICBjb25zdCBjb21wbGV0aW9uUHJvbWlzZSA9IHRoaXMuX2dldFRhc2tSZXN1bHQodGFzaywgYnJvd3NlclNldCwgcmVwb3J0ZXJzLCB0ZXN0ZWRBcHApO1xuXG4gICAgICAgIHRhc2sub24oJ3N0YXJ0Jywgc3RhcnRIYW5kbGluZ1Rlc3RFcnJvcnMpO1xuXG4gICAgICAgIGlmICghdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuc2tpcFVuY2F1Z2h0RXJyb3JzKSkge1xuICAgICAgICAgICAgdGFzay5vbigndGVzdC1ydW4tc3RhcnQnLCBhZGRSdW5uaW5nVGVzdCk7XG4gICAgICAgICAgICB0YXNrLm9uKCd0ZXN0LXJ1bi1kb25lJywgcmVtb3ZlUnVubmluZ1Rlc3QpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGFzay5vbignZG9uZScsIHN0b3BIYW5kbGluZ1Rlc3RFcnJvcnMpO1xuXG4gICAgICAgIGNvbnN0IG9uVGFza0NvbXBsZXRlZCA9ICgpID0+IHtcbiAgICAgICAgICAgIHRhc2sudW5SZWdpc3RlckNsaWVudFNjcmlwdFJvdXRpbmcoKTtcblxuICAgICAgICAgICAgY29tcGxldGVkID0gdHJ1ZTtcbiAgICAgICAgfTtcblxuICAgICAgICBjb21wbGV0aW9uUHJvbWlzZVxuICAgICAgICAgICAgLnRoZW4ob25UYXNrQ29tcGxldGVkKVxuICAgICAgICAgICAgLmNhdGNoKG9uVGFza0NvbXBsZXRlZCk7XG5cbiAgICAgICAgY29uc3QgY2FuY2VsVGFzayA9IGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmICghY29tcGxldGVkKVxuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuX2Rpc3Bvc2VUYXNrQW5kUmVsYXRlZEFzc2V0cyh0YXNrLCBicm93c2VyU2V0LCByZXBvcnRlcnMsIHRlc3RlZEFwcCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmV0dXJuIHsgY29tcGxldGlvblByb21pc2UsIGNhbmNlbFRhc2sgfTtcbiAgICB9XG5cbiAgICBfcmVnaXN0ZXJBc3NldHMgKGFzc2V0cykge1xuICAgICAgICBhc3NldHMuZm9yRWFjaChhc3NldCA9PiB0aGlzLnByb3h5LkdFVChhc3NldC5wYXRoLCBhc3NldC5pbmZvKSk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlRGVidWdMb2dnZXIgKCkge1xuICAgICAgICBjb25zdCBkZWJ1Z0xvZ2dlciA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmRlYnVnTG9nZ2VyKTtcblxuICAgICAgICBjb25zdCBkZWJ1Z0xvZ2dlckRlZmluZWRDb3JyZWN0bHkgPSBkZWJ1Z0xvZ2dlciA9PT0gbnVsbCB8fCAhIWRlYnVnTG9nZ2VyICYmXG4gICAgICAgICAgICBbJ3Nob3dCcmVha3BvaW50JywgJ2hpZGVCcmVha3BvaW50J10uZXZlcnkobWV0aG9kID0+IG1ldGhvZCBpbiBkZWJ1Z0xvZ2dlciAmJiBpc0Z1bmN0aW9uKGRlYnVnTG9nZ2VyW21ldGhvZF0pKTtcblxuICAgICAgICBpZiAoIWRlYnVnTG9nZ2VyRGVmaW5lZENvcnJlY3RseSkge1xuICAgICAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7XG4gICAgICAgICAgICAgICAgW09QVElPTl9OQU1FUy5kZWJ1Z0xvZ2dlcl06IGRlZmF1bHREZWJ1Z0xvZ2dlclxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBfdmFsaWRhdGVTcGVlZE9wdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHNwZWVkID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuc3BlZWQpO1xuXG4gICAgICAgIGlmIChzcGVlZCA9PT0gdm9pZCAwKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGlmICh0eXBlb2Ygc3BlZWQgIT09ICdudW1iZXInIHx8IGlzTmFOKHNwZWVkKSB8fCBzcGVlZCA8IDAuMDEgfHwgc3BlZWQgPiAxKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5pbnZhbGlkU3BlZWRWYWx1ZSk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlQ29uY3VycmVuY3lPcHRpb24gKCkge1xuICAgICAgICBjb25zdCBjb25jdXJyZW5jeSA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmNvbmN1cnJlbmN5KTtcblxuICAgICAgICBpZiAoY29uY3VycmVuY3kgPT09IHZvaWQgMClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBpZiAodHlwZW9mIGNvbmN1cnJlbmN5ICE9PSAnbnVtYmVyJyB8fCBpc05hTihjb25jdXJyZW5jeSkgfHwgY29uY3VycmVuY3kgPCAxKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5pbnZhbGlkQ29uY3VycmVuY3lGYWN0b3IpO1xuICAgIH1cblxuICAgIF92YWxpZGF0ZVByb3h5QnlwYXNzT3B0aW9uICgpIHtcbiAgICAgICAgbGV0IHByb3h5QnlwYXNzID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMucHJveHlCeXBhc3MpO1xuXG4gICAgICAgIGlmIChwcm94eUJ5cGFzcyA9PT0gdm9pZCAwKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGFzc2VydFR5cGUoWyBpcy5zdHJpbmcsIGlzLmFycmF5IF0sIG51bGwsICdcInByb3h5QnlwYXNzXCIgYXJndW1lbnQnLCBwcm94eUJ5cGFzcyk7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBwcm94eUJ5cGFzcyA9PT0gJ3N0cmluZycpXG4gICAgICAgICAgICBwcm94eUJ5cGFzcyA9IFtwcm94eUJ5cGFzc107XG5cbiAgICAgICAgcHJveHlCeXBhc3MgPSBwcm94eUJ5cGFzcy5yZWR1Y2UoKGFyciwgcnVsZXMpID0+IHtcbiAgICAgICAgICAgIGFzc2VydFR5cGUoaXMuc3RyaW5nLCBudWxsLCAnXCJwcm94eUJ5cGFzc1wiIGFyZ3VtZW50JywgcnVsZXMpO1xuXG4gICAgICAgICAgICByZXR1cm4gYXJyLmNvbmNhdChydWxlcy5zcGxpdCgnLCcpKTtcbiAgICAgICAgfSwgW10pO1xuXG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBwcm94eUJ5cGFzcyB9KTtcbiAgICB9XG5cbiAgICBfZ2V0U2NyZWVuc2hvdE9wdGlvbnMgKCkge1xuICAgICAgICBsZXQgeyBwYXRoLCBwYXRoUGF0dGVybiB9ID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuc2NyZWVuc2hvdHMpIHx8IHt9O1xuXG4gICAgICAgIGlmICghcGF0aClcbiAgICAgICAgICAgIHBhdGggPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5zY3JlZW5zaG90UGF0aCk7XG5cbiAgICAgICAgaWYgKCFwYXRoUGF0dGVybilcbiAgICAgICAgICAgIHBhdGhQYXR0ZXJuID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuc2NyZWVuc2hvdFBhdGhQYXR0ZXJuKTtcblxuICAgICAgICByZXR1cm4geyBwYXRoLCBwYXRoUGF0dGVybiB9O1xuICAgIH1cblxuICAgIF92YWxpZGF0ZVNjcmVlbnNob3RPcHRpb25zICgpIHtcbiAgICAgICAgY29uc3QgeyBwYXRoLCBwYXRoUGF0dGVybiB9ID0gdGhpcy5fZ2V0U2NyZWVuc2hvdE9wdGlvbnMoKTtcblxuICAgICAgICBjb25zdCBkaXNhYmxlU2NyZWVuc2hvdHMgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5kaXNhYmxlU2NyZWVuc2hvdHMpIHx8ICFwYXRoO1xuXG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBbT1BUSU9OX05BTUVTLmRpc2FibGVTY3JlZW5zaG90c106IGRpc2FibGVTY3JlZW5zaG90cyB9KTtcblxuICAgICAgICBpZiAoZGlzYWJsZVNjcmVlbnNob3RzKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGlmIChwYXRoKSB7XG4gICAgICAgICAgICB0aGlzLl92YWxpZGF0ZVNjcmVlbnNob3RQYXRoKHBhdGgsICdzY3JlZW5zaG90cyBiYXNlIGRpcmVjdG9yeSBwYXRoJyk7XG5cbiAgICAgICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBbT1BUSU9OX05BTUVTLnNjcmVlbnNob3RzXTogeyBwYXRoOiByZXNvbHZlUGF0aChwYXRoKSB9IH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHBhdGhQYXR0ZXJuKSB7XG4gICAgICAgICAgICB0aGlzLl92YWxpZGF0ZVNjcmVlbnNob3RQYXRoKHBhdGhQYXR0ZXJuLCAnc2NyZWVuc2hvdHMgcGF0aCBwYXR0ZXJuJyk7XG5cbiAgICAgICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBbT1BUSU9OX05BTUVTLnNjcmVlbnNob3RzXTogeyBwYXRoUGF0dGVybiB9IH0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgYXN5bmMgX3ZhbGlkYXRlVmlkZW9PcHRpb25zICgpIHtcbiAgICAgICAgY29uc3QgdmlkZW9QYXRoICAgICAgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy52aWRlb1BhdGgpO1xuICAgICAgICBjb25zdCB2aWRlb0VuY29kaW5nT3B0aW9ucyA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnZpZGVvRW5jb2RpbmdPcHRpb25zKTtcblxuICAgICAgICBsZXQgdmlkZW9PcHRpb25zID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMudmlkZW9PcHRpb25zKTtcblxuICAgICAgICBpZiAoIXZpZGVvUGF0aCkge1xuICAgICAgICAgICAgaWYgKHZpZGVvT3B0aW9ucyB8fCB2aWRlb0VuY29kaW5nT3B0aW9ucylcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdFNldFZpZGVvT3B0aW9uc1dpdGhvdXRCYXNlVmlkZW9QYXRoU3BlY2lmaWVkKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7IFtPUFRJT05fTkFNRVMudmlkZW9QYXRoXTogcmVzb2x2ZVBhdGgodmlkZW9QYXRoKSB9KTtcblxuICAgICAgICBpZiAoIXZpZGVvT3B0aW9ucykge1xuICAgICAgICAgICAgdmlkZW9PcHRpb25zID0ge307XG5cbiAgICAgICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBbT1BUSU9OX05BTUVTLnZpZGVvT3B0aW9uc106IHZpZGVvT3B0aW9ucyB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh2aWRlb09wdGlvbnMuZmZtcGVnUGF0aClcbiAgICAgICAgICAgIHZpZGVvT3B0aW9ucy5mZm1wZWdQYXRoID0gcmVzb2x2ZVBhdGgodmlkZW9PcHRpb25zLmZmbXBlZ1BhdGgpO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICB2aWRlb09wdGlvbnMuZmZtcGVnUGF0aCA9IGF3YWl0IGRldGVjdEZGTVBFRygpO1xuXG4gICAgICAgIGlmICghdmlkZW9PcHRpb25zLmZmbXBlZ1BhdGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdEZpbmRGRk1QRUcpO1xuICAgIH1cblxuICAgIGFzeW5jIF92YWxpZGF0ZVJ1bk9wdGlvbnMgKCkge1xuICAgICAgICB0aGlzLl92YWxpZGF0ZURlYnVnTG9nZ2VyKCk7XG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlU2NyZWVuc2hvdE9wdGlvbnMoKTtcbiAgICAgICAgYXdhaXQgdGhpcy5fdmFsaWRhdGVWaWRlb09wdGlvbnMoKTtcbiAgICAgICAgdGhpcy5fdmFsaWRhdGVTcGVlZE9wdGlvbigpO1xuICAgICAgICB0aGlzLl92YWxpZGF0ZUNvbmN1cnJlbmN5T3B0aW9uKCk7XG4gICAgICAgIHRoaXMuX3ZhbGlkYXRlUHJveHlCeXBhc3NPcHRpb24oKTtcbiAgICB9XG5cbiAgICBfdmFsaWRhdGVUZXN0Rm9yQWxsb3dNdWx0aXBsZVdpbmRvd3NPcHRpb24gKHRlc3RzKSB7XG4gICAgICAgIGlmICh0ZXN0cy5zb21lKHRlc3QgPT4gdGVzdC5pc0xlZ2FjeSkpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdFVzZUFsbG93TXVsdGlwbGVXaW5kb3dzT3B0aW9uRm9yTGVnYWN5VGVzdHMpO1xuICAgIH1cblxuICAgIF92YWxpZGF0ZUJyb3dzZXJzRm9yQWxsb3dNdWx0aXBsZVdpbmRvd3NPcHRpb24gKGJyb3dzZXJTZXQpIHtcbiAgICAgICAgY29uc3QgYnJvd3NlckNvbm5lY3Rpb25zICAgICAgICAgICAgPSBicm93c2VyU2V0LmJyb3dzZXJDb25uZWN0aW9uR3JvdXBzLm1hcChicm93c2VyQ29ubmVjdGlvbkdyb3VwID0+IGJyb3dzZXJDb25uZWN0aW9uR3JvdXBbMF0pO1xuICAgICAgICBjb25zdCB1bnN1cHBvcnRlZEJyb3dzZXJDb25uZWN0aW9ucyA9IGJyb3dzZXJDb25uZWN0aW9ucy5maWx0ZXIoYnJvd3NlckNvbm5lY3Rpb24gPT4gIWJyb3dzZXJDb25uZWN0aW9uLmFjdGl2ZVdpbmRvd0lkKTtcblxuICAgICAgICBpZiAoIXVuc3VwcG9ydGVkQnJvd3NlckNvbm5lY3Rpb25zLmxlbmd0aClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBjb25zdCB1bnN1cHBvcnRlZEJyb3dzZXJBbGlhc2VzID0gdW5zdXBwb3J0ZWRCcm93c2VyQ29ubmVjdGlvbnMubWFwKGJyb3dzZXJDb25uZWN0aW9uID0+IGJyb3dzZXJDb25uZWN0aW9uLmJyb3dzZXJJbmZvLmFsaWFzKTtcbiAgICAgICAgY29uc3QgYnJvd3NlckFsaWFzZXMgICAgICAgICAgICA9IGdldENvbmNhdGVuYXRlZFZhbHVlc1N0cmluZyh1bnN1cHBvcnRlZEJyb3dzZXJBbGlhc2VzKTtcblxuICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmNhbm5vdFVzZUFsbG93TXVsdGlwbGVXaW5kb3dzT3B0aW9uRm9yU29tZUJyb3dzZXJzLCBicm93c2VyQWxpYXNlcyk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlQWxsb3dNdWx0aXBsZVdpbmRvd3NPcHRpb24gKHRlc3RzLCBicm93c2VyU2V0KSB7XG4gICAgICAgIGNvbnN0IGFsbG93TXVsdGlwbGVXaW5kb3dzID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuYWxsb3dNdWx0aXBsZVdpbmRvd3MpO1xuXG4gICAgICAgIGlmICghYWxsb3dNdWx0aXBsZVdpbmRvd3MpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdGhpcy5fdmFsaWRhdGVUZXN0Rm9yQWxsb3dNdWx0aXBsZVdpbmRvd3NPcHRpb24odGVzdHMpO1xuICAgICAgICB0aGlzLl92YWxpZGF0ZUJyb3dzZXJzRm9yQWxsb3dNdWx0aXBsZVdpbmRvd3NPcHRpb24oYnJvd3NlclNldCk7XG4gICAgfVxuXG4gICAgX2NyZWF0ZVJ1bm5hYmxlQ29uZmlndXJhdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmJvb3RzdHJhcHBlclxuICAgICAgICAgICAgLmNyZWF0ZVJ1bm5hYmxlQ29uZmlndXJhdGlvbigpXG4gICAgICAgICAgICAudGhlbihydW5uYWJsZUNvbmZpZ3VyYXRpb24gPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuZW1pdCgnZG9uZS1ib290c3RyYXBwaW5nJyk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcnVubmFibGVDb25maWd1cmF0aW9uO1xuICAgICAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgX3ZhbGlkYXRlU2NyZWVuc2hvdFBhdGggKHNjcmVlbnNob3RQYXRoLCBwYXRoVHlwZSkge1xuICAgICAgICBjb25zdCBmb3JiaWRkZW5DaGFyc0xpc3QgPSBjaGVja0ZpbGVQYXRoKHNjcmVlbnNob3RQYXRoKTtcblxuICAgICAgICBpZiAoZm9yYmlkZGVuQ2hhcnNMaXN0Lmxlbmd0aClcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuZm9yYmlkZGVuQ2hhcmF0ZXJzSW5TY3JlZW5zaG90UGF0aCwgc2NyZWVuc2hvdFBhdGgsIHBhdGhUeXBlLCByZW5kZXJGb3JiaWRkZW5DaGFyc0xpc3QoZm9yYmlkZGVuQ2hhcnNMaXN0KSk7XG4gICAgfVxuXG4gICAgX3NldEJvb3RzdHJhcHBlck9wdGlvbnMgKCkge1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ucHJlcGFyZSgpO1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubm90aWZ5QWJvdXRPdmVycmlkZGVuT3B0aW9ucygpO1xuXG4gICAgICAgIHRoaXMuYm9vdHN0cmFwcGVyLnNvdXJjZXMgICAgICAgICAgICAgID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuc3JjKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5zb3VyY2VzO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5icm93c2VycyAgICAgICAgICAgICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmJyb3dzZXJzKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5icm93c2VycztcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIuY29uY3VycmVuY3kgICAgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5jb25jdXJyZW5jeSk7XG4gICAgICAgIHRoaXMuYm9vdHN0cmFwcGVyLmFwcENvbW1hbmQgICAgICAgICAgID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMuYXBwQ29tbWFuZCkgfHwgdGhpcy5ib290c3RyYXBwZXIuYXBwQ29tbWFuZDtcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIuYXBwSW5pdERlbGF5ICAgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5hcHBJbml0RGVsYXkpO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5maWx0ZXIgICAgICAgICAgICAgICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmZpbHRlcikgfHwgdGhpcy5ib290c3RyYXBwZXIuZmlsdGVyO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5yZXBvcnRlcnMgICAgICAgICAgICA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLnJlcG9ydGVyKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5yZXBvcnRlcnM7XG4gICAgICAgIHRoaXMuYm9vdHN0cmFwcGVyLnRzQ29uZmlnUGF0aCAgICAgICAgID0gdGhpcy5jb25maWd1cmF0aW9uLmdldE9wdGlvbihPUFRJT05fTkFNRVMudHNDb25maWdQYXRoKTtcbiAgICAgICAgdGhpcy5ib290c3RyYXBwZXIuY2xpZW50U2NyaXB0cyAgICAgICAgPSB0aGlzLmNvbmZpZ3VyYXRpb24uZ2V0T3B0aW9uKE9QVElPTl9OQU1FUy5jbGllbnRTY3JpcHRzKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5jbGllbnRTY3JpcHRzO1xuICAgICAgICB0aGlzLmJvb3RzdHJhcHBlci5hbGxvd011bHRpcGxlV2luZG93cyA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRPcHRpb24oT1BUSU9OX05BTUVTLmFsbG93TXVsdGlwbGVXaW5kb3dzKSB8fCB0aGlzLmJvb3RzdHJhcHBlci5hbGxvd011bHRpcGxlV2luZG93cztcbiAgICB9XG5cbiAgICAvLyBBUElcbiAgICBlbWJlZGRpbmdPcHRpb25zIChvcHRzKSB7XG4gICAgICAgIGNvbnN0IHsgYXNzZXRzLCBUZXN0UnVuQ3RvciB9ID0gb3B0cztcblxuICAgICAgICB0aGlzLl9yZWdpc3RlckFzc2V0cyhhc3NldHMpO1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgVGVzdFJ1bkN0b3IgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgc3JjICguLi5zb3VyY2VzKSB7XG4gICAgICAgIGlmICh0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZC5zcmMpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLm11bHRpcGxlQVBJTWV0aG9kQ2FsbEZvcmJpZGRlbiwgT1BUSU9OX05BTUVTLnNyYyk7XG5cbiAgICAgICAgc291cmNlcyA9IHRoaXMuX3ByZXBhcmVBcnJheVBhcmFtZXRlcihzb3VyY2VzKTtcbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7IFtPUFRJT05fTkFNRVMuc3JjXTogc291cmNlcyB9KTtcblxuICAgICAgICB0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZC5zcmMgPSB0cnVlO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGJyb3dzZXJzICguLi5icm93c2Vycykge1xuICAgICAgICBpZiAodGhpcy5hcGlNZXRob2RXYXNDYWxsZWQuYnJvd3NlcnMpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLm11bHRpcGxlQVBJTWV0aG9kQ2FsbEZvcmJpZGRlbiwgT1BUSU9OX05BTUVTLmJyb3dzZXJzKTtcblxuICAgICAgICBicm93c2VycyA9IHRoaXMuX3ByZXBhcmVBcnJheVBhcmFtZXRlcihicm93c2Vycyk7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBicm93c2VycyB9KTtcblxuICAgICAgICB0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZC5icm93c2VycyA9IHRydWU7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgY29uY3VycmVuY3kgKGNvbmN1cnJlbmN5KSB7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBjb25jdXJyZW5jeSB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICByZXBvcnRlciAobmFtZSwgb3V0cHV0KSB7XG4gICAgICAgIGlmICh0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZC5yZXBvcnRlcilcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMubXVsdGlwbGVBUElNZXRob2RDYWxsRm9yYmlkZGVuLCBPUFRJT05fTkFNRVMucmVwb3J0ZXIpO1xuXG4gICAgICAgIGxldCByZXBvcnRlcnMgPSBwcmVwYXJlUmVwb3J0ZXJzKG5hbWUsIG91dHB1dCk7XG5cbiAgICAgICAgcmVwb3J0ZXJzID0gdGhpcy5fcHJlcGFyZUFycmF5UGFyYW1ldGVyKHJlcG9ydGVycyk7XG5cbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7IFtPUFRJT05fTkFNRVMucmVwb3J0ZXJdOiByZXBvcnRlcnMgfSk7XG5cbiAgICAgICAgdGhpcy5hcGlNZXRob2RXYXNDYWxsZWQucmVwb3J0ZXIgPSB0cnVlO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGZpbHRlciAoZmlsdGVyKSB7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoeyBmaWx0ZXIgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgdXNlUHJveHkgKHByb3h5LCBwcm94eUJ5cGFzcykge1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgcHJveHksIHByb3h5QnlwYXNzIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHNjcmVlbnNob3RzICguLi5vcHRpb25zKSB7XG4gICAgICAgIGxldCBmdWxsUGFnZTtcbiAgICAgICAgbGV0IFtwYXRoLCB0YWtlT25GYWlscywgcGF0aFBhdHRlcm5dID0gb3B0aW9ucztcblxuICAgICAgICBpZiAob3B0aW9ucy5sZW5ndGggPT09IDEgJiYgb3B0aW9uc1swXSAmJiB0eXBlb2Ygb3B0aW9uc1swXSA9PT0gJ29iamVjdCcpXG4gICAgICAgICAgICAoeyBwYXRoLCB0YWtlT25GYWlscywgcGF0aFBhdHRlcm4sIGZ1bGxQYWdlIH0gPSBvcHRpb25zWzBdKTtcblxuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKHsgc2NyZWVuc2hvdHM6IHsgcGF0aCwgdGFrZU9uRmFpbHMsIHBhdGhQYXR0ZXJuLCBmdWxsUGFnZSB9IH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIHZpZGVvIChwYXRoLCBvcHRpb25zLCBlbmNvZGluZ09wdGlvbnMpIHtcbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7XG4gICAgICAgICAgICBbT1BUSU9OX05BTUVTLnZpZGVvUGF0aF06ICAgICAgICAgICAgcGF0aCxcbiAgICAgICAgICAgIFtPUFRJT05fTkFNRVMudmlkZW9PcHRpb25zXTogICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgW09QVElPTl9OQU1FUy52aWRlb0VuY29kaW5nT3B0aW9uc106IGVuY29kaW5nT3B0aW9uc1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBzdGFydEFwcCAoY29tbWFuZCwgaW5pdERlbGF5KSB7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoe1xuICAgICAgICAgICAgW09QVElPTl9OQU1FUy5hcHBDb21tYW5kXTogICBjb21tYW5kLFxuICAgICAgICAgICAgW09QVElPTl9OQU1FUy5hcHBJbml0RGVsYXldOiBpbml0RGVsYXlcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgdHNDb25maWdQYXRoIChwYXRoKSB7XG4gICAgICAgIHRoaXMuY29uZmlndXJhdGlvbi5tZXJnZU9wdGlvbnMoe1xuICAgICAgICAgICAgW09QVElPTl9OQU1FUy50c0NvbmZpZ1BhdGhdOiBwYXRoXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIGNsaWVudFNjcmlwdHMgKC4uLnNjcmlwdHMpIHtcbiAgICAgICAgaWYgKHRoaXMuYXBpTWV0aG9kV2FzQ2FsbGVkLmNsaWVudFNjcmlwdHMpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLm11bHRpcGxlQVBJTWV0aG9kQ2FsbEZvcmJpZGRlbiwgT1BUSU9OX05BTUVTLmNsaWVudFNjcmlwdHMpO1xuXG4gICAgICAgIHNjcmlwdHMgPSB0aGlzLl9wcmVwYXJlQXJyYXlQYXJhbWV0ZXIoc2NyaXB0cyk7XG5cbiAgICAgICAgdGhpcy5jb25maWd1cmF0aW9uLm1lcmdlT3B0aW9ucyh7IFtPUFRJT05fTkFNRVMuY2xpZW50U2NyaXB0c106IHNjcmlwdHMgfSk7XG5cbiAgICAgICAgdGhpcy5hcGlNZXRob2RXYXNDYWxsZWQuY2xpZW50U2NyaXB0cyA9IHRydWU7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgYXN5bmMgX3ByZXBhcmVDbGllbnRTY3JpcHRzICh0ZXN0cywgY2xpZW50U2NyaXB0cykge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwodGVzdHMubWFwKGFzeW5jIHRlc3QgPT4ge1xuICAgICAgICAgICAgaWYgKHRlc3QuaXNMZWdhY3kpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgICAgICBsZXQgbG9hZGVkVGVzdENsaWVudFNjcmlwdHMgPSBhd2FpdCBsb2FkQ2xpZW50U2NyaXB0cyh0ZXN0LmNsaWVudFNjcmlwdHMsIGRpcm5hbWUodGVzdC50ZXN0RmlsZS5maWxlbmFtZSkpO1xuXG4gICAgICAgICAgICBsb2FkZWRUZXN0Q2xpZW50U2NyaXB0cyA9IGNsaWVudFNjcmlwdHMuY29uY2F0KGxvYWRlZFRlc3RDbGllbnRTY3JpcHRzKTtcblxuICAgICAgICAgICAgdGVzdC5jbGllbnRTY3JpcHRzID0gc2V0VW5pcXVlVXJscyhsb2FkZWRUZXN0Q2xpZW50U2NyaXB0cyk7XG4gICAgICAgIH0pKTtcbiAgICB9XG5cbiAgICBydW4gKG9wdGlvbnMgPSB7fSkge1xuICAgICAgICB0aGlzLmFwaU1ldGhvZFdhc0NhbGxlZC5yZXNldCgpO1xuICAgICAgICB0aGlzLmNvbmZpZ3VyYXRpb24ubWVyZ2VPcHRpb25zKG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9zZXRCb290c3RyYXBwZXJPcHRpb25zKCk7XG5cbiAgICAgICAgY29uc3QgcnVuVGFza1Byb21pc2UgPSBQcm9taXNlLnJlc29sdmUoKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGhpcy5fdmFsaWRhdGVSdW5PcHRpb25zKCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB0aGlzLl9jcmVhdGVSdW5uYWJsZUNvbmZpZ3VyYXRpb24oKSlcbiAgICAgICAgICAgIC50aGVuKGFzeW5jICh7IHJlcG9ydGVyUGx1Z2lucywgYnJvd3NlclNldCwgdGVzdHMsIHRlc3RlZEFwcCwgY29tbW9uQ2xpZW50U2NyaXB0cyB9KSA9PiB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5fcHJlcGFyZUNsaWVudFNjcmlwdHModGVzdHMsIGNvbW1vbkNsaWVudFNjcmlwdHMpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5fdmFsaWRhdGVBbGxvd011bHRpcGxlV2luZG93c09wdGlvbih0ZXN0cywgYnJvd3NlclNldCk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcnVuVGFzayhyZXBvcnRlclBsdWdpbnMsIGJyb3dzZXJTZXQsIHRlc3RzLCB0ZXN0ZWRBcHApO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXMuX2NyZWF0ZUNhbmNlbGFibGVQcm9taXNlKHJ1blRhc2tQcm9taXNlKTtcbiAgICB9XG5cbiAgICBhc3luYyBzdG9wICgpIHtcbiAgICAgICAgLy8gTk9URTogV2hlbiB0YXNrUHJvbWlzZSBpcyBjYW5jZWxsZWQsIGl0IGlzIHJlbW92ZWQgZnJvbVxuICAgICAgICAvLyB0aGUgcGVuZGluZ1Rhc2tQcm9taXNlcyBhcnJheSwgd2hpY2ggbGVhZHMgdG8gc2hpZnRpbmcgaW5kZXhlc1xuICAgICAgICAvLyB0b3dhcmRzIHRoZSBiZWdpbm5pbmcuIFNvLCB3ZSBtdXN0IGNvcHkgdGhlIGFycmF5IGluIG9yZGVyIHRvIGl0ZXJhdGUgaXQsXG4gICAgICAgIC8vIG9yIHdlIGNhbiBwZXJmb3JtIGl0ZXJhdGlvbiBmcm9tIHRoZSBlbmQgdG8gdGhlIGJlZ2lubmluZy5cbiAgICAgICAgY29uc3QgY2FuY2VsbGF0aW9uUHJvbWlzZXMgPSBtYXBSZXZlcnNlKHRoaXMucGVuZGluZ1Rhc2tQcm9taXNlcywgdGFza1Byb21pc2UgPT4gdGFza1Byb21pc2UuY2FuY2VsKCkpO1xuXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKGNhbmNlbGxhdGlvblByb21pc2VzKTtcbiAgICB9XG59XG4iXX0=
\No newline at end of file