UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

540 lines 82 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CurrentActivityPrinter = exports.HistoryActivityPrinter = exports.StackActivityMonitor = exports.StackActivityProgress = void 0; const util = require("util"); const cloud_assembly_schema_1 = require("@aws-cdk/cloud-assembly-schema"); const chalk = require("chalk"); const stack_event_poller_1 = require("./stack-event-poller"); const logging_1 = require("../../../logging"); const cli_io_host_1 = require("../../../toolkit/cli-io-host"); const display_1 = require("../display"); /** * Supported display modes for stack deployment activity */ var StackActivityProgress; (function (StackActivityProgress) { /** * Displays a progress bar with only the events for the resource currently being deployed */ StackActivityProgress["BAR"] = "bar"; /** * Displays complete history with all CloudFormation stack events */ StackActivityProgress["EVENTS"] = "events"; })(StackActivityProgress || (exports.StackActivityProgress = StackActivityProgress = {})); class StackActivityMonitor { /** * Create a Stack Activity Monitor using a default printer, based on context clues */ static withDefaultPrinter(cfn, stackName, stackArtifact, options = {}) { const stream = options.ci ? process.stdout : process.stderr; const props = { resourceTypeColumnWidth: calcMaxResourceTypeLength(stackArtifact.template), resourcesTotal: options.resourcesTotal, stream, }; const isWindows = process.platform === 'win32'; const verbose = options.logLevel ?? 'info'; // 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 = !isWindows && stream.isTTY && !options.ci; const progress = options.progress ?? StackActivityProgress.BAR; const printer = fancyOutputAvailable && !verbose && progress === StackActivityProgress.BAR ? new CurrentActivityPrinter(props) : new HistoryActivityPrinter(props); return new StackActivityMonitor(cfn, stackName, printer, stackArtifact, options.changeSetCreationTime); } constructor(cfn, stackName, printer, stack, changeSetCreationTime) { this.stackName = stackName; this.printer = printer; this.stack = stack; this.errors = []; this.active = false; this.poller = new stack_event_poller_1.StackEventPoller(cfn, { stackName, startTime: changeSetCreationTime?.getTime() ?? Date.now(), }); } start() { this.active = true; this.printer.start(); this.scheduleNextTick(); return this; } async stop() { this.active = false; if (this.tickTimer) { clearTimeout(this.tickTimer); } // Do a final poll for all events. This is to handle the situation where DescribeStackStatus // already returned an error, but the monitor hasn't seen all the events yet and we'd end // up not printing the failure reason to users. await this.finalPollToEnd(); this.printer.stop(); } scheduleNextTick() { if (!this.active) { return; } this.tickTimer = setTimeout(() => void this.tick(), this.printer.updateSleep); } async tick() { if (!this.active) { return; } try { this.readPromise = this.readNewEvents(); await this.readPromise; this.readPromise = undefined; // We might have been stop()ped while the network call was in progress. if (!this.active) { return; } this.printer.print(); } catch (e) { (0, logging_1.error)('Error occurred while monitoring stack: %s', e); } this.scheduleNextTick(); } findMetadataFor(logicalId) { const metadata = this.stack?.manifest?.metadata; if (!logicalId || !metadata) { return undefined; } for (const path of Object.keys(metadata)) { const entry = metadata[path] .filter((e) => e.type === cloud_assembly_schema_1.ArtifactMetadataEntryType.LOGICAL_ID) .find((e) => e.data === logicalId); if (entry) { return { entry, constructPath: this.simplifyConstructPath(path), }; } } return undefined; } /** * Reads all new events from the stack history * * The events are returned in reverse chronological order; we continue to the next page if we * see a next page and the last event in the page is new to us (and within the time window). * haven't seen the final event */ async readNewEvents() { const pollEvents = await this.poller.poll(); const activities = pollEvents.map((event) => ({ ...event, metadata: this.findMetadataFor(event.event.LogicalResourceId), })); for (const activity of activities) { this.checkForErrors(activity); this.printer.addActivity(activity); } } /** * Perform a final poll to the end and flush out all events to the printer * * Finish any poll currently in progress, then do a final one until we've * reached the last page. */ async finalPollToEnd() { // If we were doing a poll, finish that first. It was started before // the moment we were sure we weren't going to get any new events anymore // so we need to do a new one anyway. Need to wait for this one though // because our state is single-threaded. if (this.readPromise) { await this.readPromise; } await this.readNewEvents(); } checkForErrors(activity) { if (hasErrorMessage(activity.event.ResourceStatus ?? '')) { const isCancelled = (activity.event.ResourceStatusReason ?? '').indexOf('cancelled') > -1; // Cancelled is not an interesting failure reason, nor is the stack message (stack // message will just say something like "stack failed to update") if (!isCancelled && activity.event.StackName !== activity.event.LogicalResourceId) { this.errors.push(activity.event.ResourceStatusReason ?? ''); } } } simplifyConstructPath(path) { path = path.replace(/\/Resource$/, ''); path = path.replace(/^\//, ''); // remove "/" prefix // remove "<stack-name>/" prefix if (path.startsWith(this.stackName + '/')) { path = path.slice(this.stackName.length + 1); } return path; } } exports.StackActivityMonitor = StackActivityMonitor; function padRight(n, x) { return x + ' '.repeat(Math.max(0, n - x.length)); } /** * Infamous padLeft() */ function padLeft(n, x) { return ' '.repeat(Math.max(0, n - x.length)) + x; } function calcMaxResourceTypeLength(template) { const resources = (template && template.Resources) || {}; let maxWidth = 0; for (const id of Object.keys(resources)) { const type = resources[id].Type || ''; if (type.length > maxWidth) { maxWidth = type.length; } } return maxWidth; } class ActivityPrinterBase { constructor(props) { this.props = props; /** * Fetch new activity every 5 seconds */ this.updateSleep = 5000; /** * A list of resource IDs which are currently being processed */ this.resourcesInProgress = {}; /** * Previous completion state observed by logical ID * * We use this to detect that if we see a DELETE_COMPLETE after a * CREATE_COMPLETE, it's actually a rollback and we should DECREASE * resourcesDone instead of increase it */ this.resourcesPrevCompleteState = {}; /** * Count of resources that have reported a _COMPLETE status */ this.resourcesDone = 0; /** * How many digits we need to represent the total count (for lining up the status reporting) */ this.resourceDigits = 0; this.rollingBack = false; this.failures = new Array(); this.hookFailureMap = new Map(); // +1 because the stack also emits a "COMPLETE" event at the end, and that wasn't // counted yet. This makes it line up with the amount of events we expect. this.resourcesTotal = props.resourcesTotal ? props.resourcesTotal + 1 : undefined; // How many digits does this number take to represent? this.resourceDigits = this.resourcesTotal ? Math.ceil(Math.log10(this.resourcesTotal)) : 0; } failureReason(activity) { const resourceStatusReason = activity.event.ResourceStatusReason ?? ''; const logicalResourceId = activity.event.LogicalResourceId ?? ''; const hookFailureReasonMap = this.hookFailureMap.get(logicalResourceId); if (hookFailureReasonMap !== undefined) { for (const hookType of hookFailureReasonMap.keys()) { if (resourceStatusReason.includes(hookType)) { return resourceStatusReason + ' : ' + hookFailureReasonMap.get(hookType); } } } return resourceStatusReason; } addActivity(activity) { const status = activity.event.ResourceStatus; const hookStatus = activity.event.HookStatus; const hookType = activity.event.HookType; if (!status || !activity.event.LogicalResourceId) { return; } if (status === 'ROLLBACK_IN_PROGRESS' || status === 'UPDATE_ROLLBACK_IN_PROGRESS') { // Only triggered on the stack once we've started doing a rollback this.rollingBack = true; } if (status.endsWith('_IN_PROGRESS')) { this.resourcesInProgress[activity.event.LogicalResourceId] = activity; } if (hasErrorMessage(status)) { const isCancelled = (activity.event.ResourceStatusReason ?? '').indexOf('cancelled') > -1; // Cancelled is not an interesting failure reason if (!isCancelled) { this.failures.push(activity); } } if (status.endsWith('_COMPLETE') || status.endsWith('_FAILED')) { delete this.resourcesInProgress[activity.event.LogicalResourceId]; } if (status.endsWith('_COMPLETE_CLEANUP_IN_PROGRESS')) { this.resourcesDone++; } if (status.endsWith('_COMPLETE')) { const prevState = this.resourcesPrevCompleteState[activity.event.LogicalResourceId]; if (!prevState) { this.resourcesDone++; } else { // If we completed this before and we're completing it AGAIN, means we're rolling back. // Protect against silly underflow. this.resourcesDone--; if (this.resourcesDone < 0) { this.resourcesDone = 0; } } this.resourcesPrevCompleteState[activity.event.LogicalResourceId] = status; } if (hookStatus !== undefined && hookStatus.endsWith('_COMPLETE_FAILED') && activity.event.LogicalResourceId !== undefined && hookType !== undefined) { if (this.hookFailureMap.has(activity.event.LogicalResourceId)) { this.hookFailureMap.get(activity.event.LogicalResourceId)?.set(hookType, activity.event.HookStatusReason ?? ''); } else { this.hookFailureMap.set(activity.event.LogicalResourceId, new Map()); this.hookFailureMap.get(activity.event.LogicalResourceId)?.set(hookType, activity.event.HookStatusReason ?? ''); } } } start() { // Empty on purpose } stop() { // Empty on purpose } } /** * Activity Printer which shows a full log of all CloudFormation events * * When there hasn't been activity for a while, it will print the resources * that are currently in progress, to show what's holding up the deployment. */ class HistoryActivityPrinter extends ActivityPrinterBase { constructor(props) { super(props); /** * Last time we printed something to the console. * * Used to measure timeout for progress reporting. */ this.lastPrintTime = Date.now(); /** * Number of ms of change absence before we tell the user about the resources that are currently in progress. */ this.inProgressDelay = 30000; this.printable = new Array(); } addActivity(activity) { super.addActivity(activity); this.printable.push(activity); this.print(); } print() { for (const activity of this.printable) { this.printOne(activity); } this.printable.splice(0, this.printable.length); this.printInProgress(); } stop() { // Print failures at the end if (this.failures.length > 0) { (0, logging_1.info)('\nFailed resources:'); for (const failure of this.failures) { // Root stack failures are not interesting if (failure.isStackEvent) { continue; } this.printOne(failure, false); } } } printOne(activity, progress) { const event = activity.event; const color = colorFromStatusResult(event.ResourceStatus); let reasonColor = chalk.cyan; let stackTrace = ''; const metadata = activity.metadata; if (event.ResourceStatus && event.ResourceStatus.indexOf('FAILED') !== -1) { if (progress == undefined || progress) { event.ResourceStatusReason = event.ResourceStatusReason ? this.failureReason(activity) : ''; } if (metadata) { stackTrace = metadata.entry.trace ? `\n\t${metadata.entry.trace.join('\n\t\\_ ')}` : ''; } reasonColor = chalk.red; } const resourceName = metadata ? metadata.constructPath : event.LogicalResourceId || ''; const logicalId = resourceName !== event.LogicalResourceId ? `(${event.LogicalResourceId}) ` : ''; (0, logging_1.info)(util.format('%s | %s%s | %s | %s | %s %s%s%s', event.StackName, progress !== false ? `${this.progress()} | ` : '', new Date(event.Timestamp).toLocaleTimeString(), color(padRight(STATUS_WIDTH, (event.ResourceStatus || '').slice(0, STATUS_WIDTH))), // pad left and trim padRight(this.props.resourceTypeColumnWidth, event.ResourceType || ''), color(chalk.bold(resourceName)), logicalId, reasonColor(chalk.bold(event.ResourceStatusReason ? event.ResourceStatusReason : '')), reasonColor(stackTrace))); this.lastPrintTime = Date.now(); } /** * Report the current progress as a [34/42] string, or just [34] if the total is unknown */ progress() { if (this.resourcesTotal == null) { // Don't have total, show simple count and hope the human knows return padLeft(3, util.format('%s', this.resourcesDone)); // max 500 resources } return util.format('%s/%s', padLeft(this.resourceDigits, this.resourcesDone.toString()), padLeft(this.resourceDigits, this.resourcesTotal != null ? this.resourcesTotal.toString() : '?')); } /** * If some resources are taking a while to create, notify the user about what's currently in progress */ printInProgress() { if (Date.now() < this.lastPrintTime + this.inProgressDelay) { return; } if (Object.keys(this.resourcesInProgress).length > 0) { (0, logging_1.info)(util.format('%s Currently in progress: %s', this.progress(), chalk.bold(Object.keys(this.resourcesInProgress).join(', ')))); } // We cheat a bit here. To prevent printInProgress() from repeatedly triggering, // we set the timestamp into the future. It will be reset whenever a regular print // occurs, after which we can be triggered again. this.lastPrintTime = +Infinity; } } exports.HistoryActivityPrinter = HistoryActivityPrinter; /** * Activity Printer which shows the resources currently being updated * * It will continuously reupdate the terminal and show only the resources * that are currently being updated, in addition to a progress bar which * shows how far along the deployment is. * * Resources that have failed will always be shown, and will be recapitulated * along with their stack trace when the monitoring ends. * * Resources that failed deployment because they have been cancelled are * not included. */ class CurrentActivityPrinter extends ActivityPrinterBase { constructor(props) { super(props); /** * This looks very disorienting sleeping for 5 seconds. Update quicker. */ this.updateSleep = 2000; this.oldLogThreshold = cli_io_host_1.CliIoHost.instance().logLevel; this.stream = props.stream; this.block = new display_1.RewritableBlock(this.stream); } print() { const lines = []; // Add a progress bar at the top const progressWidth = Math.max(Math.min((this.block.width ?? 80) - PROGRESSBAR_EXTRA_SPACE - 1, MAX_PROGRESSBAR_WIDTH), MIN_PROGRESSBAR_WIDTH); const prog = this.progressBar(progressWidth); if (prog) { lines.push(' ' + prog, ''); } // Normally we'd only print "resources in progress", but it's also useful // to keep an eye on the failures and know about the specific errors asquickly // as possible (while the stack is still rolling back), so add those in. const toPrint = [...this.failures, ...Object.values(this.resourcesInProgress)]; toPrint.sort((a, b) => a.event.Timestamp.getTime() - b.event.Timestamp.getTime()); lines.push(...toPrint.map((res) => { const color = colorFromStatusActivity(res.event.ResourceStatus); const resourceName = res.metadata?.constructPath ?? res.event.LogicalResourceId ?? ''; return util.format('%s | %s | %s | %s%s', padLeft(TIMESTAMP_WIDTH, new Date(res.event.Timestamp).toLocaleTimeString()), color(padRight(STATUS_WIDTH, (res.event.ResourceStatus || '').slice(0, STATUS_WIDTH))), padRight(this.props.resourceTypeColumnWidth, res.event.ResourceType || ''), color(chalk.bold(shorten(40, resourceName))), this.failureReasonOnNextLine(res)); })); this.block.displayLines(lines); } start() { // Need to prevent the waiter from printing 'stack not stable' every 5 seconds, it messes // with the output calculations. this.oldLogThreshold = cli_io_host_1.CliIoHost.instance().logLevel; cli_io_host_1.CliIoHost.instance().logLevel = 'info'; } stop() { cli_io_host_1.CliIoHost.instance().logLevel = this.oldLogThreshold; // Print failures at the end const lines = new Array(); for (const failure of this.failures) { // Root stack failures are not interesting if (failure.isStackEvent) { continue; } lines.push(util.format(chalk.red('%s | %s | %s | %s%s') + '\n', padLeft(TIMESTAMP_WIDTH, new Date(failure.event.Timestamp).toLocaleTimeString()), padRight(STATUS_WIDTH, (failure.event.ResourceStatus || '').slice(0, STATUS_WIDTH)), padRight(this.props.resourceTypeColumnWidth, failure.event.ResourceType || ''), shorten(40, failure.event.LogicalResourceId ?? ''), this.failureReasonOnNextLine(failure))); const trace = failure.metadata?.entry?.trace; if (trace) { lines.push(chalk.red(`\t${trace.join('\n\t\\_ ')}\n`)); } } // Display in the same block space, otherwise we're going to have silly empty lines. this.block.displayLines(lines); this.block.removeEmptyLines(); } progressBar(width) { if (!this.resourcesTotal) { return ''; } const fraction = Math.min(this.resourcesDone / this.resourcesTotal, 1); const innerWidth = Math.max(1, width - 2); const chars = innerWidth * fraction; const remainder = chars - Math.floor(chars); const fullChars = FULL_BLOCK.repeat(Math.floor(chars)); const partialChar = PARTIAL_BLOCK[Math.floor(remainder * PARTIAL_BLOCK.length)]; const filler = '·'.repeat(innerWidth - Math.floor(chars) - (partialChar ? 1 : 0)); const color = this.rollingBack ? chalk.yellow : chalk.green; return '[' + color(fullChars + partialChar) + filler + `] (${this.resourcesDone}/${this.resourcesTotal})`; } failureReasonOnNextLine(activity) { return hasErrorMessage(activity.event.ResourceStatus ?? '') ? `\n${' '.repeat(TIMESTAMP_WIDTH + STATUS_WIDTH + 6)}${chalk.red(this.failureReason(activity) ?? '')}` : ''; } } exports.CurrentActivityPrinter = CurrentActivityPrinter; const FULL_BLOCK = '█'; const PARTIAL_BLOCK = ['', '▏', '▎', '▍', '▌', '▋', '▊', '▉']; const MAX_PROGRESSBAR_WIDTH = 60; const MIN_PROGRESSBAR_WIDTH = 10; const PROGRESSBAR_EXTRA_SPACE = 2 /* leading spaces */ + 2 /* brackets */ + 4 /* progress number decoration */ + 6; /* 2 progress numbers up to 999 */ function hasErrorMessage(status) { return status.endsWith('_FAILED') || status === 'ROLLBACK_IN_PROGRESS' || status === 'UPDATE_ROLLBACK_IN_PROGRESS'; } function colorFromStatusResult(status) { if (!status) { return chalk.reset; } if (status.indexOf('FAILED') !== -1) { return chalk.red; } if (status.indexOf('ROLLBACK') !== -1) { return chalk.yellow; } if (status.indexOf('COMPLETE') !== -1) { return chalk.green; } return chalk.reset; } function colorFromStatusActivity(status) { if (!status) { return chalk.reset; } if (status.endsWith('_FAILED')) { return chalk.red; } if (status.startsWith('CREATE_') || status.startsWith('UPDATE_') || status.startsWith('IMPORT_')) { return chalk.green; } // For stacks, it may also be 'UPDDATE_ROLLBACK_IN_PROGRESS' if (status.indexOf('ROLLBACK_') !== -1) { return chalk.yellow; } if (status.startsWith('DELETE_')) { return chalk.yellow; } return chalk.reset; } function shorten(maxWidth, p) { if (p.length <= maxWidth) { return p; } const half = Math.floor((maxWidth - 3) / 2); return p.slice(0, half) + '...' + p.slice(-half); } const TIMESTAMP_WIDTH = 12; const STATUS_WIDTH = 20; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhY2stYWN0aXZpdHktbW9uaXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInN0YWNrLWFjdGl2aXR5LW1vbml0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsNkJBQTZCO0FBQzdCLDBFQUErRjtBQUUvRiwrQkFBK0I7QUFDL0IsNkRBQXVFO0FBQ3ZFLDhDQUErQztBQUMvQyw4REFBeUU7QUFFekUsd0NBQTZDO0FBVzdDOztHQUVHO0FBQ0gsSUFBWSxxQkFVWDtBQVZELFdBQVkscUJBQXFCO0lBQy9COztPQUVHO0lBQ0gsb0NBQVcsQ0FBQTtJQUVYOztPQUVHO0lBQ0gsMENBQWlCLENBQUE7QUFDbkIsQ0FBQyxFQVZXLHFCQUFxQixxQ0FBckIscUJBQXFCLFFBVWhDO0FBc0RELE1BQWEsb0JBQW9CO0lBQy9COztPQUVHO0lBQ0ksTUFBTSxDQUFDLGtCQUFrQixDQUM5QixHQUEwQixFQUMxQixTQUFpQixFQUNqQixhQUEwQyxFQUMxQyxVQUFtQyxFQUFFO1FBRXJDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFFNUQsTUFBTSxLQUFLLEdBQWlCO1lBQzFCLHVCQUF1QixFQUFFLHlCQUF5QixDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUM7WUFDMUUsY0FBYyxFQUFFLE9BQU8sQ0FBQyxjQUFjO1lBQ3RDLE1BQU07U0FDUCxDQUFDO1FBRUYsTUFBTSxTQUFTLEdBQUcsT0FBTyxDQUFDLFFBQVEsS0FBSyxPQUFPLENBQUM7UUFDL0MsTUFBTSxPQUFPLEdBQUcsT0FBTyxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUM7UUFDM0MsaUZBQWlGO1FBQ2pGLDREQUE0RDtRQUM1RCwwRkFBMEY7UUFDMUYsTUFBTSxvQkFBb0IsR0FBRyxDQUFDLFNBQVMsSUFBSSxNQUFNLENBQUMsS0FBSyxJQUFJLENBQUMsT0FB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QUN0QixDQUFDO0lBQ0QsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDakMsT0FBTyxLQUFLLENBQUMsTUFBTSxDQUFDO0lBQ3RCLENBQUM7SUFFRCxPQUFPLEtBQUssQ0FBQyxLQUFLLENBQUM7QUFDckIsQ0FBQztBQUVELFNBQVMsT0FBTyxDQUFDLFFBQWdCLEVBQUUsQ0FBUztJQUMxQyxJQUFJLENBQUMsQ0FBQyxNQUFNLElBQUksUUFBUSxFQUFFLENBQUM7UUFDekIsT0FBTyxDQUFDLENBQUM7SUFDWCxDQUFDO0lBQ0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsR0FBRyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUM1QyxPQUFPLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDbkQsQ0FBQztBQUVELE1BQU0sZUFBZSxHQUFHLEVBQUUsQ0FBQztBQUMzQixNQUFNLFlBQVksR0FBRyxFQUFFLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyB1dGlsIGZyb20gJ3V0aWwnO1xuaW1wb3J0IHsgQXJ0aWZhY3RNZXRhZGF0YUVudHJ5VHlwZSwgdHlwZSBNZXRhZGF0YUVudHJ5IH0gZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCB0eXBlIHsgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IH0gZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCAqIGFzIGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCB7IFJlc291cmNlRXZlbnQsIFN0YWNrRXZlbnRQb2xsZXIgfSBmcm9tICcuL3N0YWNrLWV2ZW50LXBvbGxlcic7XG5pbXBvcnQgeyBlcnJvciwgaW5mbyB9IGZyb20gJy4uLy4uLy4uL2xvZ2dpbmcnO1xuaW1wb3J0IHsgQ2xpSW9Ib3N0LCBJb01lc3NhZ2VMZXZlbCB9IGZyb20gJy4uLy4uLy4uL3Rvb2xraXQvY2xpLWlvLWhvc3QnO1xuaW1wb3J0IHR5cGUgeyBJQ2xvdWRGb3JtYXRpb25DbGllbnQgfSBmcm9tICcuLi8uLi9hd3MtYXV0aCc7XG5pbXBvcnQgeyBSZXdyaXRhYmxlQmxvY2sgfSBmcm9tICcuLi9kaXNwbGF5JztcblxuZXhwb3J0IGludGVyZmFjZSBTdGFja0FjdGl2aXR5IGV4dGVuZHMgUmVzb3VyY2VFdmVudCB7XG4gIHJlYWRvbmx5IG1ldGFkYXRhPzogUmVzb3VyY2VNZXRhZGF0YTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBSZXNvdXJjZU1ldGFkYXRhIHtcbiAgZW50cnk6IE1ldGFkYXRhRW50cnk7XG4gIGNvbnN0cnVjdFBhdGg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBTdXBwb3J0ZWQgZGlzcGxheSBtb2RlcyBmb3Igc3RhY2sgZGVwbG95bWVudCBhY3Rpdml0eVxuICovXG5leHBvcnQgZW51bSBTdGFja0FjdGl2aXR5UHJvZ3Jlc3Mge1xuICAvKipcbiAgICogRGlzcGxheXMgYSBwcm9ncmVzcyBiYXIgd2l0aCBvbmx5IHRoZSBldmVudHMgZm9yIHRoZSByZXNvdXJjZSBjdXJyZW50bHkgYmVpbmcgZGVwbG95ZWRcbiAgICovXG4gIEJBUiA9ICdiYXInLFxuXG4gIC8qKlxuICAgKiBEaXNwbGF5cyBjb21wbGV0ZSBoaXN0b3J5IHdpdGggYWxsIENsb3VkRm9ybWF0aW9uIHN0YWNrIGV2ZW50c1xuICAgKi9cbiAgRVZFTlRTID0gJ2V2ZW50cycsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgV2l0aERlZmF1bHRQcmludGVyUHJvcHMge1xuICAvKipcbiAgICogVG90YWwgbnVtYmVyIG9mIHJlc291cmNlcyB0byB1cGRhdGVcbiAgICpcbiAgICogVXNlZCB0byBjYWxjdWxhdGUgYSBwcm9ncmVzcyBiYXIuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcHJvZ3Jlc3MgcmVwb3J0aW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgcmVzb3VyY2VzVG90YWw/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFRoZSBsb2cgbGV2ZWwgdGhhdCB3YXMgcmVxdWVzdGVkIGluIHRoZSBDTElcbiAgICpcbiAgICogSWYgdmVyYm9zZSBvciB0cmFjZSBpcyByZXF1ZXN0ZWQsIHdlJ2xsIGFsd2F5cyB1c2UgdGhlIGZ1bGwgaGlzdG9yeSBwcmludGVyLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIFVzZSB2YWx1ZSBmcm9tIGxvZ2dpbmcubG9nTGV2ZWxcbiAgICovXG4gIHJlYWRvbmx5IGxvZ0