aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
433 lines • 52.4 kB
JavaScript
"use strict";
/* eslint-disable import/order */
Object.defineProperty(exports, "__esModule", { value: true });
const mockDeployStack = jest.fn();
jest.mock('../../lib/api/deploy-stack', () => ({
deployStack: mockDeployStack,
}));
const api_1 = require("../../lib/api");
const mock_sdk_1 = require("../util/mock-sdk");
let bootstrapper;
let mockGetPolicyIamCode;
let mockCreatePolicyIamCode;
let stderrMock;
beforeEach(() => {
bootstrapper = new api_1.Bootstrapper({ source: 'default' });
stderrMock = jest.spyOn(process.stderr, 'write').mockImplementation(() => { return true; });
});
afterEach(() => {
stderrMock.mockRestore();
});
function mockTheToolkitInfo(stackProps) {
const sdk = new mock_sdk_1.MockSdk();
api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.fromStack((0, mock_sdk_1.mockBootstrapStack)(sdk, stackProps)));
}
describe('Bootstrapping v2', () => {
const env = {
account: '123456789012',
region: 'us-east-1',
name: 'mock',
};
let sdk;
beforeEach(() => {
sdk = new mock_sdk_1.MockSdkProvider({ realSdk: false });
// By default, we'll return a non-found toolkit info
api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.bootstrapStackNotFoundInfo('BootstrapStack'));
const value = {
Policy: {
PolicyName: 'my-policy',
Arn: 'arn:aws:iam::0123456789012:policy/my-policy',
},
};
mockGetPolicyIamCode = jest.fn().mockReturnValue(value);
mockCreatePolicyIamCode = jest.fn().mockReturnValue(value);
sdk.stubIam({
createPolicy: mockCreatePolicyIamCode,
getPolicy: mockGetPolicyIamCode,
});
});
afterEach(() => {
mockDeployStack.mockClear();
});
test('passes the bucket name as a CFN parameter', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
bucketName: 'my-bucket-name',
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
FileAssetsBucketName: 'my-bucket-name',
PublicAccessBlockConfiguration: 'true',
}),
}));
});
test('passes the KMS key ID as a CFN parameter', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
kmsKeyId: 'my-kms-key-id',
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
FileAssetsBucketKmsKeyId: 'my-kms-key-id',
PublicAccessBlockConfiguration: 'true',
}),
}));
});
test('passes false to PublicAccessBlockConfiguration', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
publicAccessBlockConfiguration: false,
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
PublicAccessBlockConfiguration: 'false',
}),
}));
});
test('passes true to PermissionsBoundary', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
examplePermissionsBoundary: true,
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
InputPermissionsBoundary: 'cdk-hnb659fds-permissions-boundary',
}),
}));
});
test('passes value to PermissionsBoundary', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'InputPermissionsBoundary',
ParameterValue: 'existing-pb',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
customPermissionsBoundary: 'permissions-boundary-name',
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
InputPermissionsBoundary: 'permissions-boundary-name',
}),
}));
expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([
expect.arrayContaining([
expect.stringMatching(/Changing permissions boundary from existing-pb to permissions-boundary-name/),
]),
]));
});
test('permission boundary switch message does not appear', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'InputPermissionsBoundary',
ParameterValue: '',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk);
expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([
expect.not.arrayContaining([
expect.stringMatching(/Changing permissions boundary/),
]),
]));
});
test('adding new permissions boundary', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'InputPermissionsBoundary',
ParameterValue: '',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
customPermissionsBoundary: 'permissions-boundary-name',
},
});
expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([
expect.arrayContaining([
expect.stringMatching(/Adding new permissions boundary permissions-boundary-name/),
]),
]));
});
test('removing existing permissions boundary', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'InputPermissionsBoundary',
ParameterValue: 'permissions-boundary-name',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {},
});
expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([
expect.arrayContaining([
expect.stringMatching(/Removing existing permissions boundary permissions-boundary-name/),
]),
]));
});
test('adding permission boundary with path in policy name', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'InputPermissionsBoundary',
ParameterValue: '',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
customPermissionsBoundary: 'permissions-boundary-name/with/path',
},
});
expect(stderrMock.mock.calls).toEqual(expect.arrayContaining([
expect.arrayContaining([
expect.stringMatching(/Adding new permissions boundary permissions-boundary-name\/with\/path/),
]),
]));
});
test('passing trusted accounts without CFN managed policies results in an error', async () => {
await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
trustedAccounts: ['123456789012'],
},
}))
.rejects
.toThrow(/--cloudformation-execution-policies/);
});
test('passing trusted accounts without CFN managed policies on the existing stack results in an error', async () => {
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'CloudFormationExecutionPolicies',
ParameterValue: '',
},
],
});
await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
trustedAccounts: ['123456789012'],
},
}))
.rejects
.toThrow(/--cloudformation-execution-policies/);
});
test('passing no CFN managed policies without trusted accounts is okay', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
CloudFormationExecutionPolicies: '',
}),
}));
});
test('passing trusted accounts for lookup generates the correct stack parameter', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
trustedAccountsForLookup: ['123456789012'],
cloudFormationExecutionPolicies: ['aws://foo'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
TrustedAccountsForLookup: '123456789012',
}),
}));
});
test('allow adding trusted account if there was already a policy on the stack', async () => {
// GIVEN
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'CloudFormationExecutionPolicies',
ParameterValue: 'arn:aws:something',
},
],
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
trustedAccounts: ['123456789012'],
},
});
// Did not throw
});
test('Do not allow downgrading bootstrap stack version', async () => {
// GIVEN
mockTheToolkitInfo({
Outputs: [
{
OutputKey: 'BootstrapVersion',
OutputValue: '999',
},
],
});
await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
})).resolves.toEqual(expect.objectContaining({ noOp: true }));
});
test('Do not allow overwriting bootstrap stack from a different vendor', async () => {
// GIVEN
mockTheToolkitInfo({
Parameters: [
{
ParameterKey: 'BootstrapVariant',
ParameterValue: 'JoeSchmoe',
},
],
});
await expect(bootstrapper.bootstrapEnvironment(env, sdk, {})).resolves.toEqual(expect.objectContaining({ noOp: true }));
});
test('bootstrap template has the right exports', async () => {
let template;
mockDeployStack.mockImplementation((args) => {
template = args.stack.template;
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
const exports = Object.values(template.Outputs ?? {})
.filter((o) => o.Export !== undefined)
.map((o) => o.Export.Name);
expect(exports).toEqual([
// This used to be used by aws-s3-assets
{ 'Fn::Sub': 'CdkBootstrap-${Qualifier}-FileAssetKeyArn' },
]);
});
describe('termination protection', () => {
test('stack is not termination protected by default', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
stack: expect.objectContaining({
terminationProtection: false,
}),
}));
});
test('stack is termination protected when option is set', async () => {
await bootstrapper.bootstrapEnvironment(env, sdk, {
terminationProtection: true,
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
stack: expect.objectContaining({
terminationProtection: true,
}),
}));
});
test('termination protection is left alone when option is not given', async () => {
mockTheToolkitInfo({
EnableTerminationProtection: true,
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
stack: expect.objectContaining({
terminationProtection: true,
}),
}));
});
test('termination protection can be switched off', async () => {
mockTheToolkitInfo({
EnableTerminationProtection: true,
});
await bootstrapper.bootstrapEnvironment(env, sdk, {
terminationProtection: false,
parameters: {
cloudFormationExecutionPolicies: ['arn:policy'],
},
});
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
stack: expect.objectContaining({
terminationProtection: false,
}),
}));
});
});
describe('KMS key', () => {
test.each([
// Default case
[undefined, 'AWS_MANAGED_KEY'],
// Create a new key
[true, ''],
// Don't create a new key
[false, 'AWS_MANAGED_KEY'],
])('(new stack) createCustomerMasterKey=%p => parameter becomes %p ', async (createCustomerMasterKey, paramKeyId) => {
// GIVEN: no existing stack
// WHEN
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
createCustomerMasterKey,
cloudFormationExecutionPolicies: ['arn:booh'],
},
});
// THEN
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
FileAssetsBucketKmsKeyId: paramKeyId,
}),
}));
});
test.each([
// Old bootstrap stack being upgraded to new one
[undefined, undefined, 'AWS_MANAGED_KEY'],
// There is a value, user doesn't request a change
['arn:aws:key', undefined, undefined],
// Switch off existing key
['arn:aws:key', false, 'AWS_MANAGED_KEY'],
// Switch on existing key
['AWS_MANAGED_KEY', true, ''],
])('(upgrading) current param %p, createCustomerMasterKey=%p => parameter becomes %p ', async (currentKeyId, createCustomerMasterKey, paramKeyId) => {
// GIVEN
mockTheToolkitInfo({
Parameters: currentKeyId ? [
{
ParameterKey: 'FileAssetsBucketKmsKeyId',
ParameterValue: currentKeyId,
},
] : undefined,
});
// WHEN
await bootstrapper.bootstrapEnvironment(env, sdk, {
parameters: {
createCustomerMasterKey,
cloudFormationExecutionPolicies: ['arn:booh'],
},
});
// THEN
expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
parameters: expect.objectContaining({
FileAssetsBucketKmsKeyId: paramKeyId,
}),
}));
});
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwMi50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYm9vdHN0cmFwMi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxpQ0FBaUM7O0FBRWpDLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQztBQUVsQyxJQUFJLENBQUMsSUFBSSxDQUFDLDRCQUE0QixFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7SUFDN0MsV0FBVyxFQUFFLGVBQWU7Q0FDN0IsQ0FBQyxDQUFDLENBQUM7QUFHSix1Q0FBOEU7QUFDOUUsK0NBQWdGO0FBRWhGLElBQUksWUFBMEIsQ0FBQztBQUMvQixJQUFJLG9CQUF5RixDQUFDO0FBQzlGLElBQUksdUJBQWtHLENBQUM7QUFDdkcsSUFBSSxVQUE0QixDQUFDO0FBRWpDLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxZQUFZLEdBQUcsSUFBSSxrQkFBWSxDQUFDLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7SUFDdkQsVUFBVSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsQ0FBQyxrQkFBa0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxPQUFPLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQzlGLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxDQUFDLEdBQUcsRUFBRTtJQUNiLFVBQVUsQ0FBQyxXQUFXLEVBQUUsQ0FBQztBQUMzQixDQUFDLENBQUMsQ0FBQztBQUVILFNBQVMsa0JBQWtCLENBQUMsVUFBNkM7SUFDdkUsTUFBTSxHQUFHLEdBQUcsSUFBSSxrQkFBTyxFQUFFLENBQUM7SUFDekIsaUJBQW1CLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxpQkFBVyxDQUFDLFNBQVMsQ0FBQyxJQUFBLDZCQUFrQixFQUFDLEdBQUcsRUFBRSxVQUFVLENB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b3JkZXIgKi9cblxuY29uc3QgbW9ja0RlcGxveVN0YWNrID0gamVzdC5mbigpO1xuXG5qZXN0Lm1vY2soJy4uLy4uL2xpYi9hcGkvZGVwbG95LXN0YWNrJywgKCkgPT4gKHtcbiAgZGVwbG95U3RhY2s6IG1vY2tEZXBsb3lTdGFjayxcbn0pKTtcblxuaW1wb3J0IHsgSUFNIH0gZnJvbSAnYXdzLXNkayc7XG5pbXBvcnQgeyBCb290c3RyYXBwZXIsIERlcGxveVN0YWNrT3B0aW9ucywgVG9vbGtpdEluZm8gfSBmcm9tICcuLi8uLi9saWIvYXBpJztcbmltcG9ydCB7IG1vY2tCb290c3RyYXBTdGFjaywgTW9ja1NkaywgTW9ja1Nka1Byb3ZpZGVyIH0gZnJvbSAnLi4vdXRpbC9tb2NrLXNkayc7XG5cbmxldCBib290c3RyYXBwZXI6IEJvb3RzdHJhcHBlcjtcbmxldCBtb2NrR2V0UG9saWN5SWFtQ29kZTogKHBhcmFtczogSUFNLlR5cGVzLkdldFBvbGljeVJlcXVlc3QpID0+IElBTS5UeXBlcy5HZXRQb2xpY3lSZXNwb25zZTtcbmxldCBtb2NrQ3JlYXRlUG9saWN5SWFtQ29kZTogKHBhcmFtczogSUFNLlR5cGVzLkNyZWF0ZVBvbGljeVJlcXVlc3QpID0+IElBTS5UeXBlcy5DcmVhdGVQb2xpY3lSZXNwb25zZTtcbmxldCBzdGRlcnJNb2NrOiBqZXN0LlNweUluc3RhbmNlO1xuXG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgYm9vdHN0cmFwcGVyID0gbmV3IEJvb3RzdHJhcHBlcih7IHNvdXJjZTogJ2RlZmF1bHQnIH0pO1xuICBzdGRlcnJNb2NrID0gamVzdC5zcHlPbihwcm9jZXNzLnN0ZGVyciwgJ3dyaXRlJykubW9ja0ltcGxlbWVudGF0aW9uKCgpID0+IHsgcmV0dXJuIHRydWU7IH0pO1xufSk7XG5cbmFmdGVyRWFjaCgoKSA9PiB7XG4gIHN0ZGVyck1vY2subW9ja1Jlc3RvcmUoKTtcbn0pO1xuXG5mdW5jdGlvbiBtb2NrVGhlVG9vbGtpdEluZm8oc3RhY2tQcm9wczogUGFydGlhbDxBV1MuQ2xvdWRGb3JtYXRpb24uU3RhY2s+KSB7XG4gIGNvbnN0IHNkayA9IG5ldyBNb2NrU2RrKCk7XG4gIChUb29sa2l0SW5mbyBhcyBhbnkpLmxvb2t1cCA9IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShUb29sa2l0SW5mby5mcm9tU3RhY2sobW9ja0Jvb3RzdHJhcFN0YWNrKHNkaywgc3RhY2tQcm9wcykpKTtcbn1cblxuZGVzY3JpYmUoJ0Jvb3RzdHJhcHBpbmcgdjInLCAoKSA9PiB7XG4gIGNvbnN0IGVudiA9IHtcbiAgICBhY2NvdW50OiAnMTIzNDU2Nzg5MDEyJyxcbiAgICByZWdpb246ICd1cy1lYXN0LTEnLFxuICAgIG5hbWU6ICdtb2NrJyxcbiAgfTtcblxuICBsZXQgc2RrOiBNb2NrU2RrUHJvdmlkZXI7XG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIHNkayA9IG5ldyBNb2NrU2RrUHJvdmlkZXIoeyByZWFsU2RrOiBmYWxzZSB9KTtcbiAgICAvLyBCeSBkZWZhdWx0LCB3ZSdsbCByZXR1cm4gYSBub24tZm91bmQgdG9vbGtpdCBpbmZvXG4gICAgKFRvb2xraXRJbmZvIGFzIGFueSkubG9va3VwID0gamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFRvb2xraXRJbmZvLmJvb3RzdHJhcFN0YWNrTm90Rm91bmRJbmZvKCdCb290c3RyYXBTdGFjaycpKTtcbiAgICBjb25zdCB2YWx1ZSA9IHtcbiAgICAgIFBvbGljeToge1xuICAgICAgICBQb2xpY3lOYW1lOiAnbXktcG9saWN5JyxcbiAgICAgICAgQXJuOiAnYXJuOmF3czppYW06OjAxMjM0NTY3ODkwMTI6cG9saWN5L215LXBvbGljeScsXG4gICAgICB9LFxuICAgIH07XG4gICAgbW9ja0dldFBvbGljeUlhbUNvZGUgPSBqZXN0LmZuKCkubW9ja1JldHVyblZhbHVlKHZhbHVlKTtcbiAgICBtb2NrQ3JlYXRlUG9saWN5SWFtQ29kZSA9IGplc3QuZm4oKS5tb2NrUmV0dXJuVmFsdWUodmFsdWUpO1xuICAgIHNkay5zdHViSWFtKHtcbiAgICAgIGNyZWF0ZVBvbGljeTogbW9ja0NyZWF0ZVBvbGljeUlhbUNvZGUsXG4gICAgICBnZXRQb2xpY3k6IG1vY2tHZXRQb2xpY3lJYW1Db2RlLFxuICAgIH0pO1xuICB9KTtcblxuICBhZnRlckVhY2goKCkgPT4ge1xuICAgIG1vY2tEZXBsb3lTdGFjay5tb2NrQ2xlYXIoKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2VzIHRoZSBidWNrZXQgbmFtZSBhcyBhIENGTiBwYXJhbWV0ZXInLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGJ1Y2tldE5hbWU6ICdteS1idWNrZXQtbmFtZScsXG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgRmlsZUFzc2V0c0J1Y2tldE5hbWU6ICdteS1idWNrZXQtbmFtZScsXG4gICAgICAgIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjogJ3RydWUnLFxuICAgICAgfSksXG4gICAgfSkpO1xuICB9KTtcblxuICB0ZXN0KCdwYXNzZXMgdGhlIEtNUyBrZXkgSUQgYXMgYSBDRk4gcGFyYW1ldGVyJywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgICAga21zS2V5SWQ6ICdteS1rbXMta2V5LWlkJyxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBwYXJhbWV0ZXJzOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIEZpbGVBc3NldHNCdWNrZXRLbXNLZXlJZDogJ215LWttcy1rZXktaWQnLFxuICAgICAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246ICd0cnVlJyxcbiAgICAgIH0pLFxuICAgIH0pKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2VzIGZhbHNlIHRvIFB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbicsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46cG9saWN5J10sXG4gICAgICAgIHB1YmxpY0FjY2Vzc0Jsb2NrQ29uZmlndXJhdGlvbjogZmFsc2UsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246ICdmYWxzZScsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyB0cnVlIHRvIFBlcm1pc3Npb25zQm91bmRhcnknLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGV4YW1wbGVQZXJtaXNzaW9uc0JvdW5kYXJ5OiB0cnVlLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5OiAnY2RrLWhuYjY1OWZkcy1wZXJtaXNzaW9ucy1ib3VuZGFyeScsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyB2YWx1ZSB0byBQZXJtaXNzaW9uc0JvdW5kYXJ5JywgYXN5bmMgKCkgPT4ge1xuICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICBQYXJhbWV0ZXJzOiBbXG4gICAgICAgIHtcbiAgICAgICAgICBQYXJhbWV0ZXJLZXk6ICdJbnB1dFBlcm1pc3Npb25zQm91bmRhcnknLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnZXhpc3RpbmctcGInLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgY3VzdG9tUGVybWlzc2lvbnNCb3VuZGFyeTogJ3Blcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWUnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5OiAncGVybWlzc2lvbnMtYm91bmRhcnktbmFtZScsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gICAgZXhwZWN0KHN0ZGVyck1vY2subW9jay5jYWxscykudG9FcXVhbChleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgIGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL0NoYW5naW5nIHBlcm1pc3Npb25zIGJvdW5kYXJ5IGZyb20gZXhpc3RpbmctcGIgdG8gcGVybWlzc2lvbnMtYm91bmRhcnktbmFtZS8pLFxuICAgICAgXSksXG4gICAgXSkpO1xuICB9KTtcblxuICB0ZXN0KCdwZXJtaXNzaW9uIGJvdW5kYXJ5IHN3aXRjaCBtZXNzYWdlIGRvZXMgbm90IGFwcGVhcicsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5JyxcbiAgICAgICAgICBQYXJhbWV0ZXJWYWx1ZTogJycsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkayk7XG5cbiAgICBleHBlY3Qoc3RkZXJyTW9jay5tb2NrLmNhbGxzKS50b0VxdWFsKGV4cGVjdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgZXhwZWN0Lm5vdC5hcnJheUNvbnRhaW5pbmcoW1xuICAgICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL0NoYW5naW5nIHBlcm1pc3Npb25zIGJvdW5kYXJ5LyksXG4gICAgICBdKSxcbiAgICBdKSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2FkZGluZyBuZXcgcGVybWlzc2lvbnMgYm91bmRhcnknLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0lucHV0UGVybWlzc2lvbnNCb3VuZGFyeScsXG4gICAgICAgICAgUGFyYW1ldGVyVmFsdWU6ICcnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgY3VzdG9tUGVybWlzc2lvbnNCb3VuZGFyeTogJ3Blcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWUnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChzdGRlcnJNb2NrLm1vY2suY2FsbHMpLnRvRXF1YWwoZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9BZGRpbmcgbmV3IHBlcm1pc3Npb25zIGJvdW5kYXJ5IHBlcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWUvKSxcbiAgICAgIF0pLFxuICAgIF0pKTtcbiAgfSk7XG5cbiAgdGVzdCgncmVtb3ZpbmcgZXhpc3RpbmcgcGVybWlzc2lvbnMgYm91bmRhcnknLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0lucHV0UGVybWlzc2lvbnNCb3VuZGFyeScsXG4gICAgICAgICAgUGFyYW1ldGVyVmFsdWU6ICdwZXJtaXNzaW9ucy1ib3VuZGFyeS1uYW1lJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7fSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChzdGRlcnJNb2NrLm1vY2suY2FsbHMpLnRvRXF1YWwoZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9SZW1vdmluZyBleGlzdGluZyBwZXJtaXNzaW9ucyBib3VuZGFyeSBwZXJtaXNzaW9ucy1ib3VuZGFyeS1uYW1lLyksXG4gICAgICBdKSxcbiAgICBdKSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2FkZGluZyBwZXJtaXNzaW9uIGJvdW5kYXJ5IHdpdGggcGF0aCBpbiBwb2xpY3kgbmFtZScsIGFzeW5jICgpID0+IHtcbiAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgUGFyYW1ldGVyczogW1xuICAgICAgICB7XG4gICAgICAgICAgUGFyYW1ldGVyS2V5OiAnSW5wdXRQZXJtaXNzaW9uc0JvdW5kYXJ5JyxcbiAgICAgICAgICBQYXJhbWV0ZXJWYWx1ZTogJycsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBjdXN0b21QZXJtaXNzaW9uc0JvdW5kYXJ5OiAncGVybWlzc2lvbnMtYm91bmRhcnktbmFtZS93aXRoL3BhdGgnLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChzdGRlcnJNb2NrLm1vY2suY2FsbHMpLnRvRXF1YWwoZXhwZWN0LmFycmF5Q29udGFpbmluZyhbXG4gICAgICBleHBlY3QuYXJyYXlDb250YWluaW5nKFtcbiAgICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9BZGRpbmcgbmV3IHBlcm1pc3Npb25zIGJvdW5kYXJ5IHBlcm1pc3Npb25zLWJvdW5kYXJ5LW5hbWVcXC93aXRoXFwvcGF0aC8pLFxuICAgICAgXSksXG4gICAgXSkpO1xuICB9KTtcblxuICB0ZXN0KCdwYXNzaW5nIHRydXN0ZWQgYWNjb3VudHMgd2l0aG91dCBDRk4gbWFuYWdlZCBwb2xpY2llcyByZXN1bHRzIGluIGFuIGVycm9yJywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGV4cGVjdChib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgdHJ1c3RlZEFjY291bnRzOiBbJzEyMzQ1Njc4OTAxMiddLFxuICAgICAgfSxcbiAgICB9KSlcbiAgICAgIC5yZWplY3RzXG4gICAgICAudG9UaHJvdygvLS1jbG91ZGZvcm1hdGlvbi1leGVjdXRpb24tcG9saWNpZXMvKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2luZyB0cnVzdGVkIGFjY291bnRzIHdpdGhvdXQgQ0ZOIG1hbmFnZWQgcG9saWNpZXMgb24gdGhlIGV4aXN0aW5nIHN0YWNrIHJlc3VsdHMgaW4gYW4gZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXMnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50czogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgIH0sXG4gICAgfSkpXG4gICAgICAucmVqZWN0c1xuICAgICAgLnRvVGhyb3coLy0tY2xvdWRmb3JtYXRpb24tZXhlY3V0aW9uLXBvbGljaWVzLyk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3Npbmcgbm8gQ0ZOIG1hbmFnZWQgcG9saWNpZXMgd2l0aG91dCB0cnVzdGVkIGFjY291bnRzIGlzIG9rYXknLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7fSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgQ2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogJycsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NpbmcgdHJ1c3RlZCBhY2NvdW50cyBmb3IgbG9va3VwIGdlbmVyYXRlcyB0aGUgY29ycmVjdCBzdGFjayBwYXJhbWV0ZXInLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhd3M6Ly9mb28nXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBwYXJhbWV0ZXJzOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIFRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogJzEyMzQ1Njc4OTAxMicsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2FsbG93IGFkZGluZyB0cnVzdGVkIGFjY291bnQgaWYgdGhlcmUgd2FzIGFscmVhZHkgYSBwb2xpY3kgb24gdGhlIHN0YWNrJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXMnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnYXJuOmF3czpzb21ldGhpbmcnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICB0cnVzdGVkQWNjb3VudHM6IFsnMTIzNDU2Nzg5MDEyJ10sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIC8vIERpZCBub3QgdGhyb3dcbiAgfSk7XG5cbiAgdGVzdCgnRG8gbm90IGFsbG93IGRvd25ncmFkaW5nIGJvb3RzdHJhcCBzdGFjayB2ZXJzaW9uJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIE91dHB1dHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIE91dHB1dEtleTogJ0Jvb3RzdHJhcFZlcnNpb24nLFxuICAgICAgICAgIE91dHB1dFZhbHVlOiAnOTk5JyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgfSxcbiAgICB9KSkucmVzb2x2ZXMudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7IG5vT3A6IHRydWUgfSkpO1xuICB9KTtcblxuICB0ZXN0KCdEbyBub3QgYWxsb3cgb3ZlcndyaXRpbmcgYm9vdHN0cmFwIHN0YWNrIGZyb20gYSBkaWZmZXJlbnQgdmVuZG9yJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Jvb3RzdHJhcFZhcmlhbnQnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnSm9lU2NobW9lJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgfSkpLnJlc29sdmVzLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoeyBub09wOiB0cnVlIH0pKTtcbiAgfSk7XG5cbiAgdGVzdCgnYm9vdHN0cmFwIHRlbXBsYXRlIGhhcyB0aGUgcmlnaHQgZXhwb3J0cycsIGFzeW5jICgpID0+IHtcbiAgICBsZXQgdGVtcGxhdGU6IGFueTtcbiAgICBtb2NrRGVwbG95U3RhY2subW9ja0ltcGxlbWVudGF0aW9uKChhcmdzOiBEZXBsb3lTdGFja09wdGlvbnMpID0+IHtcbiAgICAgIHRlbXBsYXRlID0gYXJncy5zdGFjay50ZW1wbGF0ZTtcbiAgICB9KTtcblxuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBleHBvcnRzID0gT2JqZWN0LnZhbHVlcyh0ZW1wbGF0ZS5PdXRwdXRzID8/IHt9KVxuICAgICAgLmZpbHRlcigobzogYW55KSA9PiBvLkV4cG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICAgLm1hcCgobzogYW55KSA9PiBvLkV4cG9ydC5OYW1lKTtcblxuICAgIGV4cGVjdChleHBvcnRzKS50b0VxdWFsKFtcbiAgICAgIC8vIFRoaXMgdXNlZCB0byBiZSB1c2VkIGJ5IGF3cy1zMy1hc3NldHNcbiAgICAgIHsgJ0ZuOjpTdWInOiAnQ2RrQm9vdHN0cmFwLSR7UXVhbGlmaWVyfS1GaWxlQXNzZXRLZXlBcm4nIH0sXG4gICAgXSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd0ZXJtaW5hdGlvbiBwcm90ZWN0aW9uJywgKCkgPT4ge1xuICAgIHRlc3QoJ3N0YWNrIGlzIG5vdCB0ZXJtaW5hdGlvbiBwcm90ZWN0ZWQgYnkgZGVmYXVsdCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46cG9saWN5J10sXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBzdGFjazogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIHRlcm1pbmF0aW9uUHJvdGVjdGlvbjogZmFsc2UsXG4gICAgICAgIH0pLFxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnc3RhY2sgaXMgdGVybWluYXRpb24gcHJvdGVjdGVkIHdoZW4gb3B0aW9uIGlzIHNldCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IHRydWUsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHN0YWNrOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiB0cnVlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3Rlcm1pbmF0aW9uIHByb3RlY3Rpb24gaXMgbGVmdCBhbG9uZSB3aGVuIG9wdGlvbiBpcyBub3QgZ2l2ZW4nLCBhc3luYyAoKSA9PiB7XG4gICAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgICBFbmFibGVUZXJtaW5hdGlvblByb3RlY3Rpb246IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHN0YWNrOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiB0cnVlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3Rlcm1pbmF0aW9uIHByb3RlY3Rpb24gY2FuIGJlIHN3aXRjaGVkIG9mZicsIGFzeW5jICgpID0+IHtcbiAgICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICAgIEVuYWJsZVRlcm1pbmF0aW9uUHJvdGVjdGlvbjogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgc3RhY2s6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0tNUyBrZXknLCAoKSA9PiB7XG4gICAgdGVzdC5lYWNoKFtcbiAgICAgIC8vIERlZmF1bHQgY2FzZVxuICAgICAgW3VuZGVmaW5lZCwgJ0FXU19NQU5BR0VEX0tFWSddLFxuICAgICAgLy8gQ3JlYXRlIGEgbmV3IGtleVxuICAgICAgW3RydWUsICcnXSxcbiAgICAgIC8vIERvbid0IGNyZWF0ZSBhIG5ldyBrZXlcbiAgICAgIFtmYWxzZSwgJ0FXU19NQU5BR0VEX0tFWSddLFxuICAgIF0pKCcobmV3IHN0YWNrKSBjcmVhdGVDdXN0b21lck1hc3RlcktleT0lcCA9PiBwYXJhbWV0ZXIgYmVjb21lcyAl