@angular-devkit/build-angular
Version:
Angular Webpack Build Facade
161 lines • 20.2 kB
JavaScript
;
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const architect_1 = require("@angular-devkit/architect");
const child_process_1 = require("child_process");
const path = __importStar(require("path"));
const util_1 = require("util");
const color_1 = require("../../utils/color");
const application_1 = require("../application");
const schema_1 = require("../browser-esbuild/schema");
const options_1 = require("./options");
const test_files_1 = require("./test-files");
const execFile = (0, util_1.promisify)(child_process_1.execFile);
/** Main execution function for the Jest builder. */
exports.default = (0, architect_1.createBuilder)(async (schema, context) => {
context.logger.warn('NOTE: The Jest builder is currently EXPERIMENTAL and not ready for production use.');
const options = (0, options_1.normalizeOptions)(schema);
const testOut = 'dist/test-out'; // TODO(dgp1130): Hide in temp directory.
// Verify Jest installation and get the path to it's binary.
// We need to `node_modules/.bin/jest`, but there is no means to resolve that directly. Fortunately Jest's `package.json` exports the
// same file at `bin/jest`, so we can just resolve that instead.
const jest = resolveModule('jest/bin/jest');
if (!jest) {
return {
success: false,
// TODO(dgp1130): Display a more accurate message for non-NPM users.
error: 'Jest is not installed, most likely you need to run `npm install jest --save-dev` in your project.',
};
}
// Verify that JSDom is installed in the project.
const environment = resolveModule('jest-environment-jsdom');
if (!environment) {
return {
success: false,
// TODO(dgp1130): Display a more accurate message for non-NPM users.
error: '`jest-environment-jsdom` is not installed. Install it with `npm install jest-environment-jsdom --save-dev`.',
};
}
// Build all the test files.
const testFiles = await (0, test_files_1.findTestFiles)(options, context.workspaceRoot);
const jestGlobal = path.join(__dirname, 'jest-global.mjs');
const initTestBed = path.join(__dirname, 'init-test-bed.mjs');
const buildResult = await build(context, {
// Build all the test files and also the `jest-global` and `init-test-bed` scripts.
entryPoints: new Set([...testFiles, jestGlobal, initTestBed]),
tsConfig: options.tsConfig,
polyfills: options.polyfills ?? ['zone.js', 'zone.js/testing'],
outputPath: testOut,
aot: false,
index: false,
outputHashing: schema_1.OutputHashing.None,
outExtension: 'mjs',
optimization: false,
sourceMap: {
scripts: true,
styles: false,
vendor: false,
},
});
if (!buildResult.success) {
return buildResult;
}
// Execute Jest on the built output directory.
const jestProc = execFile(process.execPath, [
'--experimental-vm-modules',
jest,
`--rootDir="${testOut}"`,
'--testEnvironment=jsdom',
// TODO(dgp1130): Enable cache once we have a mechanism for properly clearing / disabling it.
'--no-cache',
// Run basically all files in the output directory, any excluded files were already dropped by the build.
`--testMatch="<rootDir>/**/*.mjs"`,
// Load polyfills and initialize the environment before executing each test file.
// IMPORTANT: Order matters here.
// First, we execute `jest-global.mjs` to initialize the `jest` global variable.
// Second, we execute user polyfills, including `zone.js` and `zone.js/testing`. This is dependent on the Jest global so it can patch
// the environment for fake async to work correctly.
// Third, we initialize `TestBed`. This is dependent on fake async being set up correctly beforehand.
`--setupFilesAfterEnv="<rootDir>/jest-global.mjs"`,
...(options.polyfills ? [`--setupFilesAfterEnv="<rootDir>/polyfills.mjs"`] : []),
`--setupFilesAfterEnv="<rootDir>/init-test-bed.mjs"`,
// Don't run any infrastructure files as tests, they are manually loaded where needed.
`--testPathIgnorePatterns="<rootDir>/jest-global\\.mjs"`,
...(options.polyfills ? [`--testPathIgnorePatterns="<rootDir>/polyfills\\.mjs"`] : []),
`--testPathIgnorePatterns="<rootDir>/init-test-bed\\.mjs"`,
// Skip shared chunks, as they are not entry points to tests.
`--testPathIgnorePatterns="<rootDir>/chunk-.*\\.mjs"`,
// Optionally enable color.
...(color_1.colors.enabled ? ['--colors'] : []),
]);
// Stream test output to the terminal.
jestProc.child.stdout?.on('data', (chunk) => {
context.logger.info(chunk);
});
jestProc.child.stderr?.on('data', (chunk) => {
// Write to stderr directly instead of `context.logger.error(chunk)` because the logger will overwrite Jest's coloring information.
process.stderr.write(chunk);
});
try {
await jestProc;
}
catch (error) {
// No need to propagate error message, already piped to terminal output.
// TODO(dgp1130): Handle process spawning failures.
return { success: false };
}
return { success: true };
});
async function build(context, options) {
try {
for await (const _ of (0, application_1.buildApplicationInternal)(options, context)) {
// Nothing to do for each event, just wait for the whole build.
}
return { success: true };
}
catch (err) {
return {
success: false,
error: err.message,
};
}
}
/** Safely resolves the given Node module string. */
function resolveModule(module) {
try {
return require.resolve(module);
}
catch {
return undefined;
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wYWNrYWdlcy9hbmd1bGFyX2RldmtpdC9idWlsZF9hbmd1bGFyL3NyYy9idWlsZGVycy9qZXN0L2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCx5REFBeUY7QUFDekYsaURBQXVEO0FBQ3ZELDJDQUE2QjtBQUM3QiwrQkFBaUM7QUFDakMsNkNBQTJDO0FBQzNDLGdEQUEwRDtBQUUxRCxzREFBMEQ7QUFDMUQsdUNBQTZDO0FBRTdDLDZDQUE2QztBQUU3QyxNQUFNLFFBQVEsR0FBRyxJQUFBLGdCQUFTLEVBQUMsd0JBQVUsQ0FBQyxDQUFDO0FBRXZDLG9EQUFvRDtBQUNwRCxrQkFBZSxJQUFBLHlCQUFhLEVBQzFCLEtBQUssRUFBRSxNQUF5QixFQUFFLE9BQXVCLEVBQTBCLEVBQUU7SUFDbkYsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQ2pCLG9GQUFvRixDQUNyRixDQUFDO0lBRUYsTUFBTSxPQUFPLEdBQUcsSUFBQSwwQkFBZ0IsRUFBQyxNQUFNLENBQUMsQ0FBQztJQUN6QyxNQUFNLE9BQU8sR0FBRyxlQUFlLENBQUMsQ0FBQyx5Q0FBeUM7SUFFMUUsNERBQTREO0lBQzVELHFJQUFxSTtJQUNySSxnRUFBZ0U7SUFDaEUsTUFBTSxJQUFJLEdBQUcsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQzVDLElBQUksQ0FBQyxJQUFJLEVBQUU7UUFDVCxPQUFPO1lBQ0wsT0FBTyxFQUFFLEtBQUs7WUFDZCxvRUFBb0U7WUFDcEUsS0FBSyxFQUNILG1HQUFtRztTQUN0RyxDQUFDO0tBQ0g7SUFFRCxpREFBaUQ7SUFDakQsTUFBTSxXQUFXLEdBQUcsYUFBYSxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDNUQsSUFBSSxDQUFDLFdBQVcsRUFBRTtRQUNoQixP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O0tBQ2hCO0lBQUMsT0FBTyxLQUFLLEVBQUU7UUFDZCx3RUFBd0U7UUFDeEUsbURBQW1EO1FBQ25ELE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUM7S0FDM0I7SUFFRCxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxDQUFDO0FBQzNCLENBQUMsQ0FDRixDQUFDO0FBRUYsS0FBSyxVQUFVLEtBQUssQ0FDbEIsT0FBdUIsRUFDdkIsT0FBMEM7SUFFMUMsSUFBSTtRQUNGLElBQUksS0FBSyxFQUFFLE1BQU0sQ0FBQyxJQUFJLElBQUEsc0NBQXdCLEVBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxFQUFFO1lBQ2hFLCtEQUErRDtTQUNoRTtRQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLENBQUM7S0FDMUI7SUFBQyxPQUFPLEdBQUcsRUFBRTtRQUNaLE9BQU87WUFDTCxPQUFPLEVBQUUsS0FBSztZQUNkLEtBQUssRUFBRyxHQUFhLENBQUMsT0FBTztTQUM5QixDQUFDO0tBQ0g7QUFDSCxDQUFDO0FBRUQsb0RBQW9EO0FBQ3BELFNBQVMsYUFBYSxDQUFDLE1BQWM7SUFDbkMsSUFBSTtRQUNGLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztLQUNoQztJQUFDLE1BQU07UUFDTixPQUFPLFNBQVMsQ0FBQztLQUNsQjtBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IHsgQnVpbGRlckNvbnRleHQsIEJ1aWxkZXJPdXRwdXQsIGNyZWF0ZUJ1aWxkZXIgfSBmcm9tICdAYW5ndWxhci1kZXZraXQvYXJjaGl0ZWN0JztcbmltcG9ydCB7IGV4ZWNGaWxlIGFzIGV4ZWNGaWxlQ2IgfSBmcm9tICdjaGlsZF9wcm9jZXNzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBwcm9taXNpZnkgfSBmcm9tICd1dGlsJztcbmltcG9ydCB7IGNvbG9ycyB9IGZyb20gJy4uLy4uL3V0aWxzL2NvbG9yJztcbmltcG9ydCB7IGJ1aWxkQXBwbGljYXRpb25JbnRlcm5hbCB9IGZyb20gJy4uL2FwcGxpY2F0aW9uJztcbmltcG9ydCB7IEFwcGxpY2F0aW9uQnVpbGRlckludGVybmFsT3B0aW9ucyB9IGZyb20gJy4uL2FwcGxpY2F0aW9uL29wdGlvbnMnO1xuaW1wb3J0IHsgT3V0cHV0SGFzaGluZyB9IGZyb20gJy4uL2Jyb3dzZXItZXNidWlsZC9zY2hlbWEnO1xuaW1wb3J0IHsgbm9ybWFsaXplT3B0aW9ucyB9IGZyb20gJy4vb3B0aW9ucyc7XG5pbXBvcnQgeyBTY2hlbWEgYXMgSmVzdEJ1aWxkZXJTY2hlbWEgfSBmcm9tICcuL3NjaGVtYSc7XG5pbXBvcnQgeyBmaW5kVGVzdEZpbGVzIH0gZnJvbSAnLi90ZXN0LWZpbGVzJztcblxuY29uc3QgZXhlY0ZpbGUgPSBwcm9taXNpZnkoZXhlY0ZpbGVDYik7XG5cbi8qKiBNYWluIGV4ZWN1dGlvbiBmdW5jdGlvbiBmb3IgdGhlIEplc3QgYnVpbGRlci4gKi9cbmV4cG9ydCBkZWZhdWx0IGNyZWF0ZUJ1aWxkZXIoXG4gIGFzeW5jIChzY2hlbWE6IEplc3RCdWlsZGVyU2NoZW1hLCBjb250ZXh0OiBCdWlsZGVyQ29udGV4dCk6IFByb21pc2U8QnVpbGRlck91dHB1dD4gPT4ge1xuICAgIGNvbnRleHQubG9nZ2VyLndhcm4oXG4gICAgICAnTk9URTogVGhlIEplc3QgYnVpbGRlciBpcyBjdXJyZW50bHkgRVhQRVJJTUVOVEFMIGFuZCBub3QgcmVhZHkgZm9yIHByb2R1Y3Rpb24gdXNlLicsXG4gICAgKTtcblxuICAgIGNvbnN0IG9wdGlvbnMgPSBub3JtYWxpemVPcHRpb25zKHNjaGVtYSk7XG4gICAgY29uc3QgdGVzdE91dCA9ICdkaXN0L3Rlc3Qtb3V0JzsgLy8gVE9ETyhkZ3AxMTMwKTogSGlkZSBpbiB0ZW1wIGRpcmVjdG9yeS5cblxuICAgIC8vIFZlcmlmeSBKZXN0IGluc3RhbGxhdGlvbiBhbmQgZ2V0IHRoZSBwYXRoIHRvIGl0J3MgYmluYXJ5LlxuICAgIC8vIFdlIG5lZWQgdG8gYG5vZGVfbW9kdWxlcy8uYmluL2plc3RgLCBidXQgdGhlcmUgaXMgbm8gbWVhbnMgdG8gcmVzb2x2ZSB0aGF0IGRpcmVjdGx5LiBGb3J0dW5hdGVseSBKZXN0J3MgYHBhY2thZ2UuanNvbmAgZXhwb3J0cyB0aGVcbiAgICAvLyBzYW1lIGZpbGUgYXQgYGJpbi9qZXN0YCwgc28gd2UgY2FuIGp1c3QgcmVzb2x2ZSB0aGF0IGluc3RlYWQuXG4gICAgY29uc3QgamVzdCA9IHJlc29sdmVNb2R1bGUoJ2plc3QvYmluL2plc3QnKTtcbiAgICBpZiAoIWplc3QpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAvLyBUT0RPKGRncDExMzApOiBEaXNwbGF5IGEgbW9yZSBhY2N1cmF0ZSBtZXNzYWdlIGZvciBub24tTlBNIHVzZXJzLlxuICAgICAgICBlcnJvcjpcbiAgICAgICAgICAnSmVzdCBpcyBub3QgaW5zdGFsbGVkLCBtb3N0IGxpa2VseSB5b3UgbmVlZCB0byBydW4gYG5wbSBpbnN0YWxsIGplc3QgLS1zYXZlLWRldmAgaW4geW91ciBwcm9qZWN0LicsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIFZlcmlmeSB0aGF0IEpTRG9tIGlzIGluc3RhbGxlZCBpbiB0aGUgcHJvamVjdC5cbiAgICBjb25zdCBlbnZpcm9ubWVudCA9IHJlc29sdmVNb2R1bGUoJ2plc3QtZW52aXJvbm1lbnQtanNkb20nKTtcbiAgICBpZiAoIWVudmlyb25tZW50KSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgLy8gVE9ETyhkZ3AxMTMwKTogRGlzcGxheSBhIG1vcmUgYWNjdXJhdGUgbWVzc2FnZSBmb3Igbm9uLU5QTSB1c2Vycy5cbiAgICAgICAgZXJyb3I6XG4gICAgICAgICAgJ2BqZXN0LWVudmlyb25tZW50LWpzZG9tYCBpcyBub3QgaW5zdGFsbGVkLiBJbnN0YWxsIGl0IHdpdGggYG5wbSBpbnN0YWxsIGplc3QtZW52aXJvbm1lbnQtanNkb20gLS1zYXZlLWRldmAuJyxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgYWxsIHRoZSB0ZXN0IGZpbGVzLlxuICAgIGNvbnN0IHRlc3RGaWxlcyA9IGF3YWl0IGZpbmRUZXN0RmlsZXMob3B0aW9ucywgY29udGV4dC53b3Jrc3BhY2VSb290KTtcbiAgICBjb25zdCBqZXN0R2xvYmFsID0gcGF0aC5qb2luKF9fZGlybmFtZSwgJ2plc3QtZ2xvYmFsLm1qcycpO1xuICAgIGNvbnN0IGluaXRUZXN0QmVkID0gcGF0aC5qb2luKF9fZGlybmFtZSwgJ2luaXQtdGVzdC1iZWQubWpzJyk7XG4gICAgY29uc3QgYnVpbGRSZXN1bHQgPSBhd2FpdCBidWlsZChjb250ZXh0LCB7XG4gICAgICAvLyBCdWlsZCBhbGwgdGhlIHRlc3QgZmlsZXMgYW5kIGFsc28gdGhlIGBqZXN0LWdsb2JhbGAgYW5kIGBpbml0LXRlc3QtYmVkYCBzY3JpcHRzLlxuICAgICAgZW50cnlQb2ludHM6IG5ldyBTZXQoWy4uLnRlc3RGaWxlcywgamVzdEdsb2JhbCwgaW5pdFRlc3RCZWRdKSxcbiAgICAgIHRzQ29uZmlnOiBvcHRpb25zLnRzQ29uZmlnLFxuICAgICAgcG9seWZpbGxzOiBvcHRpb25zLnBvbHlmaWxscyA/PyBbJ3pvbmUuanMnLCAnem9uZS5qcy90ZXN0aW5nJ10sXG4gICAgICBvdXRwdXRQYXRoOiB0ZXN0T3V0LFxuICAgICAgYW90OiBmYWxzZSxcbiAgICAgIGluZGV4OiBmYWxzZSxcbiAgICAgIG91dHB1dEhhc2hpbmc6IE91dHB1dEhhc2hpbmcuTm9uZSxcbiAgICAgIG91dEV4dGVuc2lvbjogJ21qcycsIC8vIEZvcmNlIG5hdGl2ZSBFU00uXG4gICAgICBvcHRpbWl6YXRpb246IGZhbHNlLFxuICAgICAgc291cmNlTWFwOiB7XG4gICAgICAgIHNjcmlwdHM6IHRydWUsXG4gICAgICAgIHN0eWxlczogZmFsc2UsXG4gICAgICAgIHZlbmRvcjogZmFsc2UsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGlmICghYnVpbGRSZXN1bHQuc3VjY2Vzcykge1xuICAgICAgcmV0dXJuIGJ1aWxkUmVzdWx0O1xuICAgIH1cblxuICAgIC8vIEV4ZWN1dGUgSmVzdCBvbiB0aGUgYnVpbHQgb3V0cHV0IGRpcmVjdG9yeS5cbiAgICBjb25zdCBqZXN0UHJvYyA9IGV4ZWNGaWxlKHByb2Nlc3MuZXhlY1BhdGgsIFtcbiAgICAgICctLWV4cGVyaW1lbnRhbC12bS1tb2R1bGVzJyxcbiAgICAgIGplc3QsXG5cbiAgICAgIGAtLXJvb3REaXI9XCIke3Rlc3RPdXR9XCJgLFxuICAgICAgJy0tdGVzdEVudmlyb25tZW50PWpzZG9tJyxcblxuICAgICAgLy8gVE9ETyhkZ3AxMTMwKTogRW5hYmxlIGNhY2hlIG9uY2Ugd2UgaGF2ZSBhIG1lY2hhbmlzbSBmb3IgcHJvcGVybHkgY2xlYXJpbmcgLyBkaXNhYmxpbmcgaXQuXG4gICAgICAnLS1uby1jYWNoZScsXG5cbiAgICAgIC8vIFJ1biBiYXNpY2FsbHkgYWxsIGZpbGVzIGluIHRoZSBvdXRwdXQgZGlyZWN0b3J5LCBhbnkgZXhjbHVkZWQgZmlsZXMgd2VyZSBhbHJlYWR5IGRyb3BwZWQgYnkgdGhlIGJ1aWxkLlxuICAgICAgYC0tdGVzdE1hdGNoPVwiPHJvb3REaXI+LyoqLyoubWpzXCJgLFxuXG4gICAgICAvLyBMb2FkIHBvbHlmaWxscyBhbmQgaW5pdGlhbGl6ZSB0aGUgZW52aXJvbm1lbnQgYmVmb3JlIGV4ZWN1dGluZyBlYWNoIHRlc3QgZmlsZS5cbiAgICAgIC8vIElNUE9SVEFOVDogT3JkZXIgbWF0dGVycyBoZXJlLlxuICAgICAgLy8gRmlyc3QsIHdlIGV4ZWN1dGUgYGplc3QtZ2xvYmFsLm1qc2AgdG8gaW5pdGlhbGl6ZSB0aGUgYGplc3RgIGdsb2JhbCB2YXJpYWJsZS5cbiAgICAgIC8vIFNlY29uZCwgd2UgZXhlY3V0ZSB1c2VyIHBvbHlmaWxscywgaW5jbHVkaW5nIGB6b25lLmpzYCBhbmQgYHpvbmUuanMvdGVzdGluZ2AuIFRoaXMgaXMgZGVwZW5kZW50IG9uIHRoZSBKZXN0IGdsb2JhbCBzbyBpdCBjYW4gcGF0Y2hcbiAgICAgIC8vIHRoZSBlbnZpcm9ubWVudCBmb3IgZmFrZSBhc3luYyB0byB3b3JrIGNvcnJlY3RseS5cbiAgICAgIC8vIFRoaXJkLCB3ZSBpbml0aWFsaXplIGBUZXN0QmVkYC4gVGhpcyBpcyBkZXBlbmRlbnQgb24gZmFrZSBhc3luYyBiZWluZyBzZXQgdXAgY29ycmVjdGx5IGJlZm9yZWhhbmQuXG4gICAgICBgLS1zZXR1cEZpbGVzQWZ0ZXJFbnY9XCI8cm9vdERpcj4vamVzdC1nbG9iYWwubWpzXCJgLFxuICAgICAgLi4uKG9wdGlvbnMucG9seWZpbGxzID8gW2AtLXNldHVwRmlsZXNBZnRlckVudj1cIjxyb290RGlyPi9wb2x5ZmlsbHMubWpzXCJgXSA6IFtdKSxcbiAgICAgIGAtLXNldHVwRmlsZXNBZnRlckVudj1cIjxyb290RGlyPi9pbml0LXRlc3QtYmVkLm1qc1wiYCxcblxuICAgICAgLy8gRG9uJ3QgcnVuIGFueSBpbmZyYXN0cnVjdHVyZSBmaWxlcyBhcyB0ZXN0cywgdGhleSBhcmUgbWFudWFsbHkgbG9hZGVkIHdoZXJlIG5lZWRlZC5cbiAgICAgIGAtLXRlc3RQYXRoSWdub3JlUGF0dGVybnM9XCI8cm9vdERpcj4vamVzdC1nbG9iYWxcXFxcLm1qc1wiYCxcbiAgICAgIC4uLihvcHRpb25zLnBvbHlmaWxscyA/IFtgLS10ZXN0UGF0aElnbm9yZVBhdHRlcm5zPVwiPHJvb3REaXI+L3BvbHlmaWxsc1xcXFwubWpzXCJgXSA6IFtdKSxcbiAgICAgIGAtLXRlc3RQYXRoSWdub3JlUGF0dGVybnM9XCI8cm9vdERpcj4vaW5pdC10ZXN0LWJlZFxcXFwubWpzXCJgLFxuXG4gICAgICAvLyBTa2lwIHNoYXJlZCBjaHVua3MsIGFzIHRoZXkgYXJlIG5vdCBlbnRyeSBwb2ludHMgdG8gdGVzdHMuXG4gICAgICBgLS10ZXN0UGF0aElnbm9yZVBhdHRlcm5zPVwiPHJvb3REaXI+L2NodW5rLS4qXFxcXC5tanNcImAsXG5cbiAgICAgIC8vIE9wdGlvbmFsbHkgZW5hYmxlIGNvbG9yLlxuICAgICAgLi4uKGNvbG9ycy5lbmFibGVkID8gWyctLWNvbG9ycyddIDogW10pLFxuICAgIF0pO1xuXG4gICAgLy8gU3RyZWFtIHRlc3Qgb3V0cHV0IHRvIHRoZSB0ZXJtaW5hbC5cbiAgICBqZXN0UHJvYy5jaGlsZC5zdGRvdXQ/Lm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKGNodW5rKTtcbiAgICB9KTtcbiAgICBqZXN0UHJvYy5jaGlsZC5zdGRlcnI/Lm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAvLyBXcml0ZSB0byBzdGRlcnIgZGlyZWN0bHkgaW5zdGVhZCBvZiBgY29udGV4dC5sb2dnZXIuZXJyb3IoY2h1bmspYCBiZWNhdXNlIHRoZSBsb2dnZXIgd2lsbCBvdmVyd3JpdGUgSmVzdCdzIGNvbG9yaW5nIGluZm9ybWF0aW9uLlxuICAgICAgcHJvY2Vzcy5zdGRlcnIud3JpdGUoY2h1bmspO1xuICAgIH0pO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGplc3RQcm9jO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAvLyBObyBuZWVkIHRvIHByb3BhZ2F0ZSBlcnJvciBtZXNzYWdlLCBhbHJlYWR5IHBpcGVkIHRvIHRlcm1pbmFsIG91dHB1dC5cbiAgICAgIC8vIFRPRE8oZGdwMTEzMCk6IEhhbmRsZSBwcm9jZXNzIHNwYXduaW5nIGZhaWx1cmVzLlxuICAgICAgcmV0dXJuIHsgc3VjY2VzczogZmFsc2UgfTtcbiAgICB9XG5cbiAgICByZXR1cm4geyBzdWNjZXNzOiB0cnVlIH07XG4gIH0sXG4pO1xuXG5hc3luYyBmdW5jdGlvbiBidWlsZChcbiAgY29udGV4dDogQnVpbGRlckNvbnRleHQsXG4gIG9wdGlvbnM6IEFwcGxpY2F0aW9uQnVpbGRlckludGVybmFsT3B0aW9ucyxcbik6IFByb21pc2U8QnVpbGRlck91dHB1dD4ge1xuICB0cnkge1xuICAgIGZvciBhd2FpdCAoY29uc3QgXyBvZiBidWlsZEFwcGxpY2F0aW9uSW50ZXJuYWwob3B0aW9ucywgY29udGV4dCkpIHtcbiAgICAgIC8vIE5vdGhpbmcgdG8gZG8gZm9yIGVhY2ggZXZlbnQsIGp1c3Qgd2FpdCBmb3IgdGhlIHdob2xlIGJ1aWxkLlxuICAgIH1cblxuICAgIHJldHVybiB7IHN1Y2Nlc3M6IHRydWUgfTtcbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgZXJyb3I6IChlcnIgYXMgRXJyb3IpLm1lc3NhZ2UsXG4gICAgfTtcbiAgfVxufVxuXG4vKiogU2FmZWx5IHJlc29sdmVzIHRoZSBnaXZlbiBOb2RlIG1vZHVsZSBzdHJpbmcuICovXG5mdW5jdGlvbiByZXNvbHZlTW9kdWxlKG1vZHVsZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgdHJ5IHtcbiAgICByZXR1cm4gcmVxdWlyZS5yZXNvbHZlKG1vZHVsZSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cbiJdfQ==