UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

319 lines (317 loc) 36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable import/order */ const stream_1 = require("stream"); const string_decoder_1 = require("string_decoder"); const cxschema = require("@aws-cdk/cloud-assembly-schema"); const util_1 = require("./util"); const deployments_1 = require("../lib/api/deployments"); const cdk_toolkit_1 = require("../lib/cdk-toolkit"); let cloudExecutable; let cloudFormation; let toolkit; describe('non-nested stacks', () => { beforeEach(() => { cloudExecutable = new util_1.MockCloudExecutable({ stacks: [{ stackName: 'A', template: { resource: 'A' }, }, { stackName: 'B', depends: ['A'], template: { resource: 'B' }, }, { stackName: 'C', depends: ['A'], template: { resource: 'C' }, metadata: { '/resource': [ { type: cxschema.ArtifactMetadataEntryType.ERROR, data: 'this is an error', }, ], }, }, { stackName: 'D', template: { resource: 'D' }, }], }); cloudFormation = (0, util_1.instanceMockFrom)(deployments_1.Deployments); toolkit = new cdk_toolkit_1.CdkToolkit({ cloudExecutable, deployments: cloudFormation, configuration: cloudExecutable.configuration, sdkProvider: cloudExecutable.sdkProvider, }); // Default implementations cloudFormation.readCurrentTemplateWithNestedStacks.mockImplementation((stackArtifact) => { if (stackArtifact.stackName === 'D') { return Promise.resolve({ deployedTemplate: { resource: 'D' }, nestedStackCount: 0, }); } return Promise.resolve({ deployedTemplate: {}, nestedStackCount: 0, }); }); cloudFormation.deployStack.mockImplementation((options) => Promise.resolve({ noOp: true, outputs: {}, stackArn: '', stackArtifact: options.stack, })); }); test('diff can diff multiple stacks', async () => { // GIVEN const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['B'], stream: buffer, }); // THEN const plainTextOutput = buffer.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, ''); expect(plainTextOutput).toContain('Stack A'); expect(plainTextOutput).toContain('Stack B'); expect(buffer.data.trim()).toContain('✨ Number of stacks with differences: 2'); expect(exitCode).toBe(0); }); test('diff number of stack diffs, not resource diffs', async () => { // GIVEN cloudExecutable = new util_1.MockCloudExecutable({ stacks: [{ stackName: 'A', template: { resourceA: 'A', resourceB: 'B' }, }, { stackName: 'B', template: { resourceC: 'C' }, }], }); toolkit = new cdk_toolkit_1.CdkToolkit({ cloudExecutable, deployments: cloudFormation, configuration: cloudExecutable.configuration, sdkProvider: cloudExecutable.sdkProvider, }); const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['A', 'B'], stream: buffer, }); // THEN const plainTextOutput = buffer.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, ''); expect(plainTextOutput).toContain('Stack A'); expect(plainTextOutput).toContain('Stack B'); expect(buffer.data.trim()).toContain('✨ Number of stacks with differences: 2'); expect(exitCode).toBe(0); }); test('exits with 1 with diffs and fail set to true', async () => { // GIVEN const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['A'], stream: buffer, fail: true, }); // THEN expect(buffer.data.trim()).toContain('✨ Number of stacks with differences: 1'); expect(exitCode).toBe(1); }); test('throws an error if no valid stack names given', async () => { const buffer = new StringWritable(); // WHEN await expect(() => toolkit.diff({ stackNames: ['X', 'Y', 'Z'], stream: buffer, })).rejects.toThrow('No stacks match the name(s) X,Y,Z'); }); test('exits with 1 with diff in first stack, but not in second stack and fail set to true', async () => { // GIVEN const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['A', 'D'], stream: buffer, fail: true, }); // THEN expect(buffer.data.trim()).toContain('✨ Number of stacks with differences: 1'); expect(exitCode).toBe(1); }); test('throws an error during diffs on stack with error metadata', async () => { const buffer = new StringWritable(); // WHEN await expect(() => toolkit.diff({ stackNames: ['C'], stream: buffer, })).rejects.toThrow(/Found errors/); }); test('when quiet mode is enabled, stacks with no diffs should not print stack name & no differences to stdout', async () => { // GIVEN const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['A', 'A'], stream: buffer, fail: false, quiet: true, }); // THEN expect(buffer.data.trim()).not.toContain('Stack A'); expect(buffer.data.trim()).not.toContain('There were no differences'); expect(exitCode).toBe(0); }); }); describe('nested stacks', () => { beforeEach(() => { cloudExecutable = new util_1.MockCloudExecutable({ stacks: [{ stackName: 'Parent', template: {}, }], }); cloudFormation = (0, util_1.instanceMockFrom)(deployments_1.Deployments); toolkit = new cdk_toolkit_1.CdkToolkit({ cloudExecutable, deployments: cloudFormation, configuration: cloudExecutable.configuration, sdkProvider: cloudExecutable.sdkProvider, }); cloudFormation.readCurrentTemplateWithNestedStacks.mockImplementation((stackArtifact) => { if (stackArtifact.stackName === 'Parent') { stackArtifact.template.Resources = { AdditionChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', Properties: { Prop: 'added-value', }, }, }, }, DeletionChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', }, }, }, ChangedChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', Properties: { Prop: 'new-value', }, }, }, }, }; return Promise.resolve({ deployedTemplate: { Resources: { AdditionChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', }, }, }, DeletionChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', Properties: { Prop: 'value-to-be-removed', }, }, }, }, ChangedChild: { Type: 'AWS::CloudFormation::Stack', Resources: { SomeResource: { Type: 'AWS::Something', Properties: { Prop: 'old-value', }, }, }, }, }, }, nestedStackCount: 3, }); } return Promise.resolve({ deployedTemplate: {}, nestedStackCount: 0, }); }); }); test('diff can diff nested stacks', async () => { // GIVEN const buffer = new StringWritable(); // WHEN const exitCode = await toolkit.diff({ stackNames: ['Parent'], stream: buffer, }); // THEN const plainTextOutput = buffer.data.replace(/\x1B\[[0-?]*[ -/]*[@-~]/g, '') .replace(/[ \t]+$/mg, ''); expect(plainTextOutput.trim()).toEqual(`Stack Parent Resources [~] AWS::CloudFormation::Stack AdditionChild └─ [~] Resources └─ [~] .SomeResource: └─ [+] Added: .Properties [~] AWS::CloudFormation::Stack DeletionChild └─ [~] Resources └─ [~] .SomeResource: └─ [-] Removed: .Properties [~] AWS::CloudFormation::Stack ChangedChild └─ [~] Resources └─ [~] .SomeResource: └─ [~] .Properties: └─ [~] .Prop: ├─ [-] old-value └─ [+] new-value ✨ Number of stacks with differences: 4`); expect(exitCode).toBe(0); }); }); class StringWritable extends stream_1.Writable { constructor(options = {}) { super(options); this._decoder = new string_decoder_1.StringDecoder(options && options.defaultEncoding); this.data = ''; } _write(chunk, encoding, callback) { if (encoding === 'buffer') { chunk = this._decoder.write(chunk); } this.data += chunk; callback(); } _final(callback) { this.data += this._decoder.end(); callback(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlmZi50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGlmZi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLG1DQUFrQztBQUNsQyxtREFBK0M7QUFDL0MsMkRBQTJEO0FBRTNELGlDQUErRDtBQUMvRCx3REFBcUQ7QUFDckQsb0RBQWdEO0FBRWhELElBQUksZUFBb0MsQ0FBQztBQUN6QyxJQUFJLGNBQXdDLENBQUM7QUFDN0MsSUFBSSxPQUFtQixDQUFDO0FBRXhCLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRSxHQUFHLEVBQUU7SUFDakMsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLGVBQWUsR0FBRyxJQUFJLDBCQUFtQixDQUFDO1lBQ3hDLE1BQU0sRUFBRSxDQUFDO29CQUNQLFNBQVMsRUFBRSxHQUFHO29CQUNkLFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7aUJBQzVCO2dCQUNEO29CQUNFLFNBQVMsRUFBRSxHQUFHO29CQUNkLE9BQU8sRUFBRSxDQUFDLEdBQUcsQ0FBQztvQkFDZCxRQUFRLEVBQUUsRUFBRSxRQUFRLEVBQUUsR0FBRyxFQUFFO2lCQUM1QjtnQkFDRDtvQkFDRSxTQUFTLEVBQUUsR0FBRztvQkFDZCxPQUFPLEVBQUUsQ0FBQyxHQUFHLENBQUM7b0JBQ2QsUUFBUSxFQUFFLEVBQUUsUUFBUSxFQUFFLEdBQUcsRUFBRTtvQkFDM0IsUUFBUSxFQUFFO3dCQUNSLFdBQVcsRUFBRTs0QkFDWDtnQ0FDRSxJQUFJLEVBQUUsUUFBUSxDQUFDLHlCQUF5QixDQUFDLEtBQUs7Z0NBQzlDLElBQUksRUFBRSxrQkFBa0I7NkJBQ3pCO3lCQUNGO3FCQUNGO2lCQUNGO2dCQUNEO29CQUNFLFNBQVMsRUFBRSxHQUFHO29CQUNkLFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUU7aUJBQzVCLENBQUM7U0FDSCxDQUFDLENBQUM7UUFFSCxjQUFjLEdBQUcsSUFBQSx1QkFB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LENBQUMsUUFBUSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNCLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxNQUFNLGNBQWUsU0FBUSxpQkFBUTtJQUluQyxZQUFZLFVBQWUsRUFBRTtRQUMzQixLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksOEJBQWEsQ0FBQyxPQUFPLElBQUksT0FBTyxDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3RFLElBQUksQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ2pCLENBQUM7SUFFTSxNQUFNLENBQUMsS0FBVSxFQUFFLFFBQWdCLEVBQUUsUUFBNkM7UUFDdkYsSUFBSSxRQUFRLEtBQUssUUFBUSxFQUFFO1lBQ3pCLEtBQUssR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztTQUNwQztRQUNELElBQUksQ0FBQyxJQUFJLElBQUksS0FBSyxDQUFDO1FBQ25CLFFBQVEsRUFBRSxDQUFDO0lBQ2IsQ0FBQztJQUVNLE1BQU0sQ0FBQyxRQUF3QztRQUNwRCxJQUFJLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLENBQUM7UUFDakMsUUFBUSxFQUFFLENBQUM7SUFDYixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBpbXBvcnQvb3JkZXIgKi9cbmltcG9ydCB7IFdyaXRhYmxlIH0gZnJvbSAnc3RyZWFtJztcbmltcG9ydCB7IFN0cmluZ0RlY29kZXIgfSBmcm9tICdzdHJpbmdfZGVjb2Rlcic7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHsgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IH0gZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB7IGluc3RhbmNlTW9ja0Zyb20sIE1vY2tDbG91ZEV4ZWN1dGFibGUgfSBmcm9tICcuL3V0aWwnO1xuaW1wb3J0IHsgRGVwbG95bWVudHMgfSBmcm9tICcuLi9saWIvYXBpL2RlcGxveW1lbnRzJztcbmltcG9ydCB7IENka1Rvb2xraXQgfSBmcm9tICcuLi9saWIvY2RrLXRvb2xraXQnO1xuXG5sZXQgY2xvdWRFeGVjdXRhYmxlOiBNb2NrQ2xvdWRFeGVjdXRhYmxlO1xubGV0IGNsb3VkRm9ybWF0aW9uOiBqZXN0Lk1vY2tlZDxEZXBsb3ltZW50cz47XG5sZXQgdG9vbGtpdDogQ2RrVG9vbGtpdDtcblxuZGVzY3JpYmUoJ25vbi1uZXN0ZWQgc3RhY2tzJywgKCkgPT4ge1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBjbG91ZEV4ZWN1dGFibGUgPSBuZXcgTW9ja0Nsb3VkRXhlY3V0YWJsZSh7XG4gICAgICBzdGFja3M6IFt7XG4gICAgICAgIHN0YWNrTmFtZTogJ0EnLFxuICAgICAgICB0ZW1wbGF0ZTogeyByZXNvdXJjZTogJ0EnIH0sXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBzdGFja05hbWU6ICdCJyxcbiAgICAgICAgZGVwZW5kczogWydBJ10sXG4gICAgICAgIHRlbXBsYXRlOiB7IHJlc291cmNlOiAnQicgfSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHN0YWNrTmFtZTogJ0MnLFxuICAgICAgICBkZXBlbmRzOiBbJ0EnXSxcbiAgICAgICAgdGVtcGxhdGU6IHsgcmVzb3VyY2U6ICdDJyB9LFxuICAgICAgICBtZXRhZGF0YToge1xuICAgICAgICAgICcvcmVzb3VyY2UnOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0TWV0YWRhdGFFbnRyeVR5cGUuRVJST1IsXG4gICAgICAgICAgICAgIGRhdGE6ICd0aGlzIGlzIGFuIGVycm9yJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICB7XG4gICAgICAgIHN0YWNrTmFtZTogJ0QnLFxuICAgICAgICB0ZW1wbGF0ZTogeyByZXNvdXJjZTogJ0QnIH0sXG4gICAgICB9XSxcbiAgICB9KTtcblxuICAgIGNsb3VkRm9ybWF0aW9uID0gaW5zdGFuY2VNb2NrRnJvbShEZXBsb3ltZW50cyk7XG5cbiAgICB0b29sa2l0ID0gbmV3IENka1Rvb2xraXQoe1xuICAgICAgY2xvdWRFeGVjdXRhYmxlLFxuICAgICAgZGVwbG95bWVudHM6IGNsb3VkRm9ybWF0aW9uLFxuICAgICAgY29uZmlndXJhdGlvbjogY2xvdWRFeGVjdXRhYmxlLmNvbmZpZ3VyYXRpb24sXG4gICAgICBzZGtQcm92aWRlcjogY2xvdWRFeGVjdXRhYmxlLnNka1Byb3ZpZGVyLFxuICAgIH0pO1xuXG4gICAgLy8gRGVmYXVsdCBpbXBsZW1lbnRhdGlvbnNcbiAgICBjbG91ZEZvcm1hdGlvbi5yZWFkQ3VycmVudFRlbXBsYXRlV2l0aE5lc3RlZFN0YWNrcy5tb2NrSW1wbGVtZW50YXRpb24oKHN0YWNrQXJ0aWZhY3Q6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCkgPT4ge1xuICAgICAgaWYgKHN0YWNrQXJ0aWZhY3Quc3RhY2tOYW1lID09PSAnRCcpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh7XG4gICAgICAgICAgZGVwbG95ZWRUZW1wbGF0ZTogeyByZXNvdXJjZTogJ0QnIH0sXG4gICAgICAgICAgbmVzdGVkU3RhY2tDb3VudDogMCxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgZGVwbG95ZWRUZW1wbGF0ZToge30sXG4gICAgICAgIG5lc3RlZFN0YWNrQ291bnQ6IDAsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBjbG91ZEZvcm1hdGlvbi5kZXBsb3lTdGFjay5tb2NrSW1wbGVtZW50YXRpb24oKG9wdGlvbnMpID0+IFByb21pc2UucmVzb2x2ZSh7XG4gICAgICBub09wOiB0cnVlLFxuICAgICAgb3V0cHV0czoge30sXG4gICAgICBzdGFja0FybjogJycsXG4gICAgICBzdGFja0FydGlmYWN0OiBvcHRpb25zLnN0YWNrLFxuICAgIH0pKTtcbiAgfSk7XG5cbiAgdGVzdCgnZGlmZiBjYW4gZGlmZiBtdWx0aXBsZSBzdGFja3MnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBidWZmZXIgPSBuZXcgU3RyaW5nV3JpdGFibGUoKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBleGl0Q29kZSA9IGF3YWl0IHRvb2xraXQuZGlmZih7XG4gICAgICBzdGFja05hbWVzOiBbJ0InXSxcbiAgICAgIHN0cmVhbTogYnVmZmVyLFxuICAgIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIGNvbnN0IHBsYWluVGV4dE91dHB1dCA9IGJ1ZmZlci5kYXRhLnJlcGxhY2UoL1xceDFCXFxbWzAtP10qWyAtL10qW0Atfl0vZywgJycpO1xuICAgIGV4cGVjdChwbGFpblRleHRPdXRwdXQpLnRvQ29udGFpbignU3RhY2sgQScpO1xuICAgIGV4cGVjdChwbGFpblRleHRPdXRwdXQpLnRvQ29udGFpbignU3RhY2sgQicpO1xuXG4gICAgZXhwZWN0KGJ1ZmZlci5kYXRhLnRyaW0oKSkudG9Db250YWluKCfinKggIE51bWJlciBvZiBzdGFja3Mgd2l0aCBkaWZmZXJlbmNlczogMicpO1xuICAgIGV4cGVjdChleGl0Q29kZSkudG9CZSgwKTtcbiAgfSk7XG5cbiAgdGVzdCgnZGlmZiBudW1iZXIgb2Ygc3RhY2sgZGlmZnMsIG5vdCByZXNvdXJjZSBkaWZmcycsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIGNsb3VkRXhlY3V0YWJsZSA9IG5ldyBNb2NrQ2xvdWRFeGVjdXRhYmxlKHtcbiAgICAgIHN0YWNrczogW3tcbiAgICAgICAgc3RhY2tOYW1lOiAnQScsXG4gICAgICAgIHRlbXBsYXRlOiB7IHJlc291cmNlQTogJ0EnLCByZXNvdXJjZUI6ICdCJyB9LFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgc3RhY2tOYW1lOiAnQicsXG4gICAgICAgIHRlbXBsYXRlOiB7IHJlc291cmNlQzogJ0MnIH0sXG4gICAgICB9XSxcbiAgICB9KTtcblxuICAgIHRvb2xraXQgPSBuZXcgQ2RrVG9vbGtpdCh7XG4gICAgICBjbG91ZEV4ZWN1dGFibGUsXG4gICAgICBkZXBsb3ltZW50czogY2xvdWRGb3JtYXRpb24sXG4gICAgICBjb25maWd1cmF0aW9uOiBjbG91ZEV4ZWN1dGFibGUuY29uZmlndXJhdGlvbixcbiAgICAgIHNka1Byb3ZpZGVyOiBjbG91ZEV4ZWN1dGFibGUuc2RrUHJvdmlkZXIsXG4gICAgfSk7XG5cbiAgICBjb25zdCBidWZmZXIgPSBuZXcgU3RyaW5nV3JpdGFibGUoKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBleGl0Q29kZSA9IGF3YWl0IHRvb2xraXQuZGlmZih7XG4gICAgICBzdGFja05hbWVzOiBbJ0EnLCAnQiddLFxuICAgICAgc3RyZWFtOiBidWZmZXIsXG4gICAgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgY29uc3QgcGxhaW5UZXh0T3V0cHV0ID0gYnVmZmVyLmRhdGEucmVwbGFjZSgvXFx4MUJcXFtbMC0/XSpbIC0vXSpbQC1+XS9nLCAnJyk7XG4gICAgZXhwZWN0KHBsYWluVGV4dE91dHB1dCkudG9Db250YWluKCdTdGFjayBBJyk7XG4gICAgZXhwZWN0KHBsYWluVGV4dE91dHB1dCkudG9Db250YWluKCdTdGFjayBCJyk7XG5cbiAgICBleHBlY3QoYnVmZmVyLmRhdGEudHJpbSgpKS50b0NvbnRhaW4oJ+KcqCAgTnVtYmVyIG9mIHN0YWNrcyB3aXRoIGRpZmZlcmVuY2VzOiAyJyk7XG4gICAgZXhwZWN0KGV4aXRDb2RlKS50b0JlKDApO1xuICB9KTtcblxuICB0ZXN0KCdleGl0cyB3aXRoIDEgd2l0aCBkaWZmcyBhbmQgZmFpbCBzZXQgdG8gdHJ1ZScsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBTdHJpbmdXcml0YWJsZSgpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGV4aXRDb2RlID0gYXdhaXQgdG9vbGtpdC5kaWZmKHtcbiAgICAgIHN0YWNrTmFtZXM6IFsnQSddLFxuICAgICAgc3RyZWFtOiBidWZmZXIsXG4gICAgICBmYWlsOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChidWZmZXIuZGF0YS50cmltKCkpLnRvQ29udGFpbign4pyoICBOdW1iZXIgb2Ygc3RhY2tzIHdpdGggZGlmZmVyZW5jZXM6IDEnKTtcbiAgICBleHBlY3QoZXhpdENvZGUpLnRvQmUoMSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Rocm93cyBhbiBlcnJvciBpZiBubyB2YWxpZCBzdGFjayBuYW1lcyBnaXZlbicsIGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBidWZmZXIgPSBuZXcgU3RyaW5nV3JpdGFibGUoKTtcblxuICAgIC8vIFdIRU5cbiAgICBhd2FpdCBleHBlY3QoKCkgPT4gdG9vbGtpdC5kaWZmKHtcbiAgICAgIHN0YWNrTmFtZXM6IFsnWCcsICdZJywgJ1onXSxcbiAgICAgIHN0cmVhbTogYnVmZmVyLFxuICAgIH0pKS5yZWplY3RzLnRvVGhyb3coJ05vIHN0YWNrcyBtYXRjaCB0aGUgbmFtZShzKSBYLFksWicpO1xuICB9KTtcblxuICB0ZXN0KCdleGl0cyB3aXRoIDEgd2l0aCBkaWZmIGluIGZpcnN0IHN0YWNrLCBidXQgbm90IGluIHNlY29uZCBzdGFjayBhbmQgZmFpbCBzZXQgdG8gdHJ1ZScsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBTdHJpbmdXcml0YWJsZSgpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGV4aXRDb2RlID0gYXdhaXQgdG9vbGtpdC5kaWZmKHtcbiAgICAgIHN0YWNrTmFtZXM6IFsnQScsICdEJ10sXG4gICAgICBzdHJlYW06IGJ1ZmZlcixcbiAgICAgIGZhaWw6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgZXhwZWN0KGJ1ZmZlci5kYXRhLnRyaW0oKSkudG9Db250YWluKCfinKggIE51bWJlciBvZiBzdGFja3Mgd2l0aCBkaWZmZXJlbmNlczogMScpO1xuICAgIGV4cGVjdChleGl0Q29kZSkudG9CZSgxKTtcbiAgfSk7XG5cbiAgdGVzdCgndGhyb3dzIGFuIGVycm9yIGR1cmluZyBkaWZmcyBvbiBzdGFjayB3aXRoIGVycm9yIG1ldGFkYXRhJywgYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBTdHJpbmdXcml0YWJsZSgpO1xuXG4gICAgLy8gV0hFTlxuICAgIGF3YWl0IGV4cGVjdCgoKSA9PiB0b29sa2l0LmRpZmYoe1xuICAgICAgc3RhY2tOYW1lczogWydDJ10sXG4gICAgICBzdHJlYW06IGJ1ZmZlcixcbiAgICB9KSkucmVqZWN0cy50b1Rocm93KC9Gb3VuZCBlcnJvcnMvKTtcbiAgfSk7XG5cbiAgdGVzdCgnd2hlbiBxdWlldCBtb2RlIGlzIGVuYWJsZWQsIHN0YWNrcyB3aXRoIG5vIGRpZmZzIHNob3VsZCBub3QgcHJpbnQgc3RhY2sgbmFtZSAmIG5vIGRpZmZlcmVuY2VzIHRvIHN0ZG91dCcsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBTdHJpbmdXcml0YWJsZSgpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGV4aXRDb2RlID0gYXdhaXQgdG9vbGtpdC5kaWZmKHtcbiAgICAgIHN0YWNrTmFtZXM6IFsnQScsICdBJ10sXG4gICAgICBzdHJlYW06IGJ1ZmZlcixcbiAgICAgIGZhaWw6IGZhbHNlLFxuICAgICAgcXVpZXQ6IHRydWUsXG4gICAgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgZXhwZWN0KGJ1ZmZlci5kYXRhLnRyaW0oKSkubm90LnRvQ29udGFpbignU3RhY2sgQScpO1xuICAgIGV4cGVjdChidWZmZXIuZGF0YS50cmltKCkpLm5vdC50b0NvbnRhaW4oJ1RoZXJlIHdlcmUgbm8gZGlmZmVyZW5jZXMnKTtcbiAgICBleHBlY3QoZXhpdENvZGUpLnRvQmUoMCk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKCduZXN0ZWQgc3RhY2tzJywgKCkgPT4ge1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBjbG91ZEV4ZWN1dGFibGUgPSBuZXcgTW9ja0Nsb3VkRXhlY3V0YWJsZSh7XG4gICAgICBzdGFja3M6IFt7XG4gICAgICAgIHN0YWNrTmFtZTogJ1BhcmVudCcsXG4gICAgICAgIHRlbXBsYXRlOiB7fSxcbiAgICAgIH1dLFxuICAgIH0pO1xuXG4gICAgY2xvdWRGb3JtYXRpb24gPSBpbnN0YW5jZU1vY2tGcm9tKERlcGxveW1lbnRzKTtcblxuICAgIHRvb2xraXQgPSBuZXcgQ2RrVG9vbGtpdCh7XG4gICAgICBjbG91ZEV4ZWN1dGFibGUsXG4gICAgICBkZXBsb3ltZW50czogY2xvdWRGb3JtYXRpb24sXG4gICAgICBjb25maWd1cmF0aW9uOiBjbG91ZEV4ZWN1dGFibGUuY29uZmlndXJhdGlvbixcbiAgICAgIHNka1Byb3ZpZGVyOiBjbG91ZEV4ZWN1dGFibGUuc2RrUHJvdmlkZXIsXG4gICAgfSk7XG5cbiAgICBjbG91ZEZvcm1hdGlvbi5yZWFkQ3VycmVudFRlbXBsYXRlV2l0aE5lc3RlZFN0YWNrcy5tb2NrSW1wbGVtZW50YXRpb24oKHN0YWNrQXJ0aWZhY3Q6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCkgPT4ge1xuICAgICAgaWYgKHN0YWNrQXJ0aWZhY3Quc3RhY2tOYW1lID09PSAnUGFyZW50Jykge1xuICAgICAgICBzdGFja0FydGlmYWN0LnRlbXBsYXRlLlJlc291cmNlcyA9IHtcbiAgICAgICAgICBBZGRpdGlvbkNoaWxkOiB7XG4gICAgICAgICAgICBUeXBlOiAnQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2snLFxuICAgICAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgICAgIFNvbWVSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgIFR5cGU6ICdBV1M6OlNvbWV0aGluZycsXG4gICAgICAgICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgICAgICAgUHJvcDogJ2FkZGVkLXZhbHVlJyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIERlbGV0aW9uQ2hpbGQ6IHtcbiAgICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICAgICAgU29tZVJlc291cmNlOiB7XG4gICAgICAgICAgICAgICAgVHlwZTogJ0FXUzo6U29tZXRoaW5nJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBDaGFuZ2VkQ2hpbGQ6IHtcbiAgICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICAgICAgU29tZVJlc291cmNlOiB7XG4gICAgICAgICAgICAgICAgVHlwZTogJ0FXUzo6U29tZXRoaW5nJyxcbiAgICAgICAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICAgICAgICBQcm9wOiAnbmV3LXZhbHVlJyxcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgICBkZXBsb3llZFRlbXBsYXRlOiB7XG4gICAgICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICAgICAgQWRkaXRpb25DaGlsZDoge1xuICAgICAgICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgICAgICAgICBTb21lUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgVHlwZTogJ0FXUzo6U29tZXRoaW5nJyxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgRGVsZXRpb25DaGlsZDoge1xuICAgICAgICAgICAgICAgIFR5cGU6ICdBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjaycsXG4gICAgICAgICAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgICAgICAgICBTb21lUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgVHlwZTogJ0FXUzo6U29tZXRoaW5nJyxcbiAgICAgICAgICAgICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgICAgICAgICAgIFByb3A6ICd2YWx1ZS10by1iZS1yZW1vdmVkJyxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgQ2hhbmdlZENoaWxkOiB7XG4gICAgICAgICAgICAgICAgVHlwZTogJ0FXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrJyxcbiAgICAgICAgICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICAgICAgICAgIFNvbWVSZXNvdXJjZToge1xuICAgICAgICAgICAgICAgICAgICBUeXBlOiAnQVdTOjpTb21ldGhpbmcnLFxuICAgICAgICAgICAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgUHJvcDogJ29sZC12YWx1ZScsXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgICAgbmVzdGVkU3RhY2tDb3VudDogMyxcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHtcbiAgICAgICAgZGVwbG95ZWRUZW1wbGF0ZToge30sXG4gICAgICAgIG5lc3RlZFN0YWNrQ291bnQ6IDAsXG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgdGVzdCgnZGlmZiBjYW4gZGlmZiBuZXN0ZWQgc3RhY2tzJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3QgYnVmZmVyID0gbmV3IFN0cmluZ1dyaXRhYmxlKCk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgZXhpdENvZGUgPSBhd2FpdCB0b29sa2l0LmRpZmYoe1xuICAgICAgc3RhY2tOYW1lczogWydQYXJlbnQnXSxcbiAgICAgIHN0cmVhbTogYnVmZmVyLFxuICAgIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIGNvbnN0IHBsYWluVGV4dE91dHB1dCA9IGJ1ZmZlci5kYXRhLnJlcGxhY2UoL1xceDFCXFxbWzAtP10qWyAtL10qW0Atfl0vZywgJycpXG4gICAgICAucmVwbGFjZSgvWyBcXHRdKyQvbWcsICcnKTtcbiAgICBleHBlY3QocGxhaW5UZXh0T3V0cHV0LnRyaW0oKSkudG9FcXVhbChgU3RhY2sgUGFyZW50XG5SZXNvdXJjZXNcblt+XSBBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjayBBZGRpdGlvbkNoaWxkXG4g4pSU4pSAIFt+XSBSZXNvdXJjZXNcbiAgICAg4pSU4pSAIFt+XSAuU29tZVJlc291cmNlOlxuICAgICAgICAg4pSU4pSAIFsrXSBBZGRlZDogLlByb3BlcnRpZXNcblt+XSBBV1M6OkNsb3VkRm9ybWF0aW9uOjpTdGFjayBEZWxldGlvbkNoaWxkXG4g4pSU4pSAIFt+XSBSZXNvdXJjZXNcbiAgICAg4pSU4pSAIFt+XSAuU29tZVJlc291cmNlOlxuICAgICAgICAg4pSU4pSAIFstXSBSZW1vdmVkOiAuUHJvcGVydGllc1xuW35dIEFXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrIENoYW5nZWRDaGlsZFxuIOKUlOKUgCBbfl0gUmVzb3VyY2VzXG4gICAgIOKUlOKUgCBbfl0gLlNvbWVSZXNvdXJjZTpcbiAgICAgICAgIOKUlOKUgCBbfl0gLlByb3BlcnRpZXM6XG4gICAgICAgICAgICAg4pSU4pSAIFt+XSAuUHJvcDpcbiAgICAgICAgICAgICAgICAg4pSc4pSAIFstXSBvbGQtdmFsdWVcbiAgICAgICAgICAgICAgICAg4pSU4pSAIFsrXSBuZXctdmFsdWVcblxuXG7inKggIE51bWJlciBvZiBzdGFja3Mgd2l0aCBkaWZmZXJlbmNlczogNGApO1xuXG4gICAgZXhwZWN0KGV4aXRDb2RlKS50b0JlKDApO1xuICB9KTtcbn0pO1xuXG5jbGFzcyBTdHJpbmdXcml0YWJsZSBleHRlbmRzIFdyaXRhYmxlIHtcbiAgcHVibGljIGRhdGE6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBfZGVjb2RlcjogU3RyaW5nRGVjb2RlcjtcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBhbnkgPSB7fSkge1xuICAgIHN1cGVyKG9wdGlvbnMpO1xuICAgIHRoaXMuX2RlY29kZXIgPSBuZXcgU3RyaW5nRGVjb2RlcihvcHRpb25zICYmIG9wdGlvbnMuZGVmYXVsdEVuY29kaW5nKTtcbiAgICB0aGlzLmRhdGEgPSAnJztcbiAgfVxuXG4gIHB1YmxpYyBfd3JpdGUoY2h1bms6IGFueSwgZW5jb2Rpbmc6IHN0cmluZywgY2FsbGJhY2s6IChlcnJvcj86IEVycm9yIHwgdW5kZWZpbmVkKSA9PiB2b2lkKSB7XG4gICAgaWYgKGVuY29kaW5nID09PSAnYnVmZmVyJykge1xuICAgICAgY2h1bmsgPSB0aGlzLl9kZWNvZGVyLndyaXRlKGNodW5rKTtcbiAgICB9XG4gICAgdGhpcy5kYXRhICs9IGNodW5rO1xuICAgIGNhbGxiYWNrKCk7XG4gIH1cblxuICBwdWJsaWMgX2ZpbmFsKGNhbGxiYWNrOiAoZXJyb3I/OiBFcnJvciB8IG51bGwpID0+IHZvaWQpIHtcbiAgICB0aGlzLmRhdGEgKz0gdGhpcy5fZGVjb2Rlci5lbmQoKTtcbiAgICBjYWxsYmFjaygpO1xuICB9XG59XG4iXX0=