aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
262 lines • 30.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TelemetrySession = void 0;
exports.isValidWrapperUserAgent = isValidWrapperUserAgent;
const node_crypto_1 = require("node:crypto");
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 {
constructor(props) {
this.props = props;
this.count = 0;
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()),
},
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.
process.on('SIGINT', 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);
});
// 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) {
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';
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNlc3Npb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBMFRBLDBEQU9DO0FBalVELDZDQUF5QztBQUN6QyxzREFBb0Q7QUFDcEQsdURBQThEO0FBQzlELHVEQUFzRDtBQUN0RCw2Q0FBNkU7QUFLN0UsOENBQStDO0FBRy9DLG9EQUF5RDtBQUN6RCxtQ0FBa0M7QUFDbEMsd0NBQTJDO0FBQzNDLG1DQUFnRDtBQUNoRCx1REFBdUQ7QUFFdkQsTUFBTSxxQkFBcUIsR0FBRyx3QkFBd0IsQ0FBQztBQUV2RDs7O0dBR0c7QUFDSCxNQUFNLGlCQUFpQixHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7QUErQnpDLE1BQWEsZ0JBQWdCO0lBUzNCLFlBQTZCLEtBQTRCO1FBQTVCLFVBQUssR0FBTCxLQUFLLENBQXVCO1FBSGpELFVBQUssR0FBRyxDQUFDLENBQUM7UUFJaEIsSUFBSSxDQUFDLE1BQU0sR0FBRyxLQUFLLENBQUMsTUFBTSxDQUFDO1FBQzNCLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILElBQVcsV0FBVztRQUNwQixPQUFPLElBQUksQ0FBQyxZQUFZLENBQUM7SUFDM0IsQ0FBQztJQUVNLEtBQUssQ0FBQyxLQUFLO1FBQ2hCLDZCQUE2QjtRQUM3QixNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxHQUFHLElBQUEseUNBQTRCLEVBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNoRixJQUFJLENBQUMsWUFBWSxHQUFHO1lBQ2xCLFdBQVcsRUFBRTtnQkFDWCxjQUFjLEVBQUUsTUFBTSxJQUFBLDJDQUF5QixFQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ3pFLFNBQVMsRUFBRSxJQUFBLHdCQUFVLEdBQUU7Z0JBQ3ZCLGdCQUFnQixF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LElBQUksS0FBSyxjQUFjLElBQUksS0FBSyxFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMscUJBQXFCLENBQUMsRUFBRSxDQUFDO1FBQ3RGLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2YsQ0FBQztBQUVELFNBQVMsT0FBTyxDQUFtQixDQUFJO0lBQ3JDLE9BQU8sQ0FBQyxDQUFDO0FBQ1gsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQix1QkFBdUIsQ0FBQyxLQUF5QjtJQUMvRCxJQUFJLENBQUMsS0FBSztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3pCLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDL0IsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNyQyxNQUFNLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUM7SUFDckMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUNwRCxPQUFPLElBQUksS0FBSyxTQUFTLElBQUksSUFBSSxLQUFLLFlBQVksQ0FBQztBQUNyRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmFuZG9tVVVJRCB9IGZyb20gJ25vZGU6Y3J5cHRvJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJ0Bhd3MtY2RrL3Rvb2xraXQtbGliJztcbmltcG9ydCB7IGdldE9yQ3JlYXRlSW5zdGFsbGF0aW9uSWQgfSBmcm9tICcuL2luc3RhbGxhdGlvbi1pZCc7XG5pbXBvcnQgeyBnZXRMaWJyYXJ5VmVyc2lvbiB9IGZyb20gJy4vbGlicmFyeS12ZXJzaW9uJztcbmltcG9ydCB7IHNhbml0aXplQ29tbWFuZExpbmVBcmd1bWVudHMsIHNhbml0aXplQ29udGV4dCB9IGZyb20gJy4vc2FuaXRhdGlvbic7XG5pbXBvcnQgeyB0eXBlIEV2ZW50VHlwZSwgdHlwZSBTZXNzaW9uU2NoZW1hLCB0eXBlIFN0YXRlLCB0eXBlIEVycm9yRGV0YWlscyB9IGZyb20gJy4vc2NoZW1hJztcbmltcG9ydCB0eXBlIHsgSVRlbGVtZXRyeVNpbmsgfSBmcm9tICcuL3Npbmsvc2luay1pbnRlcmZhY2UnO1xuaW1wb3J0IHR5cGUgeyBDb250ZXh0IH0gZnJvbSAnLi4vLi4vYXBpL2NvbnRleHQnO1xuaW1wb3J0IHR5cGUgeyBJTWVzc2FnZVNwYW4gfSBmcm9tICcuLi8uLi9hcGktcHJpdmF0ZSc7XG5pbXBvcnQgeyBkZXRlY3RDaVN5c3RlbSB9IGZyb20gJy4uL2NpLXN5c3RlbXMnO1xuaW1wb3J0IHR5cGUgeyBDbGlJb0hvc3QgfSBmcm9tICcuLi9pby1ob3N0L2NsaS1pby1ob3N0JztcbmltcG9ydCB0eXBlIHsgRXZlbnRSZXN1bHQgfSBmcm9tICcuLi90ZWxlbWV0cnkvbWVzc2FnZXMnO1xuaW1wb3J0IHsgQ0xJX1BSSVZBVEVfU1BBTiB9IGZyb20gJy4uL3RlbGVtZXRyeS9tZXNzYWdlcyc7XG5pbXBvcnQgeyBpc0NJIH0gZnJvbSAnLi4vdXRpbC9jaSc7XG5pbXBvcnQgeyB2ZXJzaW9uTnVtYmVyIH0gZnJvbSAnLi4vdmVyc2lvbic7XG5pbXBvcnQgeyBVU0VSX0lOVEVSUlVQVEVEX0NPREUgfSBmcm9tICcuL2Vycm9yJztcbmltcG9ydCB7IHdpdGhUZWxlbWV0cnlTdGF0ZSB9IGZyb20gJy4vdGVsZW1ldHJ5LXN0YXRlJztcblxuY29uc3QgQUJPUlRFRF9FUlJPUl9NRVNTQUdFID0gJ19fQ0RLLVRvb2xraXRfX0Fib3J0ZWQnO1xuXG4vKipcbiAqIFZhbGlkIHVzZXIgYWdlbnQgcHJlZml4ZXMgdGhhdCBhcmUgYWxsb3dlZCB0byByZXBvcnQgdGhyb3VnaCBDREtfQ0xJX1VTRVJBR0VOVC5cbiAqIFRoaXMgY3JlYXRlcyBhIG1lY2hhbmlzbSB0byByZXBvcnQgdXNlciBhZ2VudHMgd2UgY29udHJvbC5cbiAqL1xuY29uc3QgVkFMSURfVVNFUl9BR0VOVFMgPSBbJ2F3cy1ibG9ja3MnXTtcblxuZXhwb3J0IGludGVyZmFjZSBUZWxlbWV0cnlTZXNzaW9uUHJvcHMge1xuICByZWFkb25seSBpb0hvc3Q6IENsaUlvSG9zdDtcbiAgcmVhZG9ubHkgY2xpZW50OiBJVGVsZW1ldHJ5U2luaztcbiAgcmVhZG9ubHkgYXJndW1lbnRzOiBhbnk7XG4gIHJlYWRvbmx5IGNvbnRleHQ6IENvbnRleHQ7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVsZW1ldHJ5RXZlbnQge1xuICByZWFkb25seSBldmVudFR5cGU6IEV2ZW50VHlwZTtcbiAgcmVhZG9ubHkgZHVyYXRpb246IG51bWJlcjtcbiAgcmVhZG9ubHkgZXJyb3I/OiBFcnJvckRldGFpbHM7XG4gIHJlYWRvbmx5IGNvdW50ZXJzPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbn1cblxuLyoqXG4gKiBUaW1lciBvZiBhIHNpbmdsZSBldmVudFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFRpbWluZyB7XG4gIC8qKlxuICAgKiBUb3RhbCB0aW1lIHNwZW50IGluIHRoaXMgb3BlcmF0aW9uXG4gICAqL1xuICB0b3RhbE1zOiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIENvdW50IG9mIG9wZXJhdGlvbnMgdGhhdCB0b2dldGhlciB0b29rIGB0b3RhbE1zYC5cbiAgICovXG4gIGNvdW50OiBudW1iZXI7XG59XG5cbmV4cG9ydCBjbGFzcyBUZWxlbWV0cnlTZXNzaW9uIHtcbiAgcHJpdmF0ZSBpb0hvc3Q6IENsaUlvSG9zdDtcbiAgcHJpdmF0ZSBjbGllbnQ6IElUZWxlbWV0cnlTaW5rO1xuICBwcml2YXRlIF9zZXNzaW9uSW5mbz86IFNlc3Npb25TY2hlbWE7XG4gIHByaXZhdGUgX2NvbW1hbmRTcGFuPzogSU1lc3NhZ2VTcGFuPEV2ZW50UmVzdWx0PjtcbiAgcHJpdmF0ZSBfbmV4dEV2ZW50Q291bnRlcnM/OiBSZWNvcmQ8c3RyaW5nLCBudW1iZXI+O1xuICBwcml2YXRlIGNvdW50ID0gMDtcbiAgcHJpdmF0ZSBsb2FkVGltZT86IG51bWJlcjtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBUZWxlbWV0cnlTZXNzaW9uUHJvcHMpIHtcbiAgICB0aGlzLmlvSG9zdCA9IHByb3BzLmlvSG9zdDtcbiAgICB0aGlzLmNsaWVudCA9IHByb3BzLmNsaWVudDtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgc3BhbiB0aGF0IHJlcHJlc2VudHMgdGhlIENMSSBpbnZvY2F0aW9uLlxuICAgKlxuICAgKiBJbiB0aGUgY29kZSwgdGhpcyBzcGFuIGlzIG5hbWVkIENPTU1BTkQgYnV0IHRoZSBtYXRjaGluZyBldmVudCB0eXBlXG4gICAqIGluIHRlbGVtZXRyeSB3aWxsIGJlIElOVk9LRS5cbiAgICpcbiAgICogV2lsbCBiZSBlbWl0dGVkIGV4YWN0bHkgb25jZSwgYXQgdGhlIGVuZCBvZiB0aGUgQ0xJIG9wZXJhdGlvbi5cbiAgICovXG4gIHB1YmxpYyBnZXQgY29tbWFuZFNwYW4oKTogSU1lc3NhZ2VTcGFuPEV2ZW50UmVzdWx0PiB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2NvbW1hbmRTcGFuO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGJlZ2luKCkge1xuICAgIC8vIHNhbml0aXplIHRoZSByYXcgY2xpIGlucHV0XG4gICAgY29uc3QgeyBwYXRoLCBwYXJhbWV0ZXJzIH0gPSBzYW5pdGl6ZUNvbW1hbmRMaW5lQXJndW1lbnRzKHRoaXMucHJvcHMuYXJndW1lbnRzKTtcbiAgICB0aGlzLl9zZXNzaW9uSW5mbyA9IHtcbiAgICAgIGlkZW50aWZpZXJzOiB7XG4gICAgICAgIGluc3RhbGxhdGlvbklkOiBhd2FpdCBnZXRPckNyZWF0ZUluc3RhbGxhdGlvbklkKHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKSksXG4gICAgICAgIHNlc3Npb25JZDogcmFuZG9tVVVJRCgpLFxuICAgICAgICB0ZWxlbWV0cnlWZXJzaW9uOiAnMi4wJyxcbiAgICAgICAgY2RrQ2xpVmVyc2lvbjogdmVyc2lvbk51bWJlcigpLFxuICAgICAgICBjZGtMaWJyYXJ5VmVyc2lvbjogYXdhaXQgZ2V0TGlicmFyeVZlcnNpb24odGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpKSxcbiAgICAgIH0sXG4gICAgICBldmVudDoge1xuICAgICAgICBjb21tYW5kOiB7XG4gICAgICAgICAgcGF0aCxcbiAgICAgICAgICBwYXJhbWV0ZXJzLFxuICAgICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICAgY29udGV4dDogc2FuaXRpemVDb250ZXh0KHRoaXMucHJvcHMuY29udGV4dCksXG4gICAgICAgICAgICAuLi4oaXNWYWxpZFdyYXBwZXJVc2VyQWdlbnQocHJvY2Vzcy5lbnYuQ0RLX0NMSV9VU0VSQUdFTlQpXG4gICAgICAgICAgICAgID8geyBjZGtDbGlVc2VyQWdlbnQ6IHsgW3Byb2Nlc3MuZW52LkNES19DTElfVVNFUkFHRU5UXTogdHJ1ZSB9IH1cbiAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBjaTogaXNDSSgpIHx8IEJvb2xlYW4oZGV0ZWN0Q2lTeXN0ZW0oKSksXG4gICAgICAgIG9zOiB7XG4gICAgICAgICAgcGxhdGZvcm06IHByb2Nlc3MucGxhdGZvcm0sXG4gICAgICAgICAgcmVsZWFzZTogcHJvY2Vzcy5yZWxlYXNlLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICAgIG5vZGVWZXJzaW9uOiBwcm9jZXNzLnZlcnNpb24sXG4gICAgICB9LFxuICAgICAgcHJvamVjdDoge30sXG4gICAgfTtcblxuICAgIC8vIElmIFNJR0lOVCBoYXMgYSBsaXN0ZW5lciBpbnN0YWxsZWQsIGl0cyBkZWZhdWx0IGJlaGF2aW9yIHdpbGwgYmUgcmVtb3ZlZCAoTm9kZS5qcyB3aWxsIG5vIGxvbmdlciBleGl0KS5cbiAgICAvLyBUaGlzIGVuc3VyZXMgdGhhdCBvbiBTSUdJTlQgd2UgcHJvY2VzcyBzYWZlbHkgY2xvc2UgdGhlIHRlbGVtZXRyeSBzZXNzaW9uIGJlZm9yZSBleGl0aW5nLlxuICAgIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IHRoaXMuZW5kKHtcbiAgICAgICAgICBuYW1lOiBVU0VSX0lOVEVSUlVQVEVEX0NPREUsXG4gICAgICAgICAgbWVzc2FnZTogQUJPUlRFRF9FUlJPUl9NRVNTQUdFLFxuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBhd2FpdCB0aGlzLmlvSG9zdC5kZWZhdWx0cy50cmFjZShgRW5kaW5nIFRlbGVtZXRyeSBmYWlsZWQ6ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH0pO1xuXG4gICAgLy8gQmVnaW4gdGhlIHNlc3Npb24gc3BhblxuICAgIHRoaXMuX2NvbW1hbmRTcGFuID0gYXdhaXQgdGhpcy5pb0hvc3QuYXNJb0hlbHBlcigpLnNwYW4oQ0xJX1BSSVZBVEVfU1BBTi5DT01NQU5EKS5iZWdpbih7fSk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgYXR0YWNoUmVnaW9uKHJlZ2lvbjogc3RyaW5nKSB7XG4gICAgdGhpcy5zZXNzaW9uSW5mby5pZGVudGlmaWVycyA9IHtcbiAgICAgIC4uLnRoaXMuc2Vzc2lvbkluZm8uaWRlbnRpZmllcnMsXG4gICAgICByZWdpb24sXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggYSBsYW5ndWFnZSBndWVzc1xuICAgKi9cbiAgcHVibGljIGF0dGFjaExhbmd1YWdlKGxhbmd1YWdlOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICAvLyBEb24ndCB3YW50IHRvIGNyYXNoIGFjY2lkZW50YWxseVxuICAgIGlmICghdGhpcy5fc2Vzc2lvbkluZm8pIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAobGFuZ3VhZ2UpIHtcbiAgICAgIG11dGFibGUodGhpcy5zZXNzaW9uSW5mby5wcm9qZWN0KS5sYW5ndWFnZSA9IGxhbmd1YWdlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggb3VyIGJlc3QgZ3Vlc3MgYXQgcnVubmluZyB1bmRlciBhbiBhZ2VudCBvciBub3RcbiAgICovXG4gIHB1YmxpYyBhdHRhY2hBZ2VudChpc0FnZW50OiBib29sZWFuIHwgdW5kZWZpbmVkKSB7XG4gICAgLy8gRG9uJ3Qgd2FudCB0byBjcmFzaCBhY2NpZGVudGFsbHlcbiAgICBpZiAoIXRoaXMuX3Nlc3Npb25JbmZvKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbXV0YWJsZSh0aGlzLnNlc3Npb25JbmZvLmVudmlyb25tZW50KS5hZ2VudCA9IGlzQWdlbnQ7XG4gIH1cblxuICAvKipcbiAgICogVGVtcG9yYXJpbHkgYXR0YWNoIGNvdW50ZXJzIGZvciB0aGUgbmV4dCBldmVudCBvcGVyYXRpb24uXG4gICAqXG4gICAqIFRoZXkgbWF5IGJlIGNvbW1pdHRlZCB0byB0aGUgc2VudCB0ZWxlbWV0cnkgbGF0ZXIuXG4gICAqL1xuICBwdWJsaWMgYXR0YWNoQ291bnRlcnNUb05leHRFdmVudChjb3VudGVyczogUmVjb3JkPHN0cmluZywgbnVtYmVyPikge1xuICAgIHRoaXMuX25leHRFdmVudENvdW50ZXJzID0gY291bnRlcnM7XG4gIH1cblxuICAvKipcbiAgICogU2V0IHRoZSBsb2FkIHRpbWUgKHdpbGwgYmUgZW1pdHRlZCB3aXRoIHRoZSBDT01NQU5EIHNwYW4pXG4gICAqL1xuICBwdWJsaWMgYXR0YWNoTG9hZFRpbWUobG9hZFRpbWU6IG51bWJlcikge1xuICAgIHRoaXMubG9hZFRpbWUgPSBsb2FkVGltZTtcbiAgICB0aGlzLl9jb21tYW5kU3Bhbj8uYWRkVGltZXIoJ2xvYWQnLCBsb2FkVGltZSk7XG4gIH1cblxuICAvKipcbiAgICogTWFyayB3aGVuIHRoZSBhY3R1YWwgQ0xJIG9wZXJhdGlvbiBzdGFydHNcbiAgICpcbiAgICogRW1pdHRlZCBhcyBwYXJ0IG9mIHRoZSBDT01NQU5EIHNwYW4uXG4gICAqL1xuICBwdWJsaWMgbWFya09wZXJhdGlvblN0YXJ0KCkge1xuICAgIGlmICh0aGlzLmxvYWRUaW1lKSB7XG4gICAgICB0aGlzLl9jb21tYW5kU3Bhbj8uYWRkVGltZXIoJ2luaXQnLCBwZXJmb3JtYW5jZS5ub3coKSAtIHRoaXMubG9hZFRpbWUpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRhY2ggdGhlIENESyBsaWJyYXJ5IHZlcnNpb25cbiAgICpcbiAgICogQnkgZGVmYXVsdCB0aGUgdGVsZW1ldHJ5IHdpbGwgZ3Vlc3MgYXQgdGhlIENESyBsaWJyYXJ5IHZlcnNpb24gaWYgaXQgc29cbiAgICogaGFwcGVucyB0aGF0IHRoZSBDREsgcHJvamVjdCBpcyBhbiBOUE0gcHJvamVjdCBhbmQgdGhlIENESyBDTEkgaXMgZXhlY3V0ZWRcbiAgICogaW4gdGhlIHJvb3Qgb2YgTlBNIHByb2plY3Qgd2l0aCBgYXdzLWNkay1saWJgIGF2YWlsYWJsZSBpbiBgbm9kZV9tb2R1bGVzYC5cbiAgICogVGhpcyBtYXkgc3VjY2VlZCBvciBtYXkgZmFpbC5cbiAgICpcbiAgICogT25jZSB3ZSBoYXZlIHByb2R1Y2VkIGFuZCBsb2FkZWQgdGhlIGNsb3VkIGFzc2VtYmx5IG1vcmUgYWNjdXJhdGVcbiAgICogaW5mb3JtYXRpb24gYmVjb21lcyBhdmFpbGFibGUgdGhhdCB3ZSBjYW4gYWRkIGluLlxuICAgKi9cbiAgcHVibGljIGF0dGFjaENka0xpYlZlcnNpb24obGliVmVyc2lvbjogc3RyaW5nKSB7XG4gICAgLy8gRG9uJ3Qgd2FudCB0byBjcmFzaCBhY2NpZGVudGFsbHlcbiAgICBpZiAoIXRoaXMuX3Nlc3Npb25JbmZvKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgbXV0YWJsZSh0aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzKS5jZGtMaWJyYXJ5VmVyc2lvbiA9IGxpYlZlcnNpb247XG4gIH1cblxuICAvKipcbiAgICogV2hlbiB0aGUgY29tbWFuZCBpcyBjb21wbGV0ZSwgc28gaXMgdGhlIENsaUlvSG9zdC4gRW5kcyB0aGUgc3BhbiBvZiB0aGUgZW50aXJlIENsaUlvSG9zdFxuICAgKiBhbmQgbm90aWZpZXMgd2l0aCBhbiBvcHRpb25hbCBlcnJvciBtZXNzYWdlIGluIHRoZSBkYXRhLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIGVuZChlcnJvcj86IEVycm9yRGV0YWlscykge1xuICAgIGF3YWl0IHRoaXMuX2NvbW1hbmRTcGFuPy5lbmQoeyBlcnJvciB9KTtcbiAgICAvLyBJZGVhbGx5IHNwYW4uZW5kKCkgc2hvdWxkIG5vLW9wIGlmIGNhbGxlZCB0d2ljZSwgYnV0IHRoYXQgaXMgbm90IHRoZSBjYXNlIHJpZ2h0IG5vd1xuICAgIHRoaXMuX2NvbW1hbmRTcGFuID0gdW5kZWZpbmVkO1xuICAgIGF3YWl0IHRoaXMuY2xpZW50LmZsdXNoKCk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZW1pdChldmVudDogVGVsZW1ldHJ5RXZlbnQpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0aGlzLmNvdW50ICs9IDE7XG5cbiAgICBjb25zdCBjb3VudGVycyA9IHtcbiAgICAgIC4uLnRoaXMuX25leHRFdmVudENvdW50ZXJzLFxuICAgICAgLi4uZXZlbnQuY291bnRlcnMsXG4gICAgfTtcbiAgICB0aGlzLl9uZXh0RXZlbnRDb3VudGVycyA9IHVuZGVmaW5lZDtcblxuICAgIGlmIChldmVudC5ldmVudFR5cGUgPT0gJ0RFUExPWScpIHtcbiAgICAgIGF3YWl0IHRoaXMudHJhY2tEZXBsb3lTdGF0aXN0aWNzKGV2ZW50LmVycm9yID09PSB1bmRlZmluZWQsIGNvdW50ZXJzKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpcy5jbGllbnQuZW1pdCh7XG4gICAgICBldmVudDoge1xuICAgICAgICBjb21tYW5kOiB0aGlzLnNlc3Npb25JbmZvLmV2ZW50LmNvbW1hbmQsXG4gICAgICAgIHN0YXRlOiBnZXRTdGF0ZShldmVudC5lcnJvciksXG4gICAgICAgIGV2ZW50VHlwZTogZXZlbnQuZXZlbnRUeXBlLFxuICAgICAgfSxcbiAgICAgIGlkZW50aWZpZXJzOiB7XG4gICAgICAgIC4uLnRoaXMuc2Vzc2lvbkluZm8uaWRlbnRpZmllcnMsXG4gICAgICAgIGV2ZW50SWQ6IGAke3RoaXMuc2Vzc2lvbkluZm8uaWRlbnRpZmllcnMuc2Vzc2lvbklkfToke3RoaXMuY291bnR9YCxcbiAgICAgICAgdGltZXN0YW1wOiBuZXcgRGF0ZSgpLnRvSVNPU3RyaW5nKCksXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHRoaXMuc2Vzc2lvbkluZm8uZW52aXJvbm1lbnQsXG4gICAgICBwcm9qZWN0OiB0aGlzLnNlc3Npb25JbmZvLnByb2plY3QsXG4gICAgICBkdXJhdGlvbjoge1xuICAgICAgICB0b3RhbDogZXZlbnQuZHVyYXRpb24sXG4gICAgICB9LFxuICAgICAgLi4uKGV2ZW50LmVycm9yID8ge1xuICAgICAgICBlcnJvcjoge1xuICAgICAgICAgIG5hbWU6IGV2ZW50LmVycm9yLm5hbWUsXG4gICAgICAgIH0sXG4gICAgICB9IDoge30pLFxuICAgICAgLi4uKE9iamVjdC5rZXlzKGNvdW50ZXJzKS5sZW5ndGggPiAwID8geyBjb3VudGVycyB9IDoge30pLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoaXMgaXMgYSBERVBMT1kgZXZlbnQsIHRyYWNrIHNvbWUgYWRkaXRpb25hbCBzdGF0aXN0aWNzIGFib3V0IGl0XG4gICAqXG4gICAqIFdlIHVzZSB0aGlzIHRvIG1lYXN1cmUgdGhpbmdzIGFib3V0IGRlcGxveW1lbnQgZmFpbHVyZXMsIHN1Y2ggYXMgdGhlIG51bWJlciBvZlxuICAgKiBmYWlsZWQgREVQTE9ZIGV2ZW50cyBpbiBhIHNlcXVlbmNlLlxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyB0cmFja0RlcGxveVN0YXRpc3RpY3MoaXNTdWNjZXNzZnVsOiBib29sZWFuLCBjb3VudGVyczogUmVjb3JkPHN0cmluZywgbnVtYmVyPikge1xuICAgIGF3YWl0IHdpdGhUZWxlbWV0cnlTdGF0ZSgoc3RhdGUpID0+IHtcbiAgICAgIGNvbnN0IHJlY2VudEZhaWx1cmVzID0gc3RhdGUuc2VxdWVudGlhbERlcGxveW1lbnRGYWlsdXJlcyA/PyAwO1xuXG4gICAgICBpZiAoaXNTdWNjZXNzZnVsKSB7XG4gICAgICAgIHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPSAwO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RhdGUuc2VxdWVudGlhbERlcGxveW1lbnRGYWlsdXJlcyA9IHJlY2VudEZhaWx1cmVzICsgMTtcbiAgICAgIH1cblxuICAgICAgY291bnRlcnMuc2VxdWVudGlhbERlcGxveW1lbnRGYWlsdXJlcyA9IHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXM7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdldCBzZXNzaW9uSW5mbygpOiBTZXNzaW9uU2NoZW1hIHtcbiAgICBpZiAoIXRoaXMuX3Nlc3Npb25JbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKCdTZXNzaW9uTm90SW5pdGlhbGl6ZWQnLCAnU2Vzc2lvbiBJbmZvIG5vdCBpbml0aWFsaXplZC4gQ2FsbCBiZWdpbigpIGZpcnN0LicpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fc2Vzc2lvbkluZm87XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0U3RhdGUoZXJyb3I/OiBFcnJvckRldGFpbHMpOiBTdGF0ZSB7XG4gIGlmIChlcnJvcikge1xuICAgIHJldHVybiBpc0Fib3J0ZWRFcnJvcihlcnJvcikgPyAnQUJPUlRFRCcgOiAnRkFJTEVEJztcbiAgfVxuICByZXR1cm4gJ1NVQ0NFRURFRCc7XG59XG5cbmZ1bmN0aW9uIGlzQWJvcnRlZEVycm9yKGVycm9yPzogRXJyb3JEZXRhaWxzKSB7XG4gIGlmIChlcnJvcj8ubmFtZSA9PT0gJ1Rvb2xraXRFcnJvcicgJiYgZXJyb3I/Lm1lc3NhZ2U/LmluY2x1ZGVzKEFCT1JURURfRVJST1JfTUVTU0FHRSkpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuICByZXR1cm4gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIG11dGFibGU8QSBleHRlbmRzIG9iamVjdD4oeDogQSk6IHsgLXJlYWRvbmx5IFtrIGluIGtleW9mIEFdOiBBW2tdIH0ge1xuICByZXR1cm4geDtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhhdCB0aGUgQ0RLX0NMSV9VU0VSQUdFTlQgZW52IHZhciB2YWx1ZSBtYXRjaGVzXG4gKiB0aGUgZXhwZWN0ZWQgZm9ybWF0OiBgPG5hbWU+Lzx2ZXJzaW9uPi88bW9kZT5gIHdoZXJlIG5hbWUgaXMgb25lIG9mXG4gKiBWQUxJRF9VU0VSX0FHRU5UUyBhbmQgbW9kZSBpcyBlaXRoZXIgYHNhbmRib3hgIG9yIGBwcm9kdWN0aW9uYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVmFsaWRXcmFwcGVyVXNlckFnZW50KHZhbHVlOiBzdHJpbmcgfCB1bmRlZmluZWQpOiB2YWx1ZSBpcyBzdHJpbmcge1xuICBpZiAoIXZhbHVlKSByZXR1cm4gZmFsc2U7XG4gIGNvbnN0IHBhcnRzID0gdmFsdWUuc3BsaXQoJy8nKTtcbiAgaWYgKHBhcnRzLmxlbmd0aCAhPT0gMykgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBbbmFtZSwgX3ZlcnNpb24sIG1vZGVdID0gcGFydHM7XG4gIGlmICghVkFMSURfVVNFUl9BR0VOVFMuaW5jbHVkZXMobmFtZSkpIHJldHVybiBmYWxzZTtcbiAgcmV0dXJuIG1vZGUgPT09ICdzYW5kYm94JyB8fCBtb2RlID09PSAncHJvZHVjdGlvbic7XG59XG4iXX0=