aws-cdk
Version:
AWS CDK CLI, the command line tool for CDK apps
454 lines • 62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CliIoHost = void 0;
const util = require("node:util");
const cloud_assembly_schema_1 = require("@aws-cdk/cloud-assembly-schema");
const toolkit_lib_1 = require("@aws-cdk/toolkit-lib");
const chalk = require("chalk");
const promptly = require("promptly");
const api_private_1 = require("../../../lib/api-private");
const deploy_1 = require("../../commands/deploy");
const collect_telemetry_1 = require("../telemetry/collect-telemetry");
const messages_1 = require("../telemetry/messages");
const session_1 = require("../telemetry/session");
const endpoint_sink_1 = require("../telemetry/sink/endpoint-sink");
const file_sink_1 = require("../telemetry/sink/file-sink");
const funnel_1 = require("../telemetry/sink/funnel");
const ci_1 = require("../util/ci");
/**
* A simple IO host for the CLI that writes messages to the console.
*/
class CliIoHost {
/**
* Returns the singleton instance
*/
static instance(props = {}, forceNew = false) {
if (forceNew || !CliIoHost._instance) {
CliIoHost._instance = new CliIoHost(props);
}
return CliIoHost._instance;
}
/**
* Returns the singleton instance if it exists
*/
static get() {
return CliIoHost._instance;
}
constructor(props = {}) {
/**
* Configure the target stream for notices
*
* (Not a setter because there's no need for additional logic when this value
* is changed yet)
*/
this.noticesDestination = 'stderr';
this._progress = deploy_1.StackActivityProgress.BAR;
// Corked Logging
this.corkedCounter = 0;
this.corkedLoggingBuffer = [];
this.currentAction = props.currentAction ?? 'none';
this.isTTY = props.isTTY ?? process.stdout.isTTY ?? false;
this.logLevel = props.logLevel ?? 'info';
this.isCI = props.isCI ?? (0, ci_1.isCI)();
this.requireDeployApproval = props.requireDeployApproval ?? cloud_assembly_schema_1.RequireApproval.BROADENING;
this.stackProgress = props.stackProgress ?? deploy_1.StackActivityProgress.BAR;
this.autoRespond = props.autoRespond ?? false;
}
async startTelemetry(args, context, proxyAgent) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
const config = require('../cli-type-registry.json');
const validCommands = Object.keys(config.commands);
const cmd = args._[0];
if (!validCommands.includes(cmd)) {
// the user typed in an invalid command - no need for telemetry since the invocation is going to fail
// imminently anyway.
await this.asIoHelper().defaults.trace(`Session instantiated with an invalid command (${cmd}). Not starting telemetry.`);
return;
}
let sinks = [];
const telemetryFilePath = args['telemetry-file'];
if (telemetryFilePath) {
try {
sinks.push(new file_sink_1.FileTelemetrySink({
ioHost: this,
logFilePath: telemetryFilePath,
}));
await this.asIoHelper().defaults.trace('File Telemetry connected');
}
catch (e) {
await this.asIoHelper().defaults.trace(`File Telemetry instantiation failed: ${e.message}`);
}
}
const telemetryEndpoint = process.env.TELEMETRY_ENDPOINT ?? 'https://cdk-cli-telemetry.us-east-1.api.aws/metrics';
if ((0, collect_telemetry_1.canCollectTelemetry)(args, context) && telemetryEndpoint) {
try {
sinks.push(new endpoint_sink_1.EndpointTelemetrySink({
ioHost: this,
agent: proxyAgent,
endpoint: telemetryEndpoint,
}));
await this.asIoHelper().defaults.trace('Endpoint Telemetry connected');
}
catch (e) {
await this.asIoHelper().defaults.trace(`Endpoint Telemetry instantiation failed: ${e.message}`);
}
}
else {
await this.asIoHelper().defaults.trace('Endpoint Telemetry NOT connected');
}
if (sinks.length > 0) {
this.telemetry = new session_1.TelemetrySession({
ioHost: this,
client: new funnel_1.Funnel({ sinks }),
arguments: args,
context: context,
});
}
await this.telemetry?.begin();
}
/**
* Update the stackProgress preference.
*/
set stackProgress(type) {
this._progress = type;
}
/**
* Gets the stackProgress value.
*
* This takes into account other state of the ioHost,
* like if isTTY and isCI.
*/
get stackProgress() {
// We can always use EVENTS
if (this._progress === deploy_1.StackActivityProgress.EVENTS) {
return this._progress;
}
// if a debug message (and thus any more verbose messages) are relevant to the current log level, we have verbose logging
const verboseLogging = (0, api_private_1.isMessageRelevantForLevel)({ level: 'debug' }, this.logLevel);
if (verboseLogging) {
return deploy_1.StackActivityProgress.EVENTS;
}
// On Windows we cannot use fancy output
const isWindows = process.platform === 'win32';
if (isWindows) {
return deploy_1.StackActivityProgress.EVENTS;
}
// On some CI systems (such as CircleCI) output still reports as a TTY so we also
// need an individual check for whether we're running on CI.
// see: https://discuss.circleci.com/t/circleci-terminal-is-a-tty-but-term-is-not-set/9965
const fancyOutputAvailable = this.isTTY && !this.isCI;
if (!fancyOutputAvailable) {
return deploy_1.StackActivityProgress.EVENTS;
}
// Use the user preference
return this._progress;
}
get defaults() {
return this.asIoHelper().defaults;
}
asIoHelper() {
return (0, api_private_1.asIoHelper)(this, this.currentAction);
}
/**
* Executes a block of code with corked logging. All log messages during execution
* are buffered and only written when all nested cork blocks complete (when CORK_COUNTER reaches 0).
* The corking is bound to the specific instance of the CliIoHost.
*
* @param block - Async function to execute with corked logging
* @returns Promise that resolves with the block's return value
*/
async withCorkedLogging(block) {
this.corkedCounter++;
try {
return await block();
}
finally {
this.corkedCounter--;
if (this.corkedCounter === 0) {
// Process each buffered message through notify
for (const ioMessage of this.corkedLoggingBuffer) {
await this.notify(ioMessage);
}
// remove all buffered messages in-place
this.corkedLoggingBuffer.splice(0);
}
}
}
/**
* Notifies the host of a message.
* The caller waits until the notification completes.
*/
async notify(msg) {
await this.maybeEmitTelemetry(msg);
if (this.isStackActivity(msg)) {
if (!this.activityPrinter) {
this.activityPrinter = this.makeActivityPrinter();
}
this.activityPrinter.notify(msg);
return;
}
if (!(0, api_private_1.isMessageRelevantForLevel)(msg, this.logLevel)) {
return;
}
if (this.corkedCounter > 0) {
this.corkedLoggingBuffer.push(msg);
return;
}
const output = this.formatMessage(msg);
const stream = this.selectStream(msg);
stream?.write(output);
}
async maybeEmitTelemetry(msg) {
try {
const telemetryEvent = eventFromMessage(msg);
if (telemetryEvent) {
await this.telemetry?.emit(telemetryEvent);
}
}
catch (e) {
await this.defaults.trace(`Emit Telemetry Failed ${e.message}`);
}
}
/**
* Detect stack activity messages so they can be send to the printer.
*/
isStackActivity(msg) {
return msg.code && [
'CDK_TOOLKIT_I5501',
'CDK_TOOLKIT_I5502',
'CDK_TOOLKIT_I5503',
].includes(msg.code);
}
/**
* Detect special messages encode information about whether or not
* they require approval
*/
skipApprovalStep(msg) {
const approvalToolkitCodes = ['CDK_TOOLKIT_I5060'];
if (!(msg.code && approvalToolkitCodes.includes(msg.code))) {
false;
}
switch (this.requireDeployApproval) {
// Never require approval
case cloud_assembly_schema_1.RequireApproval.NEVER:
return true;
// Always require approval
case cloud_assembly_schema_1.RequireApproval.ANYCHANGE:
return false;
// Require approval if changes include broadening permissions
case cloud_assembly_schema_1.RequireApproval.BROADENING:
return ['none', 'non-broadening'].includes(msg.data?.permissionChangeType);
}
}
/**
* Determines the output stream, based on message and configuration.
*/
selectStream(msg) {
if (isNoticesMessage(msg)) {
return targetStreamObject(this.noticesDestination);
}
return this.selectStreamFromLevel(msg.level);
}
/**
* Determines the output stream, based on message level and configuration.
*/
selectStreamFromLevel(level) {
// The stream selection policy for the CLI is the following:
//
// (1) Messages of level `result` always go to `stdout`
// (2) Messages of level `error` always go to `stderr`.
// (3a) All remaining messages go to `stderr`.
// (3b) If we are in CI mode, all remaining messages go to `stdout`.
//
switch (level) {
case 'error':
return process.stderr;
case 'result':
return process.stdout;
default:
return this.isCI ? process.stdout : process.stderr;
}
}
/**
* Notifies the host of a message that requires a response.
*
* If the host does not return a response the suggested
* default response from the input message will be used.
*/
async requestResponse(msg) {
// If the request cannot be prompted for by the CliIoHost, we just accept the default
if (!isPromptableRequest(msg)) {
await this.notify(msg);
return msg.defaultResponse;
}
const response = await this.withCorkedLogging(async () => {
// prepare prompt data
// @todo this format is not defined anywhere, probably should be
const data = msg.data ?? {};
const motivation = data.motivation ?? 'User input is needed';
const concurrency = data.concurrency ?? 0;
const responseDescription = data.responseDescription;
// Special approval prompt
// Determine if the message needs approval. If it does, continue (it is a basic confirmation prompt)
// If it does not, return success (true). We only check messages with codes that we are aware
// are requires approval codes.
if (this.skipApprovalStep(msg)) {
return true;
}
// In --yes mode, respond for the user if we can
if (this.autoRespond) {
// respond with yes to all confirmations
if (isConfirmationPrompt(msg)) {
await this.notify({
...msg,
message: `${chalk.cyan(msg.message)} (auto-confirmed)`,
});
return true;
}
// respond with the default for all other messages
if (msg.defaultResponse) {
await this.notify({
...msg,
message: `${chalk.cyan(msg.message)} (auto-responded with default: ${util.format(msg.defaultResponse)})`,
});
return msg.defaultResponse;
}
}
// only talk to user if STDIN is a terminal (otherwise, fail)
if (!this.isTTY) {
throw new toolkit_lib_1.ToolkitError(`${motivation}, but terminal (TTY) is not attached so we are unable to get a confirmation from the user`);
}
// only talk to user if concurrency is 1 (otherwise, fail)
if (concurrency > 1) {
throw new toolkit_lib_1.ToolkitError(`${motivation}, but concurrency is greater than 1 so we are unable to get a confirmation from the user`);
}
// Basic confirmation prompt
// We treat all requests with a boolean response as confirmation prompts
if (isConfirmationPrompt(msg)) {
const confirmed = await promptly.confirm(`${chalk.cyan(msg.message)} (y/n)`);
if (!confirmed) {
throw new toolkit_lib_1.ToolkitError('Aborted by user');
}
return confirmed;
}
// Asking for a specific value
const prompt = extractPromptInfo(msg);
const desc = responseDescription ?? prompt.default;
const answer = await promptly.prompt(`${chalk.cyan(msg.message)}${desc ? ` (${desc})` : ''}`, {
default: prompt.default,
trim: true,
});
return prompt.convertAnswer(answer);
});
// We need to cast this because it is impossible to narrow the generic type
// isPromptableRequest ensures that the response type is one we can prompt for
// the remaining code ensure we are indeed returning the correct type
return response;
}
/**
* Formats a message for console output with optional color support
*/
formatMessage(msg) {
// apply provided style or a default style if we're in TTY mode
let message_text = this.isTTY
? styleMap[msg.level](msg.message)
: msg.message;
// prepend timestamp if IoMessageLevel is DEBUG or TRACE. Postpend a newline.
return ((msg.level === 'debug' || msg.level === 'trace')
? `[${this.formatTime(msg.time)}] ${message_text}`
: message_text) + '\n';
}
/**
* Formats date to HH:MM:SS
*/
formatTime(d) {
const pad = (n) => n.toString().padStart(2, '0');
return `${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}
/**
* Get an instance of the ActivityPrinter
*/
makeActivityPrinter() {
const props = {
stream: this.selectStreamFromLevel('info'),
};
switch (this.stackProgress) {
case deploy_1.StackActivityProgress.EVENTS:
return new api_private_1.HistoryActivityPrinter(props);
case deploy_1.StackActivityProgress.BAR:
return new api_private_1.CurrentActivityPrinter(props);
}
}
}
exports.CliIoHost = CliIoHost;
/**
* This IoHost implementation considers a request promptable, if:
* - it's a yes/no confirmation
* - asking for a string or number value
*/
function isPromptableRequest(msg) {
return isConfirmationPrompt(msg)
|| typeof msg.defaultResponse === 'string'
|| typeof msg.defaultResponse === 'number';
}
/**
* Check if the request is a confirmation prompt
* We treat all requests with a boolean response as confirmation prompts
*/
function isConfirmationPrompt(msg) {
return typeof msg.defaultResponse === 'boolean';
}
/**
* Helper to extract information for promptly from the request
*/
function extractPromptInfo(msg) {
const isNumber = (typeof msg.defaultResponse === 'number');
const defaultResponse = util.format(msg.defaultResponse);
return {
default: defaultResponse,
defaultDesc: 'defaultDescription' in msg && msg.defaultDescription ? util.format(msg.defaultDescription) : defaultResponse,
convertAnswer: isNumber ? (v) => Number(v) : (v) => String(v),
};
}
const styleMap = {
error: chalk.red,
warn: chalk.yellow,
result: chalk.reset,
info: chalk.reset,
debug: chalk.gray,
trace: chalk.gray,
};
function targetStreamObject(x) {
switch (x) {
case 'stderr':
return process.stderr;
case 'stdout':
return process.stdout;
case 'drop':
return undefined;
}
}
function isNoticesMessage(msg) {
return api_private_1.IO.CDK_TOOLKIT_I0100.is(msg) || api_private_1.IO.CDK_TOOLKIT_W0101.is(msg) || api_private_1.IO.CDK_TOOLKIT_E0101.is(msg) || api_private_1.IO.CDK_TOOLKIT_I0101.is(msg);
}
function eventFromMessage(msg) {
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I1001.is(msg)) {
return eventResult('SYNTH', msg);
}
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I2001.is(msg)) {
return eventResult('INVOKE', msg);
}
if (messages_1.CLI_PRIVATE_IO.CDK_CLI_I3001.is(msg)) {
return eventResult('DEPLOY', msg);
}
return undefined;
function eventResult(eventType, m) {
return {
eventType,
duration: m.data.duration,
error: m.data.error,
counters: m.data.counters,
};
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpLWlvLWhvc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbGktaW8taG9zdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSxrQ0FBa0M7QUFDbEMsMEVBQWlFO0FBQ2pFLHNEQUFvRDtBQUdwRCwrQkFBK0I7QUFDL0IscUNBQXFDO0FBRXJDLDBEQUFxSTtBQUNySSxrREFBOEQ7QUFDOUQsc0VBQXFFO0FBRXJFLG9EQUF1RDtBQUV2RCxrREFBd0Q7QUFDeEQsbUVBQXdFO0FBQ3hFLDJEQUFnRTtBQUNoRSxxREFBa0Q7QUFFbEQsbUNBQWtDO0FBb0ZsQzs7R0FFRztBQUNILE1BQWEsU0FBUztJQUNwQjs7T0FFRztJQUNILE1BQU0sQ0FBQyxRQUFRLENBQUMsUUFBd0IsRUFBRSxFQUFFLFFBQVEsR0FBRyxLQUFLO1FBQzFELElBQUksUUFBUSxJQUFJLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3JDLFNBQVMsQ0FBQyxTQUFTLEdBQUcsSUFBSSxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDN0MsQ0FBQztRQUNELE9BQU8sU0FBUyxDQUFDLFNBQVMsQ0FBQztJQUM3QixDQUFDO0lBRUQ7O09BRUc7SUFDSCxNQUFNLENBQUMsR0FBRztRQUNSLE9BQU8sU0FBUyxDQUFDLFNBQVMsQ0FBQztJQUM3QixDQUFDO0lBeURELFlBQW9CLFFBQXdCLEVBQUU7UUFyQjlDOzs7OztXQUtHO1FBQ0ksdUJBQWtCLEdBQWlCLFFBQVEsQ0FBQztRQUUzQyxjQUFTLEdBQTBCLDhCQUFxQixDQUFDLEdBQUcsQ0FBQztRQUtyRSxpQkFBaUI7UUFDVCxrQkFBYSxHQUFHLENBQUMsQ0FBQztRQUNULHdCQUFtQixHQUF5QixFQUFFLENBQUM7UUFPOUQsSUFBSSxDQUFDLGFBQWEsR0FBRyxLQUFLLENBQUMsYUFBYSxJQUFJLE1BQU0sQ0FBQztRQUNuRCxJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQyxLQUFLLElBQUksT0FBTyxDQUFD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QXNDLEVBQUUsQ0FBeUI7UUFDcEYsT0FBTztZQUNMLFNBQVM7WUFDVCxRQUFRLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxRQUFRO1lBQ3pCLEtBQUssRUFBRSxDQUFDLENBQUMsSUFBSSxDQUFDLEtBQUs7WUFDbkIsUUFBUSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsUUFBUTtTQUMxQixDQUFDO0lBQ0osQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IEFnZW50IH0gZnJvbSAnbm9kZTpodHRwcyc7XG5pbXBvcnQgKiBhcyB1dGlsIGZyb20gJ25vZGU6dXRpbCc7XG5pbXBvcnQgeyBSZXF1aXJlQXBwcm92YWwgfSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHsgVG9vbGtpdEVycm9yIH0gZnJvbSAnQGF3cy1jZGsvdG9vbGtpdC1saWInO1xuaW1wb3J0IHR5cGUgeyBJSW9Ib3N0LCBJb01lc3NhZ2UsIElvTWVzc2FnZUNvZGUsIElvTWVzc2FnZUxldmVsLCBJb1JlcXVlc3QsIFRvb2xraXRBY3Rpb24gfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYic7XG5pbXBvcnQgdHlwZSB7IENvbnRleHQgfSBmcm9tICdAYXdzLWNkay90b29sa2l0LWxpYi9saWIvYXBpJztcbmltcG9ydCAqIGFzIGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCAqIGFzIHByb21wdGx5IGZyb20gJ3Byb21wdGx5JztcbmltcG9ydCB0eXBlIHsgSW9IZWxwZXIsIEFjdGl2aXR5UHJpbnRlclByb3BzLCBJQWN0aXZpdHlQcmludGVyIH0gZnJvbSAnLi4vLi4vLi4vbGliL2FwaS1wcml2YXRlJztcbmltcG9ydCB7IGFzSW9IZWxwZXIsIElPLCBpc01lc3NhZ2VSZWxldmFudEZvckxldmVsLCBDdXJyZW50QWN0aXZpdHlQcmludGVyLCBIaXN0b3J5QWN0aXZpdHlQcmludGVyIH0gZnJvbSAnLi4vLi4vLi4vbGliL2FwaS1wcml2YXRlJztcbmltcG9ydCB7IFN0YWNrQWN0aXZpdHlQcm9ncmVzcyB9IGZyb20gJy4uLy4uL2NvbW1hbmRzL2RlcGxveSc7XG5pbXBvcnQgeyBjYW5Db2xsZWN0VGVsZW1ldHJ5IH0gZnJvbSAnLi4vdGVsZW1ldHJ5L2NvbGxlY3QtdGVsZW1ldHJ5JztcbmltcG9ydCB0eXBlIHsgRXZlbnRSZXN1bHQgfSBmcm9tICcuLi90ZWxlbWV0cnkvbWVzc2FnZXMnO1xuaW1wb3J0IHsgQ0xJX1BSSVZBVEVfSU8gfSBmcm9tICcuLi90ZWxlbWV0cnkvbWVzc2FnZXMnO1xuaW1wb3J0IHR5cGUgeyBUZWxlbWV0cnlFdmVudCB9IGZyb20gJy4uL3RlbGVtZXRyeS9zZXNzaW9uJztcbmltcG9ydCB7IFRlbGVtZXRyeVNlc3Npb24gfSBmcm9tICcuLi90ZWxlbWV0cnkvc2Vzc2lvbic7XG5pbXBvcnQgeyBFbmRwb2ludFRlbGVtZXRyeVNpbmsgfSBmcm9tICcuLi90ZWxlbWV0cnkvc2luay9lbmRwb2ludC1zaW5rJztcbmltcG9ydCB7IEZpbGVUZWxlbWV0cnlTaW5rIH0gZnJvbSAnLi4vdGVsZW1ldHJ5L3NpbmsvZmlsZS1zaW5rJztcbmltcG9ydCB7IEZ1bm5lbCB9IGZyb20gJy4uL3RlbGVtZXRyeS9zaW5rL2Z1bm5lbCc7XG5pbXBvcnQgdHlwZSB7IElUZWxlbWV0cnlTaW5rIH0gZnJvbSAnLi4vdGVsZW1ldHJ5L3Npbmsvc2luay1pbnRlcmZhY2UnO1xuaW1wb3J0IHsgaXNDSSB9IGZyb20gJy4uL3V0aWwvY2knO1xuXG5leHBvcnQgdHlwZSB7IElJb0hvc3QsIElvTWVzc2FnZSwgSW9NZXNzYWdlQ29kZSwgSW9NZXNzYWdlTGV2ZWwsIElvUmVxdWVzdCB9O1xuXG4vKipcbiAqIFRoZSBjdXJyZW50IGFjdGlvbiBiZWluZyBwZXJmb3JtZWQgYnkgdGhlIENMSS4gJ25vbmUnIHJlcHJlc2VudHMgdGhlIGFic2VuY2Ugb2YgYW4gYWN0aW9uLlxuICovXG50eXBlIENsaUFjdGlvbiA9XG4gIHwgVG9vbGtpdEFjdGlvblxuICB8ICdjb250ZXh0J1xuICB8ICdkb2NzJ1xuICB8ICdmbGFncydcbiAgfCAnbm90aWNlcydcbiAgfCAndmVyc2lvbidcbiAgfCAnY2xpLXRlbGVtZXRyeSdcbiAgfCAnbm9uZSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgQ2xpSW9Ib3N0UHJvcHMge1xuICAvKipcbiAgICogVGhlIGluaXRpYWwgVG9vbGtpdCBhY3Rpb24gdGhlIGhvc3RzIHN0YXJ0cyB3aXRoLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnbm9uZSdcbiAgICovXG4gIHJlYWRvbmx5IGN1cnJlbnRBY3Rpb24/OiBDbGlBY3Rpb247XG5cbiAgLyoqXG4gICAqIERldGVybWluZXMgdGhlIHZlcmJvc2l0eSBvZiB0aGUgb3V0cHV0LlxuICAgKlxuICAgKiBUaGUgQ2xpSW9Ib3N0IHdpbGwgc3RpbGwgcmVjZWl2ZSBhbGwgbWVzc2FnZXMgYW5kIHJlcXVlc3RzLFxuICAgKiBidXQgb25seSB0aGUgbWVzc2FnZXMgaW5jbHVkZWQgaW4gdGhpcyBsZXZlbCB3aWxsIGJlIHByaW50ZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdpbmZvJ1xuICAgKi9cbiAgcmVhZG9ubHkgbG9nTGV2ZWw/OiBJb01lc3NhZ2VMZXZlbDtcblxuICAvKipcbiAgICogT3ZlcnJpZGVzIHRoZSBhdXRvbWF0aWMgVFRZIGRldGVjdGlvbi5cbiAgICpcbiAgICogV2hlbiBUVFkgaXMgZGlzYWJsZWQsIHRoZSBDTEkgd2lsbCBoYXZlIG5vIGludGVyYWN0aW9ucyBvciBjb2xvci5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBkZXRlcm1pbmVkIGZyb20gdGhlIGN1cnJlbnQgcHJvY2Vzc1xuICAgKi9cbiAgcmVhZG9ubHkgaXNUVFk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBDbGlJb0hvc3QgaXMgcnVubmluZyBpbiBDSSBtb2RlLlxuICAgKlxuICAgKiBJbiBDSSBtb2RlLCBhbGwgbm9uLWVycm9yIG91dHB1dCBnb2VzIHRvIHN0ZG91dCBpbnN0ZWFkIG9mIHN0ZGVyci5cbiAgICogU2V0IHRvIGZhbHNlIGluIHRoZSBDbGlJb0hvc3QgY29uc3RydWN0b3IgaXQgd2lsbCBiZSBvdmVyd3JpdHRlbiBpZiB0aGUgQ0xJIENJIGFyZ3VtZW50IGlzIHBhc3NlZFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGRldGVybWluZWQgZnJvbSB0aGUgZW52aXJvbm1lbnQsIHNwZWNpZmljYWxseSBiYXNlZCBvbiBgcHJvY2Vzcy5lbnYuQ0lgXG4gICAqL1xuICByZWFkb25seSBpc0NJPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogSW4gd2hhdCBzY2VuYXJpb3Mgc2hvdWxkIHRoZSBDbGlJb0hvc3QgYXNrIGZvciBhcHByb3ZhbFxuICAgKlxuICAgKiBAZGVmYXVsdCBSZXF1aXJlQXBwcm92YWwuQlJPQURFTklOR1xuICAgKi9cbiAgcmVhZG9ubHkgcmVxdWlyZURlcGxveUFwcHJvdmFsPzogUmVxdWlyZUFwcHJvdmFsO1xuXG4gIC8qKlxuICAgKiBUaGUgaW5pdGlhbCBUb29sa2l0IGFjdGlvbiB0aGUgaG9zdHMgc3RhcnRzIHdpdGguXG4gICAqXG4gICAqIEBkZWZhdWx0IFN0YWNrQWN0aXZpdHlQcm9ncmVzcy5CQVJcbiAgICovXG4gIHJlYWRvbmx5IHN0YWNrUHJvZ3Jlc3M/OiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3M7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIENMSSBzaG91bGQgYXR0ZW1wdCB0byBhdXRvbWF0aWNhbGx5IHJlc3BvbmQgdG8gcHJvbXB0cy5cbiAgICpcbiAgICogV2hlbiB0cnVlLCBvcGVyYXRpb24gd2lsbCB1c3VhbGx5IHByb2NlZWQgd2l0aG91dCBpbnRlcmFjdGl2ZSBjb25maXJtYXRpb24uXG4gICAqIENvbmZpcm1hdGlvbnMgYXJlIHJlc3BvbmRlZCB0byB3aXRoIHllcy4gT3RoZXIgcHJvbXB0cyB3aWxsIHJlc3BvbmQgd2l0aCB0aGUgZGVmYXVsdCB2YWx1ZS5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGF1dG9SZXNwb25kPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBBIHR5cGUgZm9yIGNvbmZpZ3VyaW5nIGEgdGFyZ2V0IHN0cmVhbVxuICovXG5leHBvcnQgdHlwZSBUYXJnZXRTdHJlYW0gPSAnc3Rkb3V0JyB8ICdzdGRlcnInIHwgJ2Ryb3AnO1xuXG4vKipcbiAqIEEgc2ltcGxlIElPIGhvc3QgZm9yIHRoZSBDTEkgdGhhdCB3cml0ZXMgbWVzc2FnZXMgdG8gdGhlIGNvbnNvbGUuXG4gKi9cbmV4cG9ydCBjbGFzcyBDbGlJb0hvc3QgaW1wbGVtZW50cyBJSW9Ib3N0IHtcbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNpbmdsZXRvbiBpbnN0YW5jZVxuICAgKi9cbiAgc3RhdGljIGluc3RhbmNlKHByb3BzOiBDbGlJb0hvc3RQcm9wcyA9IHt9LCBmb3JjZU5ldyA9IGZhbHNlKTogQ2xpSW9Ib3N0IHtcbiAgICBpZiAoZm9yY2VOZXcgfHwgIUNsaUlvSG9zdC5faW5zdGFuY2UpIHtcbiAgICAgIENsaUlvSG9zdC5faW5zdGFuY2UgPSBuZXcgQ2xpSW9Ib3N0KHByb3BzKTtcbiAgICB9XG4gICAgcmV0dXJuIENsaUlvSG9zdC5faW5zdGFuY2U7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc2luZ2xldG9uIGluc3RhbmNlIGlmIGl0IGV4aXN0c1xuICAgKi9cbiAgc3RhdGljIGdldCgpOiBDbGlJb0hvc3QgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiBDbGlJb0hvc3QuX2luc3RhbmNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFNpbmdsZXRvbiBpbnN0YW5jZSBvZiB0aGUgQ2xpSW9Ib3N0XG4gICAqL1xuICBwcml2YXRlIHN0YXRpYyBfaW5zdGFuY2U6IENsaUlvSG9zdCB8IHVuZGVmaW5lZDtcblxuICAvKipcbiAgICogVGhlIGN1cnJlbnQgYWN0aW9uIGJlaW5nIHBlcmZvcm1lZCBieSB0aGUgQ0xJLlxuICAgKi9cbiAgcHVibGljIGN1cnJlbnRBY3Rpb246IENsaUFjdGlvbjtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgQ2xpSW9Ib3N0IGlzIHJ1bm5pbmcgaW4gQ0kgbW9kZS5cbiAgICpcbiAgICogSW4gQ0kgbW9kZSwgYWxsIG5vbi1lcnJvciBvdXRwdXQgZ29lcyB0byBzdGRvdXQgaW5zdGVhZCBvZiBzdGRlcnIuXG4gICAqL1xuICBwdWJsaWMgaXNDSTogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0aGUgaG9zdCBjYW4gdXNlIGludGVyYWN0aW9ucyBhbmQgbWVzc2FnZSBzdHlsaW5nLlxuICAgKi9cbiAgcHVibGljIGlzVFRZOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCB0aHJlc2hvbGQuXG4gICAqXG4gICAqIE1lc3NhZ2VzIHdpdGggYSBsb3dlciBwcmlvcml0eSBsZXZlbCB3aWxsIGJlIGlnbm9yZWQuXG4gICAqL1xuICBwdWJsaWMgbG9nTGV2ZWw6IElvTWVzc2FnZUxldmVsO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uZGl0aW9ucyBmb3IgcmVxdWlyaW5nIGFwcHJvdmFsIGluIHRoaXMgQ2xpSW9Ib3N0LlxuICAgKi9cbiAgcHVibGljIHJlcXVpcmVEZXBsb3lBcHByb3ZhbDogUmVxdWlyZUFwcHJvdmFsO1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmUgdGhlIHRhcmdldCBzdHJlYW0gZm9yIG5vdGljZXNcbiAgICpcbiAgICogKE5vdCBhIHNldHRlciBiZWNhdXNlIHRoZXJlJ3Mgbm8gbmVlZCBmb3IgYWRkaXRpb25hbCBsb2dpYyB3aGVuIHRoaXMgdmFsdWVcbiAgICogaXMgY2hhbmdlZCB5ZXQpXG4gICAqL1xuICBwdWJsaWMgbm90aWNlc0Rlc3RpbmF0aW9uOiBUYXJnZXRTdHJlYW0gPSAnc3RkZXJyJztcblxuICBwcml2YXRlIF9wcm9ncmVzczogU3RhY2tBY3Rpdml0eVByb2dyZXNzID0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkJBUjtcblxuICAvLyBTdGFjayBBY3Rpdml0eSBQcmludGVyXG4gIHByaXZhdGUgYWN0aXZpdHlQcmludGVyPzogSUFjdGl2aXR5UHJpbnRlcjtcblxuICAvLyBDb3JrZWQgTG9nZ2luZ1xuICBwcml2YXRlIGNvcmtlZENvdW50ZXIgPSAwO1xuICBwcml2YXRlIHJlYWRvbmx5IGNvcmtlZExvZ2dpbmdCdWZmZXI6IElvTWVzc2FnZTx1bmtub3duPltdID0gW107XG5cbiAgcHJpdmF0ZSByZWFkb25seSBhdXRvUmVzcG9uZDogYm9vbGVhbjtcblxuICBwdWJsaWMgdGVsZW1ldHJ5PzogVGVsZW1ldHJ5U2Vzc2lvbjtcblxuICBwcml2YXRlIGNvbnN0cnVjdG9yKHByb3BzOiBDbGlJb0hvc3RQcm9wcyA9IHt9KSB7XG4gICAgdGhpcy5jdXJyZW50QWN0aW9uID0gcHJvcHMuY3VycmVudEFjdGlvbiA/PyAnbm9uZSc7XG4gICAgdGhpcy5pc1RUWSA9IHByb3BzLmlzVFRZID8/IHByb2Nlc3Muc3Rkb3V0LmlzVFRZID8/IGZhbHNlO1xuICAgIHRoaXMubG9nTGV2ZWwgPSBwcm9wcy5sb2dMZXZlbCA/PyAnaW5mbyc7XG4gICAgdGhpcy5pc0NJID0gcHJvcHMuaXNDSSA/PyBpc0NJKCk7XG4gICAgdGhpcy5yZXF1aXJlRGVwbG95QXBwcm92YWwgPSBwcm9wcy5yZXF1aXJlRGVwbG95QXBwcm92YWwgPz8gUmVxdWlyZUFwcHJvdmFsLkJST0FERU5JTkc7XG4gICAgdGhpcy5zdGFja1Byb2dyZXNzID0gcHJvcHMuc3RhY2tQcm9ncmVzcyA/PyBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuQkFSO1xuICAgIHRoaXMuYXV0b1Jlc3BvbmQgPSBwcm9wcy5hdXRvUmVzcG9uZCA/PyBmYWxzZTtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBzdGFydFRlbGVtZXRyeShhcmdzOiBhbnksIGNvbnRleHQ6IENvbnRleHQsIHByb3h5QWdlbnQ/OiBBZ2VudCkge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gICAgY29uc3QgY29uZmlnID0gcmVxdWlyZSgnLi4vY2xpLXR5cGUtcmVnaXN0cnkuanNvbicpO1xuICAgIGNvbnN0IHZhbGlkQ29tbWFuZHMgPSBPYmplY3Qua2V5cyhjb25maWcuY29tbWFuZHMpO1xuICAgIGNvbnN0IGNtZCA9IGFyZ3MuX1swXTtcbiAgICBpZiAoIXZhbGlkQ29tbWFuZHMuaW5jbHVkZXMoY21kKSkge1xuICAgICAgLy8gdGhlIHVzZXIgdHlwZWQgaW4gYW4gaW52YWxpZCBjb21tYW5kIC0gbm8gbmVlZCBmb3IgdGVsZW1ldHJ5IHNpbmNlIHRoZSBpbnZvY2F0aW9uIGlzIGdvaW5nIHRvIGZhaWxcbiAgICAgIC8vIGltbWluZW50bHkgYW55d2F5LlxuICAgICAgYXdhaXQgdGhpcy5hc0lvSGVscGVyKCkuZGVmYXVsdHMudHJhY2UoYFNlc3Npb24gaW5zdGFudGlhdGVkIHdpdGggYW4gaW52YWxpZCBjb21tYW5kICgke2NtZH0pLiBOb3Qgc3RhcnRpbmcgdGVsZW1ldHJ5LmApO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGxldCBzaW5rczogSVRlbGVtZXRyeVNpbmtbXSA9IFtdO1xuICAgIGNvbnN0IHRlbGVtZXRyeUZpbGVQYXRoID0gYXJnc1sndGVsZW1ldHJ5LWZpbGUnXTtcbiAgICBpZiAodGVsZW1ldHJ5RmlsZVBhdGgpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHNpbmtzLnB1c2gobmV3IEZpbGVUZWxlbWV0cnlTaW5rKHtcbiAgICAgICAgICBpb0hvc3Q6IHRoaXMsXG4gICAgICAgICAgbG9nRmlsZVBhdGg6IHRlbGVtZXRyeUZpbGVQYXRoLFxuICAgICAgICB9KSk7XG4gICAgICAgIGF3YWl0IHRoaXMuYXNJb0hlbHBlcigpLmRlZmF1bHRzLnRyYWNlKCdGaWxlIFRlbGVtZXRyeSBjb25uZWN0ZWQnKTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBhd2FpdCB0aGlzLmFzSW9IZWxwZXIoKS5kZWZhdWx0cy50cmFjZShgRmlsZSBUZWxlbWV0cnkgaW5zdGFudGlhdGlvbiBmYWlsZWQ6ICR7ZS5tZXNzYWdlfWApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IHRlbGVtZXRyeUVuZHBvaW50ID0gcHJvY2Vzcy5lbnYuVEVMRU1FVFJZX0VORFBPSU5UID8/ICdodHRwczovL2Nkay1jbGktdGVsZW1ldHJ5LnVzLWVhc3QtMS5hcGkuYXdzL21ldHJpY3MnO1xuICAgIGlmIChjYW5Db2xsZWN0VGVsZW1ldHJ5KGFyZ3MsIGNvbnRleHQpICYmIHRlbGVtZXRyeUVuZHBvaW50KSB7XG4gICAgICB0cnkge1xuICAgICAgICBzaW5rcy5wdXNoKG5ldyBFbmRwb2ludFRlbGVtZXRyeVNpbmsoe1xuICAgICAgICAgIGlvSG9zdDogdGhpcyxcbiAgICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcbiAgICAgICAgICBlbmRwb2ludDogdGVsZW1ldHJ5RW5kcG9pbnQsXG4gICAgICAgIH0pKTtcbiAgICAgICAgYXdhaXQgdGhpcy5hc0lvSGVscGVyKCkuZGVmYXVsdHMudHJhY2UoJ0VuZHBvaW50IFRlbGVtZXRyeSBjb25uZWN0ZWQnKTtcbiAgICAgIH0gY2F0Y2ggKGU6IGFueSkge1xuICAgICAgICBhd2FpdCB0aGlzLmFzSW9IZWxwZXIoKS5kZWZhdWx0cy50cmFjZShgRW5kcG9pbnQgVGVsZW1ldHJ5IGluc3RhbnRpYXRpb24gZmFpbGVkOiAke2UubWVzc2FnZX1gKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgdGhpcy5hc0lvSGVscGVyKCkuZGVmYXVsdHMudHJhY2UoJ0VuZHBvaW50IFRlbGVtZXRyeSBOT1QgY29ubmVjdGVkJyk7XG4gICAgfVxuXG4gICAgaWYgKHNpbmtzLmxlbmd0aCA+IDApIHtcbiAgICAgIHRoaXMudGVsZW1ldHJ5ID0gbmV3IFRlbGVtZXRyeVNlc3Npb24oe1xuICAgICAgICBpb0hvc3Q6IHRoaXMsXG4gICAgICAgIGNsaWVudDogbmV3IEZ1bm5lbCh7IHNpbmtzIH0pLFxuICAgICAgICBhcmd1bWVudHM6IGFyZ3MsXG4gICAgICAgIGNvbnRleHQ6IGNvbnRleHQsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBhd2FpdCB0aGlzLnRlbGVtZXRyeT8uYmVnaW4oKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBVcGRhdGUgdGhlIHN0YWNrUHJvZ3Jlc3MgcHJlZmVyZW5jZS5cbiAgICovXG4gIHB1YmxpYyBzZXQgc3RhY2tQcm9ncmVzcyh0eXBlOiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MpIHtcbiAgICB0aGlzLl9wcm9ncmVzcyA9IHR5cGU7XG4gIH1cblxuICAvKipcbiAgICogR2V0cyB0aGUgc3RhY2tQcm9ncmVzcyB2YWx1ZS5cbiAgICpcbiAgICogVGhpcyB0YWtlcyBpbnRvIGFjY291bnQgb3RoZXIgc3RhdGUgb2YgdGhlIGlvSG9zdCxcbiAgICogbGlrZSBpZiBpc1RUWSBhbmQgaXNDSS5cbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tQcm9ncmVzcygpOiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3Mge1xuICAgIC8vIFdlIGNhbiBhbHdheXMgdXNlIEVWRU5UU1xuICAgIGlmICh0aGlzLl9wcm9ncmVzcyA9PT0gU3RhY2tBY3Rpdml0eVByb2dyZXNzLkVWRU5UUykge1xuICAgICAgcmV0dXJuIHRoaXMuX3Byb2dyZXNzO1xuICAgIH1cblxuICAgIC8vIGlmIGEgZGVidWcgbWVzc2FnZSAoYW5kIHRodXMgYW55IG1vcmUgdmVyYm9zZSBtZXNzYWdlcykgYXJlIHJlbGV2YW50IHRvIHRoZSBjdXJyZW50IGxvZyBsZXZlbCwgd2UgaGF2ZSB2ZXJib3NlIGxvZ2dpbmdcbiAgICBjb25zdCB2ZXJib3NlTG9nZ2luZyA9IGlzTWVzc2FnZVJlbGV2YW50Rm9yTGV2ZWwoeyBsZXZlbDogJ2RlYnVnJyB9LCB0aGlzLmxvZ0xldmVsKTtcbiAgICBpZiAodmVyYm9zZUxvZ2dpbmcpIHtcbiAgICAgIHJldHVybiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuRVZFTlRTO1xuICAgIH1cblxuICAgIC8vIE9uIFdpbmRvd3Mgd2UgY2Fubm90IHVzZSBmYW5jeSBvdXRwdXRcbiAgICBjb25zdCBpc1dpbmRvd3MgPSBwcm9jZXNzLnBsYXRmb3JtID09PSAnd2luMzInO1xuICAgIGlmIChpc1dpbmRvd3MpIHtcbiAgICAgIHJldHVybiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuRVZFTlRTO1xuICAgIH1cblxuICAgIC8vIE9uIHNvbWUgQ0kgc3lzdGVtcyAoc3VjaCBhcyBDaXJjbGVDSSkgb3V0cHV0IHN0aWxsIHJlcG9ydHMgYXMgYSBUVFkgc28gd2UgYWxzb1xuICAgIC8vIG5lZWQgYW4gaW5kaXZpZHVhbCBjaGVjayBmb3Igd2hldGhlciB3ZSdyZSBydW5uaW5nIG9uIENJLlxuICAgIC8vIHNlZTogaHR0cHM6Ly9kaXNjdXNzLmNpcmNsZWNpLmNvbS90L2NpcmNsZWNpLXRlcm1pbmFsLWlzLWEtdHR5LWJ1dC10ZXJtLWlzLW5vdC1zZXQvOTk2NVxuICAgIGNvbnN0IGZhbmN5T3V0cHV0QXZhaWxhYmxlID0gdGhpcy5pc1RUWSAmJiAhdGhpcy5pc0NJO1xuICAgIGlmICghZmFuY3lPdXRwdXRBdmFpbGFibGUpIHtcbiAgICAgIHJldHVybiBTdGFja0FjdGl2aXR5UHJvZ3Jlc3MuRVZFTlRTO1xuICAgIH1cblxuICAgIC8vIFVzZSB0aGUgdXNlciBwcmVmZXJlbmNlXG4gICAgcmV0dXJuIHRoaXMuX3Byb2dyZXNzO1xuICB9XG5cbiAgcHVibGljIGdldCBkZWZhdWx0cygpIHtcbiAgICByZXR1cm4gdGhpcy5hc0lvSGVscGVyKCkuZGVmYXVsdHM7XG4gIH1cblxuICBwdWJsaWMgYXNJb0hlbHBlcigpOiBJb0hlbHBlciB7XG4gICAgcmV0dXJuIGFzSW9IZWxwZXIodGhpcywgdGhpcy5jdXJyZW50QWN0aW9uIGFzIGFueSk7XG4gIH1cblxuICAvKipcbiAgICogRXhlY3V0ZXMgYSBibG9jayBvZiBjb2RlIHdpdGggY29ya2VkIGxvZ2dpbmcuIEFsbCBsb2cgbWVzc2FnZXMgZHVyaW5nIGV4ZWN1dGlvblxuICAgKiBhcmUgYnVmZmVyZWQgYW5kIG9ubHkgd3JpdHRlbiB3aGVuIGFsbCBuZXN0ZWQgY29yayBibG9ja3MgY29tcGxldGUgKHdoZW4gQ09SS19DT1VOVEVSIHJlYWNoZXMgMCkuXG4gICAqIFRoZSBjb3JraW5nIGlzIGJvdW5kIHRvIHRoZSBzcGVjaWZpYyBpbnN0YW5jZSBvZiB0aGUgQ2xpSW9Ib3N0LlxuICAgKlxuICAgKiBAcGFyYW0gYmxvY2sgLSBBc3luYyBmdW5jdGlvbiB0byBleGVjdXRlIHdpdGggY29ya2VkIGxvZ2dpbmdcbiAgICogQHJldHVybnMgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGJsb2NrJ3MgcmV0dXJuIHZhbHVlXG4gICAqL1xuICBwdWJsaWMgYXN5bmMgd2l0aENvcmtlZExvZ2dpbmc8VD4oYmxvY2s6ICgpID0+IFByb21pc2U8VD4pOiBQcm9taXNlPFQ+IHtcbiAgICB0aGlzLmNvcmtlZENvdW50ZXIrKztcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IGJsb2NrKCk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuY29ya2VkQ291bnRlci0tO1xuICAgICAgaWYgKHRoaXMuY29ya2VkQ291bnRlciA9PT0gMCkge1xuICAgICAgICAvLyBQcm9jZXNzIGVhY2ggYnVmZmVyZWQgbWVzc2FnZSB0aHJvdWdoIG5vdGlmeVxuICAgICAgICBmb3IgKGNvbnN0IGlvTWVzc2FnZSBvZiB0aGlzLmNvcmtlZExvZ2dpbmdCdWZmZXIpIHtcbiAgICAgICAgICBhd2FpdCB0aGlzLm5vdGlmeShpb01lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICAgIC8vIHJlbW92ZSBhbGwgYnVmZmVyZWQgbWVzc2FnZXMgaW4tcGxhY2VcbiAgICAgICAgdGhpcy5jb3JrZWRMb2dnaW5nQnVmZmVyLnNwbGljZSgwKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTm90aWZpZXMgdGhlIGhvc3Qgb2YgYSBtZXNzYWdlLlxuICAgKiBUaGUgY2FsbGVyIHdhaXRzIHVudGlsIHRoZSBub3RpZmljYXRpb24gY29tcGxldGVzLlxuICAgKi9cbiAgcHVibGljIGFzeW5jIG5vdGlmeShtc2c6IElvTWVzc2FnZTx1bmtub3duPik6IFByb21pc2U8dm9pZD4ge1xuICAgIGF3YWl0IHRoaXMubWF5YmVFbWl0VGVsZW1ldHJ5KG1zZyk7XG5cbiAgICBpZiAodGhpcy5pc1N0YWNrQWN0aXZpdHkobXNnKSkge1xuICAgICAgaWYgKCF0aGlzLmFjdGl2aXR5UHJpbnRlcikge1xuICAgICAgICB0aGlzLmFjdGl2aXR5UHJpbnRlciA9IHRoaXMubWFrZUFjdGl2aXR5UHJpbnRlcigpO1xuICAgICAgfVxuICAgICAgdGhpcy5hY3Rpdml0eVByaW50ZXIubm90aWZ5KG1zZyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKCFpc01lc3NhZ2VSZWxldmFudEZvckxldmVsKG1zZywgdGhpcy5sb2dMZXZlbCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jb3JrZWRDb3VudGVyID4gMCkge1xuICAgICAgdGhpcy5jb3JrZWRMb2dnaW5nQnVmZmVyLnB1c2gobXNnKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBvdXRwdXQgPSB0aGlzLmZvcm1hdE1lc3NhZ2UobXNnKTtcbiAgICBjb25zdCBzdHJlYW0gPSB0aGlzLnNlbGVjdFN0cmVhbShtc2cpO1xuICAgIHN0cmVhbT8ud3JpdGUob3V0cHV0KTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgbWF5YmVFbWl0VGVsZW1ldHJ5KG1zZzogSW9NZXNzYWdlPHVua25vd24+KSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHRlbGVtZXRyeUV2ZW50ID0gZXZlbnRGcm9tTWVzc2FnZShtc2cpO1xuICAgICAgaWYgKHRlbGVtZXRyeUV2ZW50KSB7XG4gICAgICAgIGF3YWl0IHRoaXMudGVsZW1ldHJ5Py5lbWl0KHRlbGVtZXRyeUV2ZW50KTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlOiBhbnkpIHtcbiAgICAgIGF3YWl0IHRoaXMuZGVmYXVsdHMudHJhY2UoYEVtaXQgVGVsZW1ldHJ5IEZhaWxlZCAke2UubWVzc2FnZX1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0IHN0YWNrIGFjdGl2aXR5IG1lc3NhZ2VzIHNvIHRoZXkgY2FuIGJlIHNlbmQgdG8gdGhlIHByaW50ZXIuXG4gICAqL1xuICBwcml2YXRlIGlzU3RhY2tBY3Rpdml0eShtc2c6IElvTWVzc2FnZTx1bmtub3duPikge1xuICAgIHJldHVybiBtc2cuY29kZSAmJiBbXG4gICAgICAnQ0RLX1RPT0xLSVRfSTU1MDEnLFxuICAgICAgJ0NES19UT09MS0lUX0k1NTAyJyxcbiAgICAgICdDREtfVE9PTEtJVF9JNTUwMycsXG4gICAgXS5pbmNsdWRlcyhtc2cuY29kZSk7XG4gIH1cblxuICAvKipcbiAgICogRGV0ZWN0IHNwZWNpYWwgbWVzc2FnZXMgZW5jb2RlIGluZm9ybWF0aW9uIGFib3V0IHdoZXRoZXIgb3Igbm90XG4gICAqIHRoZXkgcmVxdWlyZSBhcHByb3ZhbFxuICAgKi9cbiAgcHJpdmF0ZSBza2lwQXBwcm92YWxTdGVwKG1zZzogSW9SZXF1ZXN0PGFueSwgYW55Pik6IGJvb2xlYW4ge1xuICAgIGNvbnN0IGFwcHJvdmFsVG9vbGtpdENvZGVzID0gWydDREtfVE9PTEtJVF9JNTA2MCddO1xuICAgIGlmICghKG1zZy5jb2RlICYmIGFwcHJvdmFsVG9vbGtpdENvZGVzLmluY2x1ZGVzKG1zZy5jb2RlKSkpIHtcbiAgIC