aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
269 lines • 45.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const logging_1 = require("../../../lib/logging");
const cli_io_host_1 = require("../../../lib/toolkit/cli-io-host");
describe('logging', () => {
const ioHost = cli_io_host_1.CliIoHost.instance({}, true);
let mockStdout;
let mockStderr;
const stripAnsi = (str) => {
const ansiRegex = /\u001b\[[0-9;]*[a-zA-Z]/g;
return str.replace(ansiRegex, '');
};
beforeEach(() => {
ioHost.logLevel = 'info';
ioHost.isCI = false;
mockStdout = jest.fn();
mockStderr = jest.fn();
jest.spyOn(process.stdout, 'write').mockImplementation((chunk) => {
mockStdout(stripAnsi(chunk.toString()));
return true;
});
jest.spyOn(process.stderr, 'write').mockImplementation((chunk) => {
mockStderr(stripAnsi(chunk.toString()));
return true;
});
});
afterEach(() => {
jest.restoreAllMocks();
});
describe('stream selection', () => {
test('data() always writes to stdout with both styles', () => {
// String style
(0, logging_1.data)('test message');
expect(mockStdout).toHaveBeenCalledWith('test message\n');
// Object style
(0, logging_1.data)({ message: 'test message 2' });
expect(mockStdout).toHaveBeenCalledWith('test message 2\n');
expect(mockStderr).not.toHaveBeenCalled();
});
test('error() always writes to stderr with both styles', () => {
// String style
(0, logging_1.error)('test error');
expect(mockStderr).toHaveBeenCalledWith('test error\n');
// Object style
(0, logging_1.error)({ message: 'test error 2' });
expect(mockStderr).toHaveBeenCalledWith('test error 2\n');
expect(mockStdout).not.toHaveBeenCalled();
});
test('info() writes to stderr by default with both styles', () => {
// String style
(0, logging_1.info)('test print');
expect(mockStderr).toHaveBeenCalledWith('test print\n');
// Object style
(0, logging_1.info)({ message: 'test print 2' });
expect(mockStderr).toHaveBeenCalledWith('test print 2\n');
expect(mockStdout).not.toHaveBeenCalled();
});
test('info() writes to stdout in CI mode with both styles', () => {
ioHost.isCI = true;
// String style
(0, logging_1.info)('test print');
expect(mockStdout).toHaveBeenCalledWith('test print\n');
// Object style
(0, logging_1.info)({ message: 'test print 2' });
expect(mockStdout).toHaveBeenCalledWith('test print 2\n');
expect(mockStderr).not.toHaveBeenCalled();
});
});
describe('log levels', () => {
test('respects log level settings with both styles', () => {
ioHost.logLevel = 'error';
// String style
(0, logging_1.error)('error message');
(0, logging_1.warning)('warning message');
(0, logging_1.info)('print message');
// Object style
(0, logging_1.error)({ message: 'error message 2' });
(0, logging_1.warning)({ message: 'warning message 2' });
(0, logging_1.info)({ message: 'print message 2' });
expect(mockStderr).toHaveBeenCalledWith('error message\n');
expect(mockStderr).toHaveBeenCalledWith('error message 2\n');
expect(mockStderr).not.toHaveBeenCalledWith('warning message\n');
expect(mockStderr).not.toHaveBeenCalledWith('warning message 2\n');
expect(mockStderr).not.toHaveBeenCalledWith('print message\n');
expect(mockStderr).not.toHaveBeenCalledWith('print message 2\n');
});
test('debug messages only show at debug level with both styles', () => {
ioHost.logLevel = 'info';
(0, logging_1.debug)('debug message');
(0, logging_1.debug)({ message: 'debug message 2' });
expect(mockStderr).not.toHaveBeenCalled();
ioHost.logLevel = 'debug';
(0, logging_1.debug)('debug message');
(0, logging_1.debug)({ message: 'debug message 2' });
expect(mockStderr).toHaveBeenCalledWith(expect.stringMatching(/^\[\d{2}:\d{2}:\d{2}\] debug message\n$/));
expect(mockStderr).toHaveBeenCalledWith(expect.stringMatching(/^\[\d{2}:\d{2}:\d{2}\] debug message 2\n$/));
});
test('trace messages only show at trace level with both styles', () => {
ioHost.logLevel = 'debug';
(0, logging_1.trace)('trace message');
(0, logging_1.trace)({ message: 'trace message 2' });
expect(mockStderr).not.toHaveBeenCalled();
ioHost.logLevel = 'trace';
(0, logging_1.trace)('trace message');
(0, logging_1.trace)({ message: 'trace message 2' });
expect(mockStderr).toHaveBeenCalledWith(expect.stringMatching(/^\[\d{2}:\d{2}:\d{2}\] trace message\n$/));
expect(mockStderr).toHaveBeenCalledWith(expect.stringMatching(/^\[\d{2}:\d{2}:\d{2}\] trace message 2\n$/));
});
});
describe('formatted messages', () => {
test('handles format strings correctly with both styles', () => {
// String style
(0, logging_1.info)('Hello %s, you have %d messages', 'User', 5);
expect(mockStderr).toHaveBeenCalledWith('Hello User, you have 5 messages\n');
// Object style
(0, logging_1.info)({ message: 'Hello %s, you have %d messages' }, 'User', 5);
expect(mockStderr).toHaveBeenCalledWith('Hello User, you have 5 messages\n');
});
test('handles objects in format strings with both styles', () => {
const obj = { name: 'test' };
// String style
(0, logging_1.info)('Object: %j', obj);
expect(mockStderr).toHaveBeenCalledWith('Object: {"name":"test"}\n');
// Object style
(0, logging_1.info)({ message: 'Object: %j' }, obj);
expect(mockStderr).toHaveBeenCalledWith('Object: {"name":"test"}\n');
});
test('handles multiple style changes in single call', () => {
const obj = { id: 123 };
(0, logging_1.success)('Processing %s: %j at %d%%', 'task', obj, 50);
expect(mockStderr).toHaveBeenCalledWith('Processing task: {"id":123} at 50%\n');
});
});
describe('styled output', () => {
test('success() adds green color to output with both styles', () => {
// String style
(0, logging_1.success)('operation completed');
expect(mockStderr).toHaveBeenCalledWith('operation completed\n');
// Object style
(0, logging_1.success)({ message: 'operation completed 2' });
expect(mockStderr).toHaveBeenCalledWith('operation completed 2\n');
});
test('highlight() adds bold formatting to output with both styles', () => {
// String style
(0, logging_1.highlight)('important message');
expect(mockStderr).toHaveBeenCalledWith('important message\n');
// Object style
(0, logging_1.highlight)({ message: 'important message 2' });
expect(mockStderr).toHaveBeenCalledWith('important message 2\n');
});
test('success handles format strings with styling', () => {
(0, logging_1.success)('completed task %d of %d', 1, 3);
expect(mockStderr).toHaveBeenCalledWith('completed task 1 of 3\n');
// Remove the code from the test since it's an implementation detail
(0, logging_1.success)({ message: 'completed task %d of %d' }, 2, 3);
expect(mockStderr).toHaveBeenCalledWith('completed task 2 of 3\n');
});
test('highlight handles complex objects with styling', () => {
const complexObj = { status: 'active', count: 42 };
(0, logging_1.highlight)('Status: %j', complexObj);
expect(mockStderr).toHaveBeenCalledWith('Status: {"status":"active","count":42}\n');
// Remove the code from the test since it's an implementation detail
(0, logging_1.highlight)({ message: 'Status: %j' }, complexObj);
expect(mockStderr).toHaveBeenCalledWith('Status: {"status":"active","count":42}\n');
});
});
describe('edge cases', () => {
test('handles null and undefined arguments with both styles', () => {
// String style
(0, logging_1.info)('Values: %s, %s', null, undefined);
expect(mockStderr).toHaveBeenCalledWith('Values: null, undefined\n');
// Object style
(0, logging_1.info)({ message: 'Values: %s, %s' }, null, undefined);
expect(mockStderr).toHaveBeenCalledWith('Values: null, undefined\n');
});
test('handles circular references in objects with both styles', () => {
const obj = { name: 'test' };
obj.self = obj;
// String style
(0, logging_1.info)('Object: %j', obj);
expect(mockStderr).toHaveBeenCalledWith(expect.stringContaining('[Circular'));
// Object style
(0, logging_1.info)({ message: 'Object: %j' }, obj);
expect(mockStderr).toHaveBeenCalledWith(expect.stringContaining('[Circular'));
});
});
describe('message codes', () => {
test('validates message codes correctly', () => {
// Valid codes
expect(() => (0, logging_1.error)({ message: 'test', code: 'CDK_TOOLKIT_E0001' })).not.toThrow();
expect(() => (0, logging_1.warning)({ message: 'test', code: 'CDK_ASSETS_W4999' })).not.toThrow();
expect(() => (0, logging_1.info)({ message: 'test', code: 'CDK_SDK_I0000' })).not.toThrow();
});
test('uses default codes when none provided', () => {
(0, logging_1.error)('test error');
expect(mockStderr).toHaveBeenCalledWith(expect.stringContaining('test error'));
// Would need to modify the code to expose the actual message code for verification
});
});
describe('corked logging', () => {
test('buffers messages when corked', async () => {
await (0, logging_1.withCorkedLogging)(async () => {
(0, logging_1.info)('message 1');
(0, logging_1.info)({ message: 'message 2' });
expect(mockStderr).not.toHaveBeenCalled();
});
expect(mockStderr).toHaveBeenCalledWith('message 1\n');
expect(mockStderr).toHaveBeenCalledWith('message 2\n');
});
test('handles nested corking correctly', async () => {
await (0, logging_1.withCorkedLogging)(async () => {
(0, logging_1.info)('outer 1');
await (0, logging_1.withCorkedLogging)(async () => {
(0, logging_1.info)({ message: 'inner' });
});
(0, logging_1.info)({ message: 'outer 2' });
expect(mockStderr).not.toHaveBeenCalled();
});
expect(mockStderr).toHaveBeenCalledTimes(3);
expect(mockStderr).toHaveBeenCalledWith('outer 1\n');
expect(mockStderr).toHaveBeenCalledWith('inner\n');
expect(mockStderr).toHaveBeenCalledWith('outer 2\n');
});
test('handles errors in corked block while preserving buffer', async () => {
await expect((0, logging_1.withCorkedLogging)(async () => {
(0, logging_1.info)('message 1');
throw new Error('test error');
})).rejects.toThrow('test error');
// The buffered message should still be printed even if the block throws
expect(mockStderr).toHaveBeenCalledWith('message 1\n');
});
test('maintains correct order with mixed log levels in corked block', async () => {
// Set threshold to debug to allow debug messages
ioHost.logLevel = 'debug';
await (0, logging_1.withCorkedLogging)(async () => {
(0, logging_1.error)('error message');
(0, logging_1.warning)('warning message');
(0, logging_1.success)('success message');
(0, logging_1.debug)('debug message');
});
const calls = mockStderr.mock.calls.map(call => call[0]);
expect(calls).toEqual([
'error message\n',
'warning message\n',
'success message\n',
expect.stringMatching(/^\[\d{2}:\d{2}:\d{2}\] debug message\n$/),
]);
});
});
describe('CI mode behavior', () => {
test('correctly switches between stdout and stderr based on CI mode', () => {
ioHost.isCI = true;
(0, logging_1.warning)('warning in CI');
(0, logging_1.success)('success in CI');
(0, logging_1.error)('error in CI');
expect(mockStdout).toHaveBeenCalledWith('warning in CI\n');
expect(mockStdout).toHaveBeenCalledWith('success in CI\n');
expect(mockStderr).toHaveBeenCalledWith('error in CI\n');
ioHost.isCI = false;
(0, logging_1.warning)('warning not in CI');
(0, logging_1.success)('success not in CI');
(0, logging_1.error)('error not in CI');
expect(mockStderr).toHaveBeenCalledWith('warning not in CI\n');
expect(mockStderr).toHaveBeenCalledWith('success not in CI\n');
expect(mockStderr).toHaveBeenCalledWith('error not in CI\n');
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9nZ2luZy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibG9nZ2luZy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsa0RBQXVIO0FBQ3ZILGtFQUE2RDtBQUU3RCxRQUFRLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRTtJQUN2QixNQUFNLE1BQU0sR0FBRyx1QkFBUyxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDNUMsSUFBSSxVQUFxQixDQUFDO0lBQzFCLElBQUksVUFBcUIsQ0FBQztJQUUxQixNQUFNLFNBQVMsR0FBRyxDQUFDLEdBQVcsRUFBVSxFQUFFO1FBQ3hDLE1BQU0sU0FBUyxHQUFHLDBCQUEwQixDQUFDO1FBQzdDLE9BQU8sR0FBRyxDQUFDLE9BQU8sQ0FBQyxTQUFTLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDcEMsQ0FBQyxDQUFDO0lBRUYsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLE1BQU0sQ0FBQyxRQUFRLEdBQUcsTUFBTSxDQUFDO1FBQ3pCLE1BQU0sQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFDO1FBRXBCLFVBQVUsR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7UUFDdkIsVUFBVSxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUV2QixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxLQUFVLEVBQUUsRUFBRTtZQUNwRSxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDeEMsT0FBTyxJQUFJLENBQUM7UUFDZCxDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLEtBQVUsRUFBRSxFQUFFO1lBQ3BFLFVB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QUMsQ0FBQztZQUV6RCxNQUFNLENBQUMsSUFBSSxHQUFHLEtBQUssQ0FBQztZQUNwQixJQUFBLGlCQUFPLEVBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUM3QixJQUFBLGlCQUFPLEVBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUM3QixJQUFBLGVBQUssRUFBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBRXpCLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1lBQy9ELE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1lBQy9ELE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO1FBQy9ELENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGRhdGEsIHN1Y2Nlc3MsIGhpZ2hsaWdodCwgZXJyb3IsIHdhcm5pbmcsIGluZm8sIGRlYnVnLCB0cmFjZSwgd2l0aENvcmtlZExvZ2dpbmcgfSBmcm9tICcuLi8uLi8uLi9saWIvbG9nZ2luZyc7XG5pbXBvcnQgeyBDbGlJb0hvc3QgfSBmcm9tICcuLi8uLi8uLi9saWIvdG9vbGtpdC9jbGktaW8taG9zdCc7XG5cbmRlc2NyaWJlKCdsb2dnaW5nJywgKCkgPT4ge1xuICBjb25zdCBpb0hvc3QgPSBDbGlJb0hvc3QuaW5zdGFuY2Uoe30sIHRydWUpO1xuICBsZXQgbW9ja1N0ZG91dDogamVzdC5Nb2NrO1xuICBsZXQgbW9ja1N0ZGVycjogamVzdC5Nb2NrO1xuXG4gIGNvbnN0IHN0cmlwQW5zaSA9IChzdHI6IHN0cmluZyk6IHN0cmluZyA9PiB7XG4gICAgY29uc3QgYW5zaVJlZ2V4ID0gL1xcdTAwMWJcXFtbMC05O10qW2EtekEtWl0vZztcbiAgICByZXR1cm4gc3RyLnJlcGxhY2UoYW5zaVJlZ2V4LCAnJyk7XG4gIH07XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgaW9Ib3N0LmxvZ0xldmVsID0gJ2luZm8nO1xuICAgIGlvSG9zdC5pc0NJID0gZmFsc2U7XG5cbiAgICBtb2NrU3Rkb3V0ID0gamVzdC5mbigpO1xuICAgIG1vY2tTdGRlcnIgPSBqZXN0LmZuKCk7XG5cbiAgICBqZXN0LnNweU9uKHByb2Nlc3Muc3Rkb3V0LCAnd3JpdGUnKS5tb2NrSW1wbGVtZW50YXRpb24oKGNodW5rOiBhbnkpID0+IHtcbiAgICAgIG1vY2tTdGRvdXQoc3RyaXBBbnNpKGNodW5rLnRvU3RyaW5nKCkpKTtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH0pO1xuXG4gICAgamVzdC5zcHlPbihwcm9jZXNzLnN0ZGVyciwgJ3dyaXRlJykubW9ja0ltcGxlbWVudGF0aW9uKChjaHVuazogYW55KSA9PiB7XG4gICAgICBtb2NrU3RkZXJyKHN0cmlwQW5zaShjaHVuay50b1N0cmluZygpKSk7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBqZXN0LnJlc3RvcmVBbGxNb2NrcygpO1xuICB9KTtcblxuICBkZXNjcmliZSgnc3RyZWFtIHNlbGVjdGlvbicsICgpID0+IHtcbiAgICB0ZXN0KCdkYXRhKCkgYWx3YXlzIHdyaXRlcyB0byBzdGRvdXQgd2l0aCBib3RoIHN0eWxlcycsICgpID0+IHtcbiAgICAgIC8vIFN0cmluZyBzdHlsZVxuICAgICAgZGF0YSgndGVzdCBtZXNzYWdlJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZG91dCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3Rlc3QgbWVzc2FnZVxcbicpO1xuXG4gICAgICAvLyBPYmplY3Qgc3R5bGVcbiAgICAgIGRhdGEoeyBtZXNzYWdlOiAndGVzdCBtZXNzYWdlIDInIH0pO1xuICAgICAgZXhwZWN0KG1vY2tTdGRvdXQpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCd0ZXN0IG1lc3NhZ2UgMlxcbicpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdlcnJvcigpIGFsd2F5cyB3cml0ZXMgdG8gc3RkZXJyIHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICAvLyBTdHJpbmcgc3R5bGVcbiAgICAgIGVycm9yKCd0ZXN0IGVycm9yJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3Rlc3QgZXJyb3JcXG4nKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBlcnJvcih7IG1lc3NhZ2U6ICd0ZXN0IGVycm9yIDInIH0pO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCd0ZXN0IGVycm9yIDJcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3Rkb3V0KS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnaW5mbygpIHdyaXRlcyB0byBzdGRlcnIgYnkgZGVmYXVsdCB3aXRoIGJvdGggc3R5bGVzJywgKCkgPT4ge1xuICAgICAgLy8gU3RyaW5nIHN0eWxlXG4gICAgICBpbmZvKCd0ZXN0IHByaW50Jyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3Rlc3QgcHJpbnRcXG4nKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBpbmZvKHsgbWVzc2FnZTogJ3Rlc3QgcHJpbnQgMicgfSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3Rlc3QgcHJpbnQgMlxcbicpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRvdXQpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdpbmZvKCkgd3JpdGVzIHRvIHN0ZG91dCBpbiBDSSBtb2RlIHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICBpb0hvc3QuaXNDSSA9IHRydWU7XG4gICAgICAvLyBTdHJpbmcgc3R5bGVcbiAgICAgIGluZm8oJ3Rlc3QgcHJpbnQnKTtcbiAgICAgIGV4cGVjdChtb2NrU3Rkb3V0KS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgndGVzdCBwcmludFxcbicpO1xuXG4gICAgICAvLyBPYmplY3Qgc3R5bGVcbiAgICAgIGluZm8oeyBtZXNzYWdlOiAndGVzdCBwcmludCAyJyB9KTtcbiAgICAgIGV4cGVjdChtb2NrU3Rkb3V0KS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgndGVzdCBwcmludCAyXFxuJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2xvZyBsZXZlbHMnLCAoKSA9PiB7XG4gICAgdGVzdCgncmVzcGVjdHMgbG9nIGxldmVsIHNldHRpbmdzIHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICBpb0hvc3QubG9nTGV2ZWwgPSAnZXJyb3InO1xuXG4gICAgICAvLyBTdHJpbmcgc3R5bGVcbiAgICAgIGVycm9yKCdlcnJvciBtZXNzYWdlJyk7XG4gICAgICB3YXJuaW5nKCd3YXJuaW5nIG1lc3NhZ2UnKTtcbiAgICAgIGluZm8oJ3ByaW50IG1lc3NhZ2UnKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBlcnJvcih7IG1lc3NhZ2U6ICdlcnJvciBtZXNzYWdlIDInIH0pO1xuICAgICAgd2FybmluZyh7IG1lc3NhZ2U6ICd3YXJuaW5nIG1lc3NhZ2UgMicgfSk7XG4gICAgICBpbmZvKHsgbWVzc2FnZTogJ3ByaW50IG1lc3NhZ2UgMicgfSk7XG5cbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnZXJyb3IgbWVzc2FnZVxcbicpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdlcnJvciBtZXNzYWdlIDJcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS5ub3QudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3dhcm5pbmcgbWVzc2FnZVxcbicpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLm5vdC50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnd2FybmluZyBtZXNzYWdlIDJcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS5ub3QudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3ByaW50IG1lc3NhZ2VcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS5ub3QudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3ByaW50IG1lc3NhZ2UgMlxcbicpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnZGVidWcgbWVzc2FnZXMgb25seSBzaG93IGF0IGRlYnVnIGxldmVsIHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICBpb0hvc3QubG9nTGV2ZWwgPSAnaW5mbyc7XG4gICAgICBkZWJ1ZygnZGVidWcgbWVzc2FnZScpO1xuICAgICAgZGVidWcoeyBtZXNzYWdlOiAnZGVidWcgbWVzc2FnZSAyJyB9KTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gICAgICBpb0hvc3QubG9nTGV2ZWwgPSAnZGVidWcnO1xuICAgICAgZGVidWcoJ2RlYnVnIG1lc3NhZ2UnKTtcbiAgICAgIGRlYnVnKHsgbWVzc2FnZTogJ2RlYnVnIG1lc3NhZ2UgMicgfSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoXG4gICAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXlxcW1xcZHsyfTpcXGR7Mn06XFxkezJ9XFxdIGRlYnVnIG1lc3NhZ2VcXG4kLyksXG4gICAgICApO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15cXFtcXGR7Mn06XFxkezJ9OlxcZHsyfVxcXSBkZWJ1ZyBtZXNzYWdlIDJcXG4kLyksXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgdGVzdCgndHJhY2UgbWVzc2FnZXMgb25seSBzaG93IGF0IHRyYWNlIGxldmVsIHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICBpb0hvc3QubG9nTGV2ZWwgPSAnZGVidWcnO1xuICAgICAgdHJhY2UoJ3RyYWNlIG1lc3NhZ2UnKTtcbiAgICAgIHRyYWNlKHsgbWVzc2FnZTogJ3RyYWNlIG1lc3NhZ2UgMicgfSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcblxuICAgICAgaW9Ib3N0LmxvZ0xldmVsID0gJ3RyYWNlJztcbiAgICAgIHRyYWNlKCd0cmFjZSBtZXNzYWdlJyk7XG4gICAgICB0cmFjZSh7IG1lc3NhZ2U6ICd0cmFjZSBtZXNzYWdlIDInIH0pO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15cXFtcXGR7Mn06XFxkezJ9OlxcZHsyfVxcXSB0cmFjZSBtZXNzYWdlXFxuJC8pLFxuICAgICAgKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChcbiAgICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9eXFxbXFxkezJ9OlxcZHsyfTpcXGR7Mn1cXF0gdHJhY2UgbWVzc2FnZSAyXFxuJC8pLFxuICAgICAgKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2Zvcm1hdHRlZCBtZXNzYWdlcycsICgpID0+IHtcbiAgICB0ZXN0KCdoYW5kbGVzIGZvcm1hdCBzdHJpbmdzIGNvcnJlY3RseSB3aXRoIGJvdGggc3R5bGVzJywgKCkgPT4ge1xuICAgICAgLy8gU3RyaW5nIHN0eWxlXG4gICAgICBpbmZvKCdIZWxsbyAlcywgeW91IGhhdmUgJWQgbWVzc2FnZXMnLCAnVXNlcicsIDUpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdIZWxsbyBVc2VyLCB5b3UgaGF2ZSA1IG1lc3NhZ2VzXFxuJyk7XG5cbiAgICAgIC8vIE9iamVjdCBzdHlsZVxuICAgICAgaW5mbyh7IG1lc3NhZ2U6ICdIZWxsbyAlcywgeW91IGhhdmUgJWQgbWVzc2FnZXMnIH0sICdVc2VyJywgNSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ0hlbGxvIFVzZXIsIHlvdSBoYXZlIDUgbWVzc2FnZXNcXG4nKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ2hhbmRsZXMgb2JqZWN0cyBpbiBmb3JtYXQgc3RyaW5ncyB3aXRoIGJvdGggc3R5bGVzJywgKCkgPT4ge1xuICAgICAgY29uc3Qgb2JqID0geyBuYW1lOiAndGVzdCcgfTtcbiAgICAgIC8vIFN0cmluZyBzdHlsZVxuICAgICAgaW5mbygnT2JqZWN0OiAlaicsIG9iaik7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ09iamVjdDoge1wibmFtZVwiOlwidGVzdFwifVxcbicpO1xuXG4gICAgICAvLyBPYmplY3Qgc3R5bGVcbiAgICAgIGluZm8oeyBtZXNzYWdlOiAnT2JqZWN0OiAlaicgfSwgb2JqKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnT2JqZWN0OiB7XCJuYW1lXCI6XCJ0ZXN0XCJ9XFxuJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdoYW5kbGVzIG11bHRpcGxlIHN0eWxlIGNoYW5nZXMgaW4gc2luZ2xlIGNhbGwnLCAoKSA9PiB7XG4gICAgICBjb25zdCBvYmogPSB7IGlkOiAxMjMgfTtcbiAgICAgIHN1Y2Nlc3MoJ1Byb2Nlc3NpbmcgJXM6ICVqIGF0ICVkJSUnLCAndGFzaycsIG9iaiwgNTApO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKFxuICAgICAgICAnUHJvY2Vzc2luZyB0YXNrOiB7XCJpZFwiOjEyM30gYXQgNTAlXFxuJyxcbiAgICAgICk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdzdHlsZWQgb3V0cHV0JywgKCkgPT4ge1xuICAgIHRlc3QoJ3N1Y2Nlc3MoKSBhZGRzIGdyZWVuIGNvbG9yIHRvIG91dHB1dCB3aXRoIGJvdGggc3R5bGVzJywgKCkgPT4ge1xuICAgICAgLy8gU3RyaW5nIHN0eWxlXG4gICAgICBzdWNjZXNzKCdvcGVyYXRpb24gY29tcGxldGVkJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ29wZXJhdGlvbiBjb21wbGV0ZWRcXG4nKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBzdWNjZXNzKHsgbWVzc2FnZTogJ29wZXJhdGlvbiBjb21wbGV0ZWQgMicgfSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ29wZXJhdGlvbiBjb21wbGV0ZWQgMlxcbicpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnaGlnaGxpZ2h0KCkgYWRkcyBib2xkIGZvcm1hdHRpbmcgdG8gb3V0cHV0IHdpdGggYm90aCBzdHlsZXMnLCAoKSA9PiB7XG4gICAgICAvLyBTdHJpbmcgc3R5bGVcbiAgICAgIGhpZ2hsaWdodCgnaW1wb3J0YW50IG1lc3NhZ2UnKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnaW1wb3J0YW50IG1lc3NhZ2VcXG4nKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBoaWdobGlnaHQoeyBtZXNzYWdlOiAnaW1wb3J0YW50IG1lc3NhZ2UgMicgfSk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ2ltcG9ydGFudCBtZXNzYWdlIDJcXG4nKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3N1Y2Nlc3MgaGFuZGxlcyBmb3JtYXQgc3RyaW5ncyB3aXRoIHN0eWxpbmcnLCAoKSA9PiB7XG4gICAgICBzdWNjZXNzKCdjb21wbGV0ZWQgdGFzayAlZCBvZiAlZCcsIDEsIDMpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdjb21wbGV0ZWQgdGFzayAxIG9mIDNcXG4nKTtcblxuICAgICAgLy8gUmVtb3ZlIHRoZSBjb2RlIGZyb20gdGhlIHRlc3Qgc2luY2UgaXQncyBhbiBpbXBsZW1lbnRhdGlvbiBkZXRhaWxcbiAgICAgIHN1Y2Nlc3MoeyBtZXNzYWdlOiAnY29tcGxldGVkIHRhc2sgJWQgb2YgJWQnIH0sIDIsIDMpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdjb21wbGV0ZWQgdGFzayAyIG9mIDNcXG4nKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ2hpZ2hsaWdodCBoYW5kbGVzIGNvbXBsZXggb2JqZWN0cyB3aXRoIHN0eWxpbmcnLCAoKSA9PiB7XG4gICAgICBjb25zdCBjb21wbGV4T2JqID0geyBzdGF0dXM6ICdhY3RpdmUnLCBjb3VudDogNDIgfTtcbiAgICAgIGhpZ2hsaWdodCgnU3RhdHVzOiAlaicsIGNvbXBsZXhPYmopO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdTdGF0dXM6IHtcInN0YXR1c1wiOlwiYWN0aXZlXCIsXCJjb3VudFwiOjQyfVxcbicpO1xuXG4gICAgICAvLyBSZW1vdmUgdGhlIGNvZGUgZnJvbSB0aGUgdGVzdCBzaW5jZSBpdCdzIGFuIGltcGxlbWVudGF0aW9uIGRldGFpbFxuICAgICAgaGlnaGxpZ2h0KHsgbWVzc2FnZTogJ1N0YXR1czogJWonIH0sIGNvbXBsZXhPYmopO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdTdGF0dXM6IHtcInN0YXR1c1wiOlwiYWN0aXZlXCIsXCJjb3VudFwiOjQyfVxcbicpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnZWRnZSBjYXNlcycsICgpID0+IHtcbiAgICB0ZXN0KCdoYW5kbGVzIG51bGwgYW5kIHVuZGVmaW5lZCBhcmd1bWVudHMgd2l0aCBib3RoIHN0eWxlcycsICgpID0+IHtcbiAgICAgIC8vIFN0cmluZyBzdHlsZVxuICAgICAgaW5mbygnVmFsdWVzOiAlcywgJXMnLCBudWxsLCB1bmRlZmluZWQpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdWYWx1ZXM6IG51bGwsIHVuZGVmaW5lZFxcbicpO1xuXG4gICAgICAvLyBPYmplY3Qgc3R5bGVcbiAgICAgIGluZm8oeyBtZXNzYWdlOiAnVmFsdWVzOiAlcywgJXMnIH0sIG51bGwsIHVuZGVmaW5lZCk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ1ZhbHVlczogbnVsbCwgdW5kZWZpbmVkXFxuJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdoYW5kbGVzIGNpcmN1bGFyIHJlZmVyZW5jZXMgaW4gb2JqZWN0cyB3aXRoIGJvdGggc3R5bGVzJywgKCkgPT4ge1xuICAgICAgY29uc3Qgb2JqOiBhbnkgPSB7IG5hbWU6ICd0ZXN0JyB9O1xuICAgICAgb2JqLnNlbGYgPSBvYmo7XG5cbiAgICAgIC8vIFN0cmluZyBzdHlsZVxuICAgICAgaW5mbygnT2JqZWN0OiAlaicsIG9iaik7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LnN0cmluZ0NvbnRhaW5pbmcoJ1tDaXJjdWxhcicpKTtcblxuICAgICAgLy8gT2JqZWN0IHN0eWxlXG4gICAgICBpbmZvKHsgbWVzc2FnZTogJ09iamVjdDogJWonIH0sIG9iaik7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LnN0cmluZ0NvbnRhaW5pbmcoJ1tDaXJjdWxhcicpKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ21lc3NhZ2UgY29kZXMnLCAoKSA9PiB7XG4gICAgdGVzdCgndmFsaWRhdGVzIG1lc3NhZ2UgY29kZXMgY29ycmVjdGx5JywgKCkgPT4ge1xuICAgICAgLy8gVmFsaWQgY29kZXNcbiAgICAgIGV4cGVjdCgoKSA9PiBlcnJvcih7IG1lc3NhZ2U6ICd0ZXN0JywgY29kZTogJ0NES19UT09MS0lUX0UwMDAxJyB9KSkubm90LnRvVGhyb3coKTtcbiAgICAgIGV4cGVjdCgoKSA9PiB3YXJuaW5nKHsgbWVzc2FnZTogJ3Rlc3QnLCBjb2RlOiAnQ0RLX0FTU0VUU19XNDk5OScgfSkpLm5vdC50b1Rocm93KCk7XG4gICAgICBleHBlY3QoKCkgPT4gaW5mbyh7IG1lc3NhZ2U6ICd0ZXN0JywgY29kZTogJ0NES19TREtfSTAwMDAnIH0pKS5ub3QudG9UaHJvdygpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgndXNlcyBkZWZhdWx0IGNvZGVzIHdoZW4gbm9uZSBwcm92aWRlZCcsICgpID0+IHtcbiAgICAgIGVycm9yKCd0ZXN0IGVycm9yJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0LnN0cmluZ0NvbnRhaW5pbmcoJ3Rlc3QgZXJyb3InKSk7XG4gICAgICAvLyBXb3VsZCBuZWVkIHRvIG1vZGlmeSB0aGUgY29kZSB0byBleHBvc2UgdGhlIGFjdHVhbCBtZXNzYWdlIGNvZGUgZm9yIHZlcmlmaWNhdGlvblxuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY29ya2VkIGxvZ2dpbmcnLCAoKSA9PiB7XG4gICAgdGVzdCgnYnVmZmVycyBtZXNzYWdlcyB3aGVuIGNvcmtlZCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHdpdGhDb3JrZWRMb2dnaW5nKGFzeW5jICgpID0+IHtcbiAgICAgICAgaW5mbygnbWVzc2FnZSAxJyk7XG4gICAgICAgIGluZm8oeyBtZXNzYWdlOiAnbWVzc2FnZSAyJyB9KTtcbiAgICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdtZXNzYWdlIDFcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnbWVzc2FnZSAyXFxuJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdoYW5kbGVzIG5lc3RlZCBjb3JraW5nIGNvcnJlY3RseScsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IHdpdGhDb3JrZWRMb2dnaW5nKGFzeW5jICgpID0+IHtcbiAgICAgICAgaW5mbygnb3V0ZXIgMScpO1xuICAgICAgICBhd2FpdCB3aXRoQ29ya2VkTG9nZ2luZyhhc3luYyAoKSA9PiB7XG4gICAgICAgICAgaW5mbyh7IG1lc3NhZ2U6ICdpbm5lcicgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBpbmZvKHsgbWVzc2FnZTogJ291dGVyIDInIH0pO1xuICAgICAgICBleHBlY3QobW9ja1N0ZGVycikubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFRpbWVzKDMpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdvdXRlciAxXFxuJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ2lubmVyXFxuJyk7XG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ291dGVyIDJcXG4nKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ2hhbmRsZXMgZXJyb3JzIGluIGNvcmtlZCBibG9jayB3aGlsZSBwcmVzZXJ2aW5nIGJ1ZmZlcicsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IGV4cGVjdCh3aXRoQ29ya2VkTG9nZ2luZyhhc3luYyAoKSA9PiB7XG4gICAgICAgIGluZm8oJ21lc3NhZ2UgMScpO1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Rlc3QgZXJyb3InKTtcbiAgICAgIH0pKS5yZWplY3RzLnRvVGhyb3coJ3Rlc3QgZXJyb3InKTtcblxuICAgICAgLy8gVGhlIGJ1ZmZlcmVkIG1lc3NhZ2Ugc2hvdWxkIHN0aWxsIGJlIHByaW50ZWQgZXZlbiBpZiB0aGUgYmxvY2sgdGhyb3dzXG4gICAgICBleHBlY3QobW9ja1N0ZGVycikudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ21lc3NhZ2UgMVxcbicpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnbWFpbnRhaW5zIGNvcnJlY3Qgb3JkZXIgd2l0aCBtaXhlZCBsb2cgbGV2ZWxzIGluIGNvcmtlZCBibG9jaycsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFNldCB0aHJlc2hvbGQgdG8gZGVidWcgdG8gYWxsb3cgZGVidWcgbWVzc2FnZXNcbiAgICAgIGlvSG9zdC5sb2dMZXZlbCA9ICdkZWJ1Zyc7XG5cbiAgICAgIGF3YWl0IHdpdGhDb3JrZWRMb2dnaW5nKGFzeW5jICgpID0+IHtcbiAgICAgICAgZXJyb3IoJ2Vycm9yIG1lc3NhZ2UnKTtcbiAgICAgICAgd2FybmluZygnd2FybmluZyBtZXNzYWdlJyk7XG4gICAgICAgIHN1Y2Nlc3MoJ3N1Y2Nlc3MgbWVzc2FnZScpO1xuICAgICAgICBkZWJ1ZygnZGVidWcgbWVzc2FnZScpO1xuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IGNhbGxzID0gbW9ja1N0ZGVyci5tb2NrLmNhbGxzLm1hcChjYWxsID0+IGNhbGxbMF0pO1xuICAgICAgZXhwZWN0KGNhbGxzKS50b0VxdWFsKFtcbiAgICAgICAgJ2Vycm9yIG1lc3NhZ2VcXG4nLFxuICAgICAgICAnd2FybmluZyBtZXNzYWdlXFxuJyxcbiAgICAgICAgJ3N1Y2Nlc3MgbWVzc2FnZVxcbicsXG4gICAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXlxcW1xcZHsyfTpcXGR7Mn06XFxkezJ9XFxdIGRlYnVnIG1lc3NhZ2VcXG4kLyksXG4gICAgICBdKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0NJIG1vZGUgYmVoYXZpb3InLCAoKSA9PiB7XG4gICAgdGVzdCgnY29ycmVjdGx5IHN3aXRjaGVzIGJldHdlZW4gc3Rkb3V0IGFuZCBzdGRlcnIgYmFzZWQgb24gQ0kgbW9kZScsICgpID0+IHtcbiAgICAgIGlvSG9zdC5pc0NJID0gdHJ1ZTtcbiAgICAgIHdhcm5pbmcoJ3dhcm5pbmcgaW4gQ0knKTtcbiAgICAgIHN1Y2Nlc3MoJ3N1Y2Nlc3MgaW4gQ0knKTtcbiAgICAgIGVycm9yKCdlcnJvciBpbiBDSScpO1xuXG4gICAgICBleHBlY3QobW9ja1N0ZG91dCkudG9IYXZlQmVlbkNhbGxlZFdpdGgoJ3dhcm5pbmcgaW4gQ0lcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3Rkb3V0KS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnc3VjY2VzcyBpbiBDSVxcbicpO1xuICAgICAgZXhwZWN0KG1vY2tTdGRlcnIpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKCdlcnJvciBpbiBDSVxcbicpO1xuXG4gICAgICBpb0hvc3QuaXNDSSA9IGZhbHNlO1xuICAgICAgd2FybmluZygnd2FybmluZyBub3QgaW4gQ0knKTtcbiAgICAgIHN1Y2Nlc3MoJ3N1Y2Nlc3Mgbm90IGluIENJJyk7XG4gICAgICBlcnJvcignZXJyb3Igbm90IGluIENJJyk7XG5cbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnd2FybmluZyBub3QgaW4gQ0lcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnc3VjY2VzcyBub3QgaW4gQ0lcXG4nKTtcbiAgICAgIGV4cGVjdChtb2NrU3RkZXJyKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCgnZXJyb3Igbm90IGluIENJXFxuJyk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=