UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

366 lines 50.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CachedDataSource = exports.WebsiteNoticeDataSource = exports.FilteredNotice = exports.Notices = exports.NoticesFilter = void 0; const https = require("node:https"); const path = require("path"); const fs = require("fs-extra"); const semver = require("semver"); const awscli_compatible_1 = require("./api/aws-auth/awscli-compatible"); const version_1 = require("./cli/version"); const logging_1 = require("./logging"); const error_1 = require("./toolkit/error"); const tree_1 = require("./tree"); const util_1 = require("./util"); const directories_1 = require("./util/directories"); const error_2 = require("./util/error"); const CACHE_FILE_PATH = path.join((0, directories_1.cdkCacheDir)(), 'notices.json'); class NoticesFilter { static filter(options) { return [ ...this.findForCliVersion(options.data, options.cliVersion), ...this.findForFrameworkVersion(options.data, options.outDir), ...this.findForBootstrapVersion(options.data, options.bootstrappedEnvironments), ]; } static findForCliVersion(data, cliVersion) { return (0, util_1.flatMap)(data, notice => { const affectedComponent = notice.components.find(component => component.name === 'cli'); const affectedRange = affectedComponent?.version; if (affectedRange == null) { return []; } if (!semver.satisfies(cliVersion, affectedRange)) { return []; } return [new FilteredNotice(notice)]; }); } static findForFrameworkVersion(data, outDir) { const tree = (0, tree_1.loadTreeFromDir)(outDir); return (0, util_1.flatMap)(data, notice => { // A match happens when: // // 1. The version of the node matches the version in the notice, interpreted // as a semver range. // // AND // // 2. The name in the notice is a prefix of the node name when the query ends in '.', // or the two names are exactly the same, otherwise. const matched = (0, tree_1.some)(tree, node => { return this.resolveAliases(notice.components).some(component => compareNames(component.name, node.constructInfo?.fqn) && compareVersions(component.version, node.constructInfo?.version)); }); if (!matched) { return []; } return [new FilteredNotice(notice)]; function compareNames(pattern, target) { if (target == null) { return false; } return pattern.endsWith('.') ? target.startsWith(pattern) : pattern === target; } function compareVersions(pattern, target) { return semver.satisfies(target ?? '', pattern); } }); } static findForBootstrapVersion(data, bootstrappedEnvironments) { return (0, util_1.flatMap)(data, notice => { const affectedComponent = notice.components.find(component => component.name === 'bootstrap'); const affectedRange = affectedComponent?.version; if (affectedRange == null) { return []; } const affected = bootstrappedEnvironments.filter(i => { const semverBootstrapVersion = semver.coerce(i.bootstrapStackVersion); if (!semverBootstrapVersion) { // we don't throw because notices should never crash the cli. (0, logging_1.warning)(`While filtering notices, could not coerce bootstrap version '${i.bootstrapStackVersion}' into semver`); return false; } return semver.satisfies(semverBootstrapVersion, affectedRange); }); if (affected.length === 0) { return []; } const filtered = new FilteredNotice(notice); filtered.addDynamicValue('ENVIRONMENTS', affected.map(s => s.environment.name).join(',')); return [filtered]; }); } static resolveAliases(components) { return (0, util_1.flatMap)(components, component => { if (component.name === 'framework') { return [{ name: '@aws-cdk/core.', version: component.version, }, { name: 'aws-cdk-lib.', version: component.version, }]; } else { return [component]; } }); } } exports.NoticesFilter = NoticesFilter; /** * Provides access to notices the CLI can display. */ class Notices { /** * Create an instance. Note that this replaces the singleton. */ static create(props) { this._instance = new Notices(props); return this._instance; } /** * Get the singleton instance. May return `undefined` if `create` has not been called. */ static get() { return this._instance; } constructor(props) { this.data = new Set(); // sets don't deduplicate interfaces, so we use a map. this.bootstrappedEnvironments = new Map(); this.context = props.context; this.acknowledgedIssueNumbers = new Set(this.context.get('acknowledged-issue-numbers') ?? []); this.includeAcknowlegded = props.includeAcknowledged ?? false; this.output = props.output ?? 'cdk.out'; this.shouldDisplay = props.shouldDisplay ?? true; this.httpOptions = props.httpOptions ?? {}; } /** * Add a bootstrap information to filter on. Can have multiple values * in case of multi-environment deployments. */ addBootstrappedEnvironment(bootstrapped) { const key = [ bootstrapped.bootstrapStackVersion, bootstrapped.environment.account, bootstrapped.environment.region, bootstrapped.environment.name, ].join(':'); this.bootstrappedEnvironments.set(key, bootstrapped); } /** * Refresh the list of notices this instance is aware of. * To make sure this never crashes the CLI process, all failures are caught and * silently logged. * * If context is configured to not display notices, this will no-op. */ async refresh(options = {}) { if (!this.shouldDisplay) { return; } try { const underlyingDataSource = options.dataSource ?? new WebsiteNoticeDataSource(this.httpOptions); const dataSource = new CachedDataSource(CACHE_FILE_PATH, underlyingDataSource, options.force ?? false); const notices = await dataSource.fetch(); this.data = new Set(this.includeAcknowlegded ? notices : notices.filter(n => !this.acknowledgedIssueNumbers.has(n.issueNumber))); } catch (e) { (0, logging_1.debug)(`Could not refresh notices: ${e}`); } } /** * Display the relevant notices (unless context dictates we shouldn't). */ display(options = {}) { if (!this.shouldDisplay) { return; } const filteredNotices = NoticesFilter.filter({ data: Array.from(this.data), cliVersion: (0, version_1.versionNumber)(), outDir: this.output, bootstrappedEnvironments: Array.from(this.bootstrappedEnvironments.values()), }); if (filteredNotices.length > 0) { (0, logging_1.info)(''); (0, logging_1.info)('NOTICES (What\'s this? https://github.com/aws/aws-cdk/wiki/CLI-Notices)'); (0, logging_1.info)(''); for (const filtered of filteredNotices) { const formatted = filtered.format(); switch (filtered.notice.severity) { case 'warning': (0, logging_1.warning)(formatted); break; case 'error': (0, logging_1.error)(formatted); break; default: (0, logging_1.info)(formatted); } (0, logging_1.info)(''); } (0, logging_1.info)(`If you don’t want to see a notice anymore, use "cdk acknowledge <id>". For example, "cdk acknowledge ${filteredNotices[0].notice.issueNumber}".`); } if (options.showTotal ?? false) { (0, logging_1.info)(''); (0, logging_1.info)(`There are ${filteredNotices.length} unacknowledged notice(s).`); } } } exports.Notices = Notices; /** * Notice after passing the filter. A filter can augment a notice with * dynamic values as it has access to the dynamic matching data. */ class FilteredNotice { constructor(notice) { this.notice = notice; this.dynamicValues = {}; } addDynamicValue(key, value) { this.dynamicValues[`{resolve:${key}}`] = value; } format() { const componentsValue = this.notice.components.map(c => `${c.name}: ${c.version}`).join(', '); return this.resolveDynamicValues([ `${this.notice.issueNumber}\t${this.notice.title}`, this.formatOverview(), `\tAffected versions: ${componentsValue}`, `\tMore information at: https://github.com/aws/aws-cdk/issues/${this.notice.issueNumber}`, ].join('\n\n') + '\n'); } formatOverview() { const wrap = (s) => s.replace(/(?![^\n]{1,60}$)([^\n]{1,60})\s/g, '$1\n'); const heading = 'Overview: '; const separator = `\n\t${' '.repeat(heading.length)}`; const content = wrap(this.notice.overview) .split('\n') .join(separator); return '\t' + heading + content; } resolveDynamicValues(input) { const pattern = new RegExp(Object.keys(this.dynamicValues).join('|'), 'g'); return input.replace(pattern, (matched) => this.dynamicValues[matched] ?? matched); } } exports.FilteredNotice = FilteredNotice; class WebsiteNoticeDataSource { constructor(options = {}) { this.options = options; } fetch() { const timeout = 3000; return new Promise((resolve, reject) => { let req; let timer = setTimeout(() => { if (req) { req.destroy(new error_1.ToolkitError('Request timed out')); } }, timeout); timer.unref(); const options = { agent: awscli_compatible_1.AwsCliCompatible.proxyAgent(this.options), }; try { req = https.get('https://cli.cdk.dev-tools.aws.dev/notices.json', options, res => { if (res.statusCode === 200) { res.setEncoding('utf8'); let rawData = ''; res.on('data', (chunk) => { rawData += chunk; }); res.on('end', () => { try { const data = JSON.parse(rawData).notices; if (!data) { throw new error_1.ToolkitError("'notices' key is missing"); } (0, logging_1.debug)('Notices refreshed'); resolve(data ?? []); } catch (e) { reject(new error_1.ToolkitError(`Failed to parse notices: ${(0, error_2.formatErrorMessage)(e)}`)); } }); res.on('error', e => { reject(new error_1.ToolkitError(`Failed to fetch notices: ${(0, error_2.formatErrorMessage)(e)}`)); }); } else { reject(new error_1.ToolkitError(`Failed to fetch notices. Status code: ${res.statusCode}`)); } }); req.on('error', reject); } catch (e) { reject(new error_1.ToolkitError(`HTTPS 'get' call threw an error: ${(0, error_2.formatErrorMessage)(e)}`)); } }); } } exports.WebsiteNoticeDataSource = WebsiteNoticeDataSource; const TIME_TO_LIVE_SUCCESS = 60 * 60 * 1000; // 1 hour const TIME_TO_LIVE_ERROR = 1 * 60 * 1000; // 1 minute class CachedDataSource { constructor(fileName, dataSource, skipCache) { this.fileName = fileName; this.dataSource = dataSource; this.skipCache = skipCache; } async fetch() { const cachedData = await this.load(); const data = cachedData.notices; const expiration = cachedData.expiration ?? 0; if (Date.now() > expiration || this.skipCache) { const freshData = await this.fetchInner(); await this.save(freshData); return freshData.notices; } else { (0, logging_1.debug)(`Reading cached notices from ${this.fileName}`); return data; } } async fetchInner() { try { return { expiration: Date.now() + TIME_TO_LIVE_SUCCESS, notices: await this.dataSource.fetch(), }; } catch (e) { (0, logging_1.debug)(`Could not refresh notices: ${e}`); return { expiration: Date.now() + TIME_TO_LIVE_ERROR, notices: [], }; } } async load() { const defaultValue = { expiration: 0, notices: [], }; try { return fs.existsSync(this.fileName) ? await fs.readJSON(this.fileName) : defaultValue; } catch (e) { (0, logging_1.debug)(`Failed to load notices from cache: ${e}`); return defaultValue; } } async save(cached) { try { await fs.writeJSON(this.fileName, cached); } catch (e) { (0, logging_1.debug)(`Failed to store notices in the cache: ${e}`); } } } exports.CachedDataSource = CachedDataSource; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIm5vdGljZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBRUEsb0NBQW9DO0FBQ3BDLDZCQUE2QjtBQUU3QiwrQkFBK0I7QUFDL0IsaUNBQWlDO0FBRWpDLHdFQUFvRTtBQUVwRSwyQ0FBOEM7QUFDOUMsdUNBQXdEO0FBQ3hELDJDQUErQztBQUMvQyxpQ0FBK0M7QUFDL0MsaUNBQWlDO0FBQ2pDLG9EQUFpRDtBQUNqRCx3Q0FBa0Q7QUFFbEQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFBLHlCQUFXLEdBQUUsRUFBRSxjQUFjLENBQUMsQ0FBQztBQW9FakUsTUFBYSxhQUFhO0lBQ2pCLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBbUM7UUFDdEQsT0FBTztZQUNMLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQztZQUMzRCxHQUFHLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUM7WUFDN0QsR0FBRyxJQUFJLENBQUMsdUJBQXVCLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMsd0JBQXdCLENBQUM7U0FDaEYsQ0FBQztJQUNKLENBQUM7SUFFTyxNQUFNLENBQUMsaUJBQWlCLENBQUMsSUFBYyxFQUFFLFVBQWtCO1FBQ2pFLE9BQU8sSUFBQSxjQUFPLEVBQUMsSUFBSSxFQUFFLE1BQU0sQ0FBQyxFQUFFO1lBQzVCLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxLQUFLLEtBQUssQ0FBQyxDQUFDO1lBQ3hGLE1BQU0sYUFBYSxHQUFHLGlCQUFpQixFQUFFLE9BQU8sQ0FBQztZQUVqRCxJQUFJLGFBQWEsSUFBSSxJ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Q0FBa0I7Z0JBQ25ELENBQUMsQ0FBQyxZQUFZLENBQUM7UUFDbkIsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxJQUFBLGVBQUssRUFBQyxzQ0FBc0MsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUNqRCxPQUFPLFlBQVksQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQztJQUVPLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBcUI7UUFDdEMsSUFBSSxDQUFDO1lBQ0gsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDNUMsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxJQUFBLGVBQUssRUFBQyx5Q0FBeUMsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN0RCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBNURELDRDQTREQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENsaWVudFJlcXVlc3QgfSBmcm9tICdodHRwJztcbmltcG9ydCB7IFJlcXVlc3RPcHRpb25zIH0gZnJvbSAnaHR0cHMnO1xuaW1wb3J0ICogYXMgaHR0cHMgZnJvbSAnbm9kZTpodHRwcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHR5cGUgeyBFbnZpcm9ubWVudCB9IGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcy1leHRyYSc7XG5pbXBvcnQgKiBhcyBzZW12ZXIgZnJvbSAnc2VtdmVyJztcbmltcG9ydCB7IFNka0h0dHBPcHRpb25zIH0gZnJvbSAnLi9hcGknO1xuaW1wb3J0IHsgQXdzQ2xpQ29tcGF0aWJsZSB9IGZyb20gJy4vYXBpL2F3cy1hdXRoL2F3c2NsaS1jb21wYXRpYmxlJztcbmltcG9ydCB0eXBlIHsgQ29udGV4dCB9IGZyb20gJy4vYXBpL2NvbnRleHQnO1xuaW1wb3J0IHsgdmVyc2lvbk51bWJlciB9IGZyb20gJy4vY2xpL3ZlcnNpb24nO1xuaW1wb3J0IHsgZGVidWcsIGluZm8sIHdhcm5pbmcsIGVycm9yIH0gZnJvbSAnLi9sb2dnaW5nJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJy4vdG9vbGtpdC9lcnJvcic7XG5pbXBvcnQgeyBsb2FkVHJlZUZyb21EaXIsIHNvbWUgfSBmcm9tICcuL3RyZWUnO1xuaW1wb3J0IHsgZmxhdE1hcCB9IGZyb20gJy4vdXRpbCc7XG5pbXBvcnQgeyBjZGtDYWNoZURpciB9IGZyb20gJy4vdXRpbC9kaXJlY3Rvcmllcyc7XG5pbXBvcnQgeyBmb3JtYXRFcnJvck1lc3NhZ2UgfSBmcm9tICcuL3V0aWwvZXJyb3InO1xuXG5jb25zdCBDQUNIRV9GSUxFX1BBVEggPSBwYXRoLmpvaW4oY2RrQ2FjaGVEaXIoKSwgJ25vdGljZXMuanNvbicpO1xuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZXNQcm9wcyB7XG4gIC8qKlxuICAgKiBDREsgY29udGV4dFxuICAgKi9cbiAgcmVhZG9ubHkgY29udGV4dDogQ29udGV4dDtcblxuICAvKipcbiAgICogSW5jbHVkZSBub3RpY2VzIHRoYXQgaGF2ZSBhbHJlYWR5IGJlZW4gYWNrbm93bGVkZ2VkLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgaW5jbHVkZUFja25vd2xlZGdlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEdsb2JhbCBDTEkgb3B0aW9uIGZvciBvdXRwdXQgZGlyZWN0b3J5IGZvciBzeW50aGVzaXplZCBjbG91ZCBhc3NlbWJseVxuICAgKlxuICAgKiBAZGVmYXVsdCAnY2RrLm91dCdcbiAgICovXG4gIHJlYWRvbmx5IG91dHB1dD86IHN0cmluZztcblxuICAvKipcbiAgICogR2xvYmFsIENMSSBvcHRpb24gZm9yIHdoZXRoZXIgd2Ugc2hvdyBub3RpY2VzXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHNob3VsZERpc3BsYXk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0XG4gICAqL1xuICByZWFkb25seSBodHRwT3B0aW9ucz86IFNka0h0dHBPcHRpb25zO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZXNQcmludE9wdGlvbnMge1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGFwcGVuZCB0aGUgdG90YWwgbnVtYmVyIG9mIHVuYWNrbm93bGVkZ2VkIG5vdGljZXMgdG8gdGhlIGRpc3BsYXkuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBzaG93VG90YWw/OiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZXNSZWZyZXNoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGZvcmNlIGEgY2FjaGUgcmVmcmVzaCByZWdhcmRsZXNzIG9mIGV4cGlyYXRpb24gdGltZS5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGZvcmNlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRGF0YSBzb3VyY2UgZm9yIGZldGNoIG5vdGljZXMgZnJvbS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBXZWJzaXRlTm90aWNlRGF0YVNvdXJjZVxuICAgKi9cbiAgcmVhZG9ubHkgZGF0YVNvdXJjZT86IE5vdGljZURhdGFTb3VyY2U7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTm90aWNlc0ZpbHRlckZpbHRlck9wdGlvbnMge1xuICByZWFkb25seSBkYXRhOiBOb3RpY2VbXTtcbiAgcmVhZG9ubHkgY2xpVmVyc2lvbjogc3RyaW5nO1xuICByZWFkb25seSBvdXREaXI6IHN0cmluZztcbiAgcmVhZG9ubHkgYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzOiBCb290c3RyYXBwZWRFbnZpcm9ubWVudFtdO1xufVxuXG5leHBvcnQgY2xhc3MgTm90aWNlc0ZpbHRlciB7XG4gIHB1YmxpYyBzdGF0aWMgZmlsdGVyKG9wdGlvbnM6IE5vdGljZXNGaWx0ZXJGaWx0ZXJPcHRpb25zKTogRmlsdGVyZWROb3RpY2VbXSB7XG4gICAgcmV0dXJuIFtcbiAgICAgIC4uLnRoaXMuZmluZEZvckNsaVZlcnNpb24ob3B0aW9ucy5kYXRhLCBvcHRpb25zLmNsaVZlcnNpb24pLFxuICAgICAgLi4udGhpcy5maW5kRm9yRnJhbWV3b3JrVmVyc2lvbihvcHRpb25zLmRhdGEsIG9wdGlvbnMub3V0RGlyKSxcbiAgICAgIC4uLnRoaXMuZmluZEZvckJvb3RzdHJhcFZlcnNpb24ob3B0aW9ucy5kYXRhLCBvcHRpb25zLmJvb3RzdHJhcHBlZEVudmlyb25tZW50cyksXG4gICAgXTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGZpbmRGb3JDbGlWZXJzaW9uKGRhdGE6IE5vdGljZVtdLCBjbGlWZXJzaW9uOiBzdHJpbmcpOiBGaWx0ZXJlZE5vdGljZVtdIHtcbiAgICByZXR1cm4gZmxhdE1hcChkYXRhLCBub3RpY2UgPT4ge1xuICAgICAgY29uc3QgYWZmZWN0ZWRDb21wb25lbnQgPSBub3RpY2UuY29tcG9uZW50cy5maW5kKGNvbXBvbmVudCA9PiBjb21wb25lbnQubmFtZSA9PT0gJ2NsaScpO1xuICAgICAgY29uc3QgYWZmZWN0ZWRSYW5nZSA9IGFmZmVjdGVkQ29tcG9uZW50Py52ZXJzaW9uO1xuXG4gICAgICBpZiAoYWZmZWN0ZWRSYW5nZSA9PSBudWxsKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgaWYgKCFzZW12ZXIuc2F0aXNmaWVzKGNsaVZlcnNpb24sIGFmZmVjdGVkUmFuZ2UpKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFtuZXcgRmlsdGVyZWROb3RpY2Uobm90aWNlKV07XG4gICAgfSk7XG5cbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIGZpbmRGb3JGcmFtZXdvcmtWZXJzaW9uKGRhdGE6IE5vdGljZVtdLCBvdXREaXI6IHN0cmluZyk6IEZpbHRlcmVkTm90aWNlW10ge1xuICAgIGNvbnN0IHRyZWUgPSBsb2FkVHJlZUZyb21EaXIob3V0RGlyKTtcbiAgICByZXR1cm4gZmxhdE1hcChkYXRhLCBub3RpY2UgPT4ge1xuXG4gICAgICAvLyAgQSBtYXRjaCBoYXBwZW5zIHdoZW46XG4gICAgICAvL1xuICAgICAgLy8gIDEuIFRoZSB2ZXJzaW9uIG9mIHRoZSBub2RlIG1hdGNoZXMgdGhlIHZlcnNpb24gaW4gdGhlIG5vdGljZSwgaW50ZXJwcmV0ZWRcbiAgICAgIC8vICBhcyBhIHNlbXZlciByYW5nZS5cbiAgICAgIC8vXG4gICAgICAvLyAgQU5EXG4gICAgICAvL1xuICAgICAgLy8gIDIuIFRoZSBuYW1lIGluIHRoZSBub3RpY2UgaXMgYSBwcmVmaXggb2YgdGhlIG5vZGUgbmFtZSB3aGVuIHRoZSBxdWVyeSBlbmRzIGluICcuJyxcbiAgICAgIC8vICBvciB0aGUgdHdvIG5hbWVzIGFyZSBleGFjdGx5IHRoZSBzYW1lLCBvdGhlcndpc2UuXG5cbiAgICAgIGNvbnN0IG1hdGNoZWQgPSBzb21lKHRyZWUsIG5vZGUgPT4ge1xuICAgICAgICByZXR1cm4gdGhpcy5yZXNvbHZlQWxpYXNlcyhub3RpY2UuY29tcG9uZW50cykuc29tZShjb21wb25lbnQgPT5cbiAgICAgICAgICBjb21wYXJlTmFtZXMoY29tcG9uZW50Lm5hbWUsIG5vZGUuY29uc3RydWN0SW5mbz8uZnFuKSAmJlxuICAgICAgICAgIGNvbXBhcmVWZXJzaW9ucyhjb21wb25lbnQudmVyc2lvbiwgbm9kZS5jb25zdHJ1Y3RJbmZvPy52ZXJzaW9uKSk7XG4gICAgICB9KTtcblxuICAgICAgaWYgKCFtYXRjaGVkKSB7XG4gICAgICAgIHJldHVybiBbXTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIFtuZXcgRmlsdGVyZWROb3RpY2Uobm90aWNlKV07XG5cbiAgICAgIGZ1bmN0aW9uIGNvbXBhcmVOYW1lcyhwYXR0ZXJuOiBzdHJpbmcsIHRhcmdldDogc3RyaW5nIHwgdW5kZWZpbmVkKTogYm9vbGVhbiB7XG4gICAgICAgIGlmICh0YXJnZXQgPT0gbnVsbCkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgcmV0dXJuIHBhdHRlcm4uZW5kc1dpdGgoJy4nKSA/IHRhcmdldC5zdGFydHNXaXRoKHBhdHRlcm4pIDogcGF0dGVybiA9PT0gdGFyZ2V0O1xuICAgICAgfVxuXG4gICAgICBmdW5jdGlvbiBjb21wYXJlVmVyc2lvbnMocGF0dGVybjogc3RyaW5nLCB0YXJnZXQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgICAgICByZXR1cm4gc2VtdmVyLnNhdGlzZmllcyh0YXJnZXQgPz8gJycsIHBhdHRlcm4pO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGF0aWMgZmluZEZvckJvb3RzdHJhcFZlcnNpb24oZGF0YTogTm90aWNlW10sIGJvb3RzdHJhcHBlZEVudmlyb25tZW50czogQm9vdHN0cmFwcGVkRW52aXJvbm1lbnRbXSk6IEZpbHRlcmVkTm90aWNlW10ge1xuICAgIHJldHVybiBmbGF0TWFwKGRhdGEsIG5vdGljZSA9PiB7XG4gICAgICBjb25zdCBhZmZlY3RlZENvbXBvbmVudCA9IG5vdGljZS5jb21wb25lbnRzLmZpbmQoY29tcG9uZW50ID0+IGNvbXBvbmVudC5uYW1lID09PSAnYm9vdHN0cmFwJyk7XG4gICAgICBjb25zdCBhZmZlY3RlZFJhbmdlID0gYWZmZWN0ZWRDb21wb25lbnQ/LnZlcnNpb247XG5cbiAgICAgIGlmIChhZmZlY3RlZFJhbmdlID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBhZmZlY3RlZCA9IGJvb3RzdHJhcHBlZEVudmlyb25tZW50cy5maWx0ZXIoaSA9PiB7XG5cbiAgICAgICAgY29uc3Qgc2VtdmVyQm9vdHN0cmFwVmVyc2lvbiA9IHNlbXZlci5jb2VyY2UoaS5ib290c3RyYXBTdGFja1ZlcnNpb24pO1xuICAgICAgICBpZiAoIXNlbXZlckJvb3RzdHJhcFZlcnNpb24pIHtcbiAgICAgICAgICAvLyB3ZSBkb24ndCB0aHJvdyBiZWNhdXNlIG5vdGljZXMgc2hvdWxkIG5ldmVyIGNyYXNoIHRoZSBjbGkuXG4gICAgICAgICAgd2FybmluZyhgV2hpbGUgZmlsdGVyaW5nIG5vdGljZXMsIGNvdWxkIG5vdCBjb2VyY2UgYm9vdHN0cmFwIHZlcnNpb24gJyR7aS5ib290c3RyYXBTdGFja1ZlcnNpb259JyBpbnRvIHNlbXZlcmApO1xuICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzZW12ZXIuc2F0aXNmaWVzKHNlbXZlckJvb3RzdHJhcFZlcnNpb24sIGFmZmVjdGVkUmFuZ2UpO1xuXG4gICAgICB9KTtcblxuICAgICAgaWYgKGFmZmVjdGVkLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gW107XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbHRlcmVkID0gbmV3IEZpbHRlcmVkTm90aWNlKG5vdGljZSk7XG4gICAgICBmaWx0ZXJlZC5hZGREeW5hbWljVmFsdWUoJ0VOVklST05NRU5UUycsIGFmZmVjdGVkLm1hcChzID0+IHMuZW52aXJvbm1lbnQubmFtZSkuam9pbignLCcpKTtcblxuICAgICAgcmV0dXJuIFtmaWx0ZXJlZF07XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHN0YXRpYyByZXNvbHZlQWxpYXNlcyhjb21wb25lbnRzOiBDb21wb25lbnRbXSk6IENvbXBvbmVudFtdIHtcbiAgICByZXR1cm4gZmxhdE1hcChjb21wb25lbnRzLCBjb21wb25lbnQgPT4ge1xuICAgICAgaWYgKGNvbXBvbmVudC5uYW1lID09PSAnZnJhbWV3b3JrJykge1xuICAgICAgICByZXR1cm4gW3tcbiAgICAgICAgICBuYW1lOiAnQGF3cy1jZGsvY29yZS4nLFxuICAgICAgICAgIHZlcnNpb246IGNvbXBvbmVudC52ZXJzaW9uLFxuICAgICAgICB9LCB7XG4gICAgICAgICAgbmFtZTogJ2F3cy1jZGstbGliLicsXG4gICAgICAgICAgdmVyc2lvbjogY29tcG9uZW50LnZlcnNpb24sXG4gICAgICAgIH1dO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIFtjb21wb25lbnRdO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogSW5mb3JtYXRpb24gYWJvdXQgYSBib290c3RyYXBwZWQgZW52aXJvbm1lbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQm9vdHN0cmFwcGVkRW52aXJvbm1lbnQge1xuICByZWFkb25seSBib290c3RyYXBTdGFja1ZlcnNpb246IG51bWJlcjtcbiAgcmVhZG9ubHkgZW52aXJvbm1lbnQ6IEVudmlyb25tZW50O1xufVxuXG4vKipcbiAqIFByb3ZpZGVzIGFjY2VzcyB0byBub3RpY2VzIHRoZSBDTEkgY2FuIGRpc3BsYXkuXG4gKi9cbmV4cG9ydCBjbGFzcyBOb3RpY2VzIHtcbiAgLyoqXG4gICAqIENyZWF0ZSBhbiBpbnN0YW5jZS4gTm90ZSB0aGF0IHRoaXMgcmVwbGFjZXMgdGhlIHNpbmdsZXRvbi5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY3JlYXRlKHByb3BzOiBOb3RpY2VzUHJvcHMpOiBOb3RpY2VzIHtcbiAgICB0aGlzLl9pbnN0YW5jZSA9IG5ldyBOb3RpY2VzKHByb3BzKTtcbiAgICByZXR1cm4gdGhpcy5faW5zdGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBzaW5nbGV0b24gaW5zdGFuY2UuIE1heSByZXR1cm4gYHVuZGVmaW5lZGAgaWYgYGNyZWF0ZWAgaGFzIG5vdCBiZWVuIGNhbGxlZC5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgZ2V0KCk6IE5vdGljZXMgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9pbnN0YW5jZTtcbiAgfVxuXG4gIHByaXZhdGUgc3RhdGljIF9pbnN0YW5jZTogTm90aWNlcyB8IHVuZGVmaW5lZDtcblxuICBwcml2YXRlIHJlYWRvbmx5IGNvbnRleHQ6IENvbnRleHQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3V0cHV0OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgc2hvdWxkRGlzcGxheTogYm9vbGVhbjtcbiAgcHJpdmF0ZSByZWFkb25seSBhY2tub3dsZWRnZWRJc3N1ZU51bWJlcnM6IFNldDxOdW1iZXI+O1xuICBwcml2YXRlIHJlYWRvbmx5IGluY2x1ZGVBY2tub3dsZWdkZWQ6IGJvb2xlYW47XG4gIHByaXZhdGUgcmVhZG9ubHkgaHR0cE9wdGlvbnM6IFNka0h0dHBPcHRpb25zO1xuXG4gIHByaXZhdGUgZGF0YTogU2V0PE5vdGljZT4gPSBuZXcgU2V0KCk7XG5cbiAgLy8gc2V0cyBkb24ndCBkZWR1cGxpY2F0ZSBpbnRlcmZhY2VzLCBzbyB3ZSB1c2UgYSBtYXAuXG4gIHByaXZhdGUgcmVhZG9ubHkgYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzOiBNYXA8c3RyaW5nLCBCb290c3RyYXBwZWRFbnZpcm9ubWVudD4gPSBuZXcgTWFwKCk7XG5cbiAgcHJpdmF0ZSBjb25zdHJ1Y3Rvcihwcm9wczogTm90aWNlc1Byb3BzKSB7XG4gICAgdGhpcy5jb250ZXh0ID0gcHJvcHMuY29udGV4dDtcbiAgICB0aGlzLmFja25vd2xlZGdlZElzc3VlTnVtYmVycyA9IG5ldyBTZXQodGhpcy5jb250ZXh0LmdldCgnYWNrbm93bGVkZ2VkLWlzc3VlLW51bWJlcnMnKSA/PyBbXSk7XG4gICAgdGhpcy5pbmNsdWRlQWNrbm93bGVnZGVkID0gcHJvcHMuaW5jbHVkZUFja25vd2xlZGdlZCA/PyBmYWxzZTtcbiAgICB0aGlzLm91dHB1dCA9IHByb3BzLm91dHB1dCA/PyAnY2RrLm91dCc7XG4gICAgdGhpcy5zaG91bGREaXNwbGF5ID0gcHJvcHMuc2hvdWxkRGlzcGxheSA/PyB0cnVlO1xuICAgIHRoaXMuaHR0cE9wdGlvbnMgPSBwcm9wcy5odHRwT3B0aW9ucyA/PyB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBib290c3RyYXAgaW5mb3JtYXRpb24gdG8gZmlsdGVyIG9uLiBDYW4gaGF2ZSBtdWx0aXBsZSB2YWx1ZXNcbiAgICogaW4gY2FzZSBvZiBtdWx0aS1lbnZpcm9ubWVudCBkZXBsb3ltZW50cy5cbiAgICovXG4gIHB1YmxpYyBhZGRCb290c3RyYXBwZWRFbnZpcm9ubWVudChib290c3RyYXBwZWQ6IEJvb3RzdHJhcHBlZEVudmlyb25tZW50KSB7XG4gICAgY29uc3Qga2V5ID0gW1xuICAgICAgYm9vdHN0cmFwcGVkLmJvb3RzdHJhcFN0YWNrVmVyc2lvbixcbiAgICAgIGJvb3RzdHJhcHBlZC5lbnZpcm9ubWVudC5hY2NvdW50LFxuICAgICAgYm9vdHN0cmFwcGVkLmVudmlyb25tZW50LnJlZ2lvbixcbiAgICAgIGJvb3RzdHJhcHBlZC5lbnZpcm9ubWVudC5uYW1lLFxuICAgIF0uam9pbignOicpO1xuICAgIHRoaXMuYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzLnNldChrZXksIGJvb3RzdHJhcHBlZCk7XG4gIH1cblxuICAvKipcbiAgICogUmVmcmVzaCB0aGUgbGlzdCBvZiBub3RpY2VzIHRoaXMgaW5zdGFuY2UgaXMgYXdhcmUgb2YuXG4gICAqIFRvIG1ha2Ugc3VyZSB0aGlzIG5ldmVyIGNyYXNoZXMgdGhlIENMSSBwcm9jZXNzLCBhbGwgZmFpbHVyZXMgYXJlIGNhdWdodCBhbmRcbiAgICogc2lsZW50bHkgbG9nZ2VkLlxuICAgKlxuICAgKiBJZiBjb250ZXh0IGlzIGNvbmZpZ3VyZWQgdG8gbm90IGRpc3BsYXkgbm90aWNlcywgdGhpcyB3aWxsIG5vLW9wLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIHJlZnJlc2gob3B0aW9uczogTm90aWNlc1JlZnJlc2hPcHRpb25zID0ge30pIHtcbiAgICBpZiAoIXRoaXMuc2hvdWxkRGlzcGxheSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB1bmRlcmx5aW5nRGF0YVNvdXJjZSA9IG9wdGlvbnMuZGF0YVNvdXJjZSA/PyBuZXcgV2Vic2l0ZU5vdGljZURhdGFTb3VyY2UodGhpcy5odHRwT3B0aW9ucyk7XG4gICAgICBjb25zdCBkYXRhU291cmNlID0gbmV3IENhY2hlZERhdGFTb3VyY2UoQ0FDSEVfRklMRV9QQVRILCB1bmRlcmx5aW5nRGF0YVNvdXJjZSwgb3B0aW9ucy5mb3JjZSA/PyBmYWxzZSk7XG4gICAgICBjb25zdCBub3RpY2VzID0gYXdhaXQgZGF0YVNvdXJjZS5mZXRjaCgpO1xuICAgICAgdGhpcy5kYXRhID0gbmV3IFNldCh0aGlzLmluY2x1ZGVBY2tub3dsZWdkZWQgPyBub3RpY2VzIDogbm90aWNlcy5maWx0ZXIobiA9PiAhdGhpcy5hY2tub3dsZWRnZWRJc3N1ZU51bWJlcnMuaGFzKG4uaXNzdWVOdW1iZXIpKSk7XG4gICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICBkZWJ1ZyhgQ291bGQgbm90IHJlZnJlc2ggbm90aWNlczogJHtlfWApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNwbGF5IHRoZSByZWxldmFudCBub3RpY2VzICh1bmxlc3MgY29udGV4dCBkaWN0YXRlcyB3ZSBzaG91bGRuJ3QpLlxuICAgKi9cbiAgcHVibGljIGRpc3BsYXkob3B0aW9uczogTm90aWNlc1ByaW50T3B0aW9ucyA9IHt9KSB7XG4gICAgaWYgKCF0aGlzLnNob3VsZERpc3BsYXkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBmaWx0ZXJlZE5vdGljZXMgPSBOb3RpY2VzRmlsdGVyLmZpbHRlcih7XG4gICAgICBkYXRhOiBBcnJheS5mcm9tKHRoaXMuZGF0YSksXG4gICAgICBjbGlWZXJzaW9uOiB2ZXJzaW9uTnVtYmVyKCksXG4gICAgICBvdXREaXI6IHRoaXMub3V0cHV0LFxuICAgICAgYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzOiBBcnJheS5mcm9tKHRoaXMuYm9vdHN0cmFwcGVkRW52aXJvbm1lbnRzLnZhbHVlcygpKSxcbiAgICB9KTtcblxuICAgIGlmIChmaWx0ZXJlZE5vdGljZXMubGVuZ3RoID4gMCkge1xuICAgICAgaW5mbygnJyk7XG4gICAgICBpbmZvKCdOT1RJQ0VTICAgICAgICAgKFdoYXRcXCdzIHRoaXM/IGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay93aWtpL0NMSS1Ob3RpY2VzKScpO1xuICAgICAgaW5mbygnJyk7XG4gICAgICBmb3IgKGNvbnN0IGZpbHRlcmVkIG9mIGZpbHRlcmVkTm90aWNlcykge1xuICAgICAgICBjb25zdCBmb3JtYXR0ZWQgPSBmaWx0ZXJlZC5mb3JtYXQoKTtcbiAgICAgICAgc3dpdGNoIChmaWx0ZXJlZC5ub3RpY2Uuc2V2ZXJpdHkpIHtcbiAgICAgICAgICBjYXNlICd3YXJuaW5nJzpcbiAgICAgICAgICAgIHdhcm5pbmcoZm9ybWF0dGVkKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgJ2Vycm9yJzpcbiAgICAgICAgICAgIGVycm9yKGZvcm1hdHRlZCk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgaW5mbyhmb3JtYXR0ZWQpO1xuICAgICAgICB9XG4gICAgICAgIGluZm8oJycpO1xuICAgICAgfVxuICAgICAgaW5mbyhgSWYgeW91IGRvbuKAmXQgd2FudCB0byBzZWUgYSBub3RpY2UgYW55bW9yZSwgdXNlIFwiY2RrIGFja25vd2xlZGdlIDxpZD5cIi4gRm9yIGV4YW1wbGUsIFwiY2RrIGFja25vd2xlZGdlICR7ZmlsdGVyZWROb3RpY2VzWzBdLm5vdGljZS5pc3N1ZU51bWJlcn1cIi5gKTtcbiAgICB9XG5cbiAgICBpZiAob3B0aW9ucy5zaG93VG90YWwgPz8gZmFsc2UpIHtcbiAgICAgIGluZm8oJycpO1xuICAgICAgaW5mbyhgVGhlcmUgYXJlICR7ZmlsdGVyZWROb3RpY2VzLmxlbmd0aH0gdW5hY2tub3dsZWRnZWQgbm90aWNlKHMpLmApO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBvbmVudCB7XG4gIG5hbWU6IHN0cmluZztcbiAgdmVyc2lvbjogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZSB7XG4gIHRpdGxlOiBzdHJpbmc7XG4gIGlzc3VlTnVtYmVyOiBudW1iZXI7XG4gIG92ZXJ2aWV3OiBzdHJpbmc7XG4gIGNvbXBvbmVudHM6IENvbXBvbmVudFtdO1xuICBzY2hlbWFWZXJzaW9uOiBzdHJpbmc7XG4gIHNldmVyaXR5Pzogc3RyaW5nO1xufVxuXG4vKipcbiAqIE5vdGljZSBhZnRlciBwYXNzaW5nIHRoZSBmaWx0ZXIuIEEgZmlsdGVyIGNhbiBhdWdtZW50IGEgbm90aWNlIHdpdGhcbiAqIGR5bmFtaWMgdmFsdWVzIGFzIGl0IGhhcyBhY2Nlc3MgdG8gdGhlIGR5bmFtaWMgbWF0Y2hpbmcgZGF0YS5cbiAqL1xuZXhwb3J0IGNsYXNzIEZpbHRlcmVkTm90aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBkeW5hbWljVmFsdWVzOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge307XG5cbiAgcHVibGljIGNvbnN0cnVjdG9yKHB1YmxpYyByZWFkb25seSBub3RpY2U6IE5vdGljZSkge31cblxuICBwdWJsaWMgYWRkRHluYW1pY1ZhbHVlKGtleTogc3RyaW5nLCB2YWx1ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5keW5hbWljVmFsdWVzW2B7cmVzb2x2ZToke2tleX19YF0gPSB2YWx1ZTtcbiAgfVxuXG4gIHB1YmxpYyBmb3JtYXQoKTogc3RyaW5nIHtcblxuICAgIGNvbnN0IGNvbXBvbmVudHNWYWx1ZSA9IHRoaXMubm90aWNlLmNvbXBvbmVudHMubWFwKGMgPT4gYCR7Yy5uYW1lfTogJHtjLnZlcnNpb259YCkuam9pbignLCAnKTtcbiAgICByZXR1cm4gdGhpcy5yZXNvbHZlRHluYW1pY1ZhbHVlcyhbXG4gICAgICBgJHt0aGlzLm5vdGljZS5pc3N1ZU51bWJlcn1cXHQke3RoaXMubm90aWNlLnRpdGxlfWAsXG4gICAgICB0aGlzLmZvcm1hdE92ZXJ2aWV3KCksXG4gICAgICBgXFx0QWZmZWN0ZWQgdmVyc2lvbnM6ICR7Y29tcG9uZW50c1ZhbHVlfWAsXG4gICAgICBgXFx0TW9yZSBpbmZvcm1hdGlvbiBhdDogaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3MtY2RrL2lzc3Vlcy8ke3RoaXMubm90aWNlLmlzc3VlTnVtYmVyfWAsXG4gICAgXS5qb2luKCdcXG5cXG4nKSArICdcXG4nKTtcbiAgfVxuXG4gIHByaXZhdGUgZm9ybWF0T3ZlcnZpZXcoKSB7XG4gICAgY29uc3Qgd3JhcCA9IChzOiBzdHJpbmcpID0+IHMucmVwbGFjZSgvKD8hW15cXG5dezEsNjB9JCkoW15cXG5dezEsNjB9KVxccy9nLCAnJDFcXG4nKTtcblxuICAgIGNvbnN0IGhlYWRpbmcgPSAnT3ZlcnZpZXc6ICc7XG4gICAgY29uc3Qgc2VwYXJhdG9yID0gYFxcblxcdCR7JyAnLnJlcGVhdChoZWFkaW5nLmxlbmd0aCl9YDtcbiAgICBjb25zdCBjb250ZW50ID0gd3JhcCh0aGlzLm5vdGljZS5vdmVydmlldylcbiAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgIC5qb2luKHNlcGFyYXRvcik7XG5cbiAgICByZXR1cm4gJ1xcdCcgKyBoZWFkaW5nICsgY29udGVudDtcbiAgfVxuXG4gIHByaXZhdGUgcmVzb2x2ZUR5bmFtaWNWYWx1ZXMoaW5wdXQ6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgcGF0dGVybiA9IG5ldyBSZWdFeHAoT2JqZWN0LmtleXModGhpcy5keW5hbWljVmFsdWVzKS5qb2luKCd8JyksICdnJyk7XG4gICAgcmV0dXJuIGlucHV0LnJlcGxhY2UocGF0dGVybiwgKG1hdGNoZWQpID0+IHRoaXMuZHluYW1pY1ZhbHVlc1ttYXRjaGVkXSA/PyBtYXRjaGVkKTtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIE5vdGljZURhdGFTb3VyY2Uge1xuICBmZXRjaCgpOiBQcm9taXNlPE5vdGljZVtdPjtcbn1cblxuZXhwb3J0IGNsYXNzIFdlYnNpdGVOb3RpY2VEYXRhU291cmNlIGltcGxlbWVudHMgTm90aWNlRGF0YVNvdXJjZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgb3B0aW9uczogU2RrSHR0cE9wdGlvbnM7XG5cbiAgY29uc3RydWN0b3Iob3B0aW9uczogU2RrSHR0cE9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gIH1cblxuICBmZXRjaCgpOiBQcm9taXNlPE5vdGljZVtdPiB7XG4gICAgY29uc3QgdGltZW91dCA9IDMwMDA7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGxldCByZXE6IENsaWVudFJlcXVlc3QgfCB1bmRlZmluZWQ7XG5cbiAgICAgIGxldCB0aW1lciA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBpZiAocmVxKSB7XG4gICAgICAgICAgcmVxLmRlc3Ryb3kobmV3IFRvb2xraXRFcnJvcignUmVxdWVzdCB0aW1lZCBvdXQnKSk7XG4gICAgICAgIH1cbiAgICAgIH0sIHRpbWVvdXQpO1xuXG4gICAgICB0aW1lci51bnJlZigpO1xuXG4gICAgICBjb25zdCBvcHRpb25zOiBSZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgICAgYWdlbnQ6IEF3c0NsaUNvbXBhdGlibGUucHJveHlBZ2VudCh0aGlzLm9wdGlvbnMpLFxuICAgICAgfTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgcmVxID0gaHR0cHMuZ2V0KCdodHRwczovL2NsaS5jZGsuZGV2LXRvb2xzLmF3cy5kZXYvbm90aWNlcy5qc29uJyxcbiAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgIHJlcyA9PiB7XG4gICAgICAgICAgICBpZiAocmVzLnN0YXR1c0NvZGUgPT09IDIwMCkge1xuICAgICAgICAgICAgICByZXMuc2V0RW5jb2RpbmcoJ3V0ZjgnKTtcbiAgICAgICAgICAgICAgbGV0IHJhd0RhdGEgPSAnJztcbiAgICAgICAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgICAgICAgcmF3RGF0YSArPSBjaHVuaztcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICBjb25zdCBkYXRhID0gSlNPTi5wYXJzZShyYXdEYXRhKS5ub3RpY2VzIGFzIE5vdGljZVtdO1xuICAgICAgICAgICAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUb29sa2l0RXJyb3IoXCInbm90aWNlcycga2V5IGlzIG1pc3NpbmdcIik7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICBkZWJ1ZygnTm90aWNlcyByZWZyZXNoZWQnKTtcbiAgICAgICAgICAgICAgICAgIHJlc29sdmUoZGF0YSA/PyBbXSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgICAgICAgICAgICByZWplY3QobmV3IFRvb2xraXRFcnJvcihgRmFpbGVkIHRvIHBhcnNlIG5vdGljZXM6ICR7Zm9ybWF0RXJyb3JNZXNzYWdlKGUpfWApKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICByZXMub24oJ2Vycm9yJywgZSA9PiB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KG5ldyBUb29sa2l0RXJyb3IoYEZhaWxlZCB0byBmZXRjaCBub3RpY2VzOiAke2Zvcm1hdEVycm9yTWVzc2FnZShlKX1gKSk7XG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgcmVqZWN0KG5ldyBUb29sa2l0RXJyb3IoYEZhaWxlZCB0byBmZXRjaCBub3RpY2VzLiBTdGF0dXMgY29kZTogJHtyZXMuc3RhdHVzQ29kZX1gKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIHJlcS5vbignZXJyb3InLCByZWplY3QpO1xuICAgICAgfSBjYXRjaCAoZTogYW55KSB7XG4gICAgICAgIHJlamVjdChuZXcgVG9vbGtpdEVycm9yKGBIVFRQUyAnZ2V0JyBjYWxsIHRocmV3IGFuIGVycm9yOiAke2Zvcm1hdEVycm9yTWVzc2FnZShlKX1gKSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cbn1cblxuaW50ZXJmYWNlIENhY2hlZE5vdGljZXMge1xuICBleHBpcmF0aW9uOiBudW1iZXI7XG4gIG5vdGljZXM6IE5vdGljZVtdO1xufVxuXG5jb25zdCBUSU1FX1RPX0xJVkVfU1VDQ0VTUyA9IDYwICogNjAgKiAxMDAwOyAvLyAxIGhvdXJcbmNvbnN0IFRJTUVfVE9fTElWRV9FUlJPUiA9IDEgKiA2MCAqIDEwMDA7IC8vIDEgbWludXRlXG5cbmV4cG9ydCBjbGFzcyBDYWNoZWREYXRhU291cmNlIGltcGxlbWVudHMgTm90aWNlRGF0YVNvdXJjZSB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZmlsZU5hbWU6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRhdGFTb3VyY2U6IE5vdGljZURhdGFTb3VyY2UsXG4gICAgcHJpdmF0ZSByZWFkb25seSBza2lwQ2FjaGU/OiBib29sZWFuKSB7XG4gIH1cblxuICBhc3luYyBmZXRjaCgpOiBQcm9taXNlPE5vdGljZVtdPiB7XG4gICAgY29uc3QgY2FjaGVkRGF0YSA9IGF3YWl0IHRoaXMubG9hZCgpO1xuICAgIGNvbnN0IGRhdGEgPSBjYWNoZWREYXRhLm5vdGljZXM7XG4gICAgY29uc3QgZXhwaXJhdGlvbiA9IGNhY2hlZERhdGEuZXhwaXJhdGlvbiA/PyAwO1xuXG4gICAgaWYgKERhdGUubm93KCkgPiBleHBpcmF0aW9uIHx8IHRoaXMuc2tpcENhY2hlKSB7XG4gICAgICBjb25zdCBmcmVzaERhdGEgPSBhd2FpdCB0aGlzLmZldGNoSW5uZXIoKTtcbiAgICAgIGF3YWl0IHRoaXMuc2F2ZShmcmVzaERhdGEpO1xuICAgICAgcmV0dXJuIGZyZXNoRGF0YS5ub3RpY2VzO1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1ZyhgUmVhZGluZyBjYWNoZWQgbm90aWNlcyBmcm9tICR7dGhpcy5maWxlTmFtZX1gKTtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmV0Y2hJbm5lcigpOiBQcm9taXNlPENhY2hlZE5vdGljZXM+IHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgZXhwaXJhdGlvbjogRGF0ZS5ub3coKSArIFRJTUVfVE9fTElWRV9TVUNDRVNTLFxuICAgICAgICBub3RpY2VzOiBhd2FpdCB0aGlzLmRhdGFTb3VyY2UuZmV0Y2goKSxcbiAgICAgIH07XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgZGVidWcoYENvdWxkIG5vdCByZWZyZXNoIG5vdGljZXM6ICR7ZX1gKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGV4cGlyYXRpb246IERhdGUubm93KCkgKyBUSU1FX1RPX0xJVkVfRVJST1IsXG4gICAgICAgIG5vdGljZXM6IFtdLFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuI