UNPKG

aws-cdk

Version:

AWS CDK Toolkit CLI, the command line tool for CDK apps

364 lines 38.3 kB
"use strict"; 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 () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.TelemetrySession = void 0; exports.isValidWrapperUserAgent = isValidWrapperUserAgent; const node_crypto_1 = require("node:crypto"); const fs = __importStar(require("node:fs/promises")); const os = __importStar(require("os")); const pathlib = __importStar(require("path")); const toolkit_lib_1 = require("@aws-cdk/toolkit-lib"); const installation_id_1 = require("./installation-id"); const library_version_1 = require("./library-version"); const sanitation_1 = require("./sanitation"); const ci_systems_1 = require("../ci-systems"); const messages_1 = require("../telemetry/messages"); const ci_1 = require("../util/ci"); const version_1 = require("../version"); const error_1 = require("./error"); const telemetry_state_1 = require("./telemetry-state"); const ABORTED_ERROR_MESSAGE = '__CDK-Toolkit__Aborted'; /** * Valid user agent prefixes that are allowed to report through CDK_CLI_USERAGENT. * This creates a mechanism to report user agents we control. */ const VALID_USER_AGENTS = ['aws-blocks']; class TelemetrySession { props; ioHost; client; _sessionInfo; _commandSpan; sigintListener; _nextEventCounters; count = 0; loadTime; constructor(props) { this.props = props; this.ioHost = props.ioHost; this.client = props.client; } /** * The span that represents the CLI invocation. * * In the code, this span is named COMMAND but the matching event type * in telemetry will be INVOKE. * * Will be emitted exactly once, at the end of the CLI operation. */ get commandSpan() { return this._commandSpan; } async begin() { // sanitize the raw cli input const { path, parameters } = (0, sanitation_1.sanitizeCommandLineArguments)(this.props.arguments); this._sessionInfo = { identifiers: { installationId: await (0, installation_id_1.getOrCreateInstallationId)(this.ioHost.asIoHelper()), sessionId: (0, node_crypto_1.randomUUID)(), telemetryVersion: '2.0', cdkCliVersion: (0, version_1.versionNumber)(), cdkLibraryVersion: await (0, library_version_1.getLibraryVersion)(this.ioHost.asIoHelper()), amznPackage: await tryDetectAmznPackage(), }, event: { command: { path, parameters, config: { context: (0, sanitation_1.sanitizeContext)(this.props.context), ...(isValidWrapperUserAgent(process.env.CDK_CLI_USERAGENT) ? { cdkCliUserAgent: { [process.env.CDK_CLI_USERAGENT]: true } } : {}), }, }, }, environment: { ci: (0, ci_1.isCI)() || Boolean((0, ci_systems_1.detectCiSystem)()), os: { platform: process.platform, release: process.release.name, }, nodeVersion: process.version, }, project: {}, }; // If SIGINT has a listener installed, its default behavior will be removed (Node.js will no longer exit). // This ensures that on SIGINT we process safely close the telemetry session before exiting. // The listener is removed in end() -- without that, every begin() call (e.g. one per // exec() invocation in a long-running host process) would permanently add another // listener to the process-global SIGINT emitter, leaking the retained TelemetrySession // (and everything it references) for the lifetime of the process. this.sigintListener = () => { void (async () => { try { await this.end({ name: error_1.USER_INTERRUPTED_CODE, message: ABORTED_ERROR_MESSAGE, }); } catch (e) { await this.ioHost.defaults.trace(`Ending Telemetry failed: ${e.message}`); } process.exit(1); })(); }; process.on('SIGINT', this.sigintListener); // Begin the session span this._commandSpan = await this.ioHost.asIoHelper().span(messages_1.CLI_PRIVATE_SPAN.COMMAND).begin({}); } async attachRegion(region) { this.sessionInfo.identifiers = { ...this.sessionInfo.identifiers, region, }; } /** * Attach a language guess */ attachLanguage(language) { // Don't want to crash accidentally if (!this._sessionInfo) { return; } if (language) { mutable(this.sessionInfo.project).language = language; } } /** * Attach our best guess at running under an agent or not */ attachAgent(isAgent) { // Don't want to crash accidentally if (!this._sessionInfo) { return; } mutable(this.sessionInfo.environment).agent = isAgent; } /** * Temporarily attach counters for the next event operation. * * They may be committed to the sent telemetry later. */ attachCountersToNextEvent(counters) { this._nextEventCounters = counters; } /** * Set the load time (will be emitted with the COMMAND span) */ attachLoadTime(loadTime) { this.loadTime = loadTime; this._commandSpan?.addTimer('load', loadTime); } /** * Mark when the actual CLI operation starts * * Emitted as part of the COMMAND span. */ markOperationStart() { if (this.loadTime) { this._commandSpan?.addTimer('init', performance.now() - this.loadTime); } } /** * Attach the CDK library version * * By default the telemetry will guess at the CDK library version if it so * happens that the CDK project is an NPM project and the CDK CLI is executed * in the root of NPM project with `aws-cdk-lib` available in `node_modules`. * This may succeed or may fail. * * Once we have produced and loaded the cloud assembly more accurate * information becomes available that we can add in. */ attachCdkLibVersion(libVersion) { // Don't want to crash accidentally if (!this._sessionInfo) { return; } mutable(this.sessionInfo.identifiers).cdkLibraryVersion = libVersion; } /** * When the command is complete, so is the CliIoHost. Ends the span of the entire CliIoHost * and notifies with an optional error message in the data. */ async end(error) { if (this.sigintListener) { process.removeListener('SIGINT', this.sigintListener); this.sigintListener = undefined; } await this._commandSpan?.end({ error }); // Ideally span.end() should no-op if called twice, but that is not the case right now this._commandSpan = undefined; await this.client.flush(); } async emit(event) { this.count += 1; const counters = { ...this._nextEventCounters, ...event.counters, }; this._nextEventCounters = undefined; if (event.eventType == 'DEPLOY') { await this.trackDeployStatistics(event.error === undefined, counters); } return this.client.emit({ event: { command: this.sessionInfo.event.command, state: getState(event.error), eventType: event.eventType, }, identifiers: { ...this.sessionInfo.identifiers, eventId: `${this.sessionInfo.identifiers.sessionId}:${this.count}`, timestamp: new Date().toISOString(), }, environment: this.sessionInfo.environment, project: this.sessionInfo.project, duration: { total: event.duration, }, ...(event.error ? { error: { name: event.error.name, }, } : {}), ...(Object.keys(counters).length > 0 ? { counters } : {}), }); } /** * This is a DEPLOY event, track some additional statistics about it * * We use this to measure things about deployment failures, such as the number of * failed DEPLOY events in a sequence. */ async trackDeployStatistics(isSuccessful, counters) { await (0, telemetry_state_1.withTelemetryState)((state) => { const recentFailures = state.sequentialDeploymentFailures ?? 0; if (isSuccessful) { state.sequentialDeploymentFailures = 0; } else { state.sequentialDeploymentFailures = recentFailures + 1; } counters.sequentialDeploymentFailures = state.sequentialDeploymentFailures; }); } get sessionInfo() { if (!this._sessionInfo) { throw new toolkit_lib_1.ToolkitError('SessionNotInitialized', 'Session Info not initialized. Call begin() first.'); } return this._sessionInfo; } } exports.TelemetrySession = TelemetrySession; function getState(error) { if (error) { return isAbortedError(error) ? 'ABORTED' : 'FAILED'; } return 'SUCCEEDED'; } function isAbortedError(error) { if (error?.name === 'ToolkitError' && error?.message?.includes(ABORTED_ERROR_MESSAGE)) { return true; } return false; } function mutable(x) { return x; } /** * Validates that the CDK_CLI_USERAGENT env var value matches * the expected format: `<name>/<version>/<mode>` where name is one of * VALID_USER_AGENTS and mode is either `sandbox` or `production`. */ function isValidWrapperUserAgent(value) { if (!value) return false; const parts = value.split('/'); if (parts.length !== 3) return false; const [name, _version, mode] = parts; if (!VALID_USER_AGENTS.includes(name)) return false; return mode === 'sandbox' || mode === 'production'; } /** * Try to detect a Config file of which the first line looks like * * ``` * package.<packageName> = { * ``` * * Or a `brazil.ion` file with a line like * * ``` * name: "<projectName>" * ``` * * They will always be in the current working directory, and we will * only do the check if it looks like we're on an Amzn developer machine. */ async function tryDetectAmznPackage() { try { await fs.stat(pathlib.join(os.homedir(), '.midway')); } catch { // ENOENT return; } try { const configFile = await fs.readFile('Config', 'utf-8'); const m = configFile.match(/^package\.(\S+)\s*=/m); if (m) { return m[1]; } } catch { // Any error means no dice. } try { const ionFile = await fs.readFile('brazil.ion', 'utf-8'); const m = ionFile.match(/(^|\s)name:\s*"([^"]+)"/m); if (m) { return m[2]; } } catch { // Any error means no dice. } return undefined; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNlc3Npb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBMFVBLDBEQU9DO0FBalZELDZDQUF5QztBQUN6QyxxREFBdUM7QUFDdkMsdUNBQXlCO0FBQ3pCLDhDQUFnQztBQUNoQyxzREFBb0Q7QUFDcEQsdURBQThEO0FBQzlELHVEQUFzRDtBQUN0RCw2Q0FBNkU7QUFLN0UsOENBQStDO0FBRy9DLG9EQUF5RDtBQUN6RCxtQ0FBa0M7QUFDbEMsd0NBQTJDO0FBQzNDLG1DQUFnRDtBQUNoRCx1REFBdUQ7QUFFdkQsTUFBTSxxQkFBcUIsR0FBRyx3QkFBd0IsQ0FBQztBQUV2RDs7O0dBR0c7QUFDSCxNQUFNLGlCQUFpQixHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7QUErQnpDLE1BQWEsZ0JBQWdCO0lBVUU7SUFUckIsTUFBTSxDQUFZO0lBQ2xCLE1BQU0sQ0FBaUI7SUFDdkIsWUFBWSxDQUFpQjtJQUM3QixZQUFZLENBQTZCO0lBQ3pDLGNBQWMsQ0FBYztJQUM1QixrQkFBa0IsQ0FBMEI7SUFDNUMsS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNWLFFBQVEsQ0FBVTtJQUUxQixZQUE2QixLQUE0QjtRQUE1QixVQUFLLEdBQUwsS0FBSyxDQUF1QjtRQUN2RCxJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7UUFDM0IsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQzdCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsSUFBVyxXQUFXO1FBQ3BCLE9BQU8sSUFBSSxDQUFDLFlBQVksQ0FBQztJQUMzQixDQUFDO0lBRU0sS0FBSyxDQUFDLEtBQUs7UUFDaEIsNkJBQTZCO1FBQzdCLE1BQU0sRUFBRSxJQUFJLEVBQUUsVUFBVSxFQUFFLEdBQUcsSUFBQSx5Q0FBNEIsRUFBQyxJQUFJ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SUFBQyxNQUFNLENBQUM7UUFDUCwyQkFBMkI7SUFDN0IsQ0FBQztJQUVELE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyByYW5kb21VVUlEIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnbm9kZTpmcy9wcm9taXNlcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRobGliIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgVG9vbGtpdEVycm9yIH0gZnJvbSAnQGF3cy1jZGsvdG9vbGtpdC1saWInO1xuaW1wb3J0IHsgZ2V0T3JDcmVhdGVJbnN0YWxsYXRpb25JZCB9IGZyb20gJy4vaW5zdGFsbGF0aW9uLWlkJztcbmltcG9ydCB7IGdldExpYnJhcnlWZXJzaW9uIH0gZnJvbSAnLi9saWJyYXJ5LXZlcnNpb24nO1xuaW1wb3J0IHsgc2FuaXRpemVDb21tYW5kTGluZUFyZ3VtZW50cywgc2FuaXRpemVDb250ZXh0IH0gZnJvbSAnLi9zYW5pdGF0aW9uJztcbmltcG9ydCB7IHR5cGUgRXZlbnRUeXBlLCB0eXBlIFNlc3Npb25TY2hlbWEsIHR5cGUgU3RhdGUsIHR5cGUgRXJyb3JEZXRhaWxzIH0gZnJvbSAnLi9zY2hlbWEnO1xuaW1wb3J0IHR5cGUgeyBJVGVsZW1ldHJ5U2luayB9IGZyb20gJy4vc2luay9zaW5rLWludGVyZmFjZSc7XG5pbXBvcnQgdHlwZSB7IENvbnRleHQgfSBmcm9tICcuLi8uLi9hcGkvY29udGV4dCc7XG5pbXBvcnQgdHlwZSB7IElNZXNzYWdlU3BhbiB9IGZyb20gJy4uLy4uL2FwaS1wcml2YXRlJztcbmltcG9ydCB7IGRldGVjdENpU3lzdGVtIH0gZnJvbSAnLi4vY2ktc3lzdGVtcyc7XG5pbXBvcnQgdHlwZSB7IENsaUlvSG9zdCB9IGZyb20gJy4uL2lvLWhvc3QvY2xpLWlvLWhvc3QnO1xuaW1wb3J0IHR5cGUgeyBFdmVudFJlc3VsdCB9IGZyb20gJy4uL3RlbGVtZXRyeS9tZXNzYWdlcyc7XG5pbXBvcnQgeyBDTElfUFJJVkFURV9TUEFOIH0gZnJvbSAnLi4vdGVsZW1ldHJ5L21lc3NhZ2VzJztcbmltcG9ydCB7IGlzQ0kgfSBmcm9tICcuLi91dGlsL2NpJztcbmltcG9ydCB7IHZlcnNpb25OdW1iZXIgfSBmcm9tICcuLi92ZXJzaW9uJztcbmltcG9ydCB7IFVTRVJfSU5URVJSVVBURURfQ09ERSB9IGZyb20gJy4vZXJyb3InO1xuaW1wb3J0IHsgd2l0aFRlbGVtZXRyeVN0YXRlIH0gZnJvbSAnLi90ZWxlbWV0cnktc3RhdGUnO1xuXG5jb25zdCBBQk9SVEVEX0VSUk9SX01FU1NBR0UgPSAnX19DREstVG9vbGtpdF9fQWJvcnRlZCc7XG5cbi8qKlxuICogVmFsaWQgdXNlciBhZ2VudCBwcmVmaXhlcyB0aGF0IGFyZSBhbGxvd2VkIHRvIHJlcG9ydCB0aHJvdWdoIENES19DTElfVVNFUkFHRU5ULlxuICogVGhpcyBjcmVhdGVzIGEgbWVjaGFuaXNtIHRvIHJlcG9ydCB1c2VyIGFnZW50cyB3ZSBjb250cm9sLlxuICovXG5jb25zdCBWQUxJRF9VU0VSX0FHRU5UUyA9IFsnYXdzLWJsb2NrcyddO1xuXG5leHBvcnQgaW50ZXJmYWNlIFRlbGVtZXRyeVNlc3Npb25Qcm9wcyB7XG4gIHJlYWRvbmx5IGlvSG9zdDogQ2xpSW9Ib3N0O1xuICByZWFkb25seSBjbGllbnQ6IElUZWxlbWV0cnlTaW5rO1xuICByZWFkb25seSBhcmd1bWVudHM6IGFueTtcbiAgcmVhZG9ubHkgY29udGV4dDogQ29udGV4dDtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUZWxlbWV0cnlFdmVudCB7XG4gIHJlYWRvbmx5IGV2ZW50VHlwZTogRXZlbnRUeXBlO1xuICByZWFkb25seSBkdXJhdGlvbjogbnVtYmVyO1xuICByZWFkb25seSBlcnJvcj86IEVycm9yRGV0YWlscztcbiAgcmVhZG9ubHkgY291bnRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xufVxuXG4vKipcbiAqIFRpbWVyIG9mIGEgc2luZ2xlIGV2ZW50XG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVGltaW5nIHtcbiAgLyoqXG4gICAqIFRvdGFsIHRpbWUgc3BlbnQgaW4gdGhpcyBvcGVyYXRpb25cbiAgICovXG4gIHRvdGFsTXM6IG51bWJlcjtcblxuICAvKipcbiAgICogQ291bnQgb2Ygb3BlcmF0aW9ucyB0aGF0IHRvZ2V0aGVyIHRvb2sgYHRvdGFsTXNgLlxuICAgKi9cbiAgY291bnQ6IG51bWJlcjtcbn1cblxuZXhwb3J0IGNsYXNzIFRlbGVtZXRyeVNlc3Npb24ge1xuICBwcml2YXRlIGlvSG9zdDogQ2xpSW9Ib3N0O1xuICBwcml2YXRlIGNsaWVudDogSVRlbGVtZXRyeVNpbms7XG4gIHByaXZhdGUgX3Nlc3Npb25JbmZvPzogU2Vzc2lvblNjaGVtYTtcbiAgcHJpdmF0ZSBfY29tbWFuZFNwYW4/OiBJTWVzc2FnZVNwYW48RXZlbnRSZXN1bHQ+O1xuICBwcml2YXRlIHNpZ2ludExpc3RlbmVyPzogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSBfbmV4dEV2ZW50Q291bnRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xuICBwcml2YXRlIGNvdW50ID0gMDtcbiAgcHJpdmF0ZSBsb2FkVGltZT86IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBUZWxlbWV0cnlTZXNzaW9uUHJvcHMpIHtcbiAgICB0aGlzLmlvSG9zdCA9IHByb3BzLmlvSG9zdDtcbiAgICB0aGlzLmNsaWVudCA9IHByb3BzLmNsaWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc3BhbiB0aGF0IHJlcHJlc2VudHMgdGhlIENMSSBpbnZvY2F0aW9uLlxuICAgKlxuICAgKiBJbiB0aGUgY29kZSwgdGhpcyBzcGFuIGlzIG5hbWVkIENPTU1BTkQgYnV0IHRoZSBtYXRjaGluZyBldmVudCB0eXBlXG4gICAqIGluIHRlbGVtZXRyeSB3aWxsIGJlIElOVk9LRS5cbiAgICpcbiAgICogV2lsbCBiZSBlbWl0dGVkIGV4YWN0bHkgb25jZSwgYXQgdGhlIGVuZCBvZiB0aGUgQ0xJIG9wZXJhdGlvbi5cbiAgICovXG4gIHB1YmxpYyBnZXQgY29tbWFuZFNwYW4oKTogSU1lc3NhZ2VTcGFuPEV2ZW50UmVzdWx0PiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2NvbW1hbmRTcGFuO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGJlZ2luKCkge1xuICAgIC8vIHNhbml0aXplIHRoZSByYXcgY2xpIGlucHV0XG4gICAgY29uc3QgeyBwYXRoLCBwYXJhbWV0ZXJzIH0gPSBzYW5pdGl6ZUNvbW1hbmRMaW5lQXJndW1lbnRzKHRoaXMucHJvcHMuYXJndW1lbnRzKTtcbiAgICB0aGlzLl9zZXNzaW9uSW5mbyA9IHtcbiAgICAgIGlkZW50aWZpZXJzOiB7XG4gICAgICAgIGluc3RhbGxhdGlvbklkOiBhd2FpdCBnZXRPckNyZWF0ZUluc3RhbGxhdGlvbklkKHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKSksXG4gICAgICAgIHNlc3Npb25JZDogcmFuZG9tVVVJRCgpLFxuICAgICAgICB0ZWxlbWV0cnlWZXJzaW9uOiAnMi4wJyxcbiAgICAgICAgY2RrQ2xpVmVyc2lvbjogdmVyc2lvbk51bWJlcigpLFxuICAgICAgICBjZGtMaWJyYXJ5VmVyc2lvbjogYXdhaXQgZ2V0TGlicmFyeVZlcnNpb24odGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpKSxcbiAgICAgICAgYW16blBhY2thZ2U6IGF3YWl0IHRyeURldGVjdEFtem5QYWNrYWdlKCksXG4gICAgICB9LFxuICAgICAgZXZlbnQ6IHtcbiAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgIHBhdGgsXG4gICAgICAgICAgcGFyYW1ldGVycyxcbiAgICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICAgIGNvbnRleHQ6IHNhbml0aXplQ29udGV4dCh0aGlzLnByb3BzLmNvbnRleHQpLFxuICAgICAgICAgICAgLi4uKGlzVmFsaWRXcmFwcGVyVXNlckFnZW50KHByb2Nlc3MuZW52LkNES19DTElfVVNFUkFHRU5UKVxuICAgICAgICAgICAgICA/IHsgY2RrQ2xpVXNlckFnZW50OiB7IFtwcm9jZXNzLmVudi5DREtfQ0xJX1VTRVJBR0VOVF06IHRydWUgfSB9XG4gICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgY2k6IGlzQ0koKSB8fCBCb29sZWFuKGRldGVjdENpU3lzdGVtKCkpLFxuICAgICAgICBvczoge1xuICAgICAgICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLFxuICAgICAgICAgIHJlbGVhc2U6IHByb2Nlc3MucmVsZWFzZS5uYW1lLFxuICAgICAgICB9LFxuICAgICAgICBub2RlVmVyc2lvbjogcHJvY2Vzcy52ZXJzaW9uLFxuICAgICAgfSxcbiAgICAgIHByb2plY3Q6IHt9LFxuICAgIH07XG5cbiAgICAvLyBJZiBTSUdJTlQgaGFzIGEgbGlzdGVuZXIgaW5zdGFsbGVkLCBpdHMgZGVmYXVsdCBiZWhhdmlvciB3aWxsIGJlIHJlbW92ZWQgKE5vZGUuanMgd2lsbCBubyBsb25nZXIgZXhpdCkuXG4gICAgLy8gVGhpcyBlbnN1cmVzIHRoYXQgb24gU0lHSU5UIHdlIHByb2Nlc3Mgc2FmZWx5IGNsb3NlIHRoZSB0ZWxlbWV0cnkgc2Vzc2lvbiBiZWZvcmUgZXhpdGluZy5cbiAgICAvLyBUaGUgbGlzdGVuZXIgaXMgcmVtb3ZlZCBpbiBlbmQoKSAtLSB3aXRob3V0IHRoYXQsIGV2ZXJ5IGJlZ2luKCkgY2FsbCAoZS5nLiBvbmUgcGVyXG4gICAgLy8gZXhlYygpIGludm9jYXRpb24gaW4gYSBsb25nLXJ1bm5pbmcgaG9zdCBwcm9jZXNzKSB3b3VsZCBwZXJtYW5lbnRseSBhZGQgYW5vdGhlclxuICAgIC8vIGxpc3RlbmVyIHRvIHRoZSBwcm9jZXNzLWdsb2JhbCBTSUdJTlQgZW1pdHRlciwgbGVha2luZyB0aGUgcmV0YWluZWQgVGVsZW1ldHJ5U2Vzc2lvblxuICAgIC8vIChhbmQgZXZlcnl0aGluZyBpdCByZWZlcmVuY2VzKSBmb3IgdGhlIGxpZmV0aW1lIG9mIHRoZSBwcm9jZXNzLlxuICAgIHRoaXMuc2lnaW50TGlzdGVuZXIgPSAoKSA9PiB7XG4gICAgICB2b2lkIChhc3luYyAoKSA9PiB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5lbmQoe1xuICAgICAgICAgICAgbmFtZTogVVNFUl9JTlRFUlJVUFRFRF9DT0RFLFxuICAgICAgICAgICAgbWVzc2FnZTogQUJPUlRFRF9FUlJPUl9NRVNTQUdFLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5kZWZhdWx0cy50cmFjZShgRW5kaW5nIFRlbGVtZXRyeSBmYWlsZWQ6ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgICB9XG4gICAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICAgIH0pKCk7XG4gICAgfTtcbiAgICBwcm9jZXNzLm9uKCdTSUdJTlQnLCB0aGlzLnNpZ2ludExpc3RlbmVyKTtcblxuICAgIC8vIEJlZ2luIHRoZSBzZXNzaW9uIHNwYW5cbiAgICB0aGlzLl9jb21tYW5kU3BhbiA9IGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5zcGFuKENMSV9QUklWQVRFX1NQQU4uQ09NTUFORCkuYmVnaW4oe30pO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGF0dGFjaFJlZ2lvbihyZWdpb246IHN0cmluZykge1xuICAgIHRoaXMuc2Vzc2lvbkluZm8uaWRlbnRpZmllcnMgPSB7XG4gICAgICAuLi50aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLFxuICAgICAgcmVnaW9uLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIGEgbGFuZ3VhZ2UgZ3Vlc3NcbiAgICovXG4gIHB1YmxpYyBhdHRhY2hMYW5ndWFnZShsYW5ndWFnZTogc3RyaW5nIHwgdW5kZWZpbmVkKSB7XG4gICAgLy8gRG9uJ3Qgd2FudCB0byBjcmFzaCBhY2NpZGVudGFsbHlcbiAgICBpZiAoIXRoaXMuX3Nlc3Npb25JbmZvKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGxhbmd1YWdlKSB7XG4gICAgICBtdXRhYmxlKHRoaXMuc2Vzc2lvbkluZm8ucHJvamVjdCkubGFuZ3VhZ2UgPSBsYW5ndWFnZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIG91ciBiZXN0IGd1ZXNzIGF0IHJ1bm5pbmcgdW5kZXIgYW4gYWdlbnQgb3Igbm90XG4gICAqL1xuICBwdWJsaWMgYXR0YWNoQWdlbnQoaXNBZ2VudDogYm9vbGVhbiB8IHVuZGVmaW5lZCkge1xuICAgIC8vIERvbid0IHdhbnQgdG8gY3Jhc2ggYWNjaWRlbnRhbGx5XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG11dGFibGUodGhpcy5zZXNzaW9uSW5mby5lbnZpcm9ubWVudCkuYWdlbnQgPSBpc0FnZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIFRlbXBvcmFyaWx5IGF0dGFjaCBjb3VudGVycyBmb3IgdGhlIG5leHQgZXZlbnQgb3BlcmF0aW9uLlxuICAgKlxuICAgKiBUaGV5IG1heSBiZSBjb21taXR0ZWQgdG8gdGhlIHNlbnQgdGVsZW1ldHJ5IGxhdGVyLlxuICAgKi9cbiAgcHVibGljIGF0dGFjaENvdW50ZXJzVG9OZXh0RXZlbnQoY291bnRlcnM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4pIHtcbiAgICB0aGlzLl9uZXh0RXZlbnRDb3VudGVycyA9IGNvdW50ZXJzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgbG9hZCB0aW1lICh3aWxsIGJlIGVtaXR0ZWQgd2l0aCB0aGUgQ09NTUFORCBzcGFuKVxuICAgKi9cbiAgcHVibGljIGF0dGFjaExvYWRUaW1lKGxvYWRUaW1lOiBudW1iZXIpIHtcbiAgICB0aGlzLmxvYWRUaW1lID0gbG9hZFRpbWU7XG4gICAgdGhpcy5fY29tbWFuZFNwYW4/LmFkZFRpbWVyKCdsb2FkJywgbG9hZFRpbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hcmsgd2hlbiB0aGUgYWN0dWFsIENMSSBvcGVyYXRpb24gc3RhcnRzXG4gICAqXG4gICAqIEVtaXR0ZWQgYXMgcGFydCBvZiB0aGUgQ09NTUFORCBzcGFuLlxuICAgKi9cbiAgcHVibGljIG1hcmtPcGVyYXRpb25TdGFydCgpIHtcbiAgICBpZiAodGhpcy5sb2FkVGltZSkge1xuICAgICAgdGhpcy5fY29tbWFuZFNwYW4/LmFkZFRpbWVyKCdpbml0JywgcGVyZm9ybWFuY2Uubm93KCkgLSB0aGlzLmxvYWRUaW1lKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIHRoZSBDREsgbGlicmFyeSB2ZXJzaW9uXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQgdGhlIHRlbGVtZXRyeSB3aWxsIGd1ZXNzIGF0IHRoZSBDREsgbGlicmFyeSB2ZXJzaW9uIGlmIGl0IHNvXG4gICAqIGhhcHBlbnMgdGhhdCB0aGUgQ0RLIHByb2plY3QgaXMgYW4gTlBNIHByb2plY3QgYW5kIHRoZSBDREsgQ0xJIGlzIGV4ZWN1dGVkXG4gICAqIGluIHRoZSByb290IG9mIE5QTSBwcm9qZWN0IHdpdGggYGF3cy1jZGstbGliYCBhdmFpbGFibGUgaW4gYG5vZGVfbW9kdWxlc2AuXG4gICAqIFRoaXMgbWF5IHN1Y2NlZWQgb3IgbWF5IGZhaWwuXG4gICAqXG4gICAqIE9uY2Ugd2UgaGF2ZSBwcm9kdWNlZCBhbmQgbG9hZGVkIHRoZSBjbG91ZCBhc3NlbWJseSBtb3JlIGFjY3VyYXRlXG4gICAqIGluZm9ybWF0aW9uIGJlY29tZXMgYXZhaWxhYmxlIHRoYXQgd2UgY2FuIGFkZCBpbi5cbiAgICovXG4gIHB1YmxpYyBhdHRhY2hDZGtMaWJWZXJzaW9uKGxpYlZlcnNpb246IHN0cmluZykge1xuICAgIC8vIERvbid0IHdhbnQgdG8gY3Jhc2ggYWNjaWRlbnRhbGx5XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG11dGFibGUodGhpcy5zZXNzaW9uSW5mby5pZGVudGlmaWVycykuY2RrTGlicmFyeVZlcnNpb24gPSBsaWJWZXJzaW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZW4gdGhlIGNvbW1hbmQgaXMgY29tcGxldGUsIHNvIGlzIHRoZSBDbGlJb0hvc3QuIEVuZHMgdGhlIHNwYW4gb2YgdGhlIGVudGlyZSBDbGlJb0hvc3RcbiAgICogYW5kIG5vdGlmaWVzIHdpdGggYW4gb3B0aW9uYWwgZXJyb3IgbWVzc2FnZSBpbiB0aGUgZGF0YS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBlbmQoZXJyb3I/OiBFcnJvckRldGFpbHMpIHtcbiAgICBpZiAodGhpcy5zaWdpbnRMaXN0ZW5lcikge1xuICAgICAgcHJvY2Vzcy5yZW1vdmVMaXN0ZW5lcignU0lHSU5UJywgdGhpcy5zaWdpbnRMaXN0ZW5lcik7XG4gICAgICB0aGlzLnNpZ2ludExpc3RlbmVyID0gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBhd2FpdCB0aGlzLl9jb21tYW5kU3Bhbj8uZW5kKHsgZXJyb3IgfSk7XG4gICAgLy8gSWRlYWxseSBzcGFuLmVuZCgpIHNob3VsZCBuby1vcCBpZiBjYWxsZWQgdHdpY2UsIGJ1dCB0aGF0IGlzIG5vdCB0aGUgY2FzZSByaWdodCBub3dcbiAgICB0aGlzLl9jb21tYW5kU3BhbiA9IHVuZGVmaW5lZDtcbiAgICBhd2FpdCB0aGlzLmNsaWVudC5mbHVzaCgpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGVtaXQoZXZlbnQ6IFRlbGVtZXRyeUV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5jb3VudCArPSAxO1xuXG4gICAgY29uc3QgY291bnRlcnMgPSB7XG4gICAgICAuLi50aGlzLl9uZXh0RXZlbnRDb3VudGVycyxcbiAgICAgIC4uLmV2ZW50LmNvdW50ZXJzLFxuICAgIH07XG4gICAgdGhpcy5fbmV4dEV2ZW50Q291bnRlcnMgPSB1bmRlZmluZWQ7XG5cbiAgICBpZiAoZXZlbnQuZXZlbnRUeXBlID09ICdERVBMT1knKSB7XG4gICAgICBhd2FpdCB0aGlzLnRyYWNrRGVwbG95U3RhdGlzdGljcyhldmVudC5lcnJvciA9PT0gdW5kZWZpbmVkLCBjb3VudGVycyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmVtaXQoe1xuICAgICAgZXZlbnQ6IHtcbiAgICAgICAgY29tbWFuZDogdGhpcy5zZXNzaW9uSW5mby5ldmVudC5jb21tYW5kLFxuICAgICAgICBzdGF0ZTogZ2V0U3RhdGUoZXZlbnQuZXJyb3IpLFxuICAgICAgICBldmVudFR5cGU6IGV2ZW50LmV2ZW50VHlwZSxcbiAgICAgIH0sXG4gICAgICBpZGVudGlmaWVyczoge1xuICAgICAgICAuLi50aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLFxuICAgICAgICBldmVudElkOiBgJHt0aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLnNlc3Npb25JZH06JHt0aGlzLmNvdW50fWAsXG4gICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgfSxcbiAgICAgIGVudmlyb25tZW50OiB0aGlzLnNlc3Npb25JbmZvLmVudmlyb25tZW50LFxuICAgICAgcHJvamVjdDogdGhpcy5zZXNzaW9uSW5mby5wcm9qZWN0LFxuICAgICAgZHVyYXRpb246IHtcbiAgICAgICAgdG90YWw6IGV2ZW50LmR1cmF0aW9uLFxuICAgICAgfSxcbiAgICAgIC4uLihldmVudC5lcnJvciA/IHtcbiAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICBuYW1lOiBldmVudC5lcnJvci5uYW1lLFxuICAgICAgICB9LFxuICAgICAgfSA6IHt9KSxcbiAgICAgIC4uLihPYmplY3Qua2V5cyhjb3VudGVycykubGVuZ3RoID4gMCA/IHsgY291bnRlcnMgfSA6IHt9KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGlzIGEgREVQTE9ZIGV2ZW50LCB0cmFjayBzb21lIGFkZGl0aW9uYWwgc3RhdGlzdGljcyBhYm91dCBpdFxuICAgKlxuICAgKiBXZSB1c2UgdGhpcyB0byBtZWFzdXJlIHRoaW5ncyBhYm91dCBkZXBsb3ltZW50IGZhaWx1cmVzLCBzdWNoIGFzIHRoZSBudW1iZXIgb2ZcbiAgICogZmFpbGVkIERFUExPWSBldmVudHMgaW4gYSBzZXF1ZW5jZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdHJhY2tEZXBsb3lTdGF0aXN0aWNzKGlzU3VjY2Vzc2Z1bDogYm9vbGVhbiwgY291bnRlcnM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4pIHtcbiAgICBhd2FpdCB3aXRoVGVsZW1ldHJ5U3RhdGUoKHN0YXRlKSA9PiB7XG4gICAgICBjb25zdCByZWNlbnRGYWlsdXJlcyA9IHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPz8gMDtcblxuICAgICAgaWYgKGlzU3VjY2Vzc2Z1bCkge1xuICAgICAgICBzdGF0ZS5zZXF1ZW50aWFsRGVwbG95bWVudEZhaWx1cmVzID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPSByZWNlbnRGYWlsdXJlcyArIDE7XG4gICAgICB9XG5cbiAgICAgIGNvdW50ZXJzLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPSBzdGF0ZS5zZXF1ZW50aWFsRGVwbG95bWVudEZhaWx1cmVzO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgc2Vzc2lvbkluZm8oKTogU2Vzc2lvblNjaGVtYSB7XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignU2Vzc2lvbk5vdEluaXRpYWxpemVkJywgJ1Nlc3Npb24gSW5mbyBub3QgaW5pdGlhbGl6ZWQuIENhbGwgYmVnaW4oKSBmaXJzdC4nKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX3Nlc3Npb25JbmZvO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFN0YXRlKGVycm9yPzogRXJyb3JEZXRhaWxzKTogU3RhdGUge1xuICBpZiAoZXJyb3IpIHtcbiAgICByZXR1cm4gaXNBYm9ydGVkRXJyb3IoZXJyb3IpID8gJ0FCT1JURUQnIDogJ0ZBSUxFRCc7XG4gIH1cbiAgcmV0dXJuICdTVUNDRUVERUQnO1xufVxuXG5mdW5jdGlvbiBpc0Fib3J0ZWRFcnJvcihlcnJvcj86IEVycm9yRGV0YWlscykge1xuICBpZiAoZXJyb3I/Lm5hbWUgPT09ICdUb29sa2l0RXJyb3InICYmIGVycm9yPy5tZXNzYWdlPy5pbmNsdWRlcyhBQk9SVEVEX0VSUk9SX01FU1NBR0UpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5mdW5jdGlvbiBtdXRhYmxlPEEgZXh0ZW5kcyBvYmplY3Q+KHg6IEEpOiB7IC1yZWFkb25seSBbayBpbiBrZXlvZiBBXTogQVtrXSB9IHtcbiAgcmV0dXJuIHg7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoYXQgdGhlIENES19DTElfVVNFUkFHRU5UIGVudiB2YXIgdmFsdWUgbWF0Y2hlc1xuICogdGhlIGV4cGVjdGVkIGZvcm1hdDogYDxuYW1lPi88dmVyc2lvbj4vPG1vZGU+YCB3aGVyZSBuYW1lIGlzIG9uZSBvZlxuICogVkFMSURfVVNFUl9BR0VOVFMgYW5kIG1vZGUgaXMgZWl0aGVyIGBzYW5kYm94YCBvciBgcHJvZHVjdGlvbmAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkV3JhcHBlclVzZXJBZ2VudCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogdmFsdWUgaXMgc3RyaW5nIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBwYXJ0cyA9IHZhbHVlLnNwbGl0KCcvJyk7XG4gIGlmIChwYXJ0cy5sZW5ndGggIT09IDMpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgW25hbWUsIF92ZXJzaW9uLCBtb2RlXSA9IHBhcnRzO1xuICBpZiAoIVZBTElEX1VTRVJfQUdFTlRTLmluY2x1ZGVzKG5hbWUpKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiBtb2RlID09PSAnc2FuZGJveCcgfHwgbW9kZSA9PT0gJ3Byb2R1Y3Rpb24nO1xufVxuXG4vKipcbiAqIFRyeSB0byBkZXRlY3QgYSBDb25maWcgZmlsZSBvZiB3aGljaCB0aGUgZmlyc3QgbGluZSBsb29rcyBsaWtlXG4gKlxuICogYGBgXG4gKiBwYWNrYWdlLjxwYWNrYWdlTmFtZT4gPSB7XG4gKiBgYGBcbiAqXG4gKiBPciBhIGBicmF6aWwuaW9uYCBmaWxlIHdpdGggYSBsaW5lIGxpa2VcbiAqXG4gKiBgYGBcbiAqIG5hbWU6IFwiPHByb2plY3ROYW1lPlwiXG4gKiBgYGBcbiAqXG4gKiBUaGV5IHdpbGwgYWx3YXlzIGJlIGluIHRoZSBjdXJyZW50IHdvcmtpbmcgZGlyZWN0b3J5LCBhbmQgd2Ugd2lsbFxuICogb25seSBkbyB0aGUgY2hlY2sgaWYgaXQgbG9va3MgbGlrZSB3ZSdyZSBvbiBhbiBBbXpuIGRldmVsb3BlciBtYWNoaW5lLlxuICovXG5hc3luYyBmdW5jdGlvbiB0cnlEZXRlY3RBbXpuUGFja2FnZSgpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICB0cnkge1xuICAgIGF3YWl0IGZzLnN0YXQocGF0aGxpYi5qb2luKG9zLmhvbWVkaXIoKSwgJy5taWR3YXknKSk7XG4gIH0gY2F0Y2gge1xuICAgIC8vIEVOT0VOVFxuICAgIHJldHVybjtcbiAgfVxuXG4gIHRyeSB7XG4gICAgY29uc3QgY29uZmlnRmlsZSA9IGF3YWl0IGZzLnJlYWRGaWxlKCdDb25maWcnLCAndXRmLTgnKTtcbiAgICBjb25zdCBtID0gY29uZmlnRmlsZS5tYXRjaCgvXnBhY2thZ2VcXC4oXFxTKylcXHMqPS9tKTtcbiAgICBpZiAobSkge1xuICAgICAgcmV0dXJuIG1bMV07XG4gICAgfVxuICB9IGNhdGNoIHtcbiAgICAvLyBBbnkgZXJyb3IgbWVhbnMgbm8gZGljZS5cbiAgfVxuXG4gIHRyeSB7XG4gICAgY29uc3QgaW9uRmlsZSA9IGF3YWl0IGZzLnJlYWRGaWxlKCdicmF6aWwuaW9uJywgJ3V0Zi04Jyk7XG4gICAgY29uc3QgbSA9IGlvbkZpbGUubWF0Y2goLyhefFxccyluYW1lOlxccypcIihbXlwiXSspXCIvbSk7XG4gICAgaWYgKG0pIHtcbiAgICAgIHJldHVybiBtWzJdO1xuICAgIH1cbiAgfSBjYXRjaCB7XG4gICAgLy8gQW55IGVycm9yIG1lYW5zIG5vIGRpY2UuXG4gIH1cblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuIl19