@angular-devkit/build-angular
Version:
Angular Webpack Build Facade
165 lines • 26.3 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 __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.JavaScriptOptimizerPlugin = void 0;
const piscina_1 = __importDefault(require("piscina"));
const environment_options_1 = require("../../../utils/environment-options");
const webpack_diagnostics_1 = require("../../../utils/webpack-diagnostics");
const utils_1 = require("../../esbuild/utils");
const esbuild_executor_1 = require("./esbuild-executor");
/**
* The maximum number of Workers that will be created to execute optimize tasks.
*/
const MAX_OPTIMIZE_WORKERS = environment_options_1.maxWorkers;
/**
* The name of the plugin provided to Webpack when tapping Webpack compiler hooks.
*/
const PLUGIN_NAME = 'angular-javascript-optimizer';
/**
* A Webpack plugin that provides JavaScript optimization capabilities.
*
* The plugin uses both `esbuild` and `terser` to provide both fast and highly-optimized
* code output. `esbuild` is used as an initial pass to remove the majority of unused code
* as well as shorten identifiers. `terser` is then used as a secondary pass to apply
* optimizations not yet implemented by `esbuild`.
*/
class JavaScriptOptimizerPlugin {
constructor(options) {
this.options = options;
if (options.supportedBrowsers) {
this.targets = (0, utils_1.transformSupportedBrowsersToTargets)(options.supportedBrowsers);
}
}
apply(compiler) {
const { OriginalSource, SourceMapSource } = compiler.webpack.sources;
compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation) => {
const logger = compilation.getLogger('build-angular.JavaScriptOptimizerPlugin');
compilation.hooks.processAssets.tapPromise({
name: PLUGIN_NAME,
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,
}, async (compilationAssets) => {
logger.time('optimize js assets');
const scriptsToOptimize = [];
const cache = compilation.options.cache && compilation.getCache('JavaScriptOptimizerPlugin');
// Analyze the compilation assets for scripts that require optimization
for (const assetName of Object.keys(compilationAssets)) {
if (!assetName.endsWith('.js')) {
continue;
}
const scriptAsset = compilation.getAsset(assetName);
// Skip assets that have already been optimized or are verbatim copies (project assets)
if (!scriptAsset || scriptAsset.info.minimized || scriptAsset.info.copied) {
continue;
}
const { source: scriptAssetSource, name } = scriptAsset;
let cacheItem;
if (cache) {
const eTag = cache.getLazyHashedEtag(scriptAssetSource);
cacheItem = cache.getItemCache(name, eTag);
const cachedOutput = await cacheItem.getPromise();
if (cachedOutput) {
logger.debug(`${name} restored from cache`);
compilation.updateAsset(name, cachedOutput.source, (assetInfo) => ({
...assetInfo,
minimized: true,
}));
continue;
}
}
const { source, map } = scriptAssetSource.sourceAndMap();
scriptsToOptimize.push({
name: scriptAsset.name,
code: typeof source === 'string' ? source : source.toString(),
map,
cacheItem,
});
}
if (scriptsToOptimize.length === 0) {
return;
}
// Ensure all replacement values are strings which is the expected type for esbuild
let define;
if (this.options.define) {
define = {};
for (const [key, value] of Object.entries(this.options.define)) {
define[key] = String(value);
}
}
// Setup the options used by all worker tasks
const optimizeOptions = {
sourcemap: this.options.sourcemap,
define,
keepIdentifierNames: this.options.keepIdentifierNames,
target: this.targets,
removeLicenses: this.options.removeLicenses,
advanced: this.options.advanced,
// Perform a single native esbuild support check.
// This removes the need for each worker to perform the check which would
// otherwise require spawning a separate process per worker.
alwaysUseWasm: !(await esbuild_executor_1.EsbuildExecutor.hasNativeSupport()),
};
// Sort scripts so larger scripts start first - worker pool uses a FIFO queue
scriptsToOptimize.sort((a, b) => a.code.length - b.code.length);
// Initialize the task worker pool
const workerPath = require.resolve('./javascript-optimizer-worker');
const workerPool = new piscina_1.default({
filename: workerPath,
maxThreads: MAX_OPTIMIZE_WORKERS,
});
// Enqueue script optimization tasks and update compilation assets as the tasks complete
try {
const tasks = [];
for (const { name, code, map, cacheItem } of scriptsToOptimize) {
logger.time(`optimize asset: ${name}`);
tasks.push(workerPool
.run({
asset: {
name,
code,
map,
},
options: optimizeOptions,
})
.then(async ({ code, name, map, errors }) => {
if (errors?.length) {
for (const error of errors) {
(0, webpack_diagnostics_1.addError)(compilation, `Optimization error [${name}]: ${error}`);
}
return;
}
const optimizedAsset = map
? new SourceMapSource(code, name, map)
: new OriginalSource(code, name);
compilation.updateAsset(name, optimizedAsset, (assetInfo) => ({
...assetInfo,
minimized: true,
}));
logger.timeEnd(`optimize asset: ${name}`);
return cacheItem?.storePromise({
source: optimizedAsset,
});
}, (error) => {
(0, webpack_diagnostics_1.addError)(compilation, `Optimization error [${name}]: ${error.stack || error.message}`);
}));
}
await Promise.all(tasks);
}
finally {
void workerPool.destroy();
}
logger.timeEnd('optimize js assets');
});
});
}
}
exports.JavaScriptOptimizerPlugin = JavaScriptOptimizerPlugin;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiamF2YXNjcmlwdC1vcHRpbWl6ZXItcGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcGFja2FnZXMvYW5ndWxhcl9kZXZraXQvYnVpbGRfYW5ndWxhci9zcmMvdG9vbHMvd2VicGFjay9wbHVnaW5zL2phdmFzY3JpcHQtb3B0aW1pemVyLXBsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7Ozs7QUFFSCxzREFBOEI7QUFFOUIsNEVBQWdFO0FBQ2hFLDRFQUE4RDtBQUM5RCwrQ0FBMEU7QUFDMUUseURBQXFEO0FBR3JEOztHQUVHO0FBQ0gsTUFBTSxvQkFBb0IsR0FBRyxnQ0FBVSxDQUFDO0FBRXhDOztHQUVHO0FBQ0gsTUFBTSxXQUFXLEdBQUcsOEJBQThCLENBQUM7QUE2Q25EOzs7Ozs7O0dBT0c7QUFDSCxNQUFhLHlCQUF5QjtJQUdwQyxZQUFvQixPQUFtQztRQUFuQyxZQUFPLEdBQVAsT0FBTyxDQUE0QjtRQUNyRCxJQUFJLE9BQU8sQ0FBQyxpQkFBaUIsRUFBRTtZQUM3QixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUEsMkNBQW1DLEVBQUMsT0FBTyxDQUFDLGlCQUFpQixDQUFDLENBQUM7U0FDL0U7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQWtCO1FBQ3RCLE1BQU0sRUFBRSxjQUFjLEVBQUUsZUFBZSxFQUFFLEdBQUcsUUFBUSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFFckUsUUFBUSxDQUFDLEtBQUssQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDLFdBQVcsRUFBRSxFQUFFO1lBQzFELE1BQU0sTUFBTSxHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQUMseUNBQXlDLENBQUMsQ0FBQztZQUVoRixXQUFXLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQ3hDO2dCQUNFLElBQUksRUFBRSxXQUFXO2dC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QUssVUFBVSxDQUFDLE9BQU8sRUFBRSxDQUFDO2lCQUMzQjtnQkFFRCxNQUFNLENBQUMsT0FBTyxDQUFDLG9CQUFvQixDQUFDLENBQUM7WUFDdkMsQ0FBQyxDQUNGLENBQUM7UUFDSixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQXBLRCw4REFvS0MiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgR29vZ2xlIExMQyBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICpcbiAqIFVzZSBvZiB0aGlzIHNvdXJjZSBjb2RlIGlzIGdvdmVybmVkIGJ5IGFuIE1JVC1zdHlsZSBsaWNlbnNlIHRoYXQgY2FuIGJlXG4gKiBmb3VuZCBpbiB0aGUgTElDRU5TRSBmaWxlIGF0IGh0dHBzOi8vYW5ndWxhci5pby9saWNlbnNlXG4gKi9cblxuaW1wb3J0IFBpc2NpbmEgZnJvbSAncGlzY2luYSc7XG5pbXBvcnQgdHlwZSB7IENvbXBpbGVyLCBzb3VyY2VzIH0gZnJvbSAnd2VicGFjayc7XG5pbXBvcnQgeyBtYXhXb3JrZXJzIH0gZnJvbSAnLi4vLi4vLi4vdXRpbHMvZW52aXJvbm1lbnQtb3B0aW9ucyc7XG5pbXBvcnQgeyBhZGRFcnJvciB9IGZyb20gJy4uLy4uLy4uL3V0aWxzL3dlYnBhY2stZGlhZ25vc3RpY3MnO1xuaW1wb3J0IHsgdHJhbnNmb3JtU3VwcG9ydGVkQnJvd3NlcnNUb1RhcmdldHMgfSBmcm9tICcuLi8uLi9lc2J1aWxkL3V0aWxzJztcbmltcG9ydCB7IEVzYnVpbGRFeGVjdXRvciB9IGZyb20gJy4vZXNidWlsZC1leGVjdXRvcic7XG5pbXBvcnQgdHlwZSB7IE9wdGltaXplUmVxdWVzdE9wdGlvbnMgfSBmcm9tICcuL2phdmFzY3JpcHQtb3B0aW1pemVyLXdvcmtlcic7XG5cbi8qKlxuICogVGhlIG1heGltdW0gbnVtYmVyIG9mIFdvcmtlcnMgdGhhdCB3aWxsIGJlIGNyZWF0ZWQgdG8gZXhlY3V0ZSBvcHRpbWl6ZSB0YXNrcy5cbiAqL1xuY29uc3QgTUFYX09QVElNSVpFX1dPUktFUlMgPSBtYXhXb3JrZXJzO1xuXG4vKipcbiAqIFRoZSBuYW1lIG9mIHRoZSBwbHVnaW4gcHJvdmlkZWQgdG8gV2VicGFjayB3aGVuIHRhcHBpbmcgV2VicGFjayBjb21waWxlciBob29rcy5cbiAqL1xuY29uc3QgUExVR0lOX05BTUUgPSAnYW5ndWxhci1qYXZhc2NyaXB0LW9wdGltaXplcic7XG5cbi8qKlxuICogVGhlIG9wdGlvbnMgdXNlZCB0byBjb25maWd1cmUgdGhlIHtAbGluayBKYXZhU2NyaXB0T3B0aW1pemVyUGx1Z2lufS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBKYXZhU2NyaXB0T3B0aW1pemVyT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBFbmFibGVzIGFkdmFuY2VkIG9wdGltaXphdGlvbnMgaW4gdGhlIHVuZGVybHlpbmcgSmF2YVNjcmlwdCBvcHRpbWl6ZXJzLlxuICAgKiBUaGlzIGN1cnJlbnRseSBpbmNyZWFzZXMgdGhlIGB0ZXJzZXJgIHBhc3NlcyB0byAyIGFuZCBlbmFibGVzIHRoZSBgcHVyZV9nZXR0ZXJzYFxuICAgKiBvcHRpb24gZm9yIGB0ZXJzZXJgLlxuICAgKi9cbiAgYWR2YW5jZWQ/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBbiBvYmplY3QgcmVjb3JkIG9mIHN0cmluZyBrZXlzIHRoYXQgd2lsbCBiZSByZXBsYWNlZCB3aXRoIHRoZWlyIHJlc3BlY3RpdmUgdmFsdWVzIHdoZW4gZm91bmRcbiAgICogd2l0aGluIHRoZSBjb2RlIGR1cmluZyBvcHRpbWl6YXRpb24uXG4gICAqL1xuICBkZWZpbmU6IFJlY29yZDxzdHJpbmcsIHN0cmluZyB8IG51bWJlciB8IGJvb2xlYW4+O1xuXG4gIC8qKlxuICAgKiBFbmFibGVzIHRoZSBnZW5lcmF0aW9uIG9mIGEgc291cmNlbWFwIGR1cmluZyBvcHRpbWl6YXRpb24uXG4gICAqIFRoZSBvdXRwdXQgc291cmNlbWFwIHdpbGwgYmUgYSBmdWxsIHNvdXJjZW1hcCBjb250YWluaW5nIHRoZSBtZXJnZSBvZiB0aGUgaW5wdXQgc291cmNlbWFwIGFuZFxuICAgKiBhbGwgaW50ZXJtZWRpYXRlIHNvdXJjZW1hcHMuXG4gICAqL1xuICBzb3VyY2VtYXA/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBIGxpc3Qgb2Ygc3VwcG9ydGVkIGJyb3dzZXJzIHRoYXQgaXMgdXNlZCBmb3Igb3V0cHV0IGNvZGUuXG4gICAqL1xuICBzdXBwb3J0ZWRCcm93c2Vycz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBFbmFibGVzIHRoZSByZXRlbnRpb24gb2YgaWRlbnRpZmllciBuYW1lcyBhbmQgZW5zdXJlcyB0aGF0IGZ1bmN0aW9uIGFuZCBjbGFzcyBuYW1lcyBhcmVcbiAgICogcHJlc2VudCBpbiB0aGUgb3V0cHV0IGNvZGUuXG4gICAqXG4gICAqICoqTm90ZSoqOiBpbiBzb21lIGNhc2VzIHN5bWJvbHMgYXJlIHN0aWxsIHJlbmFtZWQgdG8gYXZvaWQgY29sbGlzaW9ucy5cbiAgICovXG4gIGtlZXBJZGVudGlmaWVyTmFtZXM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEVuYWJsZXMgdGhlIHJlbW92YWwgb2YgYWxsIGxpY2Vuc2UgY29tbWVudHMgZnJvbSB0aGUgb3V0cHV0IGNvZGUuXG4gICAqL1xuICByZW1vdmVMaWNlbnNlcz86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQSBXZWJwYWNrIHBsdWdpbiB0aGF0IHByb3ZpZGVzIEphdmFTY3JpcHQgb3B0aW1pemF0aW9uIGNhcGFiaWxpdGllcy5cbiAqXG4gKiBUaGUgcGx1Z2luIHVzZXMgYm90aCBgZXNidWlsZGAgYW5kIGB0ZXJzZXJgIHRvIHByb3ZpZGUgYm90aCBmYXN0IGFuZCBoaWdobHktb3B0aW1pemVkXG4gKiBjb2RlIG91dHB1dC4gYGVzYnVpbGRgIGlzIHVzZWQgYXMgYW4gaW5pdGlhbCBwYXNzIHRvIHJlbW92ZSB0aGUgbWFqb3JpdHkgb2YgdW51c2VkIGNvZGVcbiAqIGFzIHdlbGwgYXMgc2hvcnRlbiBpZGVudGlmaWVycy4gYHRlcnNlcmAgaXMgdGhlbiB1c2VkIGFzIGEgc2Vjb25kYXJ5IHBhc3MgdG8gYXBwbHlcbiAqIG9wdGltaXphdGlvbnMgbm90IHlldCBpbXBsZW1lbnRlZCBieSBgZXNidWlsZGAuXG4gKi9cbmV4cG9ydCBjbGFzcyBKYXZhU2NyaXB0T3B0aW1pemVyUGx1Z2luIHtcbiAgcHJpdmF0ZSB0YXJnZXRzOiBzdHJpbmdbXSB8IHVuZGVmaW5lZDtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIG9wdGlvbnM6IEphdmFTY3JpcHRPcHRpbWl6ZXJPcHRpb25zKSB7XG4gICAgaWYgKG9wdGlvbnMuc3VwcG9ydGVkQnJvd3NlcnMpIHtcbiAgICAgIHRoaXMudGFyZ2V0cyA9IHRyYW5zZm9ybVN1cHBvcnRlZEJyb3dzZXJzVG9UYXJnZXRzKG9wdGlvbnMuc3VwcG9ydGVkQnJvd3NlcnMpO1xuICAgIH1cbiAgfVxuXG4gIGFwcGx5KGNvbXBpbGVyOiBDb21waWxlcikge1xuICAgIGNvbnN0IHsgT3JpZ2luYWxTb3VyY2UsIFNvdXJjZU1hcFNvdXJjZSB9ID0gY29tcGlsZXIud2VicGFjay5zb3VyY2VzO1xuXG4gICAgY29tcGlsZXIuaG9va3MuY29tcGlsYXRpb24udGFwKFBMVUdJTl9OQU1FLCAoY29tcGlsYXRpb24pID0+IHtcbiAgICAgIGNvbnN0IGxvZ2dlciA9IGNvbXBpbGF0aW9uLmdldExvZ2dlcignYnVpbGQtYW5ndWxhci5KYXZhU2NyaXB0T3B0aW1pemVyUGx1Z2luJyk7XG5cbiAgICAgIGNvbXBpbGF0aW9uLmhvb2tzLnByb2Nlc3NBc3NldHMudGFwUHJvbWlzZShcbiAgICAgICAge1xuICAgICAgICAgIG5hbWU6IFBMVUdJTl9OQU1FLFxuICAgICAgICAgIHN0YWdlOiBjb21waWxlci53ZWJwYWNrLkNvbXBpbGF0aW9uLlBST0NFU1NfQVNTRVRTX1NUQUdFX09QVElNSVpFX1NJWkUsXG4gICAgICAgIH0sXG4gICAgICAgIGFzeW5jIChjb21waWxhdGlvbkFzc2V0cykgPT4ge1xuICAgICAgICAgIGxvZ2dlci50aW1lKCdvcHRpbWl6ZSBqcyBhc3NldHMnKTtcbiAgICAgICAgICBjb25zdCBzY3JpcHRzVG9PcHRpbWl6ZSA9IFtdO1xuICAgICAgICAgIGNvbnN0IGNhY2hlID1cbiAgICAgICAgICAgIGNvbXBpbGF0aW9uLm9wdGlvbnMuY2FjaGUgJiYgY29tcGlsYXRpb24uZ2V0Q2FjaGUoJ0phdmFTY3JpcHRPcHRpbWl6ZXJQbHVnaW4nKTtcblxuICAgICAgICAgIC8vIEFuYWx5emUgdGhlIGNvbXBpbGF0aW9uIGFzc2V0cyBmb3Igc2NyaXB0cyB0aGF0IHJlcXVpcmUgb3B0aW1pemF0aW9uXG4gICAgICAgICAgZm9yIChjb25zdCBhc3NldE5hbWUgb2YgT2JqZWN0LmtleXMoY29tcGlsYXRpb25Bc3NldHMpKSB7XG4gICAgICAgICAgICBpZiAoIWFzc2V0TmFtZS5lbmRzV2l0aCgnLmpzJykpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnN0IHNjcmlwdEFzc2V0ID0gY29tcGlsYXRpb24uZ2V0QXNzZXQoYXNzZXROYW1lKTtcbiAgICAgICAgICAgIC8vIFNraXAgYXNzZXRzIHRoYXQgaGF2ZSBhbHJlYWR5IGJlZW4gb3B0aW1pemVkIG9yIGFyZSB2ZXJiYXRpbSBjb3BpZXMgKHByb2plY3QgYXNzZXRzKVxuICAgICAgICAgICAgaWYgKCFzY3JpcHRBc3NldCB8fCBzY3JpcHRBc3NldC5pbmZvLm1pbmltaXplZCB8fCBzY3JpcHRBc3NldC5pbmZvLmNvcGllZCkge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgeyBzb3VyY2U6IHNjcmlwdEFzc2V0U291cmNlLCBuYW1lIH0gPSBzY3JpcHRBc3NldDtcbiAgICAgICAgICAgIGxldCBjYWNoZUl0ZW07XG5cbiAgICAgICAgICAgIGlmIChjYWNoZSkge1xuICAgICAgICAgICAgICBjb25zdCBlVGFnID0gY2FjaGUuZ2V0TGF6eUhhc2hlZEV0YWcoc2NyaXB0QXNzZXRTb3VyY2UpO1xuICAgICAgICAgICAgICBjYWNoZUl0ZW0gPSBjYWNoZS5nZXRJdGVtQ2FjaGUobmFtZSwgZVRhZyk7XG4gICAgICAgICAgICAgIGNvbnN0IGNhY2hlZE91dHB1dCA9IGF3YWl0IGNhY2hlSXRlbS5nZXRQcm9taXNlPFxuICAgICAgICAgICAgICAgIHsgc291cmNlOiBzb3VyY2VzLlNvdXJjZSB9IHwgdW5kZWZpbmVkXG4gICAgICAgICAgICAgID4oKTtcblxuICAgICAgICAgICAgICBpZiAoY2FjaGVkT3V0cHV0KSB7XG4gICAgICAgICAgICAgICAgbG9nZ2VyLmRlYnVnKGAke25hbWV9IHJlc3RvcmVkIGZyb20gY2FjaGVgKTtcbiAgICAgICAgICAgICAgICBjb21waWxhdGlvbi51cGRhdGVBc3NldChuYW1lLCBjYWNoZWRPdXRwdXQuc291cmNlLCAoYXNzZXRJbmZvKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgLi4uYXNzZXRJbmZvLFxuICAgICAgICAgICAgICAgICAgbWluaW1pemVkOiB0cnVlLFxuICAgICAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCB7IHNvdXJjZSwgbWFwIH0gPSBzY3JpcHRBc3NldFNvdXJjZS5zb3VyY2VBbmRNYXAoKTtcbiAgICAgICAgICAgIHNjcmlwdHNUb09wdGltaXplLnB1c2goe1xuICAgICAgICAgICAgICBuYW1lOiBzY3JpcHRBc3NldC5uYW1lLFxuICAgICAgICAgICAgICBjb2RlOiB0eXBlb2Ygc291cmNlID09PSAnc3RyaW5nJyA/IHNvdXJjZSA6IHNvdXJjZS50b1N0cmluZygpLFxuICAgICAgICAgICAgICBtYXAsXG4gICAgICAgICAgICAgIGNhY2hlSXRlbSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGlmIChzY3JpcHRzVG9PcHRpbWl6ZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBFbnN1cmUgYWxsIHJlcGxhY2VtZW50IHZhbHVlcyBhcmUgc3RyaW5ncyB3aGljaCBpcyB0aGUgZXhwZWN0ZWQgdHlwZSBmb3IgZXNidWlsZFxuICAgICAgICAgIGxldCBkZWZpbmU6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4gfCB1bmRlZmluZWQ7XG4gICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5kZWZpbmUpIHtcbiAgICAgICAgICAgIGRlZmluZSA9IHt9O1xuICAgICAgICAgICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5vcHRpb25zLmRlZmluZSkpIHtcbiAgICAgICAgICAgICAgZGVmaW5lW2tleV0gPSBTdHJpbmcodmFsdWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFNldHVwIHRoZSBvcHRpb25zIHVzZWQgYnkgYWxsIHdvcmtlciB0YXNrc1xuICAgICAgICAgIGNvbnN0IG9wdGltaXplT3B0aW9uczogT3B0aW1pemVSZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgICAgICAgIHNvdXJjZW1hcDogdGhpcy5vcHRpb25zLnNvdXJjZW1hcCxcbiAgICAgICAgICAgIGRlZmluZSxcbiAgICAgICAgICAgIGtlZXBJZGVudGlmaWVyTmFtZXM6IHRoaXMub3B0aW9ucy5rZWVwSWRlbnRpZmllck5hbWVzLFxuICAgICAgICAgICAgdGFyZ2V0OiB0aGlzLnRhcmdldHMsXG4gICAgICAgICAgICByZW1vdmVMaWNlbnNlczogdGhpcy5vcHRpb25zLnJlbW92ZUxpY2Vuc2VzLFxuICAgICAgICAgICAgYWR2YW5jZWQ6IHRoaXMub3B0aW9ucy5hZHZhbmNlZCxcbiAgICAgICAgICAgIC8vIFBlcmZvcm0gYSBzaW5nbGUgbmF0aXZlIGVzYnVpbGQgc3VwcG9ydCBjaGVjay5cbiAgICAgICAgICAgIC8vIFRoaXMgcmVtb3ZlcyB0aGUgbmVlZCBmb3IgZWFjaCB3b3JrZXIgdG8gcGVyZm9ybSB0aGUgY2hlY2sgd2hpY2ggd291bGRcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSByZXF1aXJlIHNwYXduaW5nIGEgc2VwYXJhdGUgcHJvY2VzcyBwZXIgd29ya2VyLlxuICAgICAgICAgICAgYWx3YXlzVXNlV2FzbTogIShhd2FpdCBFc2J1aWxkRXhlY3V0b3IuaGFzTmF0aXZlU3VwcG9ydCgpKSxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgLy8gU29ydCBzY3JpcHRzIHNvIGxhcmdlciBzY3JpcHRzIHN0YXJ0IGZpcnN0IC0gd29ya2VyIHBvb2wgdXNlcyBhIEZJRk8gcXVldWVcbiAgICAgICAgICBzY3JpcHRzVG9PcHRpbWl6ZS5zb3J0KChhLCBiKSA9PiBhLmNvZGUubGVuZ3RoIC0gYi5jb2RlLmxlbmd0aCk7XG5cbiAgICAgICAgICAvLyBJbml0aWFsaXplIHRoZSB0YXNrIHdvcmtlciBwb29sXG4gICAgICAgICAgY29uc3Qgd29ya2VyUGF0aCA9IHJlcXVpcmUucmVzb2x2ZSgnLi9qYXZhc2NyaXB0LW9wdGltaXplci13b3JrZXInKTtcbiAgICAgICAgICBjb25zdCB3b3JrZXJQb29sID0gbmV3IFBpc2NpbmEoe1xuICAgICAgICAgICAgZmlsZW5hbWU6IHdvcmtlclBhdGgsXG4gICAgICAgICAgICBtYXhUaHJlYWRzOiBNQVhfT1BUSU1JWkVfV09SS0VSUyxcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIEVucXVldWUgc2NyaXB0IG9wdGltaXphdGlvbiB0YXNrcyBhbmQgdXBkYXRlIGNvbXBpbGF0aW9uIGFzc2V0cyBhcyB0aGUgdGFza3MgY29tcGxldGVcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgdGFza3MgPSBbXTtcbiAgICAgICAgICAgIGZvciAoY29uc3QgeyBuYW1lLCBjb2RlLCBtYXAsIGNhY2hlSXRlbSB9IG9mIHNjcmlwdHNUb09wdGltaXplKSB7XG4gICAgICAgICAgICAgIGxvZ2dlci50aW1lKGBvcHRpbWl6ZSBhc3NldDogJHtuYW1lfWApO1xuXG4gICAgICAgICAgICAgIHRhc2tzLnB1c2goXG4gICAgICAgICAgICAgICAgd29ya2VyUG9vbFxuICAgICAgICAgICAgICAgICAgLnJ1bih7XG4gICAgICAgICAgICAgICAgICAgIGFzc2V0OiB7XG4gICAgICAgICAgICAgICAgICAgICAgbmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICBjb2RlLFxuICAgICAgICAgICAgICAgICAgICAgIG1hcCxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9uczogb3B0aW1pemVPcHRpb25zLFxuICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAgIC50aGVuKFxuICAgICAgICAgICAgICAgICAgICBhc3luYyAoeyBjb2RlLCBuYW1lLCBtYXAsIGVycm9ycyB9KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKGVycm9ycz8ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IGVycm9yIG9mIGVycm9ycykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBhZGRFcnJvcihjb21waWxhdGlvbiwgYE9wdGltaXphdGlvbiBlcnJvciBbJHtuYW1lfV06ICR7ZXJyb3J9YCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICBjb25zdCBvcHRpbWl6ZWRBc3NldCA9IG1hcFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBuZXcgU291cmNlTWFwU291cmNlKGNvZGUsIG5hbWUsIG1hcClcbiAgICAgICAgICAgICAgICAgICAgICAgIDogbmV3IE9yaWdpbmFsU291cmNlKGNvZGUsIG5hbWUpO1xuICAgICAgICAgICAgICAgICAgICAgIGNvbXBpbGF0aW9uLnVwZGF0ZUFzc2V0KG5hbWUsIG9wdGltaXplZEFzc2V0LCAoYXNzZXRJbmZvKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uYXNzZXRJbmZvLFxuICAgICAgICAgICAgICAgICAgICAgICAgbWluaW1pemVkOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgICAgICAgIGxvZ2dlci50aW1lRW5kKGBvcHRpbWl6ZSBhc3NldDogJHtuYW1lfWApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNhY2hlSXRlbT8uc3RvcmVQcm9taXNlKHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNvdXJjZTogb3B0aW1pemVkQXNzZXQsXG4gICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgIGFkZEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgY29tcGlsYXRpb24sXG4gICAgICAgICAgICAgICAgICAgICAgICBgT3B0aW1pemF0aW9uIGVycm9yIFske25hbWV9XTogJHtlcnJvci5zdGFjayB8fCBlcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICksXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKHRhc2tzKTtcbiAgICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgICAgdm9pZCB3b3JrZXJQb29sLmRlc3Ryb3koKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsb2dnZXIudGltZUVuZCgnb3B0aW1pemUganMgYXNzZXRzJyk7XG4gICAgICAgIH0sXG4gICAgICApO1xuICAgIH0pO1xuICB9XG59XG4iXX0=