1 | ;
|
2 | var __importDefault = (this && this.__importDefault) || function (mod) {
|
3 | return (mod && mod.__esModule) ? mod : { "default": mod };
|
4 | };
|
5 | Object.defineProperty(exports, "__esModule", { value: true });
|
6 | const path_1 = __importDefault(require("path"));
|
7 | const fs_1 = __importDefault(require("fs"));
|
8 | const is_ci_1 = __importDefault(require("is-ci"));
|
9 | const lodash_1 = require("lodash");
|
10 | const make_dir_1 = __importDefault(require("make-dir"));
|
11 | const os_family_1 = __importDefault(require("os-family"));
|
12 | const testcafe_browser_tools_1 = require("testcafe-browser-tools");
|
13 | const authentication_helper_1 = __importDefault(require("../cli/authentication-helper"));
|
14 | const compiler_1 = __importDefault(require("../compiler"));
|
15 | const connection_1 = __importDefault(require("../browser/connection"));
|
16 | const pool_1 = __importDefault(require("../browser/provider/pool"));
|
17 | const browser_set_1 = __importDefault(require("./browser-set"));
|
18 | const remote_1 = __importDefault(require("../browser/provider/built-in/remote"));
|
19 | const runtime_1 = require("../errors/runtime");
|
20 | const types_1 = require("../errors/types");
|
21 | const tested_app_1 = __importDefault(require("./tested-app"));
|
22 | const parse_file_list_1 = __importDefault(require("../utils/parse-file-list"));
|
23 | const resolve_path_relatively_cwd_1 = __importDefault(require("../utils/resolve-path-relatively-cwd"));
|
24 | const load_1 = __importDefault(require("../custom-client-scripts/load"));
|
25 | function isReporterPluginFactory(value) {
|
26 | return typeof value === 'function';
|
27 | }
|
28 | function isPromiseError(value) {
|
29 | return value.error !== void 0;
|
30 | }
|
31 | class 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 | }
|
248 | exports.default = Bootstrapper;
|
249 | module.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 |