aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
269 lines • 31 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 {
props;
ioHost;
client;
_sessionInfo;
_commandSpan;
_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()),
},
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Vzc2lvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInNlc3Npb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBMFRBLDBEQU9DO0FBalVELDZDQUF5QztBQUN6QyxzREFBb0Q7QUFDcEQsdURBQThEO0FBQzlELHVEQUFzRDtBQUN0RCw2Q0FBNkU7QUFLN0UsOENBQStDO0FBRy9DLG9EQUF5RDtBQUN6RCxtQ0FBa0M7QUFDbEMsd0NBQTJDO0FBQzNDLG1DQUFnRDtBQUNoRCx1REFBdUQ7QUFFdkQsTUFBTSxxQkFBcUIsR0FBRyx3QkFBd0IsQ0FBQztBQUV2RDs7O0dBR0c7QUFDSCxNQUFNLGlCQUFpQixHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7QUErQnpDLE1BQWEsZ0JBQWdCO0lBU0U7SUFSckIsTUFBTSxDQUFZO0lBQ2xCLE1BQU0sQ0FBaUI7SUFDdkIsWUFBWSxDQUFpQjtJQUM3QixZQUFZLENBQTZCO0lBQ3pDLGtCQUFrQixDQUEwQjtJQUM1QyxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ1YsUUFBUSxDQUFVO0lBRTFCLFlBQTZCLEtBQTRCO1FBQTVCLFVBQUssR0FBTCxLQUFLLENBQXVCO1FBQ3ZELElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUMzQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxJQUFXLFdBQVc7UUFDcEIsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzNCLENBQUM7SUFFTSxLQUFLLENBQUMsS0FBSztRQUNoQiw2QkFBNkI7UUFDN0IsTUFBTSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFBLHlDQUE0QixFQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDaEYsSUFBSSxDQUFDLFlBQVksR0FBRztZQUNsQixXQUFXLEVBQUU7Z0JBQ1gsY0FBYyxFQUFF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QUMsQ0FBQyxRQUFRLENBQUM7SUFDdEQsQ0FBQztJQUNELE9BQU8sV0FBVyxDQUFDO0FBQ3JCLENBQUM7QUFFRCxTQUFTLGNBQWMsQ0FBQyxLQUFvQjtJQUMxQyxJQUFJLEtBQUssRUFBRSxJQUFJLEtBQUssY0FBYyxJQUFJLEtBQUssRUFBRSxPQUFPLEVBQUUsUUFBUSxDQUFDLHFCQUFxQixDQUFDLEVBQUUsQ0FBQztRQUN0RixPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFDRCxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRCxTQUFTLE9BQU8sQ0FBbUIsQ0FBSTtJQUNyQyxPQUFPLENBQUMsQ0FBQztBQUNYLENBQUM7QUFFRDs7OztHQUlHO0FBQ0gsU0FBZ0IsdUJBQXVCLENBQUMsS0FBeUI7SUFDL0QsSUFBSSxDQUFDLEtBQUs7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUN6QixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQy9CLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDckMsTUFBTSxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsSUFBSSxDQUFDLEdBQUcsS0FBSyxDQUFDO0lBQ3JDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDcEQsT0FBTyxJQUFJLEtBQUssU0FBUyxJQUFJLElBQUksS0FBSyxZQUFZLENBQUM7QUFDckQsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tICdub2RlOmNyeXB0byc7XG5pbXBvcnQgeyBUb29sa2l0RXJyb3IgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgeyBnZXRPckNyZWF0ZUluc3RhbGxhdGlvbklkIH0gZnJvbSAnLi9pbnN0YWxsYXRpb24taWQnO1xuaW1wb3J0IHsgZ2V0TGlicmFyeVZlcnNpb24gfSBmcm9tICcuL2xpYnJhcnktdmVyc2lvbic7XG5pbXBvcnQgeyBzYW5pdGl6ZUNvbW1hbmRMaW5lQXJndW1lbnRzLCBzYW5pdGl6ZUNvbnRleHQgfSBmcm9tICcuL3Nhbml0YXRpb24nO1xuaW1wb3J0IHsgdHlwZSBFdmVudFR5cGUsIHR5cGUgU2Vzc2lvblNjaGVtYSwgdHlwZSBTdGF0ZSwgdHlwZSBFcnJvckRldGFpbHMgfSBmcm9tICcuL3NjaGVtYSc7XG5pbXBvcnQgdHlwZSB7IElUZWxlbWV0cnlTaW5rIH0gZnJvbSAnLi9zaW5rL3NpbmstaW50ZXJmYWNlJztcbmltcG9ydCB0eXBlIHsgQ29udGV4dCB9IGZyb20gJy4uLy4uL2FwaS9jb250ZXh0JztcbmltcG9ydCB0eXBlIHsgSU1lc3NhZ2VTcGFuIH0gZnJvbSAnLi4vLi4vYXBpLXByaXZhdGUnO1xuaW1wb3J0IHsgZGV0ZWN0Q2lTeXN0ZW0gfSBmcm9tICcuLi9jaS1zeXN0ZW1zJztcbmltcG9ydCB0eXBlIHsgQ2xpSW9Ib3N0IH0gZnJvbSAnLi4vaW8taG9zdC9jbGktaW8taG9zdCc7XG5pbXBvcnQgdHlwZSB7IEV2ZW50UmVzdWx0IH0gZnJvbSAnLi4vdGVsZW1ldHJ5L21lc3NhZ2VzJztcbmltcG9ydCB7IENMSV9QUklWQVRFX1NQQU4gfSBmcm9tICcuLi90ZWxlbWV0cnkvbWVzc2FnZXMnO1xuaW1wb3J0IHsgaXNDSSB9IGZyb20gJy4uL3V0aWwvY2knO1xuaW1wb3J0IHsgdmVyc2lvbk51bWJlciB9IGZyb20gJy4uL3ZlcnNpb24nO1xuaW1wb3J0IHsgVVNFUl9JTlRFUlJVUFRFRF9DT0RFIH0gZnJvbSAnLi9lcnJvcic7XG5pbXBvcnQgeyB3aXRoVGVsZW1ldHJ5U3RhdGUgfSBmcm9tICcuL3RlbGVtZXRyeS1zdGF0ZSc7XG5cbmNvbnN0IEFCT1JURURfRVJST1JfTUVTU0FHRSA9ICdfX0NESy1Ub29sa2l0X19BYm9ydGVkJztcblxuLyoqXG4gKiBWYWxpZCB1c2VyIGFnZW50IHByZWZpeGVzIHRoYXQgYXJlIGFsbG93ZWQgdG8gcmVwb3J0IHRocm91Z2ggQ0RLX0NMSV9VU0VSQUdFTlQuXG4gKiBUaGlzIGNyZWF0ZXMgYSBtZWNoYW5pc20gdG8gcmVwb3J0IHVzZXIgYWdlbnRzIHdlIGNvbnRyb2wuXG4gKi9cbmNvbnN0IFZBTElEX1VTRVJfQUdFTlRTID0gWydhd3MtYmxvY2tzJ107XG5cbmV4cG9ydCBpbnRlcmZhY2UgVGVsZW1ldHJ5U2Vzc2lvblByb3BzIHtcbiAgcmVhZG9ubHkgaW9Ib3N0OiBDbGlJb0hvc3Q7XG4gIHJlYWRvbmx5IGNsaWVudDogSVRlbGVtZXRyeVNpbms7XG4gIHJlYWRvbmx5IGFyZ3VtZW50czogYW55O1xuICByZWFkb25seSBjb250ZXh0OiBDb250ZXh0O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRlbGVtZXRyeUV2ZW50IHtcbiAgcmVhZG9ubHkgZXZlbnRUeXBlOiBFdmVudFR5cGU7XG4gIHJlYWRvbmx5IGR1cmF0aW9uOiBudW1iZXI7XG4gIHJlYWRvbmx5IGVycm9yPzogRXJyb3JEZXRhaWxzO1xuICByZWFkb25seSBjb3VudGVycz86IFJlY29yZDxzdHJpbmcsIG51bWJlcj47XG59XG5cbi8qKlxuICogVGltZXIgb2YgYSBzaW5nbGUgZXZlbnRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUaW1pbmcge1xuICAvKipcbiAgICogVG90YWwgdGltZSBzcGVudCBpbiB0aGlzIG9wZXJhdGlvblxuICAgKi9cbiAgdG90YWxNczogbnVtYmVyO1xuXG4gIC8qKlxuICAgKiBDb3VudCBvZiBvcGVyYXRpb25zIHRoYXQgdG9nZXRoZXIgdG9vayBgdG90YWxNc2AuXG4gICAqL1xuICBjb3VudDogbnVtYmVyO1xufVxuXG5leHBvcnQgY2xhc3MgVGVsZW1ldHJ5U2Vzc2lvbiB7XG4gIHByaXZhdGUgaW9Ib3N0OiBDbGlJb0hvc3Q7XG4gIHByaXZhdGUgY2xpZW50OiBJVGVsZW1ldHJ5U2luaztcbiAgcHJpdmF0ZSBfc2Vzc2lvbkluZm8/OiBTZXNzaW9uU2NoZW1hO1xuICBwcml2YXRlIF9jb21tYW5kU3Bhbj86IElNZXNzYWdlU3BhbjxFdmVudFJlc3VsdD47XG4gIHByaXZhdGUgX25leHRFdmVudENvdW50ZXJzPzogUmVjb3JkPHN0cmluZywgbnVtYmVyPjtcbiAgcHJpdmF0ZSBjb3VudCA9IDA7XG4gIHByaXZhdGUgbG9hZFRpbWU/OiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBwcm9wczogVGVsZW1ldHJ5U2Vzc2lvblByb3BzKSB7XG4gICAgdGhpcy5pb0hvc3QgPSBwcm9wcy5pb0hvc3Q7XG4gICAgdGhpcy5jbGllbnQgPSBwcm9wcy5jbGllbnQ7XG4gIH1cblxuICAvKipcbiAgICogVGhlIHNwYW4gdGhhdCByZXByZXNlbnRzIHRoZSBDTEkgaW52b2NhdGlvbi5cbiAgICpcbiAgICogSW4gdGhlIGNvZGUsIHRoaXMgc3BhbiBpcyBuYW1lZCBDT01NQU5EIGJ1dCB0aGUgbWF0Y2hpbmcgZXZlbnQgdHlwZVxuICAgKiBpbiB0ZWxlbWV0cnkgd2lsbCBiZSBJTlZPS0UuXG4gICAqXG4gICAqIFdpbGwgYmUgZW1pdHRlZCBleGFjdGx5IG9uY2UsIGF0IHRoZSBlbmQgb2YgdGhlIENMSSBvcGVyYXRpb24uXG4gICAqL1xuICBwdWJsaWMgZ2V0IGNvbW1hbmRTcGFuKCk6IElNZXNzYWdlU3BhbjxFdmVudFJlc3VsdD4gfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9jb21tYW5kU3BhbjtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBiZWdpbigpIHtcbiAgICAvLyBzYW5pdGl6ZSB0aGUgcmF3IGNsaSBpbnB1dFxuICAgIGNvbnN0IHsgcGF0aCwgcGFyYW1ldGVycyB9ID0gc2FuaXRpemVDb21tYW5kTGluZUFyZ3VtZW50cyh0aGlzLnByb3BzLmFyZ3VtZW50cyk7XG4gICAgdGhpcy5fc2Vzc2lvbkluZm8gPSB7XG4gICAgICBpZGVudGlmaWVyczoge1xuICAgICAgICBpbnN0YWxsYXRpb25JZDogYXdhaXQgZ2V0T3JDcmVhdGVJbnN0YWxsYXRpb25JZCh0aGlzLmlvSG9zdC5hc0lvSGVscGVyKCkpLFxuICAgICAgICBzZXNzaW9uSWQ6IHJhbmRvbVVVSUQoKSxcbiAgICAgICAgdGVsZW1ldHJ5VmVyc2lvbjogJzIuMCcsXG4gICAgICAgIGNka0NsaVZlcnNpb246IHZlcnNpb25OdW1iZXIoKSxcbiAgICAgICAgY2RrTGlicmFyeVZlcnNpb246IGF3YWl0IGdldExpYnJhcnlWZXJzaW9uKHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKSksXG4gICAgICB9LFxuICAgICAgZXZlbnQ6IHtcbiAgICAgICAgY29tbWFuZDoge1xuICAgICAgICAgIHBhdGgsXG4gICAgICAgICAgcGFyYW1ldGVycyxcbiAgICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICAgIGNvbnRleHQ6IHNhbml0aXplQ29udGV4dCh0aGlzLnByb3BzLmNvbnRleHQpLFxuICAgICAgICAgICAgLi4uKGlzVmFsaWRXcmFwcGVyVXNlckFnZW50KHByb2Nlc3MuZW52LkNES19DTElfVVNFUkFHRU5UKVxuICAgICAgICAgICAgICA/IHsgY2RrQ2xpVXNlckFnZW50OiB7IFtwcm9jZXNzLmVudi5DREtfQ0xJX1VTRVJBR0VOVF06IHRydWUgfSB9XG4gICAgICAgICAgICAgIDoge30pLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgY2k6IGlzQ0koKSB8fCBCb29sZWFuKGRldGVjdENpU3lzdGVtKCkpLFxuICAgICAgICBvczoge1xuICAgICAgICAgIHBsYXRmb3JtOiBwcm9jZXNzLnBsYXRmb3JtLFxuICAgICAgICAgIHJlbGVhc2U6IHByb2Nlc3MucmVsZWFzZS5uYW1lLFxuICAgICAgICB9LFxuICAgICAgICBub2RlVmVyc2lvbjogcHJvY2Vzcy52ZXJzaW9uLFxuICAgICAgfSxcbiAgICAgIHByb2plY3Q6IHt9LFxuICAgIH07XG5cbiAgICAvLyBJZiBTSUdJTlQgaGFzIGEgbGlzdGVuZXIgaW5zdGFsbGVkLCBpdHMgZGVmYXVsdCBiZWhhdmlvciB3aWxsIGJlIHJlbW92ZWQgKE5vZGUuanMgd2lsbCBubyBsb25nZXIgZXhpdCkuXG4gICAgLy8gVGhpcyBlbnN1cmVzIHRoYXQgb24gU0lHSU5UIHdlIHByb2Nlc3Mgc2FmZWx5IGNsb3NlIHRoZSB0ZWxlbWV0cnkgc2Vzc2lvbiBiZWZvcmUgZXhpdGluZy5cbiAgICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBhd2FpdCB0aGlzLmVuZCh7XG4gICAgICAgICAgbmFtZTogVVNFUl9JTlRFUlJVUFRFRF9DT0RFLFxuICAgICAgICAgIG1lc3NhZ2U6IEFCT1JURURfRVJST1JfTUVTU0FHRSxcbiAgICAgICAgfSk7XG4gICAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5pb0hvc3QuZGVmYXVsdHMudHJhY2UoYEVuZGluZyBUZWxlbWV0cnkgZmFpbGVkOiAke2UubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9KTtcblxuICAgIC8vIEJlZ2luIHRoZSBzZXNzaW9uIHNwYW5cbiAgICB0aGlzLl9jb21tYW5kU3BhbiA9IGF3YWl0IHRoaXMuaW9Ib3N0LmFzSW9IZWxwZXIoKS5zcGFuKENMSV9QUklWQVRFX1NQQU4uQ09NTUFORCkuYmVnaW4oe30pO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGF0dGFjaFJlZ2lvbihyZWdpb246IHN0cmluZykge1xuICAgIHRoaXMuc2Vzc2lvbkluZm8uaWRlbnRpZmllcnMgPSB7XG4gICAgICAuLi50aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLFxuICAgICAgcmVnaW9uLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIGEgbGFuZ3VhZ2UgZ3Vlc3NcbiAgICovXG4gIHB1YmxpYyBhdHRhY2hMYW5ndWFnZShsYW5ndWFnZTogc3RyaW5nIHwgdW5kZWZpbmVkKSB7XG4gICAgLy8gRG9uJ3Qgd2FudCB0byBjcmFzaCBhY2NpZGVudGFsbHlcbiAgICBpZiAoIXRoaXMuX3Nlc3Npb25JbmZvKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGxhbmd1YWdlKSB7XG4gICAgICBtdXRhYmxlKHRoaXMuc2Vzc2lvbkluZm8ucHJvamVjdCkubGFuZ3VhZ2UgPSBsYW5ndWFnZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIG91ciBiZXN0IGd1ZXNzIGF0IHJ1bm5pbmcgdW5kZXIgYW4gYWdlbnQgb3Igbm90XG4gICAqL1xuICBwdWJsaWMgYXR0YWNoQWdlbnQoaXNBZ2VudDogYm9vbGVhbiB8IHVuZGVmaW5lZCkge1xuICAgIC8vIERvbid0IHdhbnQgdG8gY3Jhc2ggYWNjaWRlbnRhbGx5XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG11dGFibGUodGhpcy5zZXNzaW9uSW5mby5lbnZpcm9ubWVudCkuYWdlbnQgPSBpc0FnZW50O1xuICB9XG5cbiAgLyoqXG4gICAqIFRlbXBvcmFyaWx5IGF0dGFjaCBjb3VudGVycyBmb3IgdGhlIG5leHQgZXZlbnQgb3BlcmF0aW9uLlxuICAgKlxuICAgKiBUaGV5IG1heSBiZSBjb21taXR0ZWQgdG8gdGhlIHNlbnQgdGVsZW1ldHJ5IGxhdGVyLlxuICAgKi9cbiAgcHVibGljIGF0dGFjaENvdW50ZXJzVG9OZXh0RXZlbnQoY291bnRlcnM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4pIHtcbiAgICB0aGlzLl9uZXh0RXZlbnRDb3VudGVycyA9IGNvdW50ZXJzO1xuICB9XG5cbiAgLyoqXG4gICAqIFNldCB0aGUgbG9hZCB0aW1lICh3aWxsIGJlIGVtaXR0ZWQgd2l0aCB0aGUgQ09NTUFORCBzcGFuKVxuICAgKi9cbiAgcHVibGljIGF0dGFjaExvYWRUaW1lKGxvYWRUaW1lOiBudW1iZXIpIHtcbiAgICB0aGlzLmxvYWRUaW1lID0gbG9hZFRpbWU7XG4gICAgdGhpcy5fY29tbWFuZFNwYW4/LmFkZFRpbWVyKCdsb2FkJywgbG9hZFRpbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIE1hcmsgd2hlbiB0aGUgYWN0dWFsIENMSSBvcGVyYXRpb24gc3RhcnRzXG4gICAqXG4gICAqIEVtaXR0ZWQgYXMgcGFydCBvZiB0aGUgQ09NTUFORCBzcGFuLlxuICAgKi9cbiAgcHVibGljIG1hcmtPcGVyYXRpb25TdGFydCgpIHtcbiAgICBpZiAodGhpcy5sb2FkVGltZSkge1xuICAgICAgdGhpcy5fY29tbWFuZFNwYW4/LmFkZFRpbWVyKCdpbml0JywgcGVyZm9ybWFuY2Uubm93KCkgLSB0aGlzLmxvYWRUaW1lKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIHRoZSBDREsgbGlicmFyeSB2ZXJzaW9uXG4gICAqXG4gICAqIEJ5IGRlZmF1bHQgdGhlIHRlbGVtZXRyeSB3aWxsIGd1ZXNzIGF0IHRoZSBDREsgbGlicmFyeSB2ZXJzaW9uIGlmIGl0IHNvXG4gICAqIGhhcHBlbnMgdGhhdCB0aGUgQ0RLIHByb2plY3QgaXMgYW4gTlBNIHByb2plY3QgYW5kIHRoZSBDREsgQ0xJIGlzIGV4ZWN1dGVkXG4gICAqIGluIHRoZSByb290IG9mIE5QTSBwcm9qZWN0IHdpdGggYGF3cy1jZGstbGliYCBhdmFpbGFibGUgaW4gYG5vZGVfbW9kdWxlc2AuXG4gICAqIFRoaXMgbWF5IHN1Y2NlZWQgb3IgbWF5IGZhaWwuXG4gICAqXG4gICAqIE9uY2Ugd2UgaGF2ZSBwcm9kdWNlZCBhbmQgbG9hZGVkIHRoZSBjbG91ZCBhc3NlbWJseSBtb3JlIGFjY3VyYXRlXG4gICAqIGluZm9ybWF0aW9uIGJlY29tZXMgYXZhaWxhYmxlIHRoYXQgd2UgY2FuIGFkZCBpbi5cbiAgICovXG4gIHB1YmxpYyBhdHRhY2hDZGtMaWJWZXJzaW9uKGxpYlZlcnNpb246IHN0cmluZykge1xuICAgIC8vIERvbid0IHdhbnQgdG8gY3Jhc2ggYWNjaWRlbnRhbGx5XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIG11dGFibGUodGhpcy5zZXNzaW9uSW5mby5pZGVudGlmaWVycykuY2RrTGlicmFyeVZlcnNpb24gPSBsaWJWZXJzaW9uO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZW4gdGhlIGNvbW1hbmQgaXMgY29tcGxldGUsIHNvIGlzIHRoZSBDbGlJb0hvc3QuIEVuZHMgdGhlIHNwYW4gb2YgdGhlIGVudGlyZSBDbGlJb0hvc3RcbiAgICogYW5kIG5vdGlmaWVzIHdpdGggYW4gb3B0aW9uYWwgZXJyb3IgbWVzc2FnZSBpbiB0aGUgZGF0YS5cbiAgICovXG4gIHB1YmxpYyBhc3luYyBlbmQoZXJyb3I/OiBFcnJvckRldGFpbHMpIHtcbiAgICBhd2FpdCB0aGlzLl9jb21tYW5kU3Bhbj8uZW5kKHsgZXJyb3IgfSk7XG4gICAgLy8gSWRlYWxseSBzcGFuLmVuZCgpIHNob3VsZCBuby1vcCBpZiBjYWxsZWQgdHdpY2UsIGJ1dCB0aGF0IGlzIG5vdCB0aGUgY2FzZSByaWdodCBub3dcbiAgICB0aGlzLl9jb21tYW5kU3BhbiA9IHVuZGVmaW5lZDtcbiAgICBhd2FpdCB0aGlzLmNsaWVudC5mbHVzaCgpO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGVtaXQoZXZlbnQ6IFRlbGVtZXRyeUV2ZW50KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgdGhpcy5jb3VudCArPSAxO1xuXG4gICAgY29uc3QgY291bnRlcnMgPSB7XG4gICAgICAuLi50aGlzLl9uZXh0RXZlbnRDb3VudGVycyxcbiAgICAgIC4uLmV2ZW50LmNvdW50ZXJzLFxuICAgIH07XG4gICAgdGhpcy5fbmV4dEV2ZW50Q291bnRlcnMgPSB1bmRlZmluZWQ7XG5cbiAgICBpZiAoZXZlbnQuZXZlbnRUeXBlID09ICdERVBMT1knKSB7XG4gICAgICBhd2FpdCB0aGlzLnRyYWNrRGVwbG95U3RhdGlzdGljcyhldmVudC5lcnJvciA9PT0gdW5kZWZpbmVkLCBjb3VudGVycyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMuY2xpZW50LmVtaXQoe1xuICAgICAgZXZlbnQ6IHtcbiAgICAgICAgY29tbWFuZDogdGhpcy5zZXNzaW9uSW5mby5ldmVudC5jb21tYW5kLFxuICAgICAgICBzdGF0ZTogZ2V0U3RhdGUoZXZlbnQuZXJyb3IpLFxuICAgICAgICBldmVudFR5cGU6IGV2ZW50LmV2ZW50VHlwZSxcbiAgICAgIH0sXG4gICAgICBpZGVudGlmaWVyczoge1xuICAgICAgICAuLi50aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLFxuICAgICAgICBldmVudElkOiBgJHt0aGlzLnNlc3Npb25JbmZvLmlkZW50aWZpZXJzLnNlc3Npb25JZH06JHt0aGlzLmNvdW50fWAsXG4gICAgICAgIHRpbWVzdGFtcDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpLFxuICAgICAgfSxcbiAgICAgIGVudmlyb25tZW50OiB0aGlzLnNlc3Npb25JbmZvLmVudmlyb25tZW50LFxuICAgICAgcHJvamVjdDogdGhpcy5zZXNzaW9uSW5mby5wcm9qZWN0LFxuICAgICAgZHVyYXRpb246IHtcbiAgICAgICAgdG90YWw6IGV2ZW50LmR1cmF0aW9uLFxuICAgICAgfSxcbiAgICAgIC4uLihldmVudC5lcnJvciA/IHtcbiAgICAgICAgZXJyb3I6IHtcbiAgICAgICAgICBuYW1lOiBldmVudC5lcnJvci5uYW1lLFxuICAgICAgICB9LFxuICAgICAgfSA6IHt9KSxcbiAgICAgIC4uLihPYmplY3Qua2V5cyhjb3VudGVycykubGVuZ3RoID4gMCA/IHsgY291bnRlcnMgfSA6IHt9KSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGlzIGEgREVQTE9ZIGV2ZW50LCB0cmFjayBzb21lIGFkZGl0aW9uYWwgc3RhdGlzdGljcyBhYm91dCBpdFxuICAgKlxuICAgKiBXZSB1c2UgdGhpcyB0byBtZWFzdXJlIHRoaW5ncyBhYm91dCBkZXBsb3ltZW50IGZhaWx1cmVzLCBzdWNoIGFzIHRoZSBudW1iZXIgb2ZcbiAgICogZmFpbGVkIERFUExPWSBldmVudHMgaW4gYSBzZXF1ZW5jZS5cbiAgICovXG4gIHByaXZhdGUgYXN5bmMgdHJhY2tEZXBsb3lTdGF0aXN0aWNzKGlzU3VjY2Vzc2Z1bDogYm9vbGVhbiwgY291bnRlcnM6IFJlY29yZDxzdHJpbmcsIG51bWJlcj4pIHtcbiAgICBhd2FpdCB3aXRoVGVsZW1ldHJ5U3RhdGUoKHN0YXRlKSA9PiB7XG4gICAgICBjb25zdCByZWNlbnRGYWlsdXJlcyA9IHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPz8gMDtcblxuICAgICAgaWYgKGlzU3VjY2Vzc2Z1bCkge1xuICAgICAgICBzdGF0ZS5zZXF1ZW50aWFsRGVwbG95bWVudEZhaWx1cmVzID0gMDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN0YXRlLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPSByZWNlbnRGYWlsdXJlcyArIDE7XG4gICAgICB9XG5cbiAgICAgIGNvdW50ZXJzLnNlcXVlbnRpYWxEZXBsb3ltZW50RmFpbHVyZXMgPSBzdGF0ZS5zZXF1ZW50aWFsRGVwbG95bWVudEZhaWx1cmVzO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXQgc2Vzc2lvbkluZm8oKTogU2Vzc2lvblNjaGVtYSB7XG4gICAgaWYgKCF0aGlzLl9zZXNzaW9uSW5mbykge1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcignU2Vzc2lvbk5vdEluaXRpYWxpemVkJywgJ1Nlc3Npb24gSW5mbyBub3QgaW5pdGlhbGl6ZWQuIENhbGwgYmVnaW4oKSBmaXJzdC4nKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX3Nlc3Npb25JbmZvO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFN0YXRlKGVycm9yPzogRXJyb3JEZXRhaWxzKTogU3RhdGUge1xuICBpZiAoZXJyb3IpIHtcbiAgICByZXR1cm4gaXNBYm9ydGVkRXJyb3IoZXJyb3IpID8gJ0FCT1JURUQnIDogJ0ZBSUxFRCc7XG4gIH1cbiAgcmV0dXJuICdTVUNDRUVERUQnO1xufVxuXG5mdW5jdGlvbiBpc0Fib3J0ZWRFcnJvcihlcnJvcj86IEVycm9yRGV0YWlscykge1xuICBpZiAoZXJyb3I/Lm5hbWUgPT09ICdUb29sa2l0RXJyb3InICYmIGVycm9yPy5tZXNzYWdlPy5pbmNsdWRlcyhBQk9SVEVEX0VSUk9SX01FU1NBR0UpKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cbiAgcmV0dXJuIGZhbHNlO1xufVxuXG5mdW5jdGlvbiBtdXRhYmxlPEEgZXh0ZW5kcyBvYmplY3Q+KHg6IEEpOiB7IC1yZWFkb25seSBbayBpbiBrZXlvZiBBXTogQVtrXSB9IHtcbiAgcmV0dXJuIHg7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoYXQgdGhlIENES19DTElfVVNFUkFHRU5UIGVudiB2YXIgdmFsdWUgbWF0Y2hlc1xuICogdGhlIGV4cGVjdGVkIGZvcm1hdDogYDxuYW1lPi88dmVyc2lvbj4vPG1vZGU+YCB3aGVyZSBuYW1lIGlzIG9uZSBvZlxuICogVkFMSURfVVNFUl9BR0VOVFMgYW5kIG1vZGUgaXMgZWl0aGVyIGBzYW5kYm94YCBvciBgcHJvZHVjdGlvbmAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1ZhbGlkV3JhcHBlclVzZXJBZ2VudCh2YWx1ZTogc3RyaW5nIHwgdW5kZWZpbmVkKTogdmFsdWUgaXMgc3RyaW5nIHtcbiAgaWYgKCF2YWx1ZSkgcmV0dXJuIGZhbHNlO1xuICBjb25zdCBwYXJ0cyA9IHZhbHVlLnNwbGl0KCcvJyk7XG4gIGlmIChwYXJ0cy5sZW5ndGggIT09IDMpIHJldHVybiBmYWxzZTtcbiAgY29uc3QgW25hbWUsIF92ZXJzaW9uLCBtb2RlXSA9IHBhcnRzO1xuICBpZiAoIVZBTElEX1VTRVJfQUdFTlRTLmluY2x1ZGVzKG5hbWUpKSByZXR1cm4gZmFsc2U7XG4gIHJldHVybiBtb2RlID09PSAnc2FuZGJveCcgfHwgbW9kZSA9PT0gJ3Byb2R1Y3Rpb24nO1xufVxuIl19