UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

333 lines (321 loc) 45.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable import/order */ const https = require("https"); const os = require("os"); const path = require("path"); const fs = require("fs-extra"); const nock = require("nock"); const logging = require("../lib/logging"); const notices_1 = require("../lib/notices"); const version = require("../lib/version"); const BASIC_NOTICE = { title: 'Toggling off auto_delete_objects for Bucket empties the bucket', issueNumber: 16603, overview: 'If a stack is deployed with an S3 bucket with auto_delete_objects=True, and then re-deployed with auto_delete_objects=False, all the objects in the bucket will be deleted.', components: [{ name: 'cli', version: '<=1.126.0', }], schemaVersion: '1', }; const MULTIPLE_AFFECTED_VERSIONS_NOTICE = { title: 'Error when building EKS cluster with monocdk import', issueNumber: 17061, overview: 'When using monocdk/aws-eks to build a stack containing an EKS cluster, error is thrown about missing lambda-layer-node-proxy-agent/layer/package.json.', components: [{ name: 'cli', version: '<1.130.0 >=1.126.0', }], schemaVersion: '1', }; const FRAMEWORK_2_1_0_AFFECTED_NOTICE = { title: 'Regression on module foobar', issueNumber: 1234, overview: 'Some bug description', components: [{ name: 'framework', version: '<= 2.1.0', }], schemaVersion: '1', }; const NOTICE_FOR_APIGATEWAYV2 = { title: 'Regression on module foobar', issueNumber: 1234, overview: 'Some bug description', components: [{ name: '@aws-cdk/aws-apigatewayv2-alpha.', version: '<= 2.13.0-alpha.0', }], schemaVersion: '1', }; const NOTICE_FOR_APIGATEWAY = { title: 'Regression on module foobar', issueNumber: 1234, overview: 'Some bug description', components: [{ name: '@aws-cdk/aws-apigateway', version: '<= 2.13.0-alpha.0', }], schemaVersion: '1', }; const NOTICE_FOR_APIGATEWAYV2_CFN_STAGE = { title: 'Regression on module foobar', issueNumber: 1234, overview: 'Some bug description', components: [{ name: 'aws-cdk-lib.aws_apigatewayv2.CfnStage', version: '<= 2.13.0-alpha.0', }], schemaVersion: '1', }; describe('cli notices', () => { beforeAll(() => { jest .spyOn(version, 'versionNumber') .mockImplementation(() => '1.0.0'); }); afterAll(() => { jest.restoreAllMocks(); }); describe(notices_1.formatNotices, () => { test('correct format', () => { const result = (0, notices_1.formatNotices)([BASIC_NOTICE])[0]; expect(result).toEqual(`16603 Toggling off auto_delete_objects for Bucket empties the bucket Overview: If a stack is deployed with an S3 bucket with auto_delete_objects=True, and then re-deployed with auto_delete_objects=False, all the objects in the bucket will be deleted. Affected versions: cli: <=1.126.0 More information at: https://github.com/aws/aws-cdk/issues/16603 `); }); test('multiple affect versions', () => { const result = (0, notices_1.formatNotices)([MULTIPLE_AFFECTED_VERSIONS_NOTICE])[0]; expect(result).toEqual(`17061 Error when building EKS cluster with monocdk import Overview: When using monocdk/aws-eks to build a stack containing an EKS cluster, error is thrown about missing lambda-layer-node-proxy-agent/layer/package.json. Affected versions: cli: <1.130.0 >=1.126.0 More information at: https://github.com/aws/aws-cdk/issues/17061 `); }); }); describe(notices_1.filterNotices, () => { test('correctly filter notices on cli', () => { const notices = [BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE]; expect((0, notices_1.filterNotices)(notices, { cliVersion: '1.0.0', })).toEqual([BASIC_NOTICE]); expect((0, notices_1.filterNotices)(notices, { cliVersion: '1.129.0', })).toEqual([MULTIPLE_AFFECTED_VERSIONS_NOTICE]); expect((0, notices_1.filterNotices)(notices, { cliVersion: '1.126.0', })).toEqual(notices); expect((0, notices_1.filterNotices)(notices, { cliVersion: '1.130.0', })).toEqual([]); }); test('correctly filter notices on framework', () => { const notices = [FRAMEWORK_2_1_0_AFFECTED_NOTICE]; expect((0, notices_1.filterNotices)(notices, { outdir: path.join(__dirname, 'cloud-assembly-trees/built-with-2_12_0'), })).toEqual([]); expect((0, notices_1.filterNotices)(notices, { outdir: path.join(__dirname, 'cloud-assembly-trees/built-with-1_144_0'), })).toEqual([FRAMEWORK_2_1_0_AFFECTED_NOTICE]); }); test('correctly filter notices on arbitrary modules', () => { const notices = [NOTICE_FOR_APIGATEWAYV2]; // module-level match expect((0, notices_1.filterNotices)(notices, { outdir: path.join(__dirname, 'cloud-assembly-trees/experimental-module'), })).toEqual([NOTICE_FOR_APIGATEWAYV2]); // no apigatewayv2 in the tree expect((0, notices_1.filterNotices)(notices, { outdir: path.join(__dirname, 'cloud-assembly-trees/built-with-2_12_0'), })).toEqual([]); // module name mismatch: apigateway != apigatewayv2 expect((0, notices_1.filterNotices)([NOTICE_FOR_APIGATEWAY], { outdir: path.join(__dirname, 'cloud-assembly-trees/experimental-module'), })).toEqual([]); // construct-level match expect((0, notices_1.filterNotices)([NOTICE_FOR_APIGATEWAYV2_CFN_STAGE], { outdir: path.join(__dirname, 'cloud-assembly-trees/experimental-module'), })).toEqual([NOTICE_FOR_APIGATEWAYV2_CFN_STAGE]); }); }); describe(notices_1.WebsiteNoticeDataSource, () => { const dataSource = new notices_1.WebsiteNoticeDataSource(); test('returns data when download succeeds', async () => { const result = await mockCall(200, { notices: [BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE], }); expect(result).toEqual([BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE]); }); test('returns appropriate error when the server returns an unexpected status code', async () => { const result = mockCall(500, { notices: [BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE], }); await expect(result).rejects.toThrow(/500/); }); test('returns appropriate error when the server returns an unexpected structure', async () => { const result = mockCall(200, { foo: [BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE], }); await expect(result).rejects.toThrow(/key is missing/); }); test('returns appropriate error when the server returns invalid json', async () => { const result = mockCall(200, '-09aiskjkj838'); await expect(result).rejects.toThrow(/Failed to parse/); }); test('returns appropriate error when HTTPS call throws', async () => { const mockGet = jest.spyOn(https, 'get') .mockImplementation(() => { throw new Error('No connection'); }); const result = dataSource.fetch(); await expect(result).rejects.toThrow(/No connection/); mockGet.mockRestore(); }); test('returns appropriate error when the request has an error', async () => { nock('https://cli.cdk.dev-tools.aws.dev') .get('/notices.json') .replyWithError('DNS resolution failed'); const result = dataSource.fetch(); await expect(result).rejects.toThrow(/DNS resolution failed/); }); test('returns appropriate error when the connection stays idle for too long', async () => { nock('https://cli.cdk.dev-tools.aws.dev') .get('/notices.json') .delayConnection(3500) .reply(200, { notices: [BASIC_NOTICE], }); const result = dataSource.fetch(); await expect(result).rejects.toThrow(/timed out/); }); test('returns empty array when the request takes too long to finish', async () => { nock('https://cli.cdk.dev-tools.aws.dev') .get('/notices.json') .delayBody(3500) .reply(200, { notices: [BASIC_NOTICE], }); const result = dataSource.fetch(); await expect(result).rejects.toThrow(/timed out/); }); function mockCall(statusCode, body) { nock('https://cli.cdk.dev-tools.aws.dev') .get('/notices.json') .reply(statusCode, body); return dataSource.fetch(); } }); describe(notices_1.CachedDataSource, () => { const fileName = path.join(os.tmpdir(), 'cache.json'); const cachedData = [BASIC_NOTICE]; const freshData = [MULTIPLE_AFFECTED_VERSIONS_NOTICE]; beforeEach(() => { fs.writeFileSync(fileName, ''); }); test('retrieves data from the delegate cache when the file is empty', async () => { const dataSource = dataSourceWithDelegateReturning(freshData); const notices = await dataSource.fetch(); expect(notices).toEqual(freshData); }); test('retrieves data from the file when the data is still valid', async () => { fs.writeJsonSync(fileName, { notices: cachedData, expiration: Date.now() + 10000, }); const dataSource = dataSourceWithDelegateReturning(freshData); const notices = await dataSource.fetch(); expect(notices).toEqual(cachedData); }); test('retrieves data from the delegate when the data is expired', async () => { fs.writeJsonSync(fileName, { notices: cachedData, expiration: 0, }); const dataSource = dataSourceWithDelegateReturning(freshData); const notices = await dataSource.fetch(); expect(notices).toEqual(freshData); }); test('retrieves data from the delegate when the file cannot be read', async () => { const debugSpy = jest.spyOn(logging, 'debug'); if (fs.existsSync('does-not-exist.json')) { fs.unlinkSync('does-not-exist.json'); } const dataSource = dataSourceWithDelegateReturning(freshData, 'does-not-exist.json'); const notices = await dataSource.fetch(); expect(notices).toEqual(freshData); expect(debugSpy).not.toHaveBeenCalled(); debugSpy.mockRestore(); if (fs.existsSync('does-not-exist.json')) { fs.unlinkSync('does-not-exist.json'); } }); test('retrieved data from the delegate when it is configured to ignore the cache', async () => { fs.writeJsonSync(fileName, { notices: cachedData, expiration: Date.now() + 10000, }); const dataSource = dataSourceWithDelegateReturning(freshData, fileName, true); const notices = await dataSource.fetch(); expect(notices).toEqual(freshData); }); test('error in delegate gets turned into empty result by cached source', async () => { // GIVEN const delegate = { fetch: jest.fn().mockRejectedValue(new Error('fetching failed')), }; const dataSource = new notices_1.CachedDataSource(fileName, delegate, true); // WHEN const notices = await dataSource.fetch(); // THEN expect(notices).toEqual([]); }); function dataSourceWithDelegateReturning(notices, file = fileName, ignoreCache = false) { const delegate = { fetch: jest.fn(), }; delegate.fetch.mockResolvedValue(notices); return new notices_1.CachedDataSource(file, delegate, ignoreCache); } }); describe(notices_1.generateMessage, () => { test('does not show anything when there are no notices', async () => { const dataSource = createDataSource(); dataSource.fetch.mockResolvedValue([]); const result = await (0, notices_1.generateMessage)(dataSource, { acknowledgedIssueNumbers: [], outdir: '/tmp', }); expect(result).toEqual(''); }); test('shows notices that pass the filter', async () => { const dataSource = createDataSource(); dataSource.fetch.mockResolvedValue([BASIC_NOTICE, MULTIPLE_AFFECTED_VERSIONS_NOTICE]); const result = await (0, notices_1.generateMessage)(dataSource, { acknowledgedIssueNumbers: [17061], outdir: '/tmp', }); expect(result).toEqual(` NOTICES (What's this? https://github.com/aws/aws-cdk/wiki/CLI-Notices) 16603 Toggling off auto_delete_objects for Bucket empties the bucket Overview: If a stack is deployed with an S3 bucket with auto_delete_objects=True, and then re-deployed with auto_delete_objects=False, all the objects in the bucket will be deleted. Affected versions: cli: <=1.126.0 More information at: https://github.com/aws/aws-cdk/issues/16603 If you don’t want to see a notice anymore, use "cdk acknowledge <id>". For example, "cdk acknowledge 16603".`); }); function createDataSource() { return { fetch: jest.fn(), }; } }); }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWNlcy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibm90aWNlcy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsaUNBQWlDO0FBQ2pDLCtCQUErQjtBQUMvQix5QkFBeUI7QUFDekIsNkJBQTZCO0FBQzdCLCtCQUErQjtBQUMvQiw2QkFBNkI7QUFDN0IsMENBQTBDO0FBQzFDLDRDQU93QjtBQUN4QiwwQ0FBMEM7QUFFMUMsTUFBTSxZQUFZLEdBQUc7SUFDbkIsS0FBSyxFQUFFLGdFQUFnRTtJQUN2RSxXQUFXLEVBQUUsS0FBSztJQUNsQixRQUFRLEVBQUUsNktBQTZLO0lBQ3ZMLFVBQVUsRUFBRSxDQUFDO1lBQ1gsSUFBSSxFQUFFLEtBQUs7WUFDWCxPQUFPLEVBQUUsV0FBVztTQUNyQixDQUFDO0lBQ0YsYUFBYSxFQUFFLEdBQUc7Q0FDbkIsQ0FBQztBQUVGLE1BQU0saUNBQWlDLEdBQUc7SUFDeEMsS0FBSyxFQUFFLHFEQUFxRDtJQUM1RCxXQUFXLEVBQUUsS0FBSztJQUNsQixRQUFRLEVBQUUsd0pBQXdKO0lBQ2xLLFVBQVUsRUFBRSxDQUFDO1lBQ1gsSUFBSSxFQUFFLEtBQUs7WUFDWCxPQUFPLEVBQUUsb0JBQW9CO1NBQzlCLENBQUM7SUFDRixhQUFhLEVBQUUsR0FBRztDQUNuQixDQUFDO0FBRUYsTUFBTSwrQkFBK0IsR0FBRztJQUN0QyxLQUFLLEVBQUUsNkJBQTZCO0lBQ3BDLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLFFBQVEsRUFBRSxzQkFBc0I7SUFDaEMsVUFBVSxFQUFFLENBQUM7WUFDWCxJQUFJLEVBQUUsV0FBVztZQUNqQixPQUFPLEVBQUUsVUFBVTtTQUNwQixDQUFDO0lBQ0YsYUFBYSxFQUFFLEdBQUc7Q0FDbkIsQ0FBQztBQUVGLE1BQU0sdUJBQXVCLEdBQUc7SUFDOUIsS0FBSyxFQUFFLDZCQUE2QjtJQUNwQyxXQUFXLEVBQUUsSUFBSTtJQUNqQixRQUFRLEVBQUUsc0JBQXNCO0lBQ2hDLFVB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QUFDLENBQUMsQ0FBQztRQUVILFNBQVMsZ0JBQWdCO1lBQ3ZCLE9BQU87Z0JBQ0wsS0FBSyxFQUFFLElBQUksQ0FBQyxFQUFFLEVBQUU7YUFDakIsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L29yZGVyICovXG5pbXBvcnQgKiBhcyBodHRwcyBmcm9tICdodHRwcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMtZXh0cmEnO1xuaW1wb3J0ICogYXMgbm9jayBmcm9tICdub2NrJztcbmltcG9ydCAqIGFzIGxvZ2dpbmcgZnJvbSAnLi4vbGliL2xvZ2dpbmcnO1xuaW1wb3J0IHtcbiAgQ2FjaGVkRGF0YVNvdXJjZSxcbiAgZmlsdGVyTm90aWNlcyxcbiAgZm9ybWF0Tm90aWNlcyxcbiAgZ2VuZXJhdGVNZXNzYWdlLFxuICBOb3RpY2UsXG4gIFdlYnNpdGVOb3RpY2VEYXRhU291cmNlLFxufSBmcm9tICcuLi9saWIvbm90aWNlcyc7XG5pbXBvcnQgKiBhcyB2ZXJzaW9uIGZyb20gJy4uL2xpYi92ZXJzaW9uJztcblxuY29uc3QgQkFTSUNfTk9USUNFID0ge1xuICB0aXRsZTogJ1RvZ2dsaW5nIG9mZiBhdXRvX2RlbGV0ZV9vYmplY3RzIGZvciBCdWNrZXQgZW1wdGllcyB0aGUgYnVja2V0JyxcbiAgaXNzdWVOdW1iZXI6IDE2NjAzLFxuICBvdmVydmlldzogJ0lmIGEgc3RhY2sgaXMgZGVwbG95ZWQgd2l0aCBhbiBTMyBidWNrZXQgd2l0aCBhdXRvX2RlbGV0ZV9vYmplY3RzPVRydWUsIGFuZCB0aGVuIHJlLWRlcGxveWVkIHdpdGggYXV0b19kZWxldGVfb2JqZWN0cz1GYWxzZSwgYWxsIHRoZSBvYmplY3RzIGluIHRoZSBidWNrZXQgd2lsbCBiZSBkZWxldGVkLicsXG4gIGNvbXBvbmVudHM6IFt7XG4gICAgbmFtZTogJ2NsaScsXG4gICAgdmVyc2lvbjogJzw9MS4xMjYuMCcsXG4gIH1dLFxuICBzY2hlbWFWZXJzaW9uOiAnMScsXG59O1xuXG5jb25zdCBNVUxUSVBMRV9BRkZFQ1RFRF9WRVJTSU9OU19OT1RJQ0UgPSB7XG4gIHRpdGxlOiAnRXJyb3Igd2hlbiBidWlsZGluZyBFS1MgY2x1c3RlciB3aXRoIG1vbm9jZGsgaW1wb3J0JyxcbiAgaXNzdWVOdW1iZXI6IDE3MDYxLFxuICBvdmVydmlldzogJ1doZW4gdXNpbmcgbW9ub2Nkay9hd3MtZWtzIHRvIGJ1aWxkIGEgc3RhY2sgY29udGFpbmluZyBhbiBFS1MgY2x1c3RlciwgZXJyb3IgaXMgdGhyb3duIGFib3V0IG1pc3NpbmcgbGFtYmRhLWxheWVyLW5vZGUtcHJveHktYWdlbnQvbGF5ZXIvcGFja2FnZS5qc29uLicsXG4gIGNvbXBvbmVudHM6IFt7XG4gICAgbmFtZTogJ2NsaScsXG4gICAgdmVyc2lvbjogJzwxLjEzMC4wID49MS4xMjYuMCcsXG4gIH1dLFxuICBzY2hlbWFWZXJzaW9uOiAnMScsXG59O1xuXG5jb25zdCBGUkFNRVdPUktfMl8xXzBfQUZGRUNURURfTk9USUNFID0ge1xuICB0aXRsZTogJ1JlZ3Jlc3Npb24gb24gbW9kdWxlIGZvb2JhcicsXG4gIGlzc3VlTnVtYmVyOiAxMjM0LFxuICBvdmVydmlldzogJ1NvbWUgYnVnIGRlc2NyaXB0aW9uJyxcbiAgY29tcG9uZW50czogW3tcbiAgICBuYW1lOiAnZnJhbWV3b3JrJyxcbiAgICB2ZXJzaW9uOiAnPD0gMi4xLjAnLFxuICB9XSxcbiAgc2NoZW1hVmVyc2lvbjogJzEnLFxufTtcblxuY29uc3QgTk9USUNFX0ZPUl9BUElHQVRFV0FZVjIgPSB7XG4gIHRpdGxlOiAnUmVncmVzc2lvbiBvbiBtb2R1bGUgZm9vYmFyJyxcbiAgaXNzdWVOdW1iZXI6IDEyMzQsXG4gIG92ZXJ2aWV3OiAnU29tZSBidWcgZGVzY3JpcHRpb24nLFxuICBjb21wb25lbnRzOiBbe1xuICAgIG5hbWU6ICdAYXdzLWNkay9hd3MtYXBpZ2F0ZXdheXYyLWFscGhhLicsXG4gICAgdmVyc2lvbjogJzw9IDIuMTMuMC1hbHBoYS4wJyxcbiAgfV0sXG4gIHNjaGVtYVZlcnNpb246ICcxJyxcbn07XG5cbmNvbnN0IE5PVElDRV9GT1JfQVBJR0FURVdBWSA9IHtcbiAgdGl0bGU6ICdSZWdyZXNzaW9uIG9uIG1vZHVsZSBmb29iYXInLFxuICBpc3N1ZU51bWJlcjogMTIzNCxcbiAgb3ZlcnZpZXc6ICdTb21lIGJ1ZyBkZXNjcmlwdGlvbicsXG4gIGNvbXBvbmVudHM6IFt7XG4gICAgbmFtZTogJ0Bhd3MtY2RrL2F3cy1hcGlnYXRld2F5JyxcbiAgICB2ZXJzaW9uOiAnPD0gMi4xMy4wLWFscGhhLjAnLFxuICB9XSxcbiAgc2NoZW1hVmVyc2lvbjogJzEnLFxufTtcblxuY29uc3QgTk9USUNFX0ZPUl9BUElHQVRFV0FZVjJfQ0ZOX1NUQUdFID0ge1xuICB0aXRsZTogJ1JlZ3Jlc3Npb24gb24gbW9kdWxlIGZvb2JhcicsXG4gIGlzc3VlTnVtYmVyOiAxMjM0LFxuICBvdmVydmlldzogJ1NvbWUgYnVnIGRlc2NyaXB0aW9uJyxcbiAgY29tcG9uZW50czogW3tcbiAgICBuYW1lOiAnYXdzLWNkay1saWIuYXdzX2FwaWdhdGV3YXl2Mi5DZm5TdGFnZScsXG4gICAgdmVyc2lvbjogJzw9IDIuMTMuMC1hbHBoYS4wJyxcbiAgfV0sXG4gIHNjaGVtYVZlcnNpb246ICcxJyxcbn07XG5cbmRlc2NyaWJlKCdjbGkgbm90aWNlcycsICgpID0+IHtcbiAgYmVmb3JlQWxsKCgpID0+IHtcbiAgICBqZXN0XG4gICAgICAuc3B5T24odmVyc2lvbiwgJ3ZlcnNpb25OdW1iZXInKVxuICAgICAgLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiAnMS4wLjAnKTtcbiAgfSk7XG5cbiAgYWZ0ZXJBbGwoKCkgPT4ge1xuICAgIGplc3QucmVzdG9yZUFsbE1vY2tzKCk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKGZvcm1hdE5vdGljZXMsICgpID0+IHtcbiAgICB0ZXN0KCdjb3JyZWN0IGZvcm1hdCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGZvcm1hdE5vdGljZXMoW0JBU0lDX05PVElDRV0pWzBdO1xuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChgMTY2MDNcdFRvZ2dsaW5nIG9mZiBhdXRvX2RlbGV0ZV9vYmplY3RzIGZvciBCdWNrZXQgZW1wdGllcyB0aGUgYnVja2V0XG5cblx0T3ZlcnZpZXc6IElmIGEgc3RhY2sgaXMgZGVwbG95ZWQgd2l0aCBhbiBTMyBidWNrZXQgd2l0aFxuXHQgICAgICAgICAgYXV0b19kZWxldGVfb2JqZWN0cz1UcnVlLCBhbmQgdGhlbiByZS1kZXBsb3llZCB3aXRoXG5cdCAgICAgICAgICBhdXRvX2RlbGV0ZV9vYmplY3RzPUZhbHNlLCBhbGwgdGhlIG9iamVjdHMgaW4gdGhlIGJ1Y2tldFxuXHQgICAgICAgICAgd2lsbCBiZSBkZWxldGVkLlxuXG5cdEFmZmVjdGVkIHZlcnNpb25zOiBjbGk6IDw9MS4xMjYuMFxuXG5cdE1vcmUgaW5mb3JtYXRpb24gYXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvMTY2MDNcbmApO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnbXVsdGlwbGUgYWZmZWN0IHZlcnNpb25zJywgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gZm9ybWF0Tm90aWNlcyhbTVVMVElQTEVfQUZGRUNURURfVkVSU0lPTlNfTk9USUNFXSlbMF07XG4gICAgICBleHBlY3QocmVzdWx0KS50b0VxdWFsKGAxNzA2MVx0RXJyb3Igd2hlbiBidWlsZGluZyBFS1MgY2x1c3RlciB3aXRoIG1vbm9jZGsgaW1wb3J0XG5cblx0T3ZlcnZpZXc6IFdoZW4gdXNpbmcgbW9ub2Nkay9hd3MtZWtzIHRvIGJ1aWxkIGEgc3RhY2sgY29udGFpbmluZyBhblxuXHQgICAgICAgICAgRUtTIGNsdXN0ZXIsIGVycm9yIGlzIHRocm93biBhYm91dCBtaXNzaW5nXG5cdCAgICAgICAgICBsYW1iZGEtbGF5ZXItbm9kZS1wcm94eS1hZ2VudC9sYXllci9wYWNrYWdlLmpzb24uXG5cblx0QWZmZWN0ZWQgdmVyc2lvbnM6IGNsaTogPDEuMTMwLjAgPj0xLjEyNi4wXG5cblx0TW9yZSBpbmZvcm1hdGlvbiBhdDogaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3MtY2RrL2lzc3Vlcy8xNzA2MVxuYCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKGZpbHRlck5vdGljZXMsICgpID0+IHtcbiAgICB0ZXN0KCdjb3JyZWN0bHkgZmlsdGVyIG5vdGljZXMgb24gY2xpJywgKCkgPT4ge1xuICAgICAgY29uc3Qgbm90aWNlcyA9IFtCQVNJQ19OT1RJQ0UsIE1VTFRJUExFX0FGRkVDVEVEX1ZFUlNJT05TX05PVElDRV07XG4gICAgICBleHBlY3QoZmlsdGVyTm90aWNlcyhub3RpY2VzLCB7XG4gICAgICAgIGNsaVZlcnNpb246ICcxLjAuMCcsXG4gICAgICB9KSkudG9FcXVhbChbQkFTSUNfTk9USUNFXSk7XG5cbiAgICAgIGV4cGVjdChmaWx0ZXJOb3RpY2VzKG5vdGljZXMsIHtcbiAgICAgICAgY2xpVmVyc2lvbjogJzEuMTI5LjAnLFxuICAgICAgfSkpLnRvRXF1YWwoW01VTFRJUExFX0FGRkVDVEVEX1ZFUlNJT05TX05PVElDRV0pO1xuXG4gICAgICBleHBlY3QoZmlsdGVyTm90aWNlcyhub3RpY2VzLCB7XG4gICAgICAgIGNsaVZlcnNpb246ICcxLjEyNi4wJyxcbiAgICAgIH0pKS50b0VxdWFsKG5vdGljZXMpO1xuXG4gICAgICBleHBlY3QoZmlsdGVyTm90aWNlcyhub3RpY2VzLCB7XG4gICAgICAgIGNsaVZlcnNpb246ICcxLjEzMC4wJyxcbiAgICAgIH0pKS50b0VxdWFsKFtdKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ2NvcnJlY3RseSBmaWx0ZXIgbm90aWNlcyBvbiBmcmFtZXdvcmsnLCAoKSA9PiB7XG4gICAgICBjb25zdCBub3RpY2VzID0gW0ZSQU1FV09SS18yXzFfMF9BRkZFQ1RFRF9OT1RJQ0VdO1xuXG4gICAgICBleHBlY3QoZmlsdGVyTm90aWNlcyhub3RpY2VzLCB7XG4gICAgICAgIG91dGRpcjogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2Nsb3VkLWFzc2VtYmx5LXRyZWVzL2J1aWx0LXdpdGgtMl8xMl8wJyksXG4gICAgICB9KSkudG9FcXVhbChbXSk7XG5cbiAgICAgIGV4cGVjdChmaWx0ZXJOb3RpY2VzKG5vdGljZXMsIHtcbiAgICAgICAgb3V0ZGlyOiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnY2xvdWQtYXNzZW1ibHktdHJlZXMvYnVpbHQtd2l0aC0xXzE0NF8wJyksXG4gICAgICB9KSkudG9FcXVhbChbRlJBTUVXT1JLXzJfMV8wX0FGRkVDVEVEX05PVElDRV0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnY29ycmVjdGx5IGZpbHRlciBub3RpY2VzIG9uIGFyYml0cmFyeSBtb2R1bGVzJywgKCkgPT4ge1xuICAgICAgY29uc3Qgbm90aWNlcyA9IFtOT1RJQ0VfRk9SX0FQSUdBVEVXQVlWMl07XG5cbiAgICAgIC8vIG1vZHVsZS1sZXZlbCBtYXRjaFxuICAgICAgZXhwZWN0KGZpbHRlck5vdGljZXMobm90aWNlcywge1xuICAgICAgICBvdXRkaXI6IHBhdGguam9pbihfX2Rpcm5hbWUsICdjbG91ZC1hc3NlbWJseS10cmVlcy9leHBlcmltZW50YWwtbW9kdWxlJyksXG4gICAgICB9KSkudG9FcXVhbChbTk9USUNFX0ZPUl9BUElHQVRFV0FZVjJdKTtcblxuICAgICAgLy8gbm8gYXBpZ2F0ZXdheXYyIGluIHRoZSB0cmVlXG4gICAgICBleHBlY3QoZmlsdGVyTm90aWNlcyhub3RpY2VzLCB7XG4gICAgICAgIG91dGRpcjogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2Nsb3VkLWFzc2VtYmx5LXRyZWVzL2J1aWx0LXdpdGgtMl8xMl8wJyksXG4gICAgICB9KSkudG9FcXVhbChbXSk7XG5cbiAgICAgIC8vIG1vZHVsZSBuYW1lIG1pc21hdGNoOiBhcGlnYXRld2F5ICE9IGFwaWdhdGV3YXl2MlxuICAgICAgZXhwZWN0KGZpbHRlck5vdGljZXMoW05PVElDRV9GT1JfQVBJR0FURVdBWV0sIHtcbiAgICAgICAgb3V0ZGlyOiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnY2xvdWQtYXNzZW1ibHktdHJlZXMvZXhwZXJpbWVudGFsLW1vZHVsZScpLFxuICAgICAgfSkpLnRvRXF1YWwoW10pO1xuXG4gICAgICAvLyBjb25zdHJ1Y3QtbGV2ZWwgbWF0Y2hcbiAgICAgIGV4cGVjdChmaWx0ZXJOb3RpY2VzKFtOT1RJQ0VfRk9SX0FQSUdBVEVXQVlWMl9DRk5fU1RBR0VdLCB7XG4gICAgICAgIG91dGRpcjogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2Nsb3VkLWFzc2VtYmx5LXRyZWVzL2V4cGVyaW1lbnRhbC1tb2R1bGUnKSxcbiAgICAgIH0pKS50b0VxdWFsKFtOT1RJQ0VfRk9SX0FQSUdBVEVXQVlWMl9DRk5fU1RBR0VdKTtcbiAgICB9KTtcblxuICB9KTtcblxuICBkZXNjcmliZShXZWJzaXRlTm90aWNlRGF0YVNvdXJjZSwgKCkgPT4ge1xuICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBuZXcgV2Vic2l0ZU5vdGljZURhdGFTb3VyY2UoKTtcblxuICAgIHRlc3QoJ3JldHVybnMgZGF0YSB3aGVuIGRvd25sb2FkIHN1Y2NlZWRzJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgbW9ja0NhbGwoMjAwLCB7XG4gICAgICAgIG5vdGljZXM6IFtCQVNJQ19OT1RJQ0UsIE1VTFRJUExFX0FGRkVDVEVEX1ZFUlNJT05TX05PVElDRV0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChbQkFTSUNfTk9USUNFLCBNVUxUSVBMRV9BRkZFQ1RFRF9WRVJTSU9OU19OT1RJQ0VdKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3JldHVybnMgYXBwcm9wcmlhdGUgZXJyb3Igd2hlbiB0aGUgc2VydmVyIHJldHVybnMgYW4gdW5leHBlY3RlZCBzdGF0dXMgY29kZScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IG1vY2tDYWxsKDUwMCwge1xuICAgICAgICBub3RpY2VzOiBbQkFTSUNfTk9USUNFLCBNVUxUSVBMRV9BRkZFQ1RFRF9WRVJTSU9OU19OT1RJQ0VdLFxuICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IGV4cGVjdChyZXN1bHQpLnJlamVjdHMudG9UaHJvdygvNTAwLyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXR1cm5zIGFwcHJvcHJpYXRlIGVycm9yIHdoZW4gdGhlIHNlcnZlciByZXR1cm5zIGFuIHVuZXhwZWN0ZWQgc3RydWN0dXJlJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcmVzdWx0ID0gbW9ja0NhbGwoMjAwLCB7XG4gICAgICAgIGZvbzogW0JBU0lDX05PVElDRSwgTVVMVElQTEVfQUZGRUNURURfVkVSU0lPTlNfTk9USUNFXSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBleHBlY3QocmVzdWx0KS5yZWplY3RzLnRvVGhyb3coL2tleSBpcyBtaXNzaW5nLyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXR1cm5zIGFwcHJvcHJpYXRlIGVycm9yIHdoZW4gdGhlIHNlcnZlciByZXR1cm5zIGludmFsaWQganNvbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IG1vY2tDYWxsKDIwMCwgJy0wOWFpc2tqa2o4MzgnKTtcblxuICAgICAgYXdhaXQgZXhwZWN0KHJlc3VsdCkucmVqZWN0cy50b1Rocm93KC9GYWlsZWQgdG8gcGFyc2UvKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3JldHVybnMgYXBwcm9wcmlhdGUgZXJyb3Igd2hlbiBIVFRQUyBjYWxsIHRocm93cycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IG1vY2tHZXQgPSBqZXN0LnNweU9uKGh0dHBzLCAnZ2V0JylcbiAgICAgICAgLm1vY2tJbXBsZW1lbnRhdGlvbigoKSA9PiB7IHRocm93IG5ldyBFcnJvcignTm8gY29ubmVjdGlvbicpOyB9KTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gZGF0YVNvdXJjZS5mZXRjaCgpO1xuXG4gICAgICBhd2FpdCBleHBlY3QocmVzdWx0KS5yZWplY3RzLnRvVGhyb3coL05vIGNvbm5lY3Rpb24vKTtcblxuICAgICAgbW9ja0dldC5tb2NrUmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgncmV0dXJucyBhcHByb3ByaWF0ZSBlcnJvciB3aGVuIHRoZSByZXF1ZXN0IGhhcyBhbiBlcnJvcicsIGFzeW5jICgpID0+IHtcbiAgICAgIG5vY2soJ2h0dHBzOi8vY2xpLmNkay5kZXYtdG9vbHMuYXdzLmRldicpXG4gICAgICAgIC5nZXQoJy9ub3RpY2VzLmpzb24nKVxuICAgICAgICAucmVwbHlXaXRoRXJyb3IoJ0ROUyByZXNvbHV0aW9uIGZhaWxlZCcpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBkYXRhU291cmNlLmZldGNoKCk7XG5cbiAgICAgIGF3YWl0IGV4cGVjdChyZXN1bHQpLnJlamVjdHMudG9UaHJvdygvRE5TIHJlc29sdXRpb24gZmFpbGVkLyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXR1cm5zIGFwcHJvcHJpYXRlIGVycm9yIHdoZW4gdGhlIGNvbm5lY3Rpb24gc3RheXMgaWRsZSBmb3IgdG9vIGxvbmcnLCBhc3luYyAoKSA9PiB7XG4gICAgICBub2NrKCdodHRwczovL2NsaS5jZGsuZGV2LXRvb2xzLmF3cy5kZXYnKVxuICAgICAgICAuZ2V0KCcvbm90aWNlcy5qc29uJylcbiAgICAgICAgLmRlbGF5Q29ubmVjdGlvbigzNTAwKVxuICAgICAgICAucmVwbHkoMjAwLCB7XG4gICAgICAgICAgbm90aWNlczogW0JBU0lDX05PVElDRV0sXG4gICAgICAgIH0pO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBkYXRhU291cmNlLmZldGNoKCk7XG5cbiAgICAgIGF3YWl0IGV4cGVjdChyZXN1bHQpLnJlamVjdHMudG9UaHJvdygvdGltZWQgb3V0Lyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXR1cm5zIGVtcHR5IGFycmF5IHdoZW4gdGhlIHJlcXVlc3QgdGFrZXMgdG9vIGxvbmcgdG8gZmluaXNoJywgYXN5bmMgKCkgPT4ge1xuICAgICAgbm9jaygnaHR0cHM6Ly9jbGkuY2RrLmRldi10b29scy5hd3MuZGV2JylcbiAgICAgICAgLmdldCgnL25vdGljZXMuanNvbicpXG4gICAgICAgIC5kZWxheUJvZHkoMzUwMClcbiAgICAgICAgLnJlcGx5KDIwMCwge1xuICAgICAgICAgIG5vdGljZXM6IFtCQVNJQ19OT1RJQ0VdLFxuICAgICAgICB9KTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gZGF0YVNvdXJjZS5mZXRjaCgpO1xuXG4gICAgICBhd2FpdCBleHBlY3QocmVzdWx0KS5yZWplY3RzLnRvVGhyb3coL3RpbWVkIG91dC8pO1xuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gbW9ja0NhbGwoc3RhdHVzQ29kZTogbnVtYmVyLCBib2R5OiBhbnkpOiBQcm9taXNlPE5vdGljZVtdPiB7XG4gICAgICBub2NrKCdodHRwczovL2NsaS5jZGsuZGV2LXRvb2xzLmF3cy5kZXYnKVxuICAgICAgICAuZ2V0KCcvbm90aWNlcy5qc29uJylcbiAgICAgICAgLnJlcGx5KHN0YXR1c0NvZGUsIGJvZHkpO1xuXG4gICAgICByZXR1cm4gZGF0YVNvdXJjZS5mZXRjaCgpO1xuICAgIH1cbiAgfSk7XG5cbiAgZGVzY3JpYmUoQ2FjaGVkRGF0YVNvdXJjZSwgKCkgPT4ge1xuICAgIGNvbnN0IGZpbGVOYW1lID0gcGF0aC5qb2luKG9zLnRtcGRpcigpLCAnY2FjaGUuanNvbicpO1xuICAgIGNvbnN0IGNhY2hlZERhdGEgPSBbQkFTSUNfTk9USUNFXTtcbiAgICBjb25zdCBmcmVzaERhdGEgPSBbTVVMVElQTEVfQUZGRUNURURfVkVSU0lPTlNfTk9USUNFXTtcblxuICAgIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgICAgZnMud3JpdGVGaWxlU3luYyhmaWxlTmFtZSwgJycpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgncmV0cmlldmVzIGRhdGEgZnJvbSB0aGUgZGVsZWdhdGUgY2FjaGUgd2hlbiB0aGUgZmlsZSBpcyBlbXB0eScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBkYXRhU291cmNlV2l0aERlbGVnYXRlUmV0dXJuaW5nKGZyZXNoRGF0YSk7XG5cbiAgICAgIGNvbnN0IG5vdGljZXMgPSBhd2FpdCBkYXRhU291cmNlLmZldGNoKCk7XG5cbiAgICAgIGV4cGVjdChub3RpY2VzKS50b0VxdWFsKGZyZXNoRGF0YSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXRyaWV2ZXMgZGF0YSBmcm9tIHRoZSBmaWxlIHdoZW4gdGhlIGRhdGEgaXMgc3RpbGwgdmFsaWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBmcy53cml0ZUpzb25TeW5jKGZpbGVOYW1lLCB7XG4gICAgICAgIG5vdGljZXM6IGNhY2hlZERhdGEsXG4gICAgICAgIGV4cGlyYXRpb246IERhdGUubm93KCkgKyAxMDAwMCxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgZGF0YVNvdXJjZSA9IGRhdGFTb3VyY2VXaXRoRGVsZWdhdGVSZXR1cm5pbmcoZnJlc2hEYXRhKTtcblxuICAgICAgY29uc3Qgbm90aWNlcyA9IGF3YWl0IGRhdGFTb3VyY2UuZmV0Y2goKTtcblxuICAgICAgZXhwZWN0KG5vdGljZXMpLnRvRXF1YWwoY2FjaGVkRGF0YSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXRyaWV2ZXMgZGF0YSBmcm9tIHRoZSBkZWxlZ2F0ZSB3aGVuIHRoZSBkYXRhIGlzIGV4cGlyZWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBmcy53cml0ZUpzb25TeW5jKGZpbGVOYW1lLCB7XG4gICAgICAgIG5vdGljZXM6IGNhY2hlZERhdGEsXG4gICAgICAgIGV4cGlyYXRpb246IDAsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBkYXRhU291cmNlV2l0aERlbGVnYXRlUmV0dXJuaW5nKGZyZXNoRGF0YSk7XG5cbiAgICAgIGNvbnN0IG5vdGljZXMgPSBhd2FpdCBkYXRhU291cmNlLmZldGNoKCk7XG5cbiAgICAgIGV4cGVjdChub3RpY2VzKS50b0VxdWFsKGZyZXNoRGF0YSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdyZXRyaWV2ZXMgZGF0YSBmcm9tIHRoZSBkZWxlZ2F0ZSB3aGVuIHRoZSBmaWxlIGNhbm5vdCBiZSByZWFkJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZGVidWdTcHkgPSBqZXN0LnNweU9uKGxvZ2dpbmcsICdkZWJ1ZycpO1xuXG4gICAgICBpZiAoZnMuZXhpc3RzU3luYygnZG9lcy1ub3QtZXhpc3QuanNvbicpKSB7XG4gICAgICAgIGZzLnVubGlua1N5bmMoJ2RvZXMtbm90LWV4aXN0Lmpzb24nKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgZGF0YVNvdXJjZSA9IGRhdGFTb3VyY2VXaXRoRGVsZWdhdGVSZXR1cm5pbmcoZnJlc2hEYXRhLCAnZG9lcy1ub3QtZXhpc3QuanNvbicpO1xuXG4gICAgICBjb25zdCBub3RpY2VzID0gYXdhaXQgZGF0YVNvdXJjZS5mZXRjaCgpO1xuXG4gICAgICBleHBlY3Qobm90aWNlcykudG9FcXVhbChmcmVzaERhdGEpO1xuICAgICAgZXhwZWN0KGRlYnVnU3B5KS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuXG4gICAgICBkZWJ1Z1NweS5tb2NrUmVzdG9yZSgpO1xuXG4gICAgICBpZiAoZnMuZXhpc3RzU3luYygnZG9lcy1ub3QtZXhpc3QuanNvbicpKSB7XG4gICAgICAgIGZzLnVubGlua1N5bmMoJ2RvZXMtbm90LWV4aXN0Lmpzb24nKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRlc3QoJ3JldHJpZXZlZCBkYXRhIGZyb20gdGhlIGRlbGVnYXRlIHdoZW4gaXQgaXMgY29uZmlndXJlZCB0byBpZ25vcmUgdGhlIGNhY2hlJywgYXN5bmMgKCkgPT4ge1xuICAgICAgZnMud3JpdGVKc29uU3luYyhmaWxlTmFtZSwge1xuICAgICAgICBub3RpY2VzOiBjYWNoZWREYXRhLFxuICAgICAgICBleHBpcmF0aW9uOiBEYXRlLm5vdygpICsgMTAwMDAsXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBkYXRhU291cmNlV2l0aERlbGVnYXRlUmV0dXJuaW5nKGZyZXNoRGF0YSwgZmlsZU5hbWUsIHRydWUpO1xuXG4gICAgICBjb25zdCBub3RpY2VzID0gYXdhaXQgZGF0YVNvdXJjZS5mZXRjaCgpO1xuXG4gICAgICBleHBlY3Qobm90aWNlcykudG9FcXVhbChmcmVzaERhdGEpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnZXJyb3IgaW4gZGVsZWdhdGUgZ2V0cyB0dXJuZWQgaW50byBlbXB0eSByZXN1bHQgYnkgY2FjaGVkIHNvdXJjZScsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEdJVkVOXG4gICAgICBjb25zdCBkZWxlZ2F0ZSA9IHtcbiAgICAgICAgZmV0Y2g6IGplc3QuZm4oKS5tb2NrUmVqZWN0ZWRWYWx1ZShuZXcgRXJyb3IoJ2ZldGNoaW5nIGZhaWxlZCcpKSxcbiAgICAgIH07XG4gICAgICBjb25zdCBkYXRhU291cmNlID0gbmV3IENhY2hlZERhdGFTb3VyY2UoZmlsZU5hbWUsIGRlbGVnYXRlLCB0cnVlKTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgY29uc3Qgbm90aWNlcyA9IGF3YWl0IGRhdGFTb3VyY2UuZmV0Y2goKTtcblxuICAgICAgLy8gVEhFTlxuICAgICAgZXhwZWN0KG5vdGljZXMpLnRvRXF1YWwoW10pO1xuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gZGF0YVNvdXJjZVdpdGhEZWxlZ2F0ZVJldHVybmluZyhub3RpY2VzOiBOb3RpY2VbXSwgZmlsZTogc3RyaW5nID0gZmlsZU5hbWUsIGlnbm9yZUNhY2hlOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICAgIGNvbnN0IGRlbGVnYXRlID0ge1xuICAgICAgICBmZXRjaDogamVzdC5mbigpLFxuICAgICAgfTtcblxuICAgICAgZGVsZWdhdGUuZmV0Y2gubW9ja1Jlc29sdmVkVmFsdWUobm90aWNlcyk7XG4gICAgICByZXR1cm4gbmV3IENhY2hlZERhdGFTb3VyY2UoZmlsZSwgZGVsZWdhdGUsIGlnbm9yZUNhY2hlKTtcbiAgICB9XG4gIH0pO1xuXG4gIGRlc2NyaWJlKGdlbmVyYXRlTWVzc2FnZSwgKCkgPT4ge1xuICAgIHRlc3QoJ2RvZXMgbm90IHNob3cgYW55dGhpbmcgd2hlbiB0aGVyZSBhcmUgbm8gbm90aWNlcycsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IGRhdGFTb3VyY2UgPSBjcmVhdGVEYXRhU291cmNlKCk7XG4gICAgICBkYXRhU291cmNlLmZldGNoLm1vY2tSZXNvbHZlZFZhbHVlKFtdKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgZ2VuZXJhdGVNZXNzYWdlKGRhdGFTb3VyY2UsIHtcbiAgICAgICAgYWNrbm93bGVkZ2VkSXNzdWVOdW1iZXJzOiBbXSxcbiAgICAgICAgb3V0ZGlyOiAnL3RtcCcsXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbCgnJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdzaG93cyBub3RpY2VzIHRoYXQgcGFzcyB0aGUgZmlsdGVyJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgZGF0YVNvdXJjZSA9IGNyZWF0ZURhdGFTb3VyY2UoKTtcbiAgICAgIGRhdGFTb3VyY2UuZmV0Y2gubW9ja1Jlc29sdmVkVmFsdWUoW0JBU0lDX05PVElDRSwgTVVMVElQTEVfQUZGRUNURURfVkVSU0lPTlNfTk9USUNFXSk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IGdlbmVyYXRlTWVzc2FnZShkYXRhU291cmNlLCB7XG4gICAgICAgIGFja25vd2xlZGdlZElzc3VlTnVtYmVyczogWzE3MDYxXSxcbiAgICAgICAgb3V0ZGlyOiAnL3RtcCcsXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KHJlc3VsdCkudG9FcXVhbChgXG5OT1RJQ0VTICAgICAgICAgKFdoYXQncyB0aGlzPyBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvd2lraS9DTEktTm90aWNlcylcblxuMTY2MDNcdFRvZ2dsaW5nIG9mZiBhdXRvX2RlbGV0ZV9vYmplY3RzIGZvciBCdWNrZXQgZW1wdGllcyB0aGUgYnVja2V0XG5cblx0T3ZlcnZpZXc6IElmIGEgc3RhY2sgaXMgZGVwbG95ZWQgd2l0aCBhbiBTMyBidWNrZXQgd2l0aFxuXHQgICAgICAgICAgYXV0b19kZWxldGVfb2JqZWN0cz1UcnVlLCBhbmQgdGhlbiByZS1kZXBsb3llZCB3aXRoXG5cdCAgICAgICAgICBhdXRvX2RlbGV0ZV9vYmplY3RzPUZhbHNlLCBhbGwgdGhlIG9iamVjdHMgaW4gdGhlIGJ1Y2tldFxuXHQgICAgICAgICAgd2lsbCBiZSBkZWxldGVkLlxuXG5cdEFmZmVjdGVkIHZlcnNpb25zOiBjbGk6IDw9MS4xMjYuMFxuXG5cdE1vcmUgaW5mb3JtYXRpb24gYXQ6IGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvMTY2MDNcblxuXG5JZiB5b3UgZG9u4oCZdCB3YW50IHRvIHNlZSBhIG5vdGljZSBhbnltb3JlLCB1c2UgXCJjZGsgYWNrbm93bGVkZ2UgPGlkPlwiLiBGb3IgZXhhbXBsZSwgXCJjZGsgYWNrbm93bGVkZ2UgMTY2MDNcIi5gKTtcbiAgICB9KTtcblxuICAgIGZ1bmN0aW9uIGNyZWF0ZURhdGFTb3VyY2UoKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICBmZXRjaDogamVzdC5mbigpLFxuICAgICAgfTtcbiAgICB9XG4gIH0pO1xufSk7XG4iXX0=