UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

320 lines 43.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const fs = require("fs"); const path = require("path"); const cxschema = require("@aws-cdk/cloud-assembly-schema"); const cx_api_1 = require("@aws-cdk/cx-api"); // eslint-disable-next-line import/no-extraneous-dependencies const globals_1 = require("@jest/globals"); const work_graph_builder_1 = require("../lib/util/work-graph-builder"); let rootBuilder; beforeEach(() => { rootBuilder = new cx_api_1.CloudAssemblyBuilder(); }); afterEach(() => { rootBuilder.delete(); }); function superset(xs) { const ret = new Set(xs); ret.isSuperset = true; return ret; } globals_1.expect.addEqualityTesters([ function (exp, act) { if (exp instanceof Set && isIterable(act)) { if (exp.isSuperset) { const actSet = new Set(act); return Array.from(exp).every((x) => actSet.has(x)); } return this.equals(Array.from(exp).sort(), Array.from(act).sort()); } return undefined; }, ]); describe('with some stacks and assets', () => { let assembly; beforeEach(() => { addSomeStacksAndAssets(rootBuilder); assembly = rootBuilder.buildAssembly(); }); test('stack depends on the asset publishing step', () => { const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); (0, globals_1.expect)(assertableNode(graph.node('stack2'))).toEqual(globals_1.expect.objectContaining({ type: 'stack', dependencies: superset(['publish-F1-add54bdbcb']), })); }); test('asset publishing step depends on asset building step', () => { const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); (0, globals_1.expect)(graph.node('publish-F1-add54bdbcb')).toEqual(globals_1.expect.objectContaining({ type: 'asset-publish', dependencies: superset(['build-F1-a533139934']), })); }); test('with prebuild off, asset building inherits dependencies from their parent stack', () => { const graph = new work_graph_builder_1.WorkGraphBuilder(false).build(assembly.artifacts); (0, globals_1.expect)(graph.node('build-F1-a533139934')).toEqual(globals_1.expect.objectContaining({ type: 'asset-build', dependencies: superset(['stack0', 'stack1']), })); }); test('with prebuild on, assets only have their own dependencies', () => { const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); (0, globals_1.expect)(graph.node('build-F1-a533139934')).toEqual(globals_1.expect.objectContaining({ type: 'asset-build', dependencies: superset(['stack0']), })); }); }); test('tree metadata is ignored', async () => { rootBuilder.addArtifact('tree', { type: cxschema.ArtifactType.CDK_TREE, properties: { file: 'doesnotexist.json', }, }); const assembly = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); (0, globals_1.expect)(graph.ready().length).toEqual(0); }); test('can handle nested assemblies', async () => { addSomeStacksAndAssets(rootBuilder); const nested = rootBuilder.createNestedAssembly('nested', 'Nested Assembly'); addSomeStacksAndAssets(nested); nested.buildAssembly(); const assembly = rootBuilder.buildAssembly(); let workDone = 0; const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); await graph.doParallel(10, { deployStack: async () => { workDone += 1; }, buildAsset: async () => { }, publishAsset: async () => { workDone += 1; }, }); // The asset is shared between parent assembly and nested assembly, but the stacks will be deployed // 3 stacks + 1 asset + 3 stacks (1 reused asset) (0, globals_1.expect)(workDone).toEqual(7); }); test('dependencies on unselected artifacts are silently ignored', async () => { addStack(rootBuilder, 'stackA', { environment: 'aws://222222/us-east-1', }); addStack(rootBuilder, 'stackB', { dependencies: ['stackA'], environment: 'aws://222222/us-east-1', }); const asm = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build([asm.getStackArtifact('stackB')]); (0, globals_1.expect)(graph.ready()[0]).toEqual(globals_1.expect.objectContaining({ id: 'stackB', dependencies: new Set(), })); }); describe('tests that use assets', () => { const files = { // Referencing an existing file on disk is important here. // It means these two assets will have the same AssetManifest // and the graph will merge the two into a single asset. 'work-graph-builder.test.js': { source: { path: __dirname }, destinations: { D1: { bucketName: 'bucket', objectKey: 'key' }, }, }, }; const environment = 'aws://11111/us-east-1'; test('assets with shared contents between dependant stacks', async () => { addStack(rootBuilder, 'StackA', { environment: 'aws://11111/us-east-1', dependencies: ['StackA.assets'], }); addAssets(rootBuilder, 'StackA.assets', { files }); addStack(rootBuilder, 'StackB', { environment: 'aws://11111/us-east-1', dependencies: ['StackB.assets', 'StackA'], }); addAssets(rootBuilder, 'StackB.assets', { files }); const assembly = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); const traversal = await traverseAndRecord(graph); (0, globals_1.expect)(traversal).toEqual([ globals_1.expect.stringMatching(/^build-work-graph-builder.test.js-.*$/), globals_1.expect.stringMatching(/^publish-work-graph-builder.test.js-.*$/), 'StackA', 'StackB', ]); }); test('a more complex way to make a cycle', async () => { // A -> B -> C | A and C share an asset. The asset will have a dependency on B, that is not a *direct* reverse dependency, and will cause a cycle. addStack(rootBuilder, 'StackA', { environment, dependencies: ['StackA.assets', 'StackB'] }); addAssets(rootBuilder, 'StackA.assets', { files }); addStack(rootBuilder, 'StackB', { environment, dependencies: ['StackC'] }); addStack(rootBuilder, 'StackC', { environment, dependencies: ['StackC.assets'] }); addAssets(rootBuilder, 'StackC.assets', { files }); const assembly = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); // THEN (0, globals_1.expect)(graph.findCycle()).toBeUndefined(); }); test('the same asset to different destinations is only built once', async () => { addStack(rootBuilder, 'StackA', { environment: 'aws://11111/us-east-1', dependencies: ['StackA.assets'], }); addAssets(rootBuilder, 'StackA.assets', { files: { abcdef: { source: { path: __dirname }, destinations: { D1: { bucketName: 'bucket1', objectKey: 'key' }, D2: { bucketName: 'bucket2', objectKey: 'key' }, }, }, }, }); addStack(rootBuilder, 'StackB', { environment: 'aws://11111/us-east-1', dependencies: ['StackB.assets', 'StackA'], }); addAssets(rootBuilder, 'StackB.assets', { files: { abcdef: { source: { path: __dirname }, destinations: { D3: { bucketName: 'bucket3', objectKey: 'key' }, }, }, }, }); const assembly = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); const traversal = await traverseAndRecord(graph); (0, globals_1.expect)(traversal).toEqual([ globals_1.expect.stringMatching(/^build-abcdef-.*$/), globals_1.expect.stringMatching(/^publish-abcdef-.*$/), globals_1.expect.stringMatching(/^publish-abcdef-.*$/), 'StackA', globals_1.expect.stringMatching(/^publish-abcdef-.*$/), 'StackB', ]); }); test('different parameters for the same named definition are both published', async () => { addStack(rootBuilder, 'StackA', { environment: 'aws://11111/us-east-1', dependencies: ['StackA.assets'], }); addAssets(rootBuilder, 'StackA.assets', { files: { abcdef: { source: { path: __dirname }, destinations: { D: { bucketName: 'bucket1', objectKey: 'key' }, }, }, }, }); addStack(rootBuilder, 'StackB', { environment: 'aws://11111/us-east-1', dependencies: ['StackB.assets', 'StackA'], }); addAssets(rootBuilder, 'StackB.assets', { files: { abcdef: { source: { path: __dirname }, destinations: { D: { bucketName: 'bucket2', objectKey: 'key' }, }, }, }, }); const assembly = rootBuilder.buildAssembly(); const graph = new work_graph_builder_1.WorkGraphBuilder(true).build(assembly.artifacts); const traversal = await traverseAndRecord(graph); (0, globals_1.expect)(traversal).toEqual([ globals_1.expect.stringMatching(/^build-abcdef-.*$/), globals_1.expect.stringMatching(/^publish-abcdef-.*$/), 'StackA', globals_1.expect.stringMatching(/^publish-abcdef-.*$/), 'StackB', ]); }); }); /** * Write an asset manifest file and add it to the assembly builder */ function addAssets(builder, artifactId, options) { const manifestFile = `${artifactId}.json`; const outPath = path.join(builder.outdir, manifestFile); const manifest = { version: cxschema.Manifest.version(), files: options.files, }; fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2)); builder.addArtifact(artifactId, { type: cxschema.ArtifactType.ASSET_MANIFEST, dependencies: options.dependencies, properties: { file: manifestFile, }, }); } /** * Add a stack to the cloud assembly */ function addStack(builder, stackId, options) { const templateFile = `${stackId}.template.json`; const outPath = path.join(builder.outdir, templateFile); fs.writeFileSync(outPath, JSON.stringify({}, undefined, 2)); builder.addArtifact(stackId, { type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK, dependencies: options.dependencies, environment: options.environment, properties: { templateFile, }, }); } function addSomeStacksAndAssets(builder) { addStack(builder, 'stack0', { environment: 'aws://11111/us-east-1', }); addAssets(builder, 'stack2assets', { dependencies: ['stack0'], files: { F1: { source: { path: 'xyz' }, destinations: { D1: { bucketName: 'bucket', objectKey: 'key' }, }, }, }, }); addStack(builder, 'stack1', { environment: 'aws://11111/us-east-1', }); addStack(builder, 'stack2', { environment: 'aws://11111/us-east-1', dependencies: ['stack2assets', 'stack1'], }); } /** * We can't do arrayContaining on the set that a Node has, so convert it to an array for asserting */ function assertableNode(x) { return { ...x, dependencies: Array.from(x.dependencies), }; } async function traverseAndRecord(graph) { const ret = []; await graph.doParallel(1, { deployStack: async (node) => { ret.push(node.id); }, buildAsset: async (node) => { ret.push(node.id); }, publishAsset: async (node) => { ret.push(node.id); }, }); return ret; } function isIterable(x) { return x && typeof x === 'object' && x[Symbol.iterator]; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29yay1ncmFwaC1idWlsZGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ3b3JrLWdyYXBoLWJ1aWxkZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsMkRBQTJEO0FBRTNELDRDQUF1RDtBQUN2RCw2REFBNkQ7QUFDN0QsMkNBQXVDO0FBRXZDLHVFQUFrRTtBQUdsRSxJQUFJLFdBQWlDLENBQUM7QUFDdEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUNkLFdBQVcsR0FBRyxJQUFJLDZCQUFvQixFQUFFLENBQUM7QUFDM0MsQ0FBQyxDQUFDLENBQUM7QUFFSCxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ2IsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO0FBQ3ZCLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxRQUFRLENBQUksRUFBTztJQUMxQixNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2QixHQUFXLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztJQUMvQixPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxnQkFBTSxDQUFDLGtCQUFrQixDQUFDO0lBQ3hCLFVBQVMsR0FBWSxFQUFFLEdBQVk7UUFDakMsSUFBSSxHQUFHLFlBQVksR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUN6QyxJQUFLLEdBQVcsQ0FBQyxVQUFVLEVBQUU7Z0JBQzNCLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM1QixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBVSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDM0Q7WUFDRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7U0FDcEU7UUFDRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0NBQ0YsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLDZCQUE2QixFQUFFLEdBQUcsRUFBRTtJQUMzQyxJQUFJLFFBQTZCLENBQUM7SUFDbEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLHNCQUFzQixDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ3BDLFFBQVEsR0FBRyxXQUFXLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDekMsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsNENBQTRDLEVBQUUsR0FBRyxFQUFFO1FBQ3RELE1BQU0sS0FBSyxHQUFHLElBQUkscUNBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVuRSxJQUFBLGdCQUFNLEVBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxnQkFBTSxDQUFDLGdCQUFnQixDQUFDO1lBQzNFLElBQUksRUFBRSxPQUFPO1lBQ2IsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFDLHVCQUF1QixDQUFDLENBQUM7U0FDNUIsQ0FBQyxDQUFDLENBQUM7SUFDNUIsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsc0RBQXNELEVBQUUsR0FBRyxFQUFFO1FBQ2hFLE1BQU0sS0FBSyxHQUFHLElBQUkscUNBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUVuRSxJQUFBLGdCQUFNLEVBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLGdCQUFNLENBQUMsZ0JBQWdCLENBQUM7WUFDMUUsSUFBSSxFQUFFLGVBQWU7WUFDckIsWUFBWSxFQUFFLFFBQVEsQ0FBQyxDQUFDLHFCQUFxQixDQUFDLENBQUM7U0FDWixDQUFDLENBQUMsQ0FBQztJQUMxQyxDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQyxpRkFBaUYsRUFBRSxHQUFHLEVBQUU7UUFDM0YsTUFBTSxLQUFLLEdBQUcsSUFBSSxxQ0FBZ0IsQ0FBQyxLQUFLLENBQUMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXBFLElBQUEsZ0JBQU0sRUFBQyxLQUFLLENBQUMsSUFBSSxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsZ0JBQU0sQ0FBQyxnQkFBZ0IsQ0FBQztZQUN4RSxJQUFJLEVBQUUsYUFBYTtZQUNuQixZQUFZLEVBQUUsUUFBUSxDQUFDLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDLDJEQUEyRCxFQUFFLEdBQUcsRUFBRTtRQUNyRSxNQUFNLEtBQUssR0FBRyxJQUFJLHFDQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFbkUsSUFBQSxnQkFBTSxFQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMscUJBQXFCLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxnQkFBTSxDQUFDLGdCQUFnQixDQUFDO1lBQ3hFLElBQUksRUFBRSxhQUFhO1lBQ25CLFlBQVksRUFBRSxRQUFRLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQztTQUNSLENBQUMsQ0FBQyxDQUFDO0lBQ2pDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsMEJBQTBCLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDMUMsV0FBVyxDQUFDLFdBQVcsQ0FBQyxNQUFNLEVBQUU7UUFDOUIsSUFBSSxFQUFFLFFBQVEsQ0FBQyxZQUFZLENBQUMsUUFBUTtRQUNwQyxVQUFVLEVBQUU7WUFDVixJQUFJLEVBQUUsbUJBQW1CO1NBQ1M7S0FDckMsQ0FBQyxDQUFDO0lBRUgsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBRTdDLE1BQU0sS0FBSyxHQUFHLElBQUkscUNBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNuRSxJQUFBLGdCQUFNLEVBQUMsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUMxQyxDQUFDLENBQUMsQ0FBQztBQUVILElBQUksQ0FBQyw4QkFBOEIsRUFBRSxLQUFLLElBQUksRUFBRTtJQUM5QyxzQkFBc0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNwQyxNQUFNLE1BQU0sR0FBRyxXQUFXLENBQUMsb0JBQW9CLENBQUMsUUFBUSxFQUFFLGlCQUFpQixDQUFDLENBQUM7SUFDN0Usc0JBQXNCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDL0IsTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO0lBRXZCLE1BQU0sUUFBUSxHQUFHLFdBQVcsQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUU3QyxJQUFJLFFBQVEsR0FBRyxDQUFDLENBQUM7SUFDakIsTUFBTSxLQUFLLEdBQUcsSUFBSSxxQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRW5FLE1BQU0sS0FBSyxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUU7UUFDekIsV0FBVyxFQUFFLEtBQUssSUFBSSxFQUFFLEdBQUcsUUFBUSxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDM0MsVUFBVSxFQUFFLEtBQUssSUFBSSxFQUFFLEdBQUcsQ0FBQztRQUMzQixZQUFZLEVBQUUsS0FBSyxJQUFJLEVBQUUsR0FBRyxRQUFRLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUM3QyxDQUFDLENBQUM7SUFFSCxtR0FBbUc7SUFDbkcsaURBQWlEO0lBQ2pELElBQUEsZ0JBQU0sRUFBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDOUIsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsMkRBQTJELEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDM0UsUUFBUSxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUU7UUFDOUIsV0FBVyxFQUFFLHdCQUF3QjtLQUN0QyxDQUFDLENBQUM7SUFDSCxRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRTtRQUM5QixZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7UUFDeEIsV0FBVyxFQUFFLHdCQUF3QjtLQUN0QyxDQUFDLENBQUM7SUFFSCxNQUFNLEdBQUcsR0FBRyxXQUFXLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDeEMsTUFBTSxLQUFLLEdBQUcsSUFBSSxxQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ2pGLElBQUEsZ0JBQU0sRUFBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsZ0JBQU0sQ0FBQyxnQkFBZ0IsQ0FBQztRQUN2RCxFQUFFLEVBQUUsUUFBUTtRQUNaLFlBQVksRUFBRSxJQUFJLEdBQUcsRUFBRTtLQUN4QixDQUFDLENBQUMsQ0FBQztBQUNOLENBQUMsQ0FBQyxDQUFDO0FBRUgsUUFBUSxDQUFDLHVCQUF1QixFQUFFLEdBQUcsRUFBRTtJQUNyQyxNQUFNLEtBQUssR0FBRztRQUNaLDBEQUEwRDtRQUMxRCw2REFBNkQ7UUFDN0Qsd0RBQXdEO1FBQ3hELDRCQUE0QixFQUFFO1lBQzVCLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUU7WUFDM0IsWUFBWSxFQUFFO2dCQUNaLEVBQUUsRUFBRSxFQUFFLFVBQVUsRUFBRSxRQUFRLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRTthQUMvQztTQUNGO0tBQ0YsQ0FBQztJQUNGLE1BQU0sV0FBVyxHQUFHLHVCQUF1QixDQUFDO0lBRTVDLElBQUksQ0FBQyxzREFBc0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN0RSxRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRTtZQUM5QixXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFlBQVksRUFBRSxDQUFDLGVBQWUsQ0FBQztTQUNoQyxDQUFDLENBQUM7UUFDSCxTQUFTLENBQUMsV0FBVyxFQUFFLGVBQWUsRUFBRSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7UUFFbkQsUUFBUSxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUU7WUFDOUIsV0FBVyxFQUFFLHVCQUF1QjtZQUNwQyxZQUFZLEVBQUUsQ0FBQyxlQUFlLEVBQUUsUUFBUSxDQUFDO1NBQzFDLENBQUMsQ0FBQztRQUNILFNBQVMsQ0FBQyxXQUFXLEVBQUUsZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVuRCxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsYUFBYSxFQUFFLENBQUM7UUFFN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxxQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ25FLE1BQU0sU0FBUyxHQUFHLE1BQU0saUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFakQsSUFBQSxnQkFBTSxFQUFDLFNBQVMsQ0FBQyxDQUFDLE9BQU8sQ0FBQztZQUN4QixnQkFBTSxDQUFDLGNBQWMsQ0FBQyx1Q0FBdUMsQ0FBQztZQUM5RCxnQkFBTSxDQUFDLGNBQWMsQ0FBQyx5Q0FBeUMsQ0FBQztZQUNoRSxRQUFRO1lBQ1IsUUFBUTtTQUNULENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDLG9DQUFvQyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3BELGtKQUFrSjtRQUNsSixRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsQ0FBQyxlQUFlLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQzVGLFNBQVMsQ0FBQyxXQUFXLEVBQUUsZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVuRCxRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRSxFQUFFLFdBQVcsRUFBRSxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFM0UsUUFBUSxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUUsRUFBRSxXQUFXLEVBQUUsWUFBWSxFQUFFLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ2xGLFNBQVMsQ0FBQyxXQUFXLEVBQUUsZUFBZSxFQUFFLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVuRCxNQUFNLFFBQVEsR0FBRyxXQUFXLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDN0MsTUFBTSxLQUFLLEdBQUcsSUFBSSxxQ0FBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRW5FLE9BQU87UUFDUCxJQUFBLGdCQUFNLEVBQUMsS0FBSyxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUMsYUFBYSxFQUFFLENBQUM7SUFDNUMsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsNkRBQTZELEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDN0UsUUFBUSxDQUFDLFdBQVcsRUFBRSxRQUFRLEVBQUU7WUFDOUIsV0FBVyxFQUFFLHVCQUF1QjtZQUNwQyxZQUFZLEVBQUUsQ0FBQyxlQUFlLENBQUM7U0FDaEMsQ0FBQyxDQUFDO1FBQ0gsU0FBUyxDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUU7WUFDdEMsS0FBSyxFQUFFO2dCQUNMLE1BQU0sRUFBRTtvQkFDTixNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO29CQUMzQixZQUFZLEVBQUU7d0JBQ1osRUFBRSxFQUFFLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFO3dCQUMvQyxFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUU7cUJBQ2hEO2lCQUNGO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFFSCxRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRTtZQUM5QixXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFlBQVksRUFBRSxDQUFDLGVBQWUsRUFBRSxRQUFRLENBQUM7U0FDMUMsQ0FBQyxDQUFDO1FBQ0gsU0FBUyxDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUU7WUFDdEMsS0FBSyxFQUFFO2dCQUNMLE1BQU0sRUFBRTtvQkFDTixNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO29CQUMzQixZQUFZLEVBQUU7d0JBQ1osRUFBRSxFQUFFLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFO3FCQUNoRDtpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRTdDLE1BQU0sS0FBSyxHQUFHLElBQUkscUNBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNuRSxNQUFNLFNBQVMsR0FBRyxNQUFNLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWpELElBQUEsZ0JBQU0sRUFBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDeEIsZ0JBQU0sQ0FBQyxjQUFjLENBQUMsbUJBQW1CLENBQUM7WUFDMUMsZ0JBQU0sQ0FBQyxjQUFjLENBQUMscUJBQXFCLENBQUM7WUFDNUMsZ0JBQU0sQ0FBQyxjQUFjLENBQUMscUJBQXFCLENBQUM7WUFDNUMsUUFBUTtZQUNSLGdCQUFNLENBQUMsY0FBYyxDQUFDLHFCQUFxQixDQUFDO1lBQzVDLFFBQVE7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQyx1RUFBdUUsRUFBRSxLQUFLLElBQUksRUFBRTtRQUN2RixRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRTtZQUM5QixXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFlBQVksRUFBRSxDQUFDLGVBQWUsQ0FBQztTQUNoQyxDQUFDLENBQUM7UUFDSCxTQUFTLENBQUMsV0FBVyxFQUFFLGVBQWUsRUFBRTtZQUN0QyxLQUFLLEVBQUU7Z0JBQ0wsTUFBTSxFQUFFO29CQUNOLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUU7b0JBQzNCLFlBQVksRUFBRTt3QkFDWixDQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUU7cUJBQy9DO2lCQUNGO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFFSCxRQUFRLENBQUMsV0FBVyxFQUFFLFFBQVEsRUFBRTtZQUM5QixXQUFXLEVBQUUsdUJBQXVCO1lBQ3BDLFlBQVksRUFBRSxDQUFDLGVBQWUsRUFBRSxRQUFRLENBQUM7U0FDMUMsQ0FBQyxDQUFDO1FBQ0gsU0FBUyxDQUFDLFdBQVcsRUFBRSxlQUFlLEVBQUU7WUFDdEMsS0FBSyxFQUFFO2dCQUNMLE1BQU0sRUFBRTtvQkFDTixNQUFNLEVBQUUsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFO29CQUMzQixZQUFZLEVBQUU7d0JBQ1osQ0FBQyxFQUFFLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFFO3FCQUMvQztpQkFDRjthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxRQUFRLEdBQUcsV0FBVyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBRTdDLE1BQU0sS0FBSyxHQUFHLElBQUkscUNBQWdCLENBQUMsSUFBSSxDQUFDLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUNuRSxNQUFNLFNBQVMsR0FBRyxNQUFNLGlCQUFpQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRWpELElBQUEsZ0JBQU0sRUFBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDeEIsZ0JBQU0sQ0FBQyxjQUFjLENBQUMsbUJBQW1CLENBQUM7WUFDMUMsZ0JBQU0sQ0FBQyxjQUFjLENBQUMscUJBQXFCLENBQUM7WUFDNUMsUUFBUTtZQUNSLGdCQUFNLENBQUMsY0FBYyxDQUFDLHFCQUFxQixDQUFDO1lBQzVDLFFBQVE7U0FDVCxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDO0FBRUg7O0dBRUc7QUFDSCxTQUFTLFNBQVMsQ0FDaEIsT0FBNkIsRUFDN0IsVUFBa0IsRUFDbEIsT0FBK0U7SUFFL0UsTUFBTSxZQUFZLEdBQUcsR0FBRyxVQUFVLE9BQU8sQ0FBQztJQUMxQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFFeEQsTUFBTSxRQUFRLEdBQTJCO1FBQ3ZDLE9BQU8sRUFBRSxRQUFRLENBQUMsUUFBUSxDQUFDLE9BQU8sRUFBRTtRQUNwQyxLQUFLLEVBQUUsT0FBTyxDQUFDLEtBQUs7S0FDckIsQ0FBQztJQUVGLEVBQUUsQ0FBQyxhQUFhLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRWxFLE9BQU8sQ0FBQyxXQUFXLENBQUMsVUFBVSxFQUFFO1FBQzlCLElBQUksRUFBRSxRQUFRLENBQUMsWUFBWSxDQUFDLGNBQWM7UUFDMUMsWUFBWSxFQUFFLE9BQU8sQ0FBQyxZQUFZO1FBQ2xDLFVBQVUsRUFBRTtZQUNWLElBQUksRUFBRSxZQUFZO1NBQ2lCO0tBQ3RDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsUUFBUSxDQUFDLE9BQTZCLEVBQUUsT0FBZSxFQUFFLE9BQXlEO0lBQ3pILE1BQU0sWUFBWSxHQUFHLEdBQUcsT0FBTyxnQkFBZ0IsQ0FBQztJQUNoRCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsWUFBWSxDQUFDLENBQUM7SUFDeEQsRUFBRSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFNUQsT0FBTyxDQUFDLFdBQVcsQ0FBQyxPQUFPLEVBQUU7UUFDM0IsSUFBSSxFQUFFLFFBQVEsQ0FBQyxZQUFZLENBQUMsd0JBQXdCO1FBQ3BELFlBQVksRUFBRSxPQUFPLENBQUMsWUFBWTtRQUNsQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFdBQVc7UUFDaEMsVUFBVSxFQUFFO1lBQ1YsWUFBWTtTQUNiO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsc0JBQXNCLENBQUMsT0FBNkI7SUFDM0QsUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUU7UUFDMUIsV0FBVyxFQUFFLHVCQUF1QjtLQUNyQyxDQUFDLENBQUM7SUFDSCxTQUFTLENBQUMsT0FBTyxFQUFFLGNBQWMsRUFBRTtRQUNqQyxZQUFZLEVBQUUsQ0FBQyxRQUFRLENBQUM7UUFDeEIsS0FBSyxFQUFFO1lBQ0wsRUFBRSxFQUFFO2dCQUNGLE1BQU0sRUFBRSxFQUFFLElBQUksRUFBRSxLQUFLLEVBQUU7Z0JBQ3ZCLFlBQVksRUFBRTtvQkFDWixFQUFFLEVBQUUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxLQUFLLEVBQUU7aUJBQy9DO2FBQ0Y7U0FDRjtLQUNGLENBQUMsQ0FBQztJQUNILFFBQVEsQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFO1FBQzFCLFdBQVcsRUFBRSx1QkFBdUI7S0FDckMsQ0FBQyxDQUFDO0lBQ0gsUUFBUSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUU7UUFDMUIsV0FBVyxFQUFFLHVCQUF1QjtRQUNwQyxZQUFZLEVBQUUsQ0FBQyxjQUFjLEVBQUUsUUFBUSxDQUFDO0tBQ3pDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFxQixDQUFJO0lBQzlDLE9BQU87UUFDTCxHQUFHLENBQUM7UUFDSixZQUFZLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO0tBQ3pDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGlCQUFpQixDQUFDLEtBQWdCO0lBQy9DLE1BQU0sR0FBRyxHQUFhLEVBQUUsQ0FBQztJQUN6QixNQUFNLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFO1FBQ3hCLFdBQVcsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkQsVUFBVSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsRCxZQUFZLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ3JELENBQUMsQ0FBQztJQUNILE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLENBQVU7SUFDNUIsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFLLENBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDbkUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB7IENsb3VkQXNzZW1ibHlCdWlsZGVyIH0gZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7IGV4cGVjdCB9IGZyb20gJ0BqZXN0L2dsb2JhbHMnO1xuaW1wb3J0IHsgV29ya0dyYXBoIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaCc7XG5pbXBvcnQgeyBXb3JrR3JhcGhCdWlsZGVyIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaC1idWlsZGVyJztcbmltcG9ydCB7IEFzc2V0QnVpbGROb2RlLCBBc3NldFB1Ymxpc2hOb2RlLCBTdGFja05vZGUsIFdvcmtOb2RlIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaC10eXBlcyc7XG5cbmxldCByb290QnVpbGRlcjogQ2xvdWRBc3NlbWJseUJ1aWxkZXI7XG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgcm9vdEJ1aWxkZXIgPSBuZXcgQ2xvdWRBc3NlbWJseUJ1aWxkZXIoKTtcbn0pO1xuXG5hZnRlckVhY2goKCkgPT4ge1xuICByb290QnVpbGRlci5kZWxldGUoKTtcbn0pO1xuXG5mdW5jdGlvbiBzdXBlcnNldDxBPih4czogQVtdKTogU2V0PEE+IHtcbiAgY29uc3QgcmV0ID0gbmV3IFNldCh4cyk7XG4gIChyZXQgYXMgYW55KS5pc1N1cGVyc2V0ID0gdHJ1ZTtcbiAgcmV0dXJuIHJldDtcbn1cblxuZXhwZWN0LmFkZEVxdWFsaXR5VGVzdGVycyhbXG4gIGZ1bmN0aW9uKGV4cDogdW5rbm93biwgYWN0OiB1bmtub3duKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKGV4cCBpbnN0YW5jZW9mIFNldCAmJiBpc0l0ZXJhYmxlKGFjdCkpIHtcbiAgICAgIGlmICgoZXhwIGFzIGFueSkuaXNTdXBlcnNldCkge1xuICAgICAgICBjb25zdCBhY3RTZXQgPSBuZXcgU2V0KGFjdCk7XG4gICAgICAgIHJldHVybiBBcnJheS5mcm9tKGV4cCBhcyBhbnkpLmV2ZXJ5KCh4KSA9PiBhY3RTZXQuaGFzKHgpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmVxdWFscyhBcnJheS5mcm9tKGV4cCkuc29ydCgpLCBBcnJheS5mcm9tKGFjdCkuc29ydCgpKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfSxcbl0pO1xuXG5kZXNjcmliZSgnd2l0aCBzb21lIHN0YWNrcyBhbmQgYXNzZXRzJywgKCkgPT4ge1xuICBsZXQgYXNzZW1ibHk6IGN4YXBpLkNsb3VkQXNzZW1ibHk7XG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIGFkZFNvbWVTdGFja3NBbmRBc3NldHMocm9vdEJ1aWxkZXIpO1xuICAgIGFzc2VtYmx5ID0gcm9vdEJ1aWxkZXIuYnVpbGRBc3NlbWJseSgpO1xuICB9KTtcblxuICB0ZXN0KCdzdGFjayBkZXBlbmRzIG9uIHRoZSBhc3NldCBwdWJsaXNoaW5nIHN0ZXAnLCAoKSA9PiB7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuXG4gICAgZXhwZWN0KGFzc2VydGFibGVOb2RlKGdyYXBoLm5vZGUoJ3N0YWNrMicpKSkudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICB0eXBlOiAnc3RhY2snLFxuICAgICAgZGVwZW5kZW5jaWVzOiBzdXBlcnNldChbJ3B1Ymxpc2gtRjEtYWRkNTRiZGJjYiddKSxcbiAgICB9IGFzIFBhcnRpYWw8U3RhY2tOb2RlPikpO1xuICB9KTtcblxuICB0ZXN0KCdhc3NldCBwdWJsaXNoaW5nIHN0ZXAgZGVwZW5kcyBvbiBhc3NldCBidWlsZGluZyBzdGVwJywgKCkgPT4ge1xuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdwdWJsaXNoLUYxLWFkZDU0YmRiY2InKSkudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICB0eXBlOiAnYXNzZXQtcHVibGlzaCcsXG4gICAgICBkZXBlbmRlbmNpZXM6IHN1cGVyc2V0KFsnYnVpbGQtRjEtYTUzMzEzOTkzNCddKSxcbiAgICB9IHNhdGlzZmllcyBQYXJ0aWFsPEFzc2V0UHVibGlzaE5vZGU+KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3dpdGggcHJlYnVpbGQgb2ZmLCBhc3NldCBidWlsZGluZyBpbmhlcml0cyBkZXBlbmRlbmNpZXMgZnJvbSB0aGVpciBwYXJlbnQgc3RhY2snLCAoKSA9PiB7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcihmYWxzZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdidWlsZC1GMS1hNTMzMTM5OTM0JykpLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgdHlwZTogJ2Fzc2V0LWJ1aWxkJyxcbiAgICAgIGRlcGVuZGVuY2llczogc3VwZXJzZXQoWydzdGFjazAnLCAnc3RhY2sxJ10pLFxuICAgIH0gYXMgUGFydGlhbDxBc3NldEJ1aWxkTm9kZT4pKTtcbiAgfSk7XG5cbiAgdGVzdCgnd2l0aCBwcmVidWlsZCBvbiwgYXNzZXRzIG9ubHkgaGF2ZSB0aGVpciBvd24gZGVwZW5kZW5jaWVzJywgKCkgPT4ge1xuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdidWlsZC1GMS1hNTMzMTM5OTM0JykpLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgdHlwZTogJ2Fzc2V0LWJ1aWxkJyxcbiAgICAgIGRlcGVuZGVuY2llczogc3VwZXJzZXQoWydzdGFjazAnXSksXG4gICAgfSBhcyBQYXJ0aWFsPEFzc2V0QnVpbGROb2RlPikpO1xuICB9KTtcbn0pO1xuXG50ZXN0KCd0cmVlIG1ldGFkYXRhIGlzIGlnbm9yZWQnLCBhc3luYyAoKSA9PiB7XG4gIHJvb3RCdWlsZGVyLmFkZEFydGlmYWN0KCd0cmVlJywge1xuICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5DREtfVFJFRSxcbiAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICBmaWxlOiAnZG9lc25vdGV4aXN0Lmpzb24nLFxuICAgIH0gYXMgY3hzY2hlbWEuVHJlZUFydGlmYWN0UHJvcGVydGllcyxcbiAgfSk7XG5cbiAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG5cbiAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuICBleHBlY3QoZ3JhcGgucmVhZHkoKS5sZW5ndGgpLnRvRXF1YWwoMCk7XG59KTtcblxudGVzdCgnY2FuIGhhbmRsZSBuZXN0ZWQgYXNzZW1ibGllcycsIGFzeW5jICgpID0+IHtcbiAgYWRkU29tZVN0YWNrc0FuZEFzc2V0cyhyb290QnVpbGRlcik7XG4gIGNvbnN0IG5lc3RlZCA9IHJvb3RCdWlsZGVyLmNyZWF0ZU5lc3RlZEFzc2VtYmx5KCduZXN0ZWQnLCAnTmVzdGVkIEFzc2VtYmx5Jyk7XG4gIGFkZFNvbWVTdGFja3NBbmRBc3NldHMobmVzdGVkKTtcbiAgbmVzdGVkLmJ1aWxkQXNzZW1ibHkoKTtcblxuICBjb25zdCBhc3NlbWJseSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcblxuICBsZXQgd29ya0RvbmUgPSAwO1xuICBjb25zdCBncmFwaCA9IG5ldyBXb3JrR3JhcGhCdWlsZGVyKHRydWUpLmJ1aWxkKGFzc2VtYmx5LmFydGlmYWN0cyk7XG5cbiAgYXdhaXQgZ3JhcGguZG9QYXJhbGxlbCgxMCwge1xuICAgIGRlcGxveVN0YWNrOiBhc3luYyAoKSA9PiB7IHdvcmtEb25lICs9IDE7IH0sXG4gICAgYnVpbGRBc3NldDogYXN5bmMgKCkgPT4geyB9LFxuICAgIHB1Ymxpc2hBc3NldDogYXN5bmMgKCkgPT4geyB3b3JrRG9uZSArPSAxOyB9LFxuICB9KTtcblxuICAvLyBUaGUgYXNzZXQgaXMgc2hhcmVkIGJldHdlZW4gcGFyZW50IGFzc2VtYmx5IGFuZCBuZXN0ZWQgYXNzZW1ibHksIGJ1dCB0aGUgc3RhY2tzIHdpbGwgYmUgZGVwbG95ZWRcbiAgLy8gMyBzdGFja3MgKyAxIGFzc2V0ICsgMyBzdGFja3MgKDEgcmV1c2VkIGFzc2V0KVxuICBleHBlY3Qod29ya0RvbmUpLnRvRXF1YWwoNyk7XG59KTtcblxudGVzdCgnZGVwZW5kZW5jaWVzIG9uIHVuc2VsZWN0ZWQgYXJ0aWZhY3RzIGFyZSBzaWxlbnRseSBpZ25vcmVkJywgYXN5bmMgKCkgPT4ge1xuICBhZGRTdGFjayhyb290QnVpbGRlciwgJ3N0YWNrQScsIHtcbiAgICBlbnZpcm9ubWVudDogJ2F3czovLzIyMjIyMi91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdzdGFja0InLCB7XG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrQSddLFxuICAgIGVudmlyb25tZW50OiAnYXdzOi8vMjIyMjIyL3VzLWVhc3QtMScsXG4gIH0pO1xuXG4gIGNvbnN0IGFzbSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcbiAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChbYXNtLmdldFN0YWNrQXJ0aWZhY3QoJ3N0YWNrQicpXSk7XG4gIGV4cGVjdChncmFwaC5yZWFkeSgpWzBdKS50b0VxdWFsKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICBpZDogJ3N0YWNrQicsXG4gICAgZGVwZW5kZW5jaWVzOiBuZXcgU2V0KCksXG4gIH0pKTtcbn0pO1xuXG5kZXNjcmliZSgndGVzdHMgdGhhdCB1c2UgYXNzZXRzJywgKCkgPT4ge1xuICBjb25zdCBmaWxlcyA9IHtcbiAgICAvLyBSZWZlcmVuY2luZyBhbiBleGlzdGluZyBmaWxlIG9uIGRpc2sgaXMgaW1wb3J0YW50IGhlcmUuXG4gICAgLy8gSXQgbWVhbnMgdGhlc2UgdHdvIGFzc2V0cyB3aWxsIGhhdmUgdGhlIHNhbWUgQXNzZXRNYW5pZmVzdFxuICAgIC8vIGFuZCB0aGUgZ3JhcGggd2lsbCBtZXJnZSB0aGUgdHdvIGludG8gYSBzaW5nbGUgYXNzZXQuXG4gICAgJ3dvcmstZ3JhcGgtYnVpbGRlci50ZXN0LmpzJzoge1xuICAgICAgc291cmNlOiB7IHBhdGg6IF9fZGlybmFtZSB9LFxuICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgIEQxOiB7IGJ1Y2tldE5hbWU6ICdidWNrZXQnLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG4gIGNvbnN0IGVudmlyb25tZW50ID0gJ2F3czovLzExMTExL3VzLWVhc3QtMSc7XG5cbiAgdGVzdCgnYXNzZXRzIHdpdGggc2hhcmVkIGNvbnRlbnRzIGJldHdlZW4gZGVwZW5kYW50IHN0YWNrcycsIGFzeW5jICgpID0+IHtcbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQScsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0EuYXNzZXRzJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tBLmFzc2V0cycsIHsgZmlsZXMgfSk7XG5cbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQicsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0IuYXNzZXRzJywgJ1N0YWNrQSddLFxuICAgIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQi5hc3NldHMnLCB7IGZpbGVzIH0pO1xuXG4gICAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG5cbiAgICBjb25zdCBncmFwaCA9IG5ldyBXb3JrR3JhcGhCdWlsZGVyKHRydWUpLmJ1aWxkKGFzc2VtYmx5LmFydGlmYWN0cyk7XG4gICAgY29uc3QgdHJhdmVyc2FsID0gYXdhaXQgdHJhdmVyc2VBbmRSZWNvcmQoZ3JhcGgpO1xuXG4gICAgZXhwZWN0KHRyYXZlcnNhbCkudG9FcXVhbChbXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15idWlsZC13b3JrLWdyYXBoLWJ1aWxkZXIudGVzdC5qcy0uKiQvKSxcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXnB1Ymxpc2gtd29yay1ncmFwaC1idWlsZGVyLnRlc3QuanMtLiokLyksXG4gICAgICAnU3RhY2tBJyxcbiAgICAgICdTdGFja0InLFxuICAgIF0pO1xuICB9KTtcblxuICB0ZXN0KCdhIG1vcmUgY29tcGxleCB3YXkgdG8gbWFrZSBhIGN5Y2xlJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEEgLT4gQiAtPiBDIHwgQSBhbmQgQyBzaGFyZSBhbiBhc3NldC4gVGhlIGFzc2V0IHdpbGwgaGF2ZSBhIGRlcGVuZGVuY3kgb24gQiwgdGhhdCBpcyBub3QgYSAqZGlyZWN0KiByZXZlcnNlIGRlcGVuZGVuY3ksIGFuZCB3aWxsIGNhdXNlIGEgY3ljbGUuXG4gICAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdTdGFja0EnLCB7IGVudmlyb25tZW50LCBkZXBlbmRlbmNpZXM6IFsnU3RhY2tBLmFzc2V0cycsICdTdGFja0InXSB9KTtcbiAgICBhZGRBc3NldHMocm9vdEJ1aWxkZXIsICdTdGFja0EuYXNzZXRzJywgeyBmaWxlcyB9KTtcblxuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tCJywgeyBlbnZpcm9ubWVudCwgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQyddIH0pO1xuXG4gICAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdTdGFja0MnLCB7IGVudmlyb25tZW50LCBkZXBlbmRlbmNpZXM6IFsnU3RhY2tDLmFzc2V0cyddIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQy5hc3NldHMnLCB7IGZpbGVzIH0pO1xuXG4gICAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChncmFwaC5maW5kQ3ljbGUoKSkudG9CZVVuZGVmaW5lZCgpO1xuICB9KTtcblxuICB0ZXN0KCd0aGUgc2FtZSBhc3NldCB0byBkaWZmZXJlbnQgZGVzdGluYXRpb25zIGlzIG9ubHkgYnVpbHQgb25jZScsIGFzeW5jICgpID0+IHtcbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQScsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0EuYXNzZXRzJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tBLmFzc2V0cycsIHtcbiAgICAgIGZpbGVzOiB7XG4gICAgICAgIGFiY2RlZjoge1xuICAgICAgICAgIHNvdXJjZTogeyBwYXRoOiBfX2Rpcm5hbWUgfSxcbiAgICAgICAgICBkZXN0aW5hdGlvbnM6IHtcbiAgICAgICAgICAgIEQxOiB7IGJ1Y2tldE5hbWU6ICdidWNrZXQxJywgb2JqZWN0S2V5OiAna2V5JyB9LFxuICAgICAgICAgICAgRDI6IHsgYnVja2V0TmFtZTogJ2J1Y2tldDInLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQicsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0IuYXNzZXRzJywgJ1N0YWNrQSddLFxuICAgIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQi5hc3NldHMnLCB7XG4gICAgICBmaWxlczoge1xuICAgICAgICBhYmNkZWY6IHtcbiAgICAgICAgICBzb3VyY2U6IHsgcGF0aDogX19kaXJuYW1lIH0sXG4gICAgICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgICAgICBEMzogeyBidWNrZXROYW1lOiAnYnVja2V0MycsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFzc2VtYmx5ID0gcm9vdEJ1aWxkZXIuYnVpbGRBc3NlbWJseSgpO1xuXG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuICAgIGNvbnN0IHRyYXZlcnNhbCA9IGF3YWl0IHRyYXZlcnNlQW5kUmVjb3JkKGdyYXBoKTtcblxuICAgIGV4cGVjdCh0cmF2ZXJzYWwpLnRvRXF1YWwoW1xuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9eYnVpbGQtYWJjZGVmLS4qJC8pLFxuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9ecHVibGlzaC1hYmNkZWYtLiokLyksXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15wdWJsaXNoLWFiY2RlZi0uKiQvKSxcbiAgICAgICdTdGFja0EnLFxuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9ecHVibGlzaC1hYmNkZWYtLiokLyksXG4gICAgICAnU3RhY2tCJyxcbiAgICBdKTtcbiAgfSk7XG5cbiAgdGVzdCgnZGlmZmVyZW50IHBhcmFtZXRlcnMgZm9yIHRoZSBzYW1lIG5hbWVkIGRlZmluaXRpb24gYXJlIGJvdGggcHVibGlzaGVkJywgYXN5bmMgKCkgPT4ge1xuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tBJywge1xuICAgICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICAgICAgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQS5hc3NldHMnXSxcbiAgICB9KTtcbiAgICBhZGRBc3NldHMocm9vdEJ1aWxkZXIsICdTdGFja0EuYXNzZXRzJywge1xuICAgICAgZmlsZXM6IHtcbiAgICAgICAgYWJjZGVmOiB7XG4gICAgICAgICAgc291cmNlOiB7IHBhdGg6IF9fZGlybmFtZSB9LFxuICAgICAgICAgIGRlc3RpbmF0aW9uczoge1xuICAgICAgICAgICAgRDogeyBidWNrZXROYW1lOiAnYnVja2V0MScsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tCJywge1xuICAgICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICAgICAgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQi5hc3NldHMnLCAnU3RhY2tBJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tCLmFzc2V0cycsIHtcbiAgICAgIGZpbGVzOiB7XG4gICAgICAgIGFiY2RlZjoge1xuICAgICAgICAgIHNvdXJjZTogeyBwYXRoOiBfX2Rpcm5hbWUgfSxcbiAgICAgICAgICBkZXN0aW5hdGlvbnM6IHtcbiAgICAgICAgICAgIEQ6IHsgYnVja2V0TmFtZTogJ2J1Y2tldDInLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBhc3NlbWJseSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcblxuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcbiAgICBjb25zdCB0cmF2ZXJzYWwgPSBhd2FpdCB0cmF2ZXJzZUFuZFJlY29yZChncmFwaCk7XG5cbiAgICBleHBlY3QodHJhdmVyc2FsKS50b0VxdWFsKFtcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXmJ1aWxkLWFiY2RlZi0uKiQvKSxcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXnB1Ymxpc2gtYWJjZGVmLS4qJC8pLFxuICAgICAgJ1N0YWNrQScsXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15wdWJsaXNoLWFiY2RlZi0uKiQvKSxcbiAgICAgICdTdGFja0InLFxuICAgIF0pO1xuICB9KTtcbn0pO1xuXG4vKipcbiAqIFdyaXRlIGFuIGFzc2V0IG1hbmlmZXN0IGZpbGUgYW5kIGFkZCBpdCB0byB0aGUgYXNzZW1ibHkgYnVpbGRlclxuICovXG5mdW5jdGlvbiBhZGRBc3NldHMoXG4gIGJ1aWxkZXI6IENsb3VkQXNzZW1ibHlCdWlsZGVyLFxuICBhcnRpZmFjdElkOiBzdHJpbmcsXG4gIG9wdGlvbnM6IHsgZmlsZXM6IFJlY29yZDxzdHJpbmcsIGN4c2NoZW1hLkZpbGVBc3NldD4sIGRlcGVuZGVuY2llcz86IHN0cmluZ1tdIH0sXG4pIHtcbiAgY29uc3QgbWFuaWZlc3RGaWxlID0gYCR7YXJ0aWZhY3RJZH0uanNvbmA7XG4gIGNvbnN0IG91dFBhdGggPSBwYXRoLmpvaW4oYnVpbGRlci5vdXRkaXIsIG1hbmlmZXN0RmlsZSk7XG5cbiAgY29uc3QgbWFuaWZlc3Q6IGN4c2NoZW1hLkFzc2V0TWFuaWZlc3QgPSB7XG4gICAgdmVyc2lvbjogY3hzY2hlbWEuTWFuaWZlc3QudmVyc2lvbigpLFxuICAgIGZpbGVzOiBvcHRpb25zLmZpbGVzLFxuICB9O1xuXG4gIGZzLndyaXRlRmlsZVN5bmMob3V0UGF0aCwgSlNPTi5zdHJpbmdpZnkobWFuaWZlc3QsIHVuZGVmaW5lZCwgMikpO1xuXG4gIGJ1aWxkZXIuYWRkQXJ0aWZhY3QoYXJ0aWZhY3RJZCwge1xuICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5BU1NFVF9NQU5JRkVTVCxcbiAgICBkZXBlbmRlbmNpZXM6IG9wdGlvbnMuZGVwZW5kZW5jaWVzLFxuICAgIHByb3BlcnRpZXM6IHtcbiAgICAgIGZpbGU6IG1hbmlmZXN0RmlsZSxcbiAgICB9IGFzIGN4c2NoZW1hLkFzc2V0TWFuaWZlc3RQcm9wZXJ0aWVzLFxuICB9KTtcbn1cblxuLyoqXG4gKiBBZGQgYSBzdGFjayB0byB0aGUgY2xvdWQgYXNzZW1ibHlcbiAqL1xuZnVuY3Rpb24gYWRkU3RhY2soYnVpbGRlcjogQ2xvdWRBc3NlbWJseUJ1aWxkZXIsIHN0YWNrSWQ6IHN0cmluZywgb3B0aW9uczogeyBlbnZpcm9ubWVudDogc3RyaW5nLCBkZXBlbmRlbmNpZXM/OiBzdHJpbmdbXSB9KSB7XG4gIGNvbnN0IHRlbXBsYXRlRmlsZSA9IGAke3N0YWNrSWR9LnRlbXBsYXRlLmpzb25gO1xuICBjb25zdCBvdXRQYXRoID0gcGF0aC5qb2luKGJ1aWxkZXIub3V0ZGlyLCB0ZW1wbGF0ZUZpbGUpO1xuICBmcy53cml0ZUZpbGVTeW5jKG91dFBhdGgsIEpTT04uc3RyaW5naWZ5KHt9LCB1bmRlZmluZWQsIDIpKTtcblxuICBidWlsZGVyLmFkZEFydGlmYWN0KHN0YWNrSWQsIHtcbiAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVdTX0NMT1VERk9STUFUSU9OX1NUQUNLLFxuICAgIGRlcGVuZGVuY2llczogb3B0aW9ucy5kZXBlbmRlbmNpZXMsXG4gICAgZW52aXJvbm1lbnQ6IG9wdGlvbnMuZW52aXJvbm1lbnQsXG4gICAgcHJvcGVydGllczoge1xuICAgICAgdGVtcGxhdGVGaWxlLFxuICAgIH0sXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhZGRTb21lU3RhY2tzQW5kQXNzZXRzKGJ1aWxkZXI6IENsb3VkQXNzZW1ibHlCdWlsZGVyKSB7XG4gIGFkZFN0YWNrKGJ1aWxkZXIsICdzdGFjazAnLCB7XG4gICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkQXNzZXRzKGJ1aWxkZXIsICdzdGFjazJhc3NldHMnLCB7XG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrMCddLFxuICAgIGZpbGVzOiB7XG4gICAgICBGMToge1xuICAgICAgICBzb3VyY2U6IHsgcGF0aDogJ3h5eicgfSxcbiAgICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgICAgRDE6IHsgYnVja2V0TmFtZTogJ2J1Y2tldCcsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG4gIGFkZFN0YWNrKGJ1aWxkZXIsICdzdGFjazEnLCB7XG4gICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkU3RhY2soYnVpbGRlciwgJ3N0YWNrMicsIHtcbiAgICBlbnZpcm9ubWVudDogJ2F3czovLzExMTExL3VzLWVhc3QtMScsXG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrMmFzc2V0cycsICdzdGFjazEnXSxcbiAgfSk7XG59XG5cbi8qKlxuICogV2UgY2FuJ3QgZG8gYXJyYXlDb250YWluaW5nIG9uIHRoZSBzZXQgdGhhdCBhIE5vZGUgaGFzLCBzbyBjb252ZXJ0IGl0IHRvIGFuIGFycmF5IGZvciBhc3NlcnRpbmdcbiAqL1xuZnVuY3Rpb24gYXNzZXJ0YWJsZU5vZGU8QSBleHRlbmRzIFdvcmtOb2RlPih4OiBBKSB7XG4gIHJldHVybiB7XG4gICAgLi4ueCxcbiAgICBkZXBlbmRlbmNpZXM6IEFycmF5LmZyb20oeC5kZXBlbmRlbmNpZXMpLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0cmF2ZXJzZUFuZFJlY29yZChncmFwaDogV29ya0dyYXBoKSB7XG4gIGNvbnN0IHJldDogc3RyaW5nW10gPSBbXTtcbiAgYXdhaXQgZ3JhcGguZG9QYXJhbGxlbCgxLCB7XG4gICAgZGVwbG95U3RhY2s6IGFzeW5jIChub2RlKSA9PiB7IHJldC5wdXNoKG5vZGUuaWQpOyB9LFxuICAgIGJ1aWxkQXNzZXQ6IGFzeW5jIChub2RlKSA9PiB7IHJldC5wdXNoKG5vZGUuaWQpOyB9LFxuICAgIHB1Ymxpc2hBc3NldDogYXN5bmMgKG5vZGUpID0+IHsgcmV0LnB1c2gobm9kZS5pZCk7IH0sXG4gIH0pO1xuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBpc0l0ZXJhYmxlKHg6IHVua25vd24pOiB4IGlzIEl0ZXJhYmxlPGFueT4ge1xuICByZXR1cm4geCAmJiB0eXBlb2YgeCA9PT0gJ29iamVjdCcgJiYgKHggYXMgYW55KVtTeW1ib2wuaXRlcmF0b3JdO1xufSJdfQ==