UNPKG

44.3 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 = __importDefault(require("path"));
7const fs_1 = __importDefault(require("fs"));
8const is_ci_1 = __importDefault(require("is-ci"));
9const lodash_1 = require("lodash");
10const make_dir_1 = __importDefault(require("make-dir"));
11const os_family_1 = __importDefault(require("os-family"));
12const testcafe_browser_tools_1 = require("testcafe-browser-tools");
13const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
14const compiler_1 = __importDefault(require("../compiler"));
15const connection_1 = __importDefault(require("../browser/connection"));
16const pool_1 = __importDefault(require("../browser/provider/pool"));
17const browser_set_1 = __importDefault(require("./browser-set"));
18const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
19const runtime_1 = require("../errors/runtime");
20const types_1 = require("../errors/types");
21const tested_app_1 = __importDefault(require("./tested-app"));
22const parse_file_list_1 = __importDefault(require("../utils/parse-file-list"));
23const resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd"));
24const load_1 = __importDefault(require("../custom-client-scripts/load"));
25function isReporterPluginFactory(value) {
26 return typeof value === 'function';
27}
28function isPromiseError(value) {
29 return value.error !== void 0;
30}
31class Bootstrapper {
32 constructor(browserConnectionGateway) {
33 this.browserConnectionGateway = browserConnectionGateway;
34 this.concurrency = 1;
35 this.sources = [];
36 this.browsers = [];
37 this.reporters = [];
38 this.filter = void 0;
39 this.appCommand = void 0;
40 this.appInitDelay = void 0;
41 this.tsConfigPath = void 0;
42 this.clientScripts = [];
43 this.allowMultipleWindows = false;
44 }
45 static _getBrowserName(browser) {
46 if (browser instanceof connection_1.default)
47 return browser.browserInfo.browserName;
48 return browser.browserName;
49 }
50 static _splitBrowserInfo(browserInfo) {
51 const remotes = [];
52 const automated = [];
53 browserInfo.forEach(browser => {
54 if (browser instanceof connection_1.default)
55 remotes.push(browser);
56 else
57 automated.push(browser);
58 });
59 return { remotes, automated };
60 }
61 static async _hasLocalBrowsers(browserInfo) {
62 for (const browser of browserInfo) {
63 if (browser instanceof connection_1.default)
64 continue;
65 if (await browser.provider.isLocalBrowser(void 0, browser.browserName))
66 return true;
67 }
68 return false;
69 }
70 static async _checkRequiredPermissions(browserInfo) {
71 const hasLocalBrowsers = await Bootstrapper._hasLocalBrowsers(browserInfo);
72 const { error } = await authentication_helper_1.default(() => testcafe_browser_tools_1.findWindow(''), testcafe_browser_tools_1.errors.UnableToAccessScreenRecordingAPIError, {
73 interactive: hasLocalBrowsers && !is_ci_1.default
74 });
75 if (!error)
76 return;
77 if (hasLocalBrowsers)
78 throw error;
79 remote_1.default.canDetectLocalBrowsers = false;
80 }
81 async _getBrowserInfo() {
82 if (!this.browsers.length)
83 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.browserNotSet);
84 const browserInfo = await Promise.all(this.browsers.map(browser => pool_1.default.getBrowserInfo(browser)));
85 return lodash_1.flatten(browserInfo);
86 }
87 _createAutomatedConnections(browserInfo) {
88 if (!browserInfo)
89 return [];
90 return browserInfo
91 .map(browser => lodash_1.times(this.concurrency, () => new connection_1.default(this.browserConnectionGateway, browser, false, this.allowMultipleWindows)));
92 }
93 async _getBrowserConnections(browserInfo) {
94 const { automated, remotes } = Bootstrapper._splitBrowserInfo(browserInfo);
95 if (remotes && remotes.length % this.concurrency)
96 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotDivideRemotesCountByConcurrency);
97 let browserConnections = this._createAutomatedConnections(automated);
98 browserConnections = browserConnections.concat(lodash_1.chunk(remotes, this.concurrency));
99 return await browser_set_1.default.from(browserConnections);
100 }
101 _filterTests(tests, predicate) {
102 return tests.filter(test => predicate(test.name, test.fixture.name, test.fixture.path, test.meta, test.fixture.meta));
103 }
104 async _getTests() {
105 const { parsedFileList, compilerOptions } = await this._getCompilerArguments();
106 if (!parsedFileList.length)
107 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.testFilesNotFound);
108 const compiler = new compiler_1.default(parsedFileList, compilerOptions);
109 let tests = await compiler.getTests();
110 const testsWithOnlyFlag = tests.filter(test => test.only);
111 if (testsWithOnlyFlag.length)
112 tests = testsWithOnlyFlag;
113 if (this.filter)
114 tests = this._filterTests(tests, this.filter);
115 if (!tests.length)
116 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.noTestsToRun);
117 return tests;
118 }
119 async _getCompilerArguments() {
120 const parsedFileList = await parse_file_list_1.default(this.sources, process.cwd());
121 const compilerOptions = {
122 typeScriptOptions: {
123 tsConfigPath: this.tsConfigPath
124 }
125 };
126 return { parsedFileList, compilerOptions };
127 }
128 async _ensureOutStream(outStream) {
129 if (typeof outStream !== 'string')
130 return outStream;
131 const fullReporterOutputPath = resolve_path_relatively_cwd_1.default(outStream);
132 await make_dir_1.default(path_1.default.dirname(fullReporterOutputPath));
133 return fs_1.default.createWriteStream(fullReporterOutputPath);
134 }
135 static _addDefaultReporter(reporters) {
136 reporters.push({
137 name: 'spec',
138 output: process.stdout
139 });
140 }
141 _requireReporterPluginFactory(reporterName) {
142 try {
143 return require('testcafe-reporter-' + reporterName);
144 }
145 catch (err) {
146 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.cannotFindReporterForAlias, reporterName);
147 }
148 }
149 _getPluginFactory(reporterFactorySource) {
150 if (!isReporterPluginFactory(reporterFactorySource))
151 return this._requireReporterPluginFactory(reporterFactorySource);
152 return reporterFactorySource;
153 }
154 async _getReporterPlugins() {
155 const stdoutReporters = lodash_1.filter(this.reporters, r => lodash_1.isUndefined(r.output) || r.output === process.stdout);
156 if (stdoutReporters.length > 1)
157 throw new runtime_1.GeneralError(types_1.RUNTIME_ERRORS.multipleStdoutReporters, stdoutReporters.map(r => r.name).join(', '));
158 if (!this.reporters.length)
159 Bootstrapper._addDefaultReporter(this.reporters);
160 return Promise.all(this.reporters.map(async ({ name, output }) => {
161 const pluginFactory = this._getPluginFactory(name);
162 const outStream = output ? await this._ensureOutStream(output) : void 0;
163 return {
164 plugin: pluginFactory(),
165 outStream
166 };
167 }));
168 }
169 async _startTestedApp() {
170 if (!this.appCommand)
171 return void 0;
172 const testedApp = new tested_app_1.default();
173 await testedApp.start(this.appCommand, this.appInitDelay);
174 return testedApp;
175 }
176 async _canUseParallelBootstrapping(browserInfo) {
177 const isLocalPromises = browserInfo.map(browser => browser.provider.isLocalBrowser(void 0, Bootstrapper._getBrowserName(browser)));
178 const isLocalBrowsers = await Promise.all(isLocalPromises);
179 return isLocalBrowsers.every(result => result);
180 }
181 async _bootstrapSequence(browserInfo) {
182 const tests = await this._getTests();
183 const testedApp = await this._startTestedApp();
184 const browserSet = await this._getBrowserConnections(browserInfo);
185 return { tests, testedApp, browserSet };
186 }
187 _wrapBootstrappingPromise(promise) {
188 return promise
189 .then(result => ({ error: void 0, result }))
190 .catch(error => ({ result: void 0, error }));
191 }
192 async _getBootstrappingError(browserSetStatus, testsStatus, testedAppStatus) {
193 if (!isPromiseError(browserSetStatus))
194 await browserSetStatus.result.dispose();
195 if (!isPromiseError(browserSetStatus) && !isPromiseError(testedAppStatus) && testedAppStatus.result)
196 await testedAppStatus.result.kill();
197 if (isPromiseError(testsStatus))
198 return testsStatus.error;
199 if (isPromiseError(testedAppStatus))
200 return testedAppStatus.error;
201 if (isPromiseError(browserSetStatus))
202 return browserSetStatus.error;
203 return new Error('Unexpected call');
204 }
205 _getBootstrappingPromises(arg) {
206 const result = {};
207 for (const k in arg)
208 result[k] = this._wrapBootstrappingPromise(arg[k]);
209 return result;
210 }
211 async _bootstrapParallel(browserInfo) {
212 const bootstrappingPromises = {
213 browserSet: this._getBrowserConnections(browserInfo),
214 tests: this._getTests(),
215 app: this._startTestedApp()
216 };
217 const bootstrappingResultPromises = this._getBootstrappingPromises(bootstrappingPromises);
218 const bootstrappingResults = await Promise.all([
219 bootstrappingResultPromises.browserSet,
220 bootstrappingResultPromises.tests,
221 bootstrappingResultPromises.app
222 ]);
223 const [browserSetResults, testResults, appResults] = bootstrappingResults;
224 if (isPromiseError(browserSetResults) || isPromiseError(testResults) || isPromiseError(appResults))
225 throw await this._getBootstrappingError(...bootstrappingResults);
226 return {
227 browserSet: browserSetResults.result,
228 tests: testResults.result,
229 testedApp: appResults.result
230 };
231 }
232 // API
233 async createRunnableConfiguration() {
234 const reporterPlugins = await this._getReporterPlugins();
235 const commonClientScripts = await load_1.default(this.clientScripts);
236 // NOTE: If a user forgot to specify a browser, but has specified a path to tests, the specified path will be
237 // considered as the browser argument, and the tests path argument will have the predefined default value.
238 // It's very ambiguous for the user, who might be confused by compilation errors from an unexpected test.
239 // So, we need to retrieve the browser aliases and paths before tests compilation.
240 const browserInfo = await this._getBrowserInfo();
241 if (os_family_1.default.mac)
242 await Bootstrapper._checkRequiredPermissions(browserInfo);
243 if (await this._canUseParallelBootstrapping(browserInfo))
244 return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapParallel(browserInfo)), { commonClientScripts });
245 return Object.assign(Object.assign({ reporterPlugins }, await this._bootstrapSequence(browserInfo)), { commonClientScripts });
246 }
247}
248exports.default = Bootstrapper;
249module.exports = exports.default;
250//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwcGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3J1bm5lci9ib290c3RyYXBwZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxnREFBd0I7QUFDeEIsNENBQW9CO0FBQ3BCLGtEQUF5QjtBQUN6QixtQ0FBb0U7QUFDcEUsd0RBQStCO0FBQy9CLDBEQUEyQjtBQUMzQixtRUFBNEQ7QUFDNUQseUZBQWdFO0FBQ2hFLDJEQUFtQztBQUNuQyx1RUFBc0Q7QUFDdEQsb0VBQTJEO0FBQzNELGdFQUF1QztBQUN2QyxpRkFBd0U7QUFDeEUsK0NBQWlEO0FBQ2pELDJDQUFpRDtBQUNqRCw4REFBcUM7QUFDckMsK0VBQXFEO0FBQ3JELHVHQUE0RTtBQUM1RSx5RUFBOEQ7QUFxQzlELFNBQVMsdUJBQXVCLENBQUUsS0FBd0I7SUFDdEQsT0FBTyxPQUFPLEtBQUssS0FBSyxVQUFVLENBQUM7QUFDdkMsQ0FBQztBQWdERCxTQUFTLGNBQWMsQ0FBOEIsS0FBMEI7SUFDM0UsT0FBUSxLQUF5QixDQUFDLEtBQUssS0FBSyxLQUFLLENBQUMsQ0FBQztBQUN2RCxDQUFDO0FBYUQsTUFBcUIsWUFBWTtJQWM3QixZQUFvQix3QkFBa0Q7UUFDbEUsSUFBSSxDQUFDLHdCQUF3QixHQUFHLHdCQUF3QixDQUFDO1FBQ3pELElBQUksQ0FBQyxXQUFXLEdBQWdCLENBQUMsQ0FBQztRQUNsQyxJQUFJLENBQUMsT0FBTyxHQUFvQixFQUFFLENBQUM7UUFDbkMsSUFBSSxDQUFDLFFBQVEsR0FBbUIsRUFBRSxDQUFDO1FBQ25DLElBQUksQ0FBQyxTQUFTLEdBQWtCLEVBQUUsQ0FBQztRQUNuQyxJQUFJLENBQUMsTUFBTSxHQUFxQixLQUFLLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsVUFBVSxHQUFpQixLQUFLLENBQUMsQ0FBQztRQUN2QyxJQUFJLENBQUMsWUFBWSxHQUFlLEtBQUssQ0FBQyxDQUFDO1FBQ3ZDLElBQUksQ0FB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LFVBQVUsQ0FBQztZQUM5RixNQUFNLE1BQU0sSUFBSSxDQUFDLHNCQUFzQixDQUFDLEdBQUcsb0JBQW9CLENBQUMsQ0FBQztRQUVyRSxPQUFPO1lBQ0gsVUFBVSxFQUFFLGlCQUFpQixDQUFDLE1BQU07WUFDcEMsS0FBSyxFQUFPLFdBQVcsQ0FBQyxNQUFNO1lBQzlCLFNBQVMsRUFBRyxVQUFVLENBQUMsTUFBTTtTQUNoQyxDQUFDO0lBQ04sQ0FBQztJQUVELE1BQU07SUFDQyxLQUFLLENBQUMsMkJBQTJCO1FBQ3BDLE1BQU0sZUFBZSxHQUFPLE1BQU0sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7UUFDN0QsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLGNBQWlCLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBRXhFLDZHQUE2RztRQUM3RywwR0FBMEc7UUFDMUcseUdBQXlHO1FBQ3pHLGtGQUFrRjtRQUNsRixNQUFNLFdBQVcsR0FBRyxNQUFNLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUVqRCxJQUFJLG1CQUFFLENBQUMsR0FBRztZQUNOLE1BQU0sWUFBWSxDQUFDLHlCQUF5QixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBRTlELElBQUksTUFBTSxJQUFJLENBQUMsNEJBQTRCLENBQUMsV0FBVyxDQUFDO1lBQ3BELHFDQUFTLGVBQWUsSUFBSyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsS0FBRSxtQkFBbUIsSUFBRztRQUVuRyxxQ0FBUyxlQUFlLElBQUssTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsV0FBVyxDQUFDLEtBQUUsbUJBQW1CLElBQUc7SUFDbkcsQ0FBQztDQUNKO0FBdFRELCtCQXNUQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCBpc0NJIGZyb20gJ2lzLWNpJztcbmltcG9ydCB7IGlzVW5kZWZpbmVkLCBmaWx0ZXIsIGZsYXR0ZW4sIGNodW5rLCB0aW1lcyB9IGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgbWFrZURpciBmcm9tICdtYWtlLWRpcic7XG5pbXBvcnQgT1MgZnJvbSAnb3MtZmFtaWx5JztcbmltcG9ydCB7IGVycm9ycywgZmluZFdpbmRvdyB9IGZyb20gJ3Rlc3RjYWZlLWJyb3dzZXItdG9vbHMnO1xuaW1wb3J0IGF1dGhlbnRpY2F0aW9uSGVscGVyIGZyb20gJy4uL2NsaS9hdXRoZW50aWNhdGlvbi1oZWxwZXInO1xuaW1wb3J0IENvbXBpbGVyIGZyb20gJy4uL2NvbXBpbGVyJztcbmltcG9ydCBCcm93c2VyQ29ubmVjdGlvbiBmcm9tICcuLi9icm93c2VyL2Nvbm5lY3Rpb24nO1xuaW1wb3J0IGJyb3dzZXJQcm92aWRlclBvb2wgZnJvbSAnLi4vYnJvd3Nlci9wcm92aWRlci9wb29sJztcbmltcG9ydCBCcm93c2VyU2V0IGZyb20gJy4vYnJvd3Nlci1zZXQnO1xuaW1wb3J0IFJlbW90ZUJyb3dzZXJQcm92aWRlciBmcm9tICcuLi9icm93c2VyL3Byb3ZpZGVyL2J1aWx0LWluL3JlbW90ZSc7XG5pbXBvcnQgeyBHZW5lcmFsRXJyb3IgfSBmcm9tICcuLi9lcnJvcnMvcnVudGltZSc7XG5pbXBvcnQgeyBSVU5USU1FX0VSUk9SUyB9IGZyb20gJy4uL2Vycm9ycy90eXBlcyc7XG5pbXBvcnQgVGVzdGVkQXBwIGZyb20gJy4vdGVzdGVkLWFwcCc7XG5pbXBvcnQgcGFyc2VGaWxlTGlzdCBmcm9tICcuLi91dGlscy9wYXJzZS1maWxlLWxpc3QnO1xuaW1wb3J0IHJlc29sdmVQYXRoUmVsYXRpdmVseUN3ZCBmcm9tICcuLi91dGlscy9yZXNvbHZlLXBhdGgtcmVsYXRpdmVseS1jd2QnO1xuaW1wb3J0IGxvYWRDbGllbnRTY3JpcHRzIGZyb20gJy4uL2N1c3RvbS1jbGllbnQtc2NyaXB0cy9sb2FkJztcblxuaW1wb3J0IHsgV3JpdGFibGUgYXMgV3JpdGFibGVTdHJlYW0gfSBmcm9tICdzdHJlYW0nO1xuaW1wb3J0IENsaWVudFNjcmlwdCBmcm9tICcuLi9jdXN0b20tY2xpZW50LXNjcmlwdHMvY2xpZW50LXNjcmlwdCc7XG5pbXBvcnQgQ2xpZW50U2NyaXB0SW5pdCBmcm9tICcuLi9jdXN0b20tY2xpZW50LXNjcmlwdHMvY2xpZW50LXNjcmlwdC1pbml0JztcbmltcG9ydCBCcm93c2VyUHJvdmlkZXIgZnJvbSAnLi4vYnJvd3Nlci9wcm92aWRlcic7XG5pbXBvcnQgQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5IGZyb20gJy4uL2Jyb3dzZXIvY29ubmVjdGlvbi9nYXRld2F5JztcblxudHlwZSBUZXN0U291cmNlID0gdW5rbm93bjtcblxudHlwZSBSZXBvcnRlclBsdWdpbiA9IHVua25vd247XG5cbmludGVyZmFjZSBDb21waWxlckFyZ3VtZW50cyB7XG4gICAgcGFyc2VkRmlsZUxpc3Q6IHN0cmluZ1tdO1xuICAgIGNvbXBpbGVyT3B0aW9uczogb2JqZWN0O1xufVxuXG5pbnRlcmZhY2UgTWV0YWRhdGEge1xuICAgIFtrZXk6IHN0cmluZ106IHN0cmluZztcbn1cblxudHlwZSBCcm93c2VyU291cmNlID0gQnJvd3NlckNvbm5lY3Rpb24gfCBzdHJpbmc7XG5cbmludGVyZmFjZSBSZXBvcnRlclNvdXJjZSB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIG91dHB1dD86IHN0cmluZyB8IFdyaXRhYmxlU3RyZWFtO1xufVxuXG5pbnRlcmZhY2UgUmVwb3J0ZXJQbHVnaW5Tb3VyY2Uge1xuICAgIHBsdWdpbjogUmVwb3J0ZXJQbHVnaW47XG4gICAgb3V0U3RyZWFtPzogV3JpdGFibGVTdHJlYW07XG59XG5cbmludGVyZmFjZSBSZXBvcnRlclBsdWdpbkZhY3Rvcnkge1xuICAgICgpOiBSZXBvcnRlclBsdWdpbjtcbn1cblxuZnVuY3Rpb24gaXNSZXBvcnRlclBsdWdpbkZhY3RvcnkgKHZhbHVlOiBzdHJpbmcgfCBGdW5jdGlvbik6IHZhbHVlIGlzIFJlcG9ydGVyUGx1Z2luRmFjdG9yeSB7XG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJztcbn1cblxuaW50ZXJmYWNlIEZpbHRlciB7XG4gICAgKHRlc3ROYW1lOiBzdHJpbmcsIGZpeHR1cmVOYW1lOiBzdHJpbmcsIGZpeHR1cmVQYXRoOiBzdHJpbmcsIHRlc3RNZXRhOiBNZXRhZGF0YSwgZml4dHVyZU1ldGE6IE1ldGFkYXRhKTogYm9vbGVhbjtcbn1cblxuaW50ZXJmYWNlIEJyb3dzZXJJbmZvIHtcbiAgICBicm93c2VyTmFtZTogc3RyaW5nO1xuICAgIHByb3ZpZGVyTmFtZTogc3RyaW5nO1xuICAgIHByb3ZpZGVyOiBCcm93c2VyUHJvdmlkZXI7XG59XG5cbnR5cGUgQnJvd3NlckluZm9Tb3VyY2UgPSBCcm93c2VySW5mbyB8IEJyb3dzZXJDb25uZWN0aW9uO1xuXG5cbmludGVyZmFjZSBGaXh0dXJlIHtcbiAgICBuYW1lOiBzdHJpbmc7XG4gICAgcGF0aDogc3RyaW5nO1xuICAgIG1ldGE6IE1ldGFkYXRhO1xufVxuXG5pbnRlcmZhY2UgVGVzdCB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIGZpeHR1cmU6IEZpeHR1cmU7XG4gICAgbWV0YTogTWV0YWRhdGE7XG59XG5cbmludGVyZmFjZSBQcm9taXNlU3VjY2VzczxUPiB7XG4gICAgcmVzdWx0OiBUO1xufVxuXG5pbnRlcmZhY2UgUHJvbWlzZUVycm9yPEUgZXh0ZW5kcyBFcnJvciA9IEVycm9yPiB7XG4gICAgZXJyb3I6IEU7XG59XG5cbmludGVyZmFjZSBCYXNpY1J1bnRpbWVSZXNvdXJjZXMge1xuICAgIGJyb3dzZXJTZXQ6IEJyb3dzZXJTZXQ7XG4gICAgdGVzdHM6IFRlc3RbXTtcbiAgICB0ZXN0ZWRBcHA/OiBUZXN0ZWRBcHA7XG59XG5cbmludGVyZmFjZSBSdW50aW1lUmVzb3VyY2VzIGV4dGVuZHMgQmFzaWNSdW50aW1lUmVzb3VyY2VzIHtcbiAgICByZXBvcnRlclBsdWdpbnM6IFJlcG9ydGVyUGx1Z2luU291cmNlW107XG4gICAgY29tbW9uQ2xpZW50U2NyaXB0czogQ2xpZW50U2NyaXB0W107XG59XG5cbnR5cGUgUHJvbWlzZVJlc3VsdDxULCBFIGV4dGVuZHMgRXJyb3IgPSBFcnJvcj4gPSBQcm9taXNlU3VjY2VzczxUPiB8IFByb21pc2VFcnJvcjxFPjtcblxuZnVuY3Rpb24gaXNQcm9taXNlRXJyb3I8VCwgRSBleHRlbmRzIEVycm9yID0gRXJyb3I+ICh2YWx1ZTogUHJvbWlzZVJlc3VsdDxULCBFPik6IHZhbHVlIGlzIFByb21pc2VFcnJvcjxFPiB7XG4gICAgcmV0dXJuICh2YWx1ZSBhcyBQcm9taXNlRXJyb3I8RT4pLmVycm9yICE9PSB2b2lkIDA7XG59XG5cbmludGVyZmFjZSBTZXBhcmF0ZWRCcm93c2VySW5mbyB7XG4gICAgcmVtb3RlczogQnJvd3NlckNvbm5lY3Rpb25bXTtcbiAgICBhdXRvbWF0ZWQ6IEJyb3dzZXJJbmZvW107XG59XG5cbnR5cGUgUHJvbWlzZUNvbGxlY3Rpb248VD4gPSB7XG4gICAgW0sgaW4ga2V5b2YgVF06IFByb21pc2U8VFtLXT5cbn1cblxudHlwZSBSZXN1bHRDb2xsZWN0aW9uPFQ+ID0geyBbUCBpbiBrZXlvZiBUXTogUHJvbWlzZVJlc3VsdDxUW1BdPiB9O1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCb290c3RyYXBwZXIge1xuICAgIHByaXZhdGUgcmVhZG9ubHkgYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5OiBCcm93c2VyQ29ubmVjdGlvbkdhdGV3YXk7XG5cbiAgICBwdWJsaWMgY29uY3VycmVuY3k6IG51bWJlcjtcbiAgICBwdWJsaWMgc291cmNlczogVGVzdFNvdXJjZVtdO1xuICAgIHB1YmxpYyBicm93c2VyczogQnJvd3NlclNvdXJjZVtdO1xuICAgIHB1YmxpYyByZXBvcnRlcnM6IFJlcG9ydGVyU291cmNlW107XG4gICAgcHVibGljIGZpbHRlcj86IEZpbHRlcjtcbiAgICBwdWJsaWMgYXBwQ29tbWFuZD86IHN0cmluZztcbiAgICBwdWJsaWMgYXBwSW5pdERlbGF5PzogbnVtYmVyO1xuICAgIHB1YmxpYyB0c0NvbmZpZ1BhdGg/OiBzdHJpbmc7XG4gICAgcHVibGljIGNsaWVudFNjcmlwdHM6IENsaWVudFNjcmlwdEluaXRbXTtcbiAgICBwdWJsaWMgYWxsb3dNdWx0aXBsZVdpbmRvd3M6IGJvb2xlYW47XG5cbiAgICBwdWJsaWMgY29uc3RydWN0b3IgKGJyb3dzZXJDb25uZWN0aW9uR2F0ZXdheTogQnJvd3NlckNvbm5lY3Rpb25HYXRld2F5KSB7XG4gICAgICAgIHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5ID0gYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5O1xuICAgICAgICB0aGlzLmNvbmN1cnJlbmN5ICAgICAgICAgICAgICA9IDE7XG4gICAgICAgIHRoaXMuc291cmNlcyAgICAgICAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuYnJvd3NlcnMgICAgICAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMucmVwb3J0ZXJzICAgICAgICAgICAgICAgID0gW107XG4gICAgICAgIHRoaXMuZmlsdGVyICAgICAgICAgICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLmFwcENvbW1hbmQgICAgICAgICAgICAgICA9IHZvaWQgMDtcbiAgICAgICAgdGhpcy5hcHBJbml0RGVsYXkgICAgICAgICAgICAgPSB2b2lkIDA7XG4gICAgICAgIHRoaXMudHNDb25maWdQYXRoICAgICAgICAgICAgID0gdm9pZCAwO1xuICAgICAgICB0aGlzLmNsaWVudFNjcmlwdHMgICAgICAgICAgICA9IFtdO1xuICAgICAgICB0aGlzLmFsbG93TXVsdGlwbGVXaW5kb3dzICAgICA9IGZhbHNlO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9nZXRCcm93c2VyTmFtZSAoYnJvd3NlcjogQnJvd3NlckluZm9Tb3VyY2UpOiBzdHJpbmcge1xuICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgcmV0dXJuIGJyb3dzZXIuYnJvd3NlckluZm8uYnJvd3Nlck5hbWU7XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXIuYnJvd3Nlck5hbWU7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgX3NwbGl0QnJvd3NlckluZm8gKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogU2VwYXJhdGVkQnJvd3NlckluZm8ge1xuICAgICAgICBjb25zdCByZW1vdGVzOiBCcm93c2VyQ29ubmVjdGlvbltdICA9IFtdO1xuICAgICAgICBjb25zdCBhdXRvbWF0ZWQ6IEJyb3dzZXJJbmZvW10gICAgICA9IFtdO1xuXG4gICAgICAgIGJyb3dzZXJJbmZvLmZvckVhY2goYnJvd3NlciA9PiB7XG4gICAgICAgICAgICBpZiAoYnJvd3NlciBpbnN0YW5jZW9mIEJyb3dzZXJDb25uZWN0aW9uKVxuICAgICAgICAgICAgICAgIHJlbW90ZXMucHVzaChicm93c2VyKTtcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBhdXRvbWF0ZWQucHVzaChicm93c2VyKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHsgcmVtb3RlcywgYXV0b21hdGVkIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBzdGF0aWMgYXN5bmMgX2hhc0xvY2FsQnJvd3NlcnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGZvciAoY29uc3QgYnJvd3NlciBvZiBicm93c2VySW5mbykge1xuICAgICAgICAgICAgaWYgKGJyb3dzZXIgaW5zdGFuY2VvZiBCcm93c2VyQ29ubmVjdGlvbilcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgaWYgKGF3YWl0IGJyb3dzZXIucHJvdmlkZXIuaXNMb2NhbEJyb3dzZXIodm9pZCAwLCBicm93c2VyLmJyb3dzZXJOYW1lKSlcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBhc3luYyBfY2hlY2tSZXF1aXJlZFBlcm1pc3Npb25zIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICBjb25zdCBoYXNMb2NhbEJyb3dzZXJzID0gYXdhaXQgQm9vdHN0cmFwcGVyLl9oYXNMb2NhbEJyb3dzZXJzKGJyb3dzZXJJbmZvKTtcblxuICAgICAgICBjb25zdCB7IGVycm9yIH0gPSBhd2FpdCBhdXRoZW50aWNhdGlvbkhlbHBlcihcbiAgICAgICAgICAgICgpID0+IGZpbmRXaW5kb3coJycpLFxuICAgICAgICAgICAgZXJyb3JzLlVuYWJsZVRvQWNjZXNzU2NyZWVuUmVjb3JkaW5nQVBJRXJyb3IsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaW50ZXJhY3RpdmU6IGhhc0xvY2FsQnJvd3NlcnMgJiYgIWlzQ0lcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoIWVycm9yKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIGlmIChoYXNMb2NhbEJyb3dzZXJzKVxuICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG5cbiAgICAgICAgUmVtb3RlQnJvd3NlclByb3ZpZGVyLmNhbkRldGVjdExvY2FsQnJvd3NlcnMgPSBmYWxzZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRCcm93c2VySW5mbyAoKTogUHJvbWlzZTxCcm93c2VySW5mb1NvdXJjZVtdPiB7XG4gICAgICAgIGlmICghdGhpcy5icm93c2Vycy5sZW5ndGgpXG4gICAgICAgICAgICB0aHJvdyBuZXcgR2VuZXJhbEVycm9yKFJVTlRJTUVfRVJST1JTLmJyb3dzZXJOb3RTZXQpO1xuXG4gICAgICAgIGNvbnN0IGJyb3dzZXJJbmZvID0gYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5icm93c2Vycy5tYXAoYnJvd3NlciA9PiBicm93c2VyUHJvdmlkZXJQb29sLmdldEJyb3dzZXJJbmZvKGJyb3dzZXIpKSk7XG5cbiAgICAgICAgcmV0dXJuIGZsYXR0ZW4oYnJvd3NlckluZm8pO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zIChicm93c2VySW5mbzogQnJvd3NlckluZm9bXSk6IEJyb3dzZXJDb25uZWN0aW9uW11bXSB7XG4gICAgICAgIGlmICghYnJvd3NlckluZm8pXG4gICAgICAgICAgICByZXR1cm4gW107XG5cbiAgICAgICAgcmV0dXJuIGJyb3dzZXJJbmZvXG4gICAgICAgICAgICAubWFwKGJyb3dzZXIgPT4gdGltZXModGhpcy5jb25jdXJyZW5jeSwgKCkgPT4gbmV3IEJyb3dzZXJDb25uZWN0aW9uKHRoaXMuYnJvd3NlckNvbm5lY3Rpb25HYXRld2F5LCBicm93c2VyLCBmYWxzZSwgdGhpcy5hbGxvd011bHRpcGxlV2luZG93cykpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRCcm93c2VyQ29ubmVjdGlvbnMgKGJyb3dzZXJJbmZvOiBCcm93c2VySW5mb1NvdXJjZVtdKTogUHJvbWlzZTxCcm93c2VyU2V0PiB7XG4gICAgICAgIGNvbnN0IHsgYXV0b21hdGVkLCByZW1vdGVzIH0gPSBCb290c3RyYXBwZXIuX3NwbGl0QnJvd3NlckluZm8oYnJvd3NlckluZm8pO1xuXG4gICAgICAgIGlmIChyZW1vdGVzICYmIHJlbW90ZXMubGVuZ3RoICUgdGhpcy5jb25jdXJyZW5jeSlcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RGl2aWRlUmVtb3Rlc0NvdW50QnlDb25jdXJyZW5jeSk7XG5cbiAgICAgICAgbGV0IGJyb3dzZXJDb25uZWN0aW9ucyA9IHRoaXMuX2NyZWF0ZUF1dG9tYXRlZENvbm5lY3Rpb25zKGF1dG9tYXRlZCk7XG5cbiAgICAgICAgYnJvd3NlckNvbm5lY3Rpb25zID0gYnJvd3NlckNvbm5lY3Rpb25zLmNvbmNhdChjaHVuayhyZW1vdGVzLCB0aGlzLmNvbmN1cnJlbmN5KSk7XG5cbiAgICAgICAgcmV0dXJuIGF3YWl0IEJyb3dzZXJTZXQuZnJvbShicm93c2VyQ29ubmVjdGlvbnMpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2ZpbHRlclRlc3RzICh0ZXN0czogVGVzdFtdLCBwcmVkaWNhdGU6IEZpbHRlcik6IFRlc3RbXSB7XG4gICAgICAgIHJldHVybiB0ZXN0cy5maWx0ZXIodGVzdCA9PiBwcmVkaWNhdGUodGVzdC5uYW1lLCB0ZXN0LmZpeHR1cmUubmFtZSwgdGVzdC5maXh0dXJlLnBhdGgsIHRlc3QubWV0YSwgdGVzdC5maXh0dXJlLm1ldGEpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRUZXN0cyAoKTogUHJvbWlzZTxUZXN0W10+IHtcbiAgICAgICAgY29uc3QgeyBwYXJzZWRGaWxlTGlzdCwgY29tcGlsZXJPcHRpb25zIH0gPSBhd2FpdCB0aGlzLl9nZXRDb21waWxlckFyZ3VtZW50cygpO1xuXG4gICAgICAgIGlmICghcGFyc2VkRmlsZUxpc3QubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy50ZXN0RmlsZXNOb3RGb3VuZCk7XG5cbiAgICAgICAgY29uc3QgY29tcGlsZXIgPSBuZXcgQ29tcGlsZXIocGFyc2VkRmlsZUxpc3QsIGNvbXBpbGVyT3B0aW9ucyk7XG4gICAgICAgIGxldCB0ZXN0cyAgICAgID0gYXdhaXQgY29tcGlsZXIuZ2V0VGVzdHMoKTtcblxuICAgICAgICBjb25zdCB0ZXN0c1dpdGhPbmx5RmxhZyA9IHRlc3RzLmZpbHRlcih0ZXN0ID0+IHRlc3Qub25seSk7XG5cbiAgICAgICAgaWYgKHRlc3RzV2l0aE9ubHlGbGFnLmxlbmd0aClcbiAgICAgICAgICAgIHRlc3RzID0gdGVzdHNXaXRoT25seUZsYWc7XG5cbiAgICAgICAgaWYgKHRoaXMuZmlsdGVyKVxuICAgICAgICAgICAgdGVzdHMgPSB0aGlzLl9maWx0ZXJUZXN0cyh0ZXN0cywgdGhpcy5maWx0ZXIpO1xuXG4gICAgICAgIGlmICghdGVzdHMubGVuZ3RoKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5ub1Rlc3RzVG9SdW4pO1xuXG4gICAgICAgIHJldHVybiB0ZXN0cztcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRDb21waWxlckFyZ3VtZW50cyAoKTogUHJvbWlzZTxDb21waWxlckFyZ3VtZW50cz4ge1xuICAgICAgICBjb25zdCBwYXJzZWRGaWxlTGlzdCA9IGF3YWl0IHBhcnNlRmlsZUxpc3QodGhpcy5zb3VyY2VzLCBwcm9jZXNzLmN3ZCgpKTtcblxuICAgICAgICBjb25zdCBjb21waWxlck9wdGlvbnMgPSB7XG4gICAgICAgICAgICB0eXBlU2NyaXB0T3B0aW9uczoge1xuICAgICAgICAgICAgICAgIHRzQ29uZmlnUGF0aDogdGhpcy50c0NvbmZpZ1BhdGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4geyBwYXJzZWRGaWxlTGlzdCwgY29tcGlsZXJPcHRpb25zIH07XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfZW5zdXJlT3V0U3RyZWFtIChvdXRTdHJlYW06IHN0cmluZyB8IFdyaXRhYmxlU3RyZWFtKTogUHJvbWlzZTxXcml0YWJsZVN0cmVhbT4ge1xuICAgICAgICBpZiAodHlwZW9mIG91dFN0cmVhbSAhPT0gJ3N0cmluZycpXG4gICAgICAgICAgICByZXR1cm4gb3V0U3RyZWFtO1xuXG4gICAgICAgIGNvbnN0IGZ1bGxSZXBvcnRlck91dHB1dFBhdGggPSByZXNvbHZlUGF0aFJlbGF0aXZlbHlDd2Qob3V0U3RyZWFtKTtcblxuICAgICAgICBhd2FpdCBtYWtlRGlyKHBhdGguZGlybmFtZShmdWxsUmVwb3J0ZXJPdXRwdXRQYXRoKSk7XG5cbiAgICAgICAgcmV0dXJuIGZzLmNyZWF0ZVdyaXRlU3RyZWFtKGZ1bGxSZXBvcnRlck91dHB1dFBhdGgpO1xuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIF9hZGREZWZhdWx0UmVwb3J0ZXIgKHJlcG9ydGVyczogUmVwb3J0ZXJTb3VyY2VbXSk6IHZvaWQge1xuICAgICAgICByZXBvcnRlcnMucHVzaCh7XG4gICAgICAgICAgICBuYW1lOiAgICdzcGVjJyxcbiAgICAgICAgICAgIG91dHB1dDogcHJvY2Vzcy5zdGRvdXRcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBfcmVxdWlyZVJlcG9ydGVyUGx1Z2luRmFjdG9yeSAocmVwb3J0ZXJOYW1lOiBzdHJpbmcpOiBSZXBvcnRlclBsdWdpbkZhY3Rvcnkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIHJlcXVpcmUoJ3Rlc3RjYWZlLXJlcG9ydGVyLScgKyByZXBvcnRlck5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBHZW5lcmFsRXJyb3IoUlVOVElNRV9FUlJPUlMuY2Fubm90RmluZFJlcG9ydGVyRm9yQWxpYXMsIHJlcG9ydGVyTmFtZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIF9nZXRQbHVnaW5GYWN0b3J5IChyZXBvcnRlckZhY3RvcnlTb3VyY2U6IHN0cmluZyB8IFJlcG9ydGVyUGx1Z2luRmFjdG9yeSk6IFJlcG9ydGVyUGx1Z2luRmFjdG9yeSB7XG4gICAgICAgIGlmICghaXNSZXBvcnRlclBsdWdpbkZhY3RvcnkocmVwb3J0ZXJGYWN0b3J5U291cmNlKSlcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9yZXF1aXJlUmVwb3J0ZXJQbHVnaW5GYWN0b3J5KHJlcG9ydGVyRmFjdG9yeVNvdXJjZSk7XG5cbiAgICAgICAgcmV0dXJuIHJlcG9ydGVyRmFjdG9yeVNvdXJjZTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9nZXRSZXBvcnRlclBsdWdpbnMgKCk6IFByb21pc2U8UmVwb3J0ZXJQbHVnaW5Tb3VyY2VbXT4ge1xuICAgICAgICBjb25zdCBzdGRvdXRSZXBvcnRlcnMgPSBmaWx0ZXIodGhpcy5yZXBvcnRlcnMsIHIgPT4gaXNVbmRlZmluZWQoci5vdXRwdXQpIHx8IHIub3V0cHV0ID09PSBwcm9jZXNzLnN0ZG91dCk7XG5cbiAgICAgICAgaWYgKHN0ZG91dFJlcG9ydGVycy5sZW5ndGggPiAxKVxuICAgICAgICAgICAgdGhyb3cgbmV3IEdlbmVyYWxFcnJvcihSVU5USU1FX0VSUk9SUy5tdWx0aXBsZVN0ZG91dFJlcG9ydGVycywgc3Rkb3V0UmVwb3J0ZXJzLm1hcChyID0+IHIubmFtZSkuam9pbignLCAnKSk7XG5cbiAgICAgICAgaWYgKCF0aGlzLnJlcG9ydGVycy5sZW5ndGgpXG4gICAgICAgICAgICBCb290c3RyYXBwZXIuX2FkZERlZmF1bHRSZXBvcnRlcih0aGlzLnJlcG9ydGVycyk7XG5cbiAgICAgICAgcmV0dXJuIFByb21pc2UuYWxsKHRoaXMucmVwb3J0ZXJzLm1hcChhc3luYyAoeyBuYW1lLCBvdXRwdXQgfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcGx1Z2luRmFjdG9yeSA9IHRoaXMuX2dldFBsdWdpbkZhY3RvcnkobmFtZSk7XG4gICAgICAgICAgICBjb25zdCBvdXRTdHJlYW0gICAgID0gb3V0cHV0ID8gYXdhaXQgdGhpcy5fZW5zdXJlT3V0U3RyZWFtKG91dHB1dCkgOiB2b2lkIDA7XG5cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcGx1Z2luOiBwbHVnaW5GYWN0b3J5KCksXG4gICAgICAgICAgICAgICAgb3V0U3RyZWFtXG4gICAgICAgICAgICB9O1xuICAgICAgICB9KSk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBhc3luYyBfc3RhcnRUZXN0ZWRBcHAgKCk6IFByb21pc2U8VGVzdGVkQXBwfHVuZGVmaW5lZD4ge1xuICAgICAgICBpZiAoIXRoaXMuYXBwQ29tbWFuZClcbiAgICAgICAgICAgIHJldHVybiB2b2lkIDA7XG5cbiAgICAgICAgY29uc3QgdGVzdGVkQXBwID0gbmV3IFRlc3RlZEFwcCgpO1xuXG4gICAgICAgIGF3YWl0IHRlc3RlZEFwcC5zdGFydCh0aGlzLmFwcENvbW1hbmQsIHRoaXMuYXBwSW5pdERlbGF5KTtcblxuICAgICAgICByZXR1cm4gdGVzdGVkQXBwO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2NhblVzZVBhcmFsbGVsQm9vdHN0cmFwcGluZyAoYnJvd3NlckluZm86IEJyb3dzZXJJbmZvU291cmNlW10pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICAgICAgY29uc3QgaXNMb2NhbFByb21pc2VzID0gYnJvd3NlckluZm8ubWFwKGJyb3dzZXIgPT4gYnJvd3Nlci5wcm92aWRlci5pc0xvY2FsQnJvd3Nlcih2b2lkIDAsIEJvb3RzdHJhcHBlci5fZ2V0QnJvd3Nlck5hbWUoYnJvd3NlcikpKTtcbiAgICAgICAgY29uc3QgaXNMb2NhbEJyb3dzZXJzID0gYXdhaXQgUHJvbWlzZS5hbGwoaXNMb2NhbFByb21pc2VzKTtcblxuICAgICAgICByZXR1cm4gaXNMb2NhbEJyb3dzZXJzLmV2ZXJ5KHJlc3VsdCA9PiByZXN1bHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2Jvb3RzdHJhcFNlcXVlbmNlIChicm93c2VySW5mbzogQnJvd3NlckluZm9Tb3VyY2VbXSk6IFByb21pc2U8QmFzaWNSdW50aW1lUmVzb3VyY2VzPiB7XG4gICAgICAgIGNvbnN0IHRlc3RzICAgICAgID0gYXdhaXQgdGhpcy5fZ2V0VGVzdHMoKTtcbiAgICAgICAgY29uc3QgdGVzdGVkQXBwICAgPSBhd2FpdCB0aGlzLl9zdGFydFRlc3RlZEFwcCgpO1xuICAgICAgICBjb25zdCBicm93c2VyU2V0ICA9IGF3YWl0IHRoaXMuX2dldEJyb3dzZXJDb25uZWN0aW9ucyhicm93c2VySW5mbyk7XG5cbiAgICAgICAgcmV0dXJuIHsgdGVzdHMsIHRlc3RlZEFwcCwgYnJvd3NlclNldCB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgX3dyYXBCb290c3RyYXBwaW5nUHJvbWlzZTxUPiAocHJvbWlzZTogUHJvbWlzZTxUPik6IFByb21pc2U8UHJvbWlzZVJlc3VsdDxUPj4ge1xuICAgICAgICByZXR1cm4gcHJvbWlzZVxuICAgICAgICAgICAgLnRoZW4ocmVzdWx0ID0+ICh7IGVycm9yOiB2b2lkIDAsIHJlc3VsdCB9KSlcbiAgICAgICAgICAgIC5jYXRjaChlcnJvciA9PiAoeyByZXN1bHQ6IHZvaWQgMCwgZXJyb3IgfSkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgYXN5bmMgX2dldEJvb3RzdHJhcHBpbmdFcnJvciAoYnJvd3NlclNldFN0YXR1czogUHJvbWlzZVJlc3VsdDxCcm93c2VyU2V0PiwgdGVzdHNTdGF0dXM6IFByb21pc2VSZXN1bHQ8VGVzdFtdPiwgdGVzdGVkQXBwU3RhdHVzOiBQcm9taXNlUmVzdWx0PFRlc3RlZEFwcHx1bmRlZmluZWQ+KTogUHJvbWlzZTxFcnJvcj4ge1xuICAgICAgICBpZiAoIWlzUHJvbWlzZUVycm9yKGJyb3dzZXJTZXRTdGF0dXMpKVxuICAgICAgICAgICAgYXdhaXQgYnJvd3NlclNldFN0YXR1cy5yZXN1bHQuZGlzcG9zZSgpO1xuXG4gICAgICAgIGlmICghaXNQcm9taXNlRXJyb3IoYnJvd3NlclNldFN0YXR1cykgJiYgIWlzUHJvbWlzZUVycm9yKHRlc3RlZEFwcFN0YXR1cykgJiYgdGVzdGVkQXBwU3RhdHVzLnJlc3VsdClcbiAgICAgICAgICAgIGF3YWl0IHRlc3RlZEFwcFN0YXR1cy5yZXN1bHQua2lsbCgpO1xuXG4gICAgICAgIGlmIChpc1Byb21pc2VFcnJvcih0ZXN0c1N0YXR1cykpXG4gICAgICAgICAgICByZXR1cm4gdGVzdHNTdGF0dXMuZXJyb3I7XG5cbiAgICAgICAgaWYgKGlzUHJvbWlzZUVycm9yKHRlc3RlZEFwcFN0YXR1cykpXG4gICAgICAgICAgICByZXR1cm4gdGVzdGVkQXBwU3RhdHVzLmVycm9yO1xuXG4gICAgICAgIGlmIChpc1Byb21pc2VFcnJvcihicm93c2VyU2V0U3RhdHVzKSlcbiAgICAgICAgICAgIHJldHVybiBicm93c2VyU2V0U3RhdHVzLmVycm9yO1xuXG4gICAgICAgIHJldHVybiBuZXcgRXJyb3IoJ1VuZXhwZWN0ZWQgY2FsbCcpO1xuICAgIH1cblxuICAgIHByaXZhdGUgX2dldEJvb3RzdHJhcHBpbmdQcm9taXNlczxUPiAoYXJnOiBQcm9taXNlQ29sbGVjdGlvbjxUPik6IFByb21pc2VDb2xsZWN0aW9uPFJlc3VsdENvbGxlY3Rpb248VD4+IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0ge30gYXMgdW5rbm93biBhcyBQcm9taXNlQ29sbGVjdGlvbjxSZXN1bHRDb2xsZWN0aW9uPFQ+PjtcblxuICAgICAgICBmb3IgKGNvbnN0IGsgaW4gYXJnKVxuICAgICAgICAgICAgcmVzdWx0W2tdID0gdGhpcy5fd3JhcEJvb3RzdHJhcHBpbmdQcm9taXNlKGFyZ1trXSk7XG5cbiAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIF9ib290c3RyYXBQYXJhbGxlbCAoYnJvd3NlckluZm86IEJyb3dzZXJJbmZvU291cmNlW10pOiBQcm9taXNlPEJhc2ljUnVudGltZVJlc291cmNlcz4ge1xuICAgICAgICBjb25zdCBib290c3RyYXBwaW5nUHJvbWlzZXMgPSB7XG4gICAgICAgICAgICBicm93c2VyU2V0OiB0aGlzLl9nZXRCcm93c2VyQ29ubmVjdGlvbnMoYnJvd3NlckluZm8pLFxuICAgICAgICAgICAgdGVzdHM6ICAgICAgdGhpcy5fZ2V0VGVzdHMoKSxcbiAgICAgICAgICAgIGFwcDogICAgICAgIHRoaXMuX3N0YXJ0VGVzdGVkQXBwKClcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBib290c3RyYXBwaW5nUmVzdWx0UHJvbWlzZXMgPSB0aGlzLl9nZXRCb290c3RyYXBwaW5nUHJvbWlzZXMoYm9vdHN0cmFwcGluZ1Byb21pc2VzKTtcblxuICAgICAgICBjb25zdCBib290c3RyYXBwaW5nUmVzdWx0cyA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIGJvb3RzdHJhcHBpbmdSZXN1bHRQcm9taXNlcy5icm93c2VyU2V0LFxuICAgICAgICAgICAgYm9vdHN0cmFwcGluZ1Jlc3VsdFByb21pc2VzLnRlc3RzLFxuICAgICAgICAgICAgYm9vdHN0cmFwcGluZ1Jlc3VsdFByb21pc2VzLmFwcFxuICAgICAgICBdKTtcblxuICAgICAgICBjb25zdCBbYnJvd3NlclNldFJlc3VsdHMsIHRlc3RSZXN1bHRzLCBhcHBSZXN1bHRzXSA9IGJvb3RzdHJhcHBpbmdSZXN1bHRzO1xuXG4gICAgICAgIGlmIChpc1Byb21pc2VFcnJvcihicm93c2VyU2V0UmVzdWx0cykgfHwgaXNQcm9taXNlRXJyb3IodGVzdFJlc3VsdHMpIHx8IGlzUHJvbWlzZUVycm9yKGFwcFJlc3VsdHMpKVxuICAgICAgICAgICAgdGhyb3cgYXdhaXQgdGhpcy5fZ2V0Qm9vdHN0cmFwcGluZ0Vycm9yKC4uLmJvb3RzdHJhcHBpbmdSZXN1bHRzKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgYnJvd3NlclNldDogYnJvd3NlclNldFJlc3VsdHMucmVzdWx0LFxuICAgICAgICAgICAgdGVzdHM6ICAgICAgdGVzdFJlc3VsdHMucmVzdWx0LFxuICAgICAgICAgICAgdGVzdGVkQXBwOiAgYXBwUmVzdWx0cy5yZXN1bHRcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBBUElcbiAgICBwdWJsaWMgYXN5bmMgY3JlYXRlUnVubmFibGVDb25maWd1cmF0aW9uICgpOiBQcm9taXNlPFJ1bnRpbWVSZXNvdXJjZXM+IHtcbiAgICAgICAgY29uc3QgcmVwb3J0ZXJQbHVnaW5zICAgICA9IGF3YWl0IHRoaXMuX2dldFJlcG9ydGVyUGx1Z2lucygpO1xuICAgICAgICBjb25zdCBjb21tb25DbGllbnRTY3JpcHRzID0gYXdhaXQgbG9hZENsaWVudFNjcmlwdHModGhpcy5jbGllbnRTY3JpcHRzKTtcblxuICAgICAgICAvLyBOT1RFOiBJZiBhIHVzZXIgZm9yZ290IHRvIHNwZWNpZnkgYSBicm93c2VyLCBidXQgaGFzIHNwZWNpZmllZCBhIHBhdGggdG8gdGVzdHMsIHRoZSBzcGVjaWZpZWQgcGF0aCB3aWxsIGJlXG4gICAgICAgIC8vIGNvbnNpZGVyZWQgYXMgdGhlIGJyb3dzZXIgYXJndW1lbnQsIGFuZCB0aGUgdGVzdHMgcGF0aCBhcmd1bWVudCB3aWxsIGhhdmUgdGhlIHByZWRlZmluZWQgZGVmYXVsdCB2YWx1ZS5cbiAgICAgICAgLy8gSXQncyB2ZXJ5IGFtYmlndW91cyBmb3IgdGhlIHVzZXIsIHdobyBtaWdodCBiZSBjb25mdXNlZCBieSBjb21waWxhdGlvbiBlcnJvcnMgZnJvbSBhbiB1bmV4cGVjdGVkIHRlc3QuXG4gICAgICAgIC8vIFNvLCB3ZSBuZWVkIHRvIHJldHJpZXZlIHRoZSBicm93c2VyIGFsaWFzZXMgYW5kIHBhdGhzIGJlZm9yZSB0ZXN0cyBjb21waWxhdGlvbi5cbiAgICAgICAgY29uc3QgYnJvd3NlckluZm8gPSBhd2FpdCB0aGlzLl9nZXRCcm93c2VySW5mbygpO1xuXG4gICAgICAgIGlmIChPUy5tYWMpXG4gICAgICAgICAgICBhd2FpdCBCb290c3RyYXBwZXIuX2NoZWNrUmVxdWlyZWRQZXJtaXNzaW9ucyhicm93c2VySW5mbyk7XG5cbiAgICAgICAgaWYgKGF3YWl0IHRoaXMuX2NhblVzZVBhcmFsbGVsQm9vdHN0cmFwcGluZyhicm93c2VySW5mbykpXG4gICAgICAgICAgICByZXR1cm4geyByZXBvcnRlclBsdWdpbnMsIC4uLmF3YWl0IHRoaXMuX2Jvb3RzdHJhcFBhcmFsbGVsKGJyb3dzZXJJbmZvKSwgY29tbW9uQ2xpZW50U2NyaXB0cyB9O1xuXG4gICAgICAgIHJldHVybiB7IHJlcG9ydGVyUGx1Z2lucywgLi4uYXdhaXQgdGhpcy5fYm9vdHN0cmFwU2VxdWVuY2UoYnJvd3NlckluZm8pLCBjb21tb25DbGllbnRTY3JpcHRzIH07XG4gICAgfVxufVxuIl19
\No newline at end of file