/** * @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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; (function (factory) { if (typeof module === "object" && typeof module.exports === "object") { var v = factory(require, exports); if (v !== undefined) module.exports = v; } else if (typeof define === "function" && define.amd) { define("@nguniversal/builders/src/ssr-dev-server/index", ["require", "exports", "@angular-devkit/architect", "@angular-devkit/core", "browser-sync", "http-proxy-middleware", "path", "rxjs", "rxjs/operators", "url", "@nguniversal/builders/src/ssr-dev-server/utils"], factory); } })(function (require, exports) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const architect_1 = require("@angular-devkit/architect"); const core_1 = require("@angular-devkit/core"); const browserSync = require("browser-sync"); const http_proxy_middleware_1 = require("http-proxy-middleware"); const path_1 = require("path"); const rxjs_1 = require("rxjs"); const operators_1 = require("rxjs/operators"); const url = require("url"); const utils_1 = require("@nguniversal/builders/src/ssr-dev-server/utils"); /** Log messages to ignore and not rely to the logger */ const IGNORED_STDOUT_MESSAGES = [ 'server listening on', 'Angular is running in the development mode. Call enableProdMode() to enable the production mode.' ]; function execute(options, context) { const browserTarget = architect_1.targetFromTargetString(options.browserTarget); const serverTarget = architect_1.targetFromTargetString(options.serverTarget); const getBaseUrl = (bs) => `${bs.getOption('scheme')}://${bs.getOption('host')}:${bs.getOption('port')}`; const browserTargetRun = context.scheduleTarget(browserTarget, { extractCss: true, serviceWorker: false, watch: true, progress: options.progress, }); const serverTargetRun = context.scheduleTarget(serverTarget, { watch: true, progress: options.progress, }); const bsInstance = browserSync.create(); context.logger.error(core_1.tags.stripIndents ` **************************************************************************************** This is a simple server for use in testing or debugging Angular applications locally. It hasn't been reviewed for security issues. DON'T USE IT FOR PRODUCTION! **************************************************************************************** `); return rxjs_1.zip(browserTargetRun, serverTargetRun, utils_1.getAvailablePort()).pipe(operators_1.switchMap(([br, sr, nodeServerPort]) => { return rxjs_1.combineLatest([br.output, sr.output]).pipe( // This is needed so that if both server and browser emit close to each other // we only emit once. This typically happens on the first build. operators_1.debounceTime(120), operators_1.switchMap(([b, s]) => { if (!s.success || !b.success) { return rxjs_1.of([b, s]); } return startNodeServer(s, nodeServerPort, context.logger).pipe(operators_1.mapTo([b, s]), operators_1.catchError(err => { context.logger.error(`A server error has occurred.\n${mapErrorToMessage(err)}`); return rxjs_1.EMPTY; })); }), operators_1.map(([b, s]) => [ { success: b.success && s.success, error: b.error || s.error, }, nodeServerPort, ]), operators_1.tap(([builderOutput]) => { if (builderOutput.success) { context.logger.info('\nCompiled successfully.'); } }), operators_1.debounce(([builderOutput]) => builderOutput.success ? utils_1.waitUntilServerIsListening(nodeServerPort) : rxjs_1.EMPTY)); }), operators_1.concatMap(([builderOutput, nodeServerPort]) => { if (!builderOutput.success) { return rxjs_1.of(builderOutput); } if (bsInstance.active) { bsInstance.reload(); return rxjs_1.of(builderOutput); } else { return rxjs_1.from(initBrowserSync(bsInstance, nodeServerPort, options)) .pipe(operators_1.tap(bs => { const baseUrl = getBaseUrl(bs); context.logger.info(core_1.tags.oneLine ` ** Angular Universal Live Development Server is listening on ${baseUrl}, open your browser on ${baseUrl} ** `); }), operators_1.mapTo(builderOutput)); } }), operators_1.map(builderOutput => ({ success: builderOutput.success, error: builderOutput.error, baseUrl: bsInstance && getBaseUrl(bsInstance), })), operators_1.finalize(() => { if (bsInstance) { bsInstance.exit(); bsInstance.cleanup(); } }), operators_1.catchError(error => rxjs_1.of({ success: false, error: mapErrorToMessage(error), }))); } exports.execute = execute; function startNodeServer(serverOutput, port, logger) { const outputPath = serverOutput.outputPath; const path = path_1.join(outputPath, 'main.js'); const env = Object.assign(Object.assign({}, process.env), { PORT: '' + port }); return rxjs_1.of(null) .pipe(operators_1.delay(0), // Avoid EADDRINUSE error since it will cause the kill event to be finish. operators_1.switchMap(() => utils_1.spawnAsObservable('node', [`"${path}"`], { env, shell: true })), operators_1.tap(({ stderr, stdout }) => { if (stderr) { logger.error(stderr); } if (stdout && !IGNORED_STDOUT_MESSAGES.some(x => stdout.includes(x))) { logger.info(stdout); } }), operators_1.ignoreElements(), // Emit a signal after the process has been started operators_1.startWith(undefined)); } function initBrowserSync(browserSyncInstance, nodeServerPort, options) { return __awaiter(this, void 0, void 0, function* () { if (browserSyncInstance.active) { return browserSyncInstance; } const { port: browserSyncPort, open, host, publicHost } = options; const bsPort = browserSyncPort || (yield utils_1.getAvailablePort()); const bsOptions = { proxy: { target: `localhost:${nodeServerPort}`, proxyOptions: { xfwd: true }, proxyRes: [ proxyRes => { if ('headers' in proxyRes) { proxyRes.headers['cache-control'] = undefined; } }, ] // proxyOptions is not in the typings }, host, port: bsPort, ui: false, server: false, notify: false, ghostMode: false, logLevel: 'silent', open, }; const publicHostNormalized = publicHost && publicHost.endsWith('/') ? publicHost.substring(0, publicHost.length - 1) : publicHost; if (publicHostNormalized) { const { protocol, hostname, port, pathname } = url.parse(publicHostNormalized); const defaultSocketIoPath = '/browser-sync/socket.io'; const defaultNamespace = '/browser-sync'; const hasPathname = !!(pathname && pathname !== '/'); const namespace = hasPathname ? pathname + defaultNamespace : defaultNamespace; const path = hasPathname ? pathname + defaultSocketIoPath : defaultSocketIoPath; bsOptions.socket = { namespace, path, domain: url.format({ protocol, hostname, port, }), }; // When having a pathname we also need to create a reverse proxy because socket.io // will be listening on: 'http://localhost:4200/ssr/browser-sync/socket.io' // However users will typically have a reverse proxy that will redirect all matching requests // ex: http://testinghost.com/ssr -> http://localhost:4200 which will result in a 404. if (hasPathname) { // Remove leading slash bsOptions.scriptPath = p => p.substring(1), bsOptions.middleware = [ http_proxy_middleware_1.createProxyMiddleware(defaultSocketIoPath, { target: url.format({ protocol: 'http', hostname: host, port: bsPort, pathname: path, }), ws: true, logLevel: 'silent', }), ]; } } return new Promise((resolve, reject) => { browserSyncInstance.init(bsOptions, (error, bs) => { if (error) { reject(error); } else { resolve(bs); } }); }); }); } function mapErrorToMessage(error) { if (error instanceof Error) { return error.message; } if (typeof error === 'string') { return error; } return ''; } exports.default = architect_1.createBuilder(execute); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9tb2R1bGVzL2J1aWxkZXJzL3NyYy9zc3ItZGV2LXNlcnZlci9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7O0dBTUc7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztJQUVILHlEQUttQztJQUNuQywrQ0FBMkQ7SUFDM0QsNENBQTRDO0lBQzVDLGlFQUE4RDtJQUM5RCwrQkFBNEI7SUFDNUIsK0JBT2M7SUFDZCw4Q0Fhd0I7SUFDeEIsMkJBQTJCO0lBRzNCLDBFQUEwRjtJQUUxRix3REFBd0Q7SUFDeEQsTUFBTSx1QkFBdUIsR0FBRztRQUM5QixxQkFBcUI7UUFDckIsa0dBQWtHO0tBQ25HLENBQUM7SUFRRixTQUFnQixPQUFPLENBQ3JCLE9BQW1DLEVBQ25DLE9BQXVCO1FBRXZCLE1BQU0sYUFBYSxHQUFHLGtDQUFzQixDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNwRSxNQUFNLFlBQVksR0FBRyxrQ0FBc0IsQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDbEUsTUFBTSxVQUFVLEdBQUcsQ0FBQyxFQUFtQyxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7UUFFMUksTUFBTSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLGFBQWEsRUFBRTtZQUM3RCxVQUFVLEVBQUUsSUFBSTtZQUNoQixhQUFhLEVBQUUsS0FBSztZQUNwQixLQUFLLEVBQUUsSUFBSTtZQUNYLFFBQVEsRUFBRSxPQUFPLENBQUMsUUFBUTtTQUMzQixDQUFDLENBQUM7UUFFSCxNQUFNLGVBQWUsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDLFlBQVksRUFB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QUFDLENBQUM7UUFDTCxDQUFDO0tBQUE7SUFFRCxTQUFTLGlCQUFpQixDQUFDLEtBQWM7UUFDdkMsSUFBSSxLQUFLLFlBQVksS0FBSyxFQUFFO1lBQzFCLE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQztTQUN0QjtRQUVELElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxFQUFFO1lBQzdCLE9BQU8sS0FBSyxDQUFDO1NBQ2Q7UUFFRCxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFFRCxrQkFBZSx5QkFBYSxDQUE0QyxPQUFPLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGxpY2Vuc2VcbiAqIENvcHlyaWdodCBHb29nbGUgTExDIEFsbCBSaWdodHMgUmVzZXJ2ZWQuXG4gKlxuICogVXNlIG9mIHRoaXMgc291cmNlIGNvZGUgaXMgZ292ZXJuZWQgYnkgYW4gTUlULXN0eWxlIGxpY2Vuc2UgdGhhdCBjYW4gYmVcbiAqIGZvdW5kIGluIHRoZSBMSUNFTlNFIGZpbGUgYXQgaHR0cHM6Ly9hbmd1bGFyLmlvL2xpY2Vuc2VcbiAqL1xuXG5pbXBvcnQge1xuICBCdWlsZGVyQ29udGV4dCxcbiAgQnVpbGRlck91dHB1dCxcbiAgY3JlYXRlQnVpbGRlcixcbiAgdGFyZ2V0RnJvbVRhcmdldFN0cmluZyxcbn0gZnJvbSAnQGFuZ3VsYXItZGV2a2l0L2FyY2hpdGVjdCc7XG5pbXBvcnQgeyBqc29uLCBsb2dnaW5nLCB0YWdzIH0gZnJvbSAnQGFuZ3VsYXItZGV2a2l0L2NvcmUnO1xuaW1wb3J0ICogYXMgYnJvd3NlclN5bmMgZnJvbSAnYnJvd3Nlci1zeW5jJztcbmltcG9ydCB7IGNyZWF0ZVByb3h5TWlkZGxld2FyZSB9IGZyb20gJ2h0dHAtcHJveHktbWlkZGxld2FyZSc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQge1xuICBFTVBUWSxcbiAgT2JzZXJ2YWJsZSxcbiAgY29tYmluZUxhdGVzdCxcbiAgZnJvbSxcbiAgb2YsXG4gIHppcCxcbn0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBjYXRjaEVycm9yLFxuICBjb25jYXRNYXAsXG4gIGRlYm91bmNlLFxuICBkZWJvdW5jZVRpbWUsXG4gIGRlbGF5LFxuICBmaW5hbGl6ZSxcbiAgaWdub3JlRWxlbWVudHMsXG4gIG1hcCxcbiAgbWFwVG8sXG4gIHN0YXJ0V2l0aCxcbiAgc3dpdGNoTWFwLFxuICB0YXAsXG59IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuaW1wb3J0IHsgU2NoZW1hIH0gZnJvbSAnLi9zY2hlbWEnO1xuXG5pbXBvcnQgeyBnZXRBdmFpbGFibGVQb3J0LCBzcGF3bkFzT2JzZXJ2YWJsZSwgd2FpdFVudGlsU2VydmVySXNMaXN0ZW5pbmcgfSBmcm9tICcuL3V0aWxzJztcblxuLyoqIExvZyBtZXNzYWdlcyB0byBpZ25vcmUgYW5kIG5vdCByZWx5IHRvIHRoZSBsb2dnZXIgKi9cbmNvbnN0IElHTk9SRURfU1RET1VUX01FU1NBR0VTID0gW1xuICAnc2VydmVyIGxpc3RlbmluZyBvbicsXG4gICdBbmd1bGFyIGlzIHJ1bm5pbmcgaW4gdGhlIGRldmVsb3BtZW50IG1vZGUuIENhbGwgZW5hYmxlUHJvZE1vZGUoKSB0byBlbmFibGUgdGhlIHByb2R1Y3Rpb24gbW9kZS4nXG5dO1xuXG5cbmV4cG9ydCB0eXBlIFNTUkRldlNlcnZlckJ1aWxkZXJPcHRpb25zID0gU2NoZW1hICYganNvbi5Kc29uT2JqZWN0O1xuZXhwb3J0IHR5cGUgU1NSRGV2U2VydmVyQnVpbGRlck91dHB1dCA9IEJ1aWxkZXJPdXRwdXQgJiB7XG4gIGJhc2VVcmw/OiBzdHJpbmc7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZXhlY3V0ZShcbiAgb3B0aW9uczogU1NSRGV2U2VydmVyQnVpbGRlck9wdGlvbnMsXG4gIGNvbnRleHQ6IEJ1aWxkZXJDb250ZXh0LFxuKTogT2JzZXJ2YWJsZTxTU1JEZXZTZXJ2ZXJCdWlsZGVyT3V0cHV0PiB7XG4gIGNvbnN0IGJyb3dzZXJUYXJnZXQgPSB0YXJnZXRGcm9tVGFyZ2V0U3RyaW5nKG9wdGlvbnMuYnJvd3NlclRhcmdldCk7XG4gIGNvbnN0IHNlcnZlclRhcmdldCA9IHRhcmdldEZyb21UYXJnZXRTdHJpbmcob3B0aW9ucy5zZXJ2ZXJUYXJnZXQpO1xuICBjb25zdCBnZXRCYXNlVXJsID0gKGJzOiBicm93c2VyU3luYy5Ccm93c2VyU3luY0luc3RhbmNlKSA9PiBgJHticy5nZXRPcHRpb24oJ3NjaGVtZScpfTovLyR7YnMuZ2V0T3B0aW9uKCdob3N0Jyl9OiR7YnMuZ2V0T3B0aW9uKCdwb3J0Jyl9YDtcblxuICBjb25zdCBicm93c2VyVGFyZ2V0UnVuID0gY29udGV4dC5zY2hlZHVsZVRhcmdldChicm93c2VyVGFyZ2V0LCB7XG4gICAgZXh0cmFjdENzczogdHJ1ZSxcbiAgICBzZXJ2aWNlV29ya2VyOiBmYWxzZSxcbiAgICB3YXRjaDogdHJ1ZSxcbiAgICBwcm9ncmVzczogb3B0aW9ucy5wcm9ncmVzcyxcbiAgfSk7XG5cbiAgY29uc3Qgc2VydmVyVGFyZ2V0UnVuID0gY29udGV4dC5zY2hlZHVsZVRhcmdldChzZXJ2ZXJUYXJnZXQsIHtcbiAgICB3YXRjaDogdHJ1ZSxcbiAgICBwcm9ncmVzczogb3B0aW9ucy5wcm9ncmVzcyxcbiAgfSk7XG5cbiAgY29uc3QgYnNJbnN0YW5jZSA9IGJyb3dzZXJTeW5jLmNyZWF0ZSgpO1xuXG4gIGNvbnRleHQubG9nZ2VyLmVycm9yKHRhZ3Muc3RyaXBJbmRlbnRzYFxuICAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gIFRoaXMgaXMgYSBzaW1wbGUgc2VydmVyIGZvciB1c2UgaW4gdGVzdGluZyBvciBkZWJ1Z2dpbmcgQW5ndWxhciBhcHBsaWNhdGlvbnMgbG9jYWxseS5cbiAgSXQgaGFzbid0IGJlZW4gcmV2aWV3ZWQgZm9yIHNlY3VyaXR5IGlzc3Vlcy5cblxuICBET04nVCBVU0UgSVQgRk9SIFBST0RVQ1RJT04hXG4gICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiBgKTtcblxuICByZXR1cm4gemlwKFxuICAgIGJyb3dzZXJUYXJnZXRSdW4sXG4gICAgc2VydmVyVGFyZ2V0UnVuLFxuICAgIGdldEF2YWlsYWJsZVBvcnQoKSxcbiAgKS5waXBlKFxuICAgIHN3aXRjaE1hcCgoW2JyLCBzciwgbm9kZVNlcnZlclBvcnRdKSA9PiB7XG4gICAgICByZXR1cm4gY29tYmluZUxhdGVzdChbYnIub3V0cHV0LCBzci5vdXRwdXRdKS5waXBlKFxuICAgICAgICAvLyBUaGlzIGlzIG5lZWRlZCBzbyB0aGF0IGlmIGJvdGggc2VydmVyIGFuZCBicm93c2VyIGVtaXQgY2xvc2UgdG8gZWFjaCBvdGhlclxuICAgICAgICAvLyB3ZSBvbmx5IGVtaXQgb25jZS4gVGhpcyB0eXBpY2FsbHkgaGFwcGVucyBvbiB0aGUgZmlyc3QgYnVpbGQuXG4gICAgICAgIGRlYm91bmNlVGltZSgxMjApLFxuICAgICAgICBzd2l0Y2hNYXAoKFtiLCBzXSkgPT4ge1xuICAgICAgICAgIGlmICghcy5zdWNjZXNzIHx8ICFiLnN1Y2Nlc3MpIHtcbiAgICAgICAgICAgIHJldHVybiBvZihbYiwgc10pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiBzdGFydE5vZGVTZXJ2ZXIocywgbm9kZVNlcnZlclBvcnQsIGNvbnRleHQubG9nZ2VyKS5waXBlKFxuICAgICAgICAgICAgbWFwVG8oW2IsIHNdKSxcbiAgICAgICAgICAgIGNhdGNoRXJyb3IoZXJyID0+IHtcbiAgICAgICAgICAgICAgY29udGV4dC5sb2dnZXIuZXJyb3IoYEEgc2VydmVyIGVycm9yIGhhcyBvY2N1cnJlZC5cXG4ke21hcEVycm9yVG9NZXNzYWdlKGVycil9YCk7XG5cbiAgICAgICAgICAgICAgcmV0dXJuIEVNUFRZO1xuICAgICAgICAgICAgfSksXG4gICAgICAgICAgKTtcbiAgICAgICAgfSksXG4gICAgICAgIG1hcCgoW2IsIHNdKSA9PiAoW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIHN1Y2Nlc3M6IGIuc3VjY2VzcyAmJiBzLnN1Y2Nlc3MsXG4gICAgICAgICAgICBlcnJvcjogYi5lcnJvciB8fCBzLmVycm9yLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgbm9kZVNlcnZlclBvcnQsXG4gICAgICAgIF0gYXMgW1NTUkRldlNlcnZlckJ1aWxkZXJPdXRwdXQsIG51bWJlcl0pKSxcbiAgICAgICAgdGFwKChbYnVpbGRlck91dHB1dF0pID0+IHtcbiAgICAgICAgICBpZiAoYnVpbGRlck91dHB1dC5zdWNjZXNzKSB7XG4gICAgICAgICAgICBjb250ZXh0LmxvZ2dlci5pbmZvKCdcXG5Db21waWxlZCBzdWNjZXNzZnVsbHkuJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICAgZGVib3VuY2UoKFtidWlsZGVyT3V0cHV0XSkgPT4gYnVpbGRlck91dHB1dC5zdWNjZXNzXG4gICAgICAgICAgPyB3YWl0VW50aWxTZXJ2ZXJJc0xpc3RlbmluZyhub2RlU2VydmVyUG9ydClcbiAgICAgICAgICA6IEVNUFRZKVxuICAgICAgKTtcbiAgICB9KSxcbiAgICBjb25jYXRNYXAoKFtidWlsZGVyT3V0cHV0LCBub2RlU2VydmVyUG9ydF0pID0+IHtcbiAgICAgIGlmICghYnVpbGRlck91dHB1dC5zdWNjZXNzKSB7XG4gICAgICAgIHJldHVybiBvZihidWlsZGVyT3V0cHV0KTtcbiAgICAgIH1cblxuICAgICAgaWYgKGJzSW5zdGFuY2UuYWN0aXZlKSB7XG4gICAgICAgIGJzSW5zdGFuY2UucmVsb2FkKCk7XG5cbiAgICAgICAgcmV0dXJuIG9mKGJ1aWxkZXJPdXRwdXQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIGZyb20oaW5pdEJyb3dzZXJTeW5jKGJzSW5zdGFuY2UsIG5vZGVTZXJ2ZXJQb3J0LCBvcHRpb25zKSlcbiAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgIHRhcChicyA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IGJhc2VVcmwgPSBnZXRCYXNlVXJsKGJzKTtcbiAgICAgICAgICAgICAgY29udGV4dC5sb2dnZXIuaW5mbyh0YWdzLm9uZUxpbmVgXG4gICAgICAgICAgICAgICAgKipcbiAgICAgICAgICAgICAgICBBbmd1bGFyIFVuaXZlcnNhbCBMaXZlIERldmVsb3BtZW50IFNlcnZlciBpcyBsaXN0ZW5pbmcgb24gJHtiYXNlVXJsfSxcbiAgICAgICAgICAgICAgICBvcGVuIHlvdXIgYnJvd3NlciBvbiAke2Jhc2VVcmx9XG4gICAgICAgICAgICAgICAgKipcbiAgICAgICAgICAgICAgYCk7XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIG1hcFRvKGJ1aWxkZXJPdXRwdXQpLFxuICAgICAgICAgICk7XG4gICAgICB9XG4gICAgfSksXG4gICAgbWFwKGJ1aWxkZXJPdXRwdXQgPT4gKHtcbiAgICAgIHN1Y2Nlc3M6IGJ1aWxkZXJPdXRwdXQuc3VjY2VzcyxcbiAgICAgIGVycm9yOiBidWlsZGVyT3V0cHV0LmVycm9yLFxuICAgICAgYmFzZVVybDogYnNJbnN0YW5jZSAmJiBnZXRCYXNlVXJsKGJzSW5zdGFuY2UpLFxuICAgIH0gYXMgU1NSRGV2U2VydmVyQnVpbGRlck91dHB1dCkpLFxuICAgIGZpbmFsaXplKCgpID0+IHtcbiAgICAgIGlmIChic0luc3RhbmNlKSB7XG4gICAgICAgIGJzSW5zdGFuY2UuZXhpdCgpO1xuICAgICAgICBic0luc3RhbmNlLmNsZWFudXAoKTtcbiAgICAgIH1cbiAgICB9KSxcbiAgICBjYXRjaEVycm9yKGVycm9yID0+IG9mKHtcbiAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgZXJyb3I6IG1hcEVycm9yVG9NZXNzYWdlKGVycm9yKSxcbiAgICB9KSksXG4gICk7XG59XG5cbmZ1bmN0aW9uIHN0YXJ0Tm9kZVNlcnZlcihcbiAgc2VydmVyT3V0cHV0OiBCdWlsZGVyT3V0cHV0LFxuICBwb3J0OiBudW1iZXIsXG4gIGxvZ2dlcjogbG9nZ2luZy5Mb2dnZXJBcGksXG4pOiBPYnNlcnZhYmxlPHZvaWQ+IHtcbiAgY29uc3Qgb3V0cHV0UGF0aCA9IHNlcnZlck91dHB1dC5vdXRwdXRQYXRoIGFzIHN0cmluZztcbiAgY29uc3QgcGF0aCA9IGpvaW4ob3V0cHV0UGF0aCwgJ21haW4uanMnKTtcbiAgY29uc3QgZW52ID0geyAuLi5wcm9jZXNzLmVudiwgUE9SVDogJycgKyBwb3J0IH07XG5cbiAgcmV0dXJuIG9mKG51bGwpXG4gICAgLnBpcGUoXG4gICAgICBkZWxheSgwKSwgLy8gQXZvaWQgRUFERFJJTlVTRSBlcnJvciBzaW5jZSBpdCB3aWxsIGNhdXNlIHRoZSBraWxsIGV2ZW50IHRvIGJlIGZpbmlzaC5cbiAgICAgIHN3aXRjaE1hcCgoKSA9PiBzcGF3bkFzT2JzZXJ2YWJsZSgnbm9kZScsIFtgXCIke3BhdGh9XCJgXSwgeyBlbnYsIHNoZWxsOiB0cnVlIH0pKSxcbiAgICAgIHRhcCgoeyBzdGRlcnIsIHN0ZG91dCB9KSA9PiB7XG4gICAgICAgIGlmIChzdGRlcnIpIHtcbiAgICAgICAgICBsb2dnZXIuZXJyb3Ioc3RkZXJyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChzdGRvdXQgJiYgIUlHTk9SRURfU1RET1VUX01FU1NBR0VTLnNvbWUoeCA9PiBzdGRvdXQuaW5jbHVkZXMoeCkpKSB7XG4gICAgICAgICAgbG9nZ2VyLmluZm8oc3Rkb3V0KTtcbiAgICAgICAgfVxuICAgICAgfSksXG4gICAgICBpZ25vcmVFbGVtZW50cygpLFxuICAgICAgLy8gRW1pdCBhIHNpZ25hbCBhZnRlciB0aGUgcHJvY2VzcyBoYXMgYmVlbiBzdGFydGVkXG4gICAgICBzdGFydFdpdGgodW5kZWZpbmVkKSxcbiAgICApO1xufVxuXG5hc3luYyBmdW5jdGlvbiBpbml0QnJvd3NlclN5bmMoXG4gIGJyb3dzZXJTeW5jSW5zdGFuY2U6IGJyb3dzZXJTeW5jLkJyb3dzZXJTeW5jSW5zdGFuY2UsXG4gIG5vZGVTZXJ2ZXJQb3J0OiBudW1iZXIsXG4gIG9wdGlvbnM6IFNTUkRldlNlcnZlckJ1aWxkZXJPcHRpb25zLFxuKTogUHJvbWlzZTxicm93c2VyU3luYy5Ccm93c2VyU3luY0luc3RhbmNlPiB7XG4gIGlmIChicm93c2VyU3luY0luc3RhbmNlLmFjdGl2ZSkge1xuICAgIHJldHVybiBicm93c2VyU3luY0luc3RhbmNlO1xuICB9XG5cbiAgY29uc3QgeyBwb3J0OiBicm93c2VyU3luY1BvcnQsIG9wZW4sIGhvc3QsIHB1YmxpY0hvc3QgfSA9IG9wdGlvbnM7XG4gIGNvbnN0IGJzUG9ydCA9IGJyb3dzZXJTeW5jUG9ydCB8fCBhd2FpdCBnZXRBdmFpbGFibGVQb3J0KCk7XG4gIGNvbnN0IGJzT3B0aW9uczogYnJvd3NlclN5bmMuT3B0aW9ucyA9IHtcbiAgICBwcm94eToge1xuICAgICAgdGFyZ2V0OiBgbG9jYWxob3N0OiR7bm9kZVNlcnZlclBvcnR9YCxcbiAgICAgIHByb3h5T3B0aW9uczoge1xuICAgICAgICB4ZndkOiB0cnVlXG4gICAgICB9LFxuICAgICAgcHJveHlSZXM6IFtcbiAgICAgICAgcHJveHlSZXMgPT4ge1xuICAgICAgICAgIGlmICgnaGVhZGVycycgaW4gcHJveHlSZXMpIHtcbiAgICAgICAgICAgIHByb3h5UmVzLmhlYWRlcnNbJ2NhY2hlLWNvbnRyb2wnXSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICBdXG4gICAgICAvLyBwcm94eU9wdGlvbnMgaXMgbm90IGluIHRoZSB0eXBpbmdzXG4gICAgfSBhcyBicm93c2VyU3luYy5Qcm94eU9wdGlvbnMgJiB7IHByb3h5T3B0aW9uczogeyB4ZndkOiBib29sZWFuIH0gfSxcbiAgICBob3N0LFxuICAgIHBvcnQ6IGJzUG9ydCxcbiAgICB1aTogZmFsc2UsXG4gICAgc2VydmVyOiBmYWxzZSxcbiAgICBub3RpZnk6IGZhbHNlLFxuICAgIGdob3N0TW9kZTogZmFsc2UsXG4gICAgbG9nTGV2ZWw6ICdzaWxlbnQnLFxuICAgIG9wZW4sXG4gIH07XG5cbiAgY29uc3QgcHVibGljSG9zdE5vcm1hbGl6ZWQgPSBwdWJsaWNIb3N0ICYmIHB1YmxpY0hvc3QuZW5kc1dpdGgoJy8nKVxuICAgID8gcHVibGljSG9zdC5zdWJzdHJpbmcoMCwgcHVibGljSG9zdC5sZW5ndGggLSAxKVxuICAgIDogcHVibGljSG9zdDtcblxuICBpZiAocHVibGljSG9zdE5vcm1hbGl6ZWQpIHtcbiAgICBjb25zdCB7IHByb3RvY29sLCBob3N0bmFtZSwgcG9ydCwgcGF0aG5hbWUgfSA9IHVybC5wYXJzZShwdWJsaWNIb3N0Tm9ybWFsaXplZCk7XG4gICAgY29uc3QgZGVmYXVsdFNvY2tldElvUGF0aCA9ICcvYnJvd3Nlci1zeW5jL3NvY2tldC5pbyc7XG4gICAgY29uc3QgZGVmYXVsdE5hbWVzcGFjZSA9ICcvYnJvd3Nlci1zeW5jJztcbiAgICBjb25zdCBoYXNQYXRobmFtZSA9ICEhKHBhdGhuYW1lICYmIHBhdGhuYW1lICE9PSAnLycpO1xuICAgIGNvbnN0IG5hbWVzcGFjZSA9IGhhc1BhdGhuYW1lID8gcGF0aG5hbWUgKyBkZWZhdWx0TmFtZXNwYWNlIDogZGVmYXVsdE5hbWVzcGFjZTtcbiAgICBjb25zdCBwYXRoID0gaGFzUGF0aG5hbWUgPyBwYXRobmFtZSArIGRlZmF1bHRTb2NrZXRJb1BhdGggOiBkZWZhdWx0U29ja2V0SW9QYXRoO1xuXG4gICAgYnNPcHRpb25zLnNvY2tldCA9IHtcbiAgICAgIG5hbWVzcGFjZSxcbiAgICAgIHBhdGgsXG4gICAgICBkb21haW46IHVybC5mb3JtYXQoe1xuICAgICAgICBwcm90b2NvbCxcbiAgICAgICAgaG9zdG5hbWUsXG4gICAgICAgIHBvcnQsXG4gICAgICB9KSxcbiAgICB9O1xuXG4gICAgLy8gV2hlbiBoYXZpbmcgYSBwYXRobmFtZSB3ZSBhbHNvIG5lZWQgdG8gY3JlYXRlIGEgcmV2ZXJzZSBwcm94eSBiZWNhdXNlIHNvY2tldC5pb1xuICAgIC8vIHdpbGwgYmUgbGlzdGVuaW5nIG9uOiAnaHR0cDovL2xvY2FsaG9zdDo0MjAwL3Nzci9icm93c2VyLXN5bmMvc29ja2V0LmlvJ1xuICAgIC8vIEhvd2V2ZXIgdXNlcnMgd2lsbCB0eXBpY2FsbHkgaGF2ZSBhIHJldmVyc2UgcHJveHkgdGhhdCB3aWxsIHJlZGlyZWN0IGFsbCBtYXRjaGluZyByZXF1ZXN0c1xuICAgIC8vIGV4OiBodHRwOi8vdGVzdGluZ2hvc3QuY29tL3NzciAtPiBodHRwOi8vbG9jYWxob3N0OjQyMDAgd2hpY2ggd2lsbCByZXN1bHQgaW4gYSA0MDQuXG4gICAgaWYgKGhhc1BhdGhuYW1lKSB7XG4gICAgICAvLyBSZW1vdmUgbGVhZGluZyBzbGFzaFxuICAgICAgYnNPcHRpb25zLnNjcmlwdFBhdGggPSBwID0+IHAuc3Vic3RyaW5nKDEpLFxuICAgICAgICBic09wdGlvbnMubWlkZGxld2FyZSA9IFtcbiAgICAgICAgICBjcmVhdGVQcm94eU1pZGRsZXdhcmUoZGVmYXVsdFNvY2tldElvUGF0aCwge1xuICAgICAgICAgICAgdGFyZ2V0OiB1cmwuZm9ybWF0KHtcbiAgICAgICAgICAgICAgcHJvdG9jb2w6ICdodHRwJyxcbiAgICAgICAgICAgICAgaG9zdG5hbWU6IGhvc3QsXG4gICAgICAgICAgICAgIHBvcnQ6IGJzUG9ydCxcbiAgICAgICAgICAgICAgcGF0aG5hbWU6IHBhdGgsXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHdzOiB0cnVlLFxuICAgICAgICAgICAgbG9nTGV2ZWw6ICdzaWxlbnQnLFxuICAgICAgICAgIH0pIGFzIGFueSxcbiAgICAgICAgXTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGJyb3dzZXJTeW5jSW5zdGFuY2UuaW5pdChic09wdGlvbnMsIChlcnJvciwgYnMpID0+IHtcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzb2x2ZShicyk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBtYXBFcnJvclRvTWVzc2FnZShlcnJvcjogdW5rbm93bik6IHN0cmluZyB7XG4gIGlmIChlcnJvciBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgcmV0dXJuIGVycm9yLm1lc3NhZ2U7XG4gIH1cblxuICBpZiAodHlwZW9mIGVycm9yID09PSAnc3RyaW5nJykge1xuICAgIHJldHVybiBlcnJvcjtcbiAgfVxuXG4gIHJldHVybiAnJztcbn1cblxuZXhwb3J0IGRlZmF1bHQgY3JlYXRlQnVpbGRlcjxTU1JEZXZTZXJ2ZXJCdWlsZGVyT3B0aW9ucywgQnVpbGRlck91dHB1dD4oZXhlY3V0ZSk7XG4iXX0=