aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
320 lines • 43.3 kB
JavaScript
"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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29yay1ncmFwaC1idWlsZGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ3b3JrLWdyYXBoLWJ1aWxkZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsMkRBQTJEO0FBRTNELDRDQUF1RDtBQUN2RCw2REFBNkQ7QUFDN0QsMkNBQXVDO0FBRXZDLHVFQUFrRTtBQUdsRSxJQUFJLFdBQWlDLENBQUM7QUFDdEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUNkLFdBQVcsR0FBRyxJQUFJLDZCQUFvQixFQUFFLENBQUM7QUFDM0MsQ0FBQyxDQUFDLENBQUM7QUFFSCxTQUFTLENBQUMsR0FBRyxFQUFFO0lBQ2IsV0FBVyxDQUFDLE1BQU0sRUFBRSxDQUFDO0FBQ3ZCLENBQUMsQ0FBQyxDQUFDO0FBRUgsU0FBUyxRQUFRLENBQUksRUFBTztJQUMxQixNQUFNLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN2QixHQUFXLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQztJQUMvQixPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxnQkFBTSxDQUFDLGtCQUFrQixDQUFDO0lBQ3hCLFVBQVMsR0FBWSxFQUFFLEdBQVk7UUFDakMsSUFBSSxHQUFHLFlBQVksR0FBRyxJQUFJLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUN6QyxJQUFLLEdBQVcsQ0FBQyxVQUFVLEVBQUU7Z0JBQzNCLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDO2dCQUM1QixPQUFPLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBVSxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7YUFDM0Q7WUFDRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsS0FB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Q0FBQyxjQUFjLEVBQUUsUUFBUSxDQUFDO0tBQ3pDLENBQUMsQ0FBQztBQUNMLENBQUM7QUFFRDs7R0FFRztBQUNILFNBQVMsY0FBYyxDQUFxQixDQUFJO0lBQzlDLE9BQU87UUFDTCxHQUFHLENBQUM7UUFDSixZQUFZLEVBQUUsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsWUFBWSxDQUFDO0tBQ3pDLENBQUM7QUFDSixDQUFDO0FBRUQsS0FBSyxVQUFVLGlCQUFpQixDQUFDLEtBQWdCO0lBQy9DLE1BQU0sR0FBRyxHQUFhLEVBQUUsQ0FBQztJQUN6QixNQUFNLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFO1FBQ3hCLFdBQVcsRUFBRSxLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUUsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbkQsVUFBVSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxHQUFHLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsRCxZQUFZLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxFQUFFLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ3JELENBQUMsQ0FBQztJQUNILE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELFNBQVMsVUFBVSxDQUFDLENBQVU7SUFDNUIsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLEtBQUssUUFBUSxJQUFLLENBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7QUFDbkUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB7IENsb3VkQXNzZW1ibHlCdWlsZGVyIH0gZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tZXh0cmFuZW91cy1kZXBlbmRlbmNpZXNcbmltcG9ydCB7IGV4cGVjdCB9IGZyb20gJ0BqZXN0L2dsb2JhbHMnO1xuaW1wb3J0IHsgV29ya0dyYXBoIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaCc7XG5pbXBvcnQgeyBXb3JrR3JhcGhCdWlsZGVyIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaC1idWlsZGVyJztcbmltcG9ydCB7IEFzc2V0QnVpbGROb2RlLCBBc3NldFB1Ymxpc2hOb2RlLCBTdGFja05vZGUsIFdvcmtOb2RlIH0gZnJvbSAnLi4vbGliL3V0aWwvd29yay1ncmFwaC10eXBlcyc7XG5cbmxldCByb290QnVpbGRlcjogQ2xvdWRBc3NlbWJseUJ1aWxkZXI7XG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgcm9vdEJ1aWxkZXIgPSBuZXcgQ2xvdWRBc3NlbWJseUJ1aWxkZXIoKTtcbn0pO1xuXG5hZnRlckVhY2goKCkgPT4ge1xuICByb290QnVpbGRlci5kZWxldGUoKTtcbn0pO1xuXG5mdW5jdGlvbiBzdXBlcnNldDxBPih4czogQVtdKTogU2V0PEE+IHtcbiAgY29uc3QgcmV0ID0gbmV3IFNldCh4cyk7XG4gIChyZXQgYXMgYW55KS5pc1N1cGVyc2V0ID0gdHJ1ZTtcbiAgcmV0dXJuIHJldDtcbn1cblxuZXhwZWN0LmFkZEVxdWFsaXR5VGVzdGVycyhbXG4gIGZ1bmN0aW9uKGV4cDogdW5rbm93biwgYWN0OiB1bmtub3duKTogYm9vbGVhbiB8IHVuZGVmaW5lZCB7XG4gICAgaWYgKGV4cCBpbnN0YW5jZW9mIFNldCAmJiBpc0l0ZXJhYmxlKGFjdCkpIHtcbiAgICAgIGlmICgoZXhwIGFzIGFueSkuaXNTdXBlcnNldCkge1xuICAgICAgICBjb25zdCBhY3RTZXQgPSBuZXcgU2V0KGFjdCk7XG4gICAgICAgIHJldHVybiBBcnJheS5mcm9tKGV4cCBhcyBhbnkpLmV2ZXJ5KCh4KSA9PiBhY3RTZXQuaGFzKHgpKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmVxdWFscyhBcnJheS5mcm9tKGV4cCkuc29ydCgpLCBBcnJheS5mcm9tKGFjdCkuc29ydCgpKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfSxcbl0pO1xuXG5kZXNjcmliZSgnd2l0aCBzb21lIHN0YWNrcyBhbmQgYXNzZXRzJywgKCkgPT4ge1xuICBsZXQgYXNzZW1ibHk6IGN4YXBpLkNsb3VkQXNzZW1ibHk7XG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIGFkZFNvbWVTdGFja3NBbmRBc3NldHMocm9vdEJ1aWxkZXIpO1xuICAgIGFzc2VtYmx5ID0gcm9vdEJ1aWxkZXIuYnVpbGRBc3NlbWJseSgpO1xuICB9KTtcblxuICB0ZXN0KCdzdGFjayBkZXBlbmRzIG9uIHRoZSBhc3NldCBwdWJsaXNoaW5nIHN0ZXAnLCAoKSA9PiB7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuXG4gICAgZXhwZWN0KGFzc2VydGFibGVOb2RlKGdyYXBoLm5vZGUoJ3N0YWNrMicpKSkudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICB0eXBlOiAnc3RhY2snLFxuICAgICAgZGVwZW5kZW5jaWVzOiBzdXBlcnNldChbJ3B1Ymxpc2gtRjEtYWRkNTRiZGJjYiddKSxcbiAgICB9IGFzIFBhcnRpYWw8U3RhY2tOb2RlPikpO1xuICB9KTtcblxuICB0ZXN0KCdhc3NldCBwdWJsaXNoaW5nIHN0ZXAgZGVwZW5kcyBvbiBhc3NldCBidWlsZGluZyBzdGVwJywgKCkgPT4ge1xuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdwdWJsaXNoLUYxLWFkZDU0YmRiY2InKSkudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICB0eXBlOiAnYXNzZXQtcHVibGlzaCcsXG4gICAgICBkZXBlbmRlbmNpZXM6IHN1cGVyc2V0KFsnYnVpbGQtRjEtYTUzMzEzOTkzNCddKSxcbiAgICB9IHNhdGlzZmllcyBQYXJ0aWFsPEFzc2V0UHVibGlzaE5vZGU+KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3dpdGggcHJlYnVpbGQgb2ZmLCBhc3NldCBidWlsZGluZyBpbmhlcml0cyBkZXBlbmRlbmNpZXMgZnJvbSB0aGVpciBwYXJlbnQgc3RhY2snLCAoKSA9PiB7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcihmYWxzZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdidWlsZC1GMS1hNTMzMTM5OTM0JykpLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgdHlwZTogJ2Fzc2V0LWJ1aWxkJyxcbiAgICAgIGRlcGVuZGVuY2llczogc3VwZXJzZXQoWydzdGFjazAnLCAnc3RhY2sxJ10pLFxuICAgIH0gYXMgUGFydGlhbDxBc3NldEJ1aWxkTm9kZT4pKTtcbiAgfSk7XG5cbiAgdGVzdCgnd2l0aCBwcmVidWlsZCBvbiwgYXNzZXRzIG9ubHkgaGF2ZSB0aGVpciBvd24gZGVwZW5kZW5jaWVzJywgKCkgPT4ge1xuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcblxuICAgIGV4cGVjdChncmFwaC5ub2RlKCdidWlsZC1GMS1hNTMzMTM5OTM0JykpLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgdHlwZTogJ2Fzc2V0LWJ1aWxkJyxcbiAgICAgIGRlcGVuZGVuY2llczogc3VwZXJzZXQoWydzdGFjazAnXSksXG4gICAgfSBhcyBQYXJ0aWFsPEFzc2V0QnVpbGROb2RlPikpO1xuICB9KTtcbn0pO1xuXG50ZXN0KCd0cmVlIG1ldGFkYXRhIGlzIGlnbm9yZWQnLCBhc3luYyAoKSA9PiB7XG4gIHJvb3RCdWlsZGVyLmFkZEFydGlmYWN0KCd0cmVlJywge1xuICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5DREtfVFJFRSxcbiAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICBmaWxlOiAnZG9lc25vdGV4aXN0Lmpzb24nLFxuICAgIH0gYXMgY3hzY2hlbWEuVHJlZUFydGlmYWN0UHJvcGVydGllcyxcbiAgfSk7XG5cbiAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG5cbiAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuICBleHBlY3QoZ3JhcGgucmVhZHkoKS5sZW5ndGgpLnRvRXF1YWwoMCk7XG59KTtcblxudGVzdCgnY2FuIGhhbmRsZSBuZXN0ZWQgYXNzZW1ibGllcycsIGFzeW5jICgpID0+IHtcbiAgYWRkU29tZVN0YWNrc0FuZEFzc2V0cyhyb290QnVpbGRlcik7XG4gIGNvbnN0IG5lc3RlZCA9IHJvb3RCdWlsZGVyLmNyZWF0ZU5lc3RlZEFzc2VtYmx5KCduZXN0ZWQnLCAnTmVzdGVkIEFzc2VtYmx5Jyk7XG4gIGFkZFNvbWVTdGFja3NBbmRBc3NldHMobmVzdGVkKTtcbiAgbmVzdGVkLmJ1aWxkQXNzZW1ibHkoKTtcblxuICBjb25zdCBhc3NlbWJseSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcblxuICBsZXQgd29ya0RvbmUgPSAwO1xuICBjb25zdCBncmFwaCA9IG5ldyBXb3JrR3JhcGhCdWlsZGVyKHRydWUpLmJ1aWxkKGFzc2VtYmx5LmFydGlmYWN0cyk7XG5cbiAgYXdhaXQgZ3JhcGguZG9QYXJhbGxlbCgxMCwge1xuICAgIGRlcGxveVN0YWNrOiBhc3luYyAoKSA9PiB7IHdvcmtEb25lICs9IDE7IH0sXG4gICAgYnVpbGRBc3NldDogYXN5bmMgKCkgPT4geyB9LFxuICAgIHB1Ymxpc2hBc3NldDogYXN5bmMgKCkgPT4geyB3b3JrRG9uZSArPSAxOyB9LFxuICB9KTtcblxuICAvLyBUaGUgYXNzZXQgaXMgc2hhcmVkIGJldHdlZW4gcGFyZW50IGFzc2VtYmx5IGFuZCBuZXN0ZWQgYXNzZW1ibHksIGJ1dCB0aGUgc3RhY2tzIHdpbGwgYmUgZGVwbG95ZWRcbiAgLy8gMyBzdGFja3MgKyAxIGFzc2V0ICsgMyBzdGFja3MgKDEgcmV1c2VkIGFzc2V0KVxuICBleHBlY3Qod29ya0RvbmUpLnRvRXF1YWwoNyk7XG59KTtcblxudGVzdCgnZGVwZW5kZW5jaWVzIG9uIHVuc2VsZWN0ZWQgYXJ0aWZhY3RzIGFyZSBzaWxlbnRseSBpZ25vcmVkJywgYXN5bmMgKCkgPT4ge1xuICBhZGRTdGFjayhyb290QnVpbGRlciwgJ3N0YWNrQScsIHtcbiAgICBlbnZpcm9ubWVudDogJ2F3czovLzIyMjIyMi91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdzdGFja0InLCB7XG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrQSddLFxuICAgIGVudmlyb25tZW50OiAnYXdzOi8vMjIyMjIyL3VzLWVhc3QtMScsXG4gIH0pO1xuXG4gIGNvbnN0IGFzbSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcbiAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChbYXNtLmdldFN0YWNrQXJ0aWZhY3QoJ3N0YWNrQicpXSk7XG4gIGV4cGVjdChncmFwaC5yZWFkeSgpWzBdKS50b0VxdWFsKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICBpZDogJ3N0YWNrQicsXG4gICAgZGVwZW5kZW5jaWVzOiBuZXcgU2V0KCksXG4gIH0pKTtcbn0pO1xuXG5kZXNjcmliZSgndGVzdHMgdGhhdCB1c2UgYXNzZXRzJywgKCkgPT4ge1xuICBjb25zdCBmaWxlcyA9IHtcbiAgICAvLyBSZWZlcmVuY2luZyBhbiBleGlzdGluZyBmaWxlIG9uIGRpc2sgaXMgaW1wb3J0YW50IGhlcmUuXG4gICAgLy8gSXQgbWVhbnMgdGhlc2UgdHdvIGFzc2V0cyB3aWxsIGhhdmUgdGhlIHNhbWUgQXNzZXRNYW5pZmVzdFxuICAgIC8vIGFuZCB0aGUgZ3JhcGggd2lsbCBtZXJnZSB0aGUgdHdvIGludG8gYSBzaW5nbGUgYXNzZXQuXG4gICAgJ3dvcmstZ3JhcGgtYnVpbGRlci50ZXN0LmpzJzoge1xuICAgICAgc291cmNlOiB7IHBhdGg6IF9fZGlybmFtZSB9LFxuICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgIEQxOiB7IGJ1Y2tldE5hbWU6ICdidWNrZXQnLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG4gIGNvbnN0IGVudmlyb25tZW50ID0gJ2F3czovLzExMTExL3VzLWVhc3QtMSc7XG5cbiAgdGVzdCgnYXNzZXRzIHdpdGggc2hhcmVkIGNvbnRlbnRzIGJldHdlZW4gZGVwZW5kYW50IHN0YWNrcycsIGFzeW5jICgpID0+IHtcbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQScsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0EuYXNzZXRzJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tBLmFzc2V0cycsIHsgZmlsZXMgfSk7XG5cbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQicsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0IuYXNzZXRzJywgJ1N0YWNrQSddLFxuICAgIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQi5hc3NldHMnLCB7IGZpbGVzIH0pO1xuXG4gICAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG5cbiAgICBjb25zdCBncmFwaCA9IG5ldyBXb3JrR3JhcGhCdWlsZGVyKHRydWUpLmJ1aWxkKGFzc2VtYmx5LmFydGlmYWN0cyk7XG4gICAgY29uc3QgdHJhdmVyc2FsID0gYXdhaXQgdHJhdmVyc2VBbmRSZWNvcmQoZ3JhcGgpO1xuXG4gICAgZXhwZWN0KHRyYXZlcnNhbCkudG9FcXVhbChbXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15idWlsZC13b3JrLWdyYXBoLWJ1aWxkZXIudGVzdC5qcy0uKiQvKSxcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXnB1Ymxpc2gtd29yay1ncmFwaC1idWlsZGVyLnRlc3QuanMtLiokLyksXG4gICAgICAnU3RhY2tBJyxcbiAgICAgICdTdGFja0InLFxuICAgIF0pO1xuICB9KTtcblxuICB0ZXN0KCdhIG1vcmUgY29tcGxleCB3YXkgdG8gbWFrZSBhIGN5Y2xlJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEEgLT4gQiAtPiBDIHwgQSBhbmQgQyBzaGFyZSBhbiBhc3NldC4gVGhlIGFzc2V0IHdpbGwgaGF2ZSBhIGRlcGVuZGVuY3kgb24gQiwgdGhhdCBpcyBub3QgYSAqZGlyZWN0KiByZXZlcnNlIGRlcGVuZGVuY3ksIGFuZCB3aWxsIGNhdXNlIGEgY3ljbGUuXG4gICAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdTdGFja0EnLCB7IGVudmlyb25tZW50LCBkZXBlbmRlbmNpZXM6IFsnU3RhY2tBLmFzc2V0cycsICdTdGFja0InXSB9KTtcbiAgICBhZGRBc3NldHMocm9vdEJ1aWxkZXIsICdTdGFja0EuYXNzZXRzJywgeyBmaWxlcyB9KTtcblxuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tCJywgeyBlbnZpcm9ubWVudCwgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQyddIH0pO1xuXG4gICAgYWRkU3RhY2socm9vdEJ1aWxkZXIsICdTdGFja0MnLCB7IGVudmlyb25tZW50LCBkZXBlbmRlbmNpZXM6IFsnU3RhY2tDLmFzc2V0cyddIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQy5hc3NldHMnLCB7IGZpbGVzIH0pO1xuXG4gICAgY29uc3QgYXNzZW1ibHkgPSByb290QnVpbGRlci5idWlsZEFzc2VtYmx5KCk7XG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChncmFwaC5maW5kQ3ljbGUoKSkudG9CZVVuZGVmaW5lZCgpO1xuICB9KTtcblxuICB0ZXN0KCd0aGUgc2FtZSBhc3NldCB0byBkaWZmZXJlbnQgZGVzdGluYXRpb25zIGlzIG9ubHkgYnVpbHQgb25jZScsIGFzeW5jICgpID0+IHtcbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQScsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0EuYXNzZXRzJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tBLmFzc2V0cycsIHtcbiAgICAgIGZpbGVzOiB7XG4gICAgICAgIGFiY2RlZjoge1xuICAgICAgICAgIHNvdXJjZTogeyBwYXRoOiBfX2Rpcm5hbWUgfSxcbiAgICAgICAgICBkZXN0aW5hdGlvbnM6IHtcbiAgICAgICAgICAgIEQxOiB7IGJ1Y2tldE5hbWU6ICdidWNrZXQxJywgb2JqZWN0S2V5OiAna2V5JyB9LFxuICAgICAgICAgICAgRDI6IHsgYnVja2V0TmFtZTogJ2J1Y2tldDInLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBhZGRTdGFjayhyb290QnVpbGRlciwgJ1N0YWNrQicsIHtcbiAgICAgIGVudmlyb25tZW50OiAnYXdzOi8vMTExMTEvdXMtZWFzdC0xJyxcbiAgICAgIGRlcGVuZGVuY2llczogWydTdGFja0IuYXNzZXRzJywgJ1N0YWNrQSddLFxuICAgIH0pO1xuICAgIGFkZEFzc2V0cyhyb290QnVpbGRlciwgJ1N0YWNrQi5hc3NldHMnLCB7XG4gICAgICBmaWxlczoge1xuICAgICAgICBhYmNkZWY6IHtcbiAgICAgICAgICBzb3VyY2U6IHsgcGF0aDogX19kaXJuYW1lIH0sXG4gICAgICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgICAgICBEMzogeyBidWNrZXROYW1lOiAnYnVja2V0MycsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGFzc2VtYmx5ID0gcm9vdEJ1aWxkZXIuYnVpbGRBc3NlbWJseSgpO1xuXG4gICAgY29uc3QgZ3JhcGggPSBuZXcgV29ya0dyYXBoQnVpbGRlcih0cnVlKS5idWlsZChhc3NlbWJseS5hcnRpZmFjdHMpO1xuICAgIGNvbnN0IHRyYXZlcnNhbCA9IGF3YWl0IHRyYXZlcnNlQW5kUmVjb3JkKGdyYXBoKTtcblxuICAgIGV4cGVjdCh0cmF2ZXJzYWwpLnRvRXF1YWwoW1xuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9eYnVpbGQtYWJjZGVmLS4qJC8pLFxuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9ecHVibGlzaC1hYmNkZWYtLiokLyksXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15wdWJsaXNoLWFiY2RlZi0uKiQvKSxcbiAgICAgICdTdGFja0EnLFxuICAgICAgZXhwZWN0LnN0cmluZ01hdGNoaW5nKC9ecHVibGlzaC1hYmNkZWYtLiokLyksXG4gICAgICAnU3RhY2tCJyxcbiAgICBdKTtcbiAgfSk7XG5cbiAgdGVzdCgnZGlmZmVyZW50IHBhcmFtZXRlcnMgZm9yIHRoZSBzYW1lIG5hbWVkIGRlZmluaXRpb24gYXJlIGJvdGggcHVibGlzaGVkJywgYXN5bmMgKCkgPT4ge1xuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tBJywge1xuICAgICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICAgICAgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQS5hc3NldHMnXSxcbiAgICB9KTtcbiAgICBhZGRBc3NldHMocm9vdEJ1aWxkZXIsICdTdGFja0EuYXNzZXRzJywge1xuICAgICAgZmlsZXM6IHtcbiAgICAgICAgYWJjZGVmOiB7XG4gICAgICAgICAgc291cmNlOiB7IHBhdGg6IF9fZGlybmFtZSB9LFxuICAgICAgICAgIGRlc3RpbmF0aW9uczoge1xuICAgICAgICAgICAgRDogeyBidWNrZXROYW1lOiAnYnVja2V0MScsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGFkZFN0YWNrKHJvb3RCdWlsZGVyLCAnU3RhY2tCJywge1xuICAgICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICAgICAgZGVwZW5kZW5jaWVzOiBbJ1N0YWNrQi5hc3NldHMnLCAnU3RhY2tBJ10sXG4gICAgfSk7XG4gICAgYWRkQXNzZXRzKHJvb3RCdWlsZGVyLCAnU3RhY2tCLmFzc2V0cycsIHtcbiAgICAgIGZpbGVzOiB7XG4gICAgICAgIGFiY2RlZjoge1xuICAgICAgICAgIHNvdXJjZTogeyBwYXRoOiBfX2Rpcm5hbWUgfSxcbiAgICAgICAgICBkZXN0aW5hdGlvbnM6IHtcbiAgICAgICAgICAgIEQ6IHsgYnVja2V0TmFtZTogJ2J1Y2tldDInLCBvYmplY3RLZXk6ICdrZXknIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBhc3NlbWJseSA9IHJvb3RCdWlsZGVyLmJ1aWxkQXNzZW1ibHkoKTtcblxuICAgIGNvbnN0IGdyYXBoID0gbmV3IFdvcmtHcmFwaEJ1aWxkZXIodHJ1ZSkuYnVpbGQoYXNzZW1ibHkuYXJ0aWZhY3RzKTtcbiAgICBjb25zdCB0cmF2ZXJzYWwgPSBhd2FpdCB0cmF2ZXJzZUFuZFJlY29yZChncmFwaCk7XG5cbiAgICBleHBlY3QodHJhdmVyc2FsKS50b0VxdWFsKFtcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXmJ1aWxkLWFiY2RlZi0uKiQvKSxcbiAgICAgIGV4cGVjdC5zdHJpbmdNYXRjaGluZygvXnB1Ymxpc2gtYWJjZGVmLS4qJC8pLFxuICAgICAgJ1N0YWNrQScsXG4gICAgICBleHBlY3Quc3RyaW5nTWF0Y2hpbmcoL15wdWJsaXNoLWFiY2RlZi0uKiQvKSxcbiAgICAgICdTdGFja0InLFxuICAgIF0pO1xuICB9KTtcbn0pO1xuXG4vKipcbiAqIFdyaXRlIGFuIGFzc2V0IG1hbmlmZXN0IGZpbGUgYW5kIGFkZCBpdCB0byB0aGUgYXNzZW1ibHkgYnVpbGRlclxuICovXG5mdW5jdGlvbiBhZGRBc3NldHMoXG4gIGJ1aWxkZXI6IENsb3VkQXNzZW1ibHlCdWlsZGVyLFxuICBhcnRpZmFjdElkOiBzdHJpbmcsXG4gIG9wdGlvbnM6IHsgZmlsZXM6IFJlY29yZDxzdHJpbmcsIGN4c2NoZW1hLkZpbGVBc3NldD4sIGRlcGVuZGVuY2llcz86IHN0cmluZ1tdIH0sXG4pIHtcbiAgY29uc3QgbWFuaWZlc3RGaWxlID0gYCR7YXJ0aWZhY3RJZH0uanNvbmA7XG4gIGNvbnN0IG91dFBhdGggPSBwYXRoLmpvaW4oYnVpbGRlci5vdXRkaXIsIG1hbmlmZXN0RmlsZSk7XG5cbiAgY29uc3QgbWFuaWZlc3Q6IGN4c2NoZW1hLkFzc2V0TWFuaWZlc3QgPSB7XG4gICAgdmVyc2lvbjogY3hzY2hlbWEuTWFuaWZlc3QudmVyc2lvbigpLFxuICAgIGZpbGVzOiBvcHRpb25zLmZpbGVzLFxuICB9O1xuXG4gIGZzLndyaXRlRmlsZVN5bmMob3V0UGF0aCwgSlNPTi5zdHJpbmdpZnkobWFuaWZlc3QsIHVuZGVmaW5lZCwgMikpO1xuXG4gIGJ1aWxkZXIuYWRkQXJ0aWZhY3QoYXJ0aWZhY3RJZCwge1xuICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5BU1NFVF9NQU5JRkVTVCxcbiAgICBkZXBlbmRlbmNpZXM6IG9wdGlvbnMuZGVwZW5kZW5jaWVzLFxuICAgIHByb3BlcnRpZXM6IHtcbiAgICAgIGZpbGU6IG1hbmlmZXN0RmlsZSxcbiAgICB9IGFzIGN4c2NoZW1hLkFzc2V0TWFuaWZlc3RQcm9wZXJ0aWVzLFxuICB9KTtcbn1cblxuLyoqXG4gKiBBZGQgYSBzdGFjayB0byB0aGUgY2xvdWQgYXNzZW1ibHlcbiAqL1xuZnVuY3Rpb24gYWRkU3RhY2soYnVpbGRlcjogQ2xvdWRBc3NlbWJseUJ1aWxkZXIsIHN0YWNrSWQ6IHN0cmluZywgb3B0aW9uczogeyBlbnZpcm9ubWVudDogc3RyaW5nLCBkZXBlbmRlbmNpZXM/OiBzdHJpbmdbXSB9KSB7XG4gIGNvbnN0IHRlbXBsYXRlRmlsZSA9IGAke3N0YWNrSWR9LnRlbXBsYXRlLmpzb25gO1xuICBjb25zdCBvdXRQYXRoID0gcGF0aC5qb2luKGJ1aWxkZXIub3V0ZGlyLCB0ZW1wbGF0ZUZpbGUpO1xuICBmcy53cml0ZUZpbGVTeW5jKG91dFBhdGgsIEpTT04uc3RyaW5naWZ5KHt9LCB1bmRlZmluZWQsIDIpKTtcblxuICBidWlsZGVyLmFkZEFydGlmYWN0KHN0YWNrSWQsIHtcbiAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVdTX0NMT1VERk9STUFUSU9OX1NUQUNLLFxuICAgIGRlcGVuZGVuY2llczogb3B0aW9ucy5kZXBlbmRlbmNpZXMsXG4gICAgZW52aXJvbm1lbnQ6IG9wdGlvbnMuZW52aXJvbm1lbnQsXG4gICAgcHJvcGVydGllczoge1xuICAgICAgdGVtcGxhdGVGaWxlLFxuICAgIH0sXG4gIH0pO1xufVxuXG5mdW5jdGlvbiBhZGRTb21lU3RhY2tzQW5kQXNzZXRzKGJ1aWxkZXI6IENsb3VkQXNzZW1ibHlCdWlsZGVyKSB7XG4gIGFkZFN0YWNrKGJ1aWxkZXIsICdzdGFjazAnLCB7XG4gICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkQXNzZXRzKGJ1aWxkZXIsICdzdGFjazJhc3NldHMnLCB7XG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrMCddLFxuICAgIGZpbGVzOiB7XG4gICAgICBGMToge1xuICAgICAgICBzb3VyY2U6IHsgcGF0aDogJ3h5eicgfSxcbiAgICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgICAgRDE6IHsgYnVja2V0TmFtZTogJ2J1Y2tldCcsIG9iamVjdEtleTogJ2tleScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG4gIGFkZFN0YWNrKGJ1aWxkZXIsICdzdGFjazEnLCB7XG4gICAgZW52aXJvbm1lbnQ6ICdhd3M6Ly8xMTExMS91cy1lYXN0LTEnLFxuICB9KTtcbiAgYWRkU3RhY2soYnVpbGRlciwgJ3N0YWNrMicsIHtcbiAgICBlbnZpcm9ubWVudDogJ2F3czovLzExMTExL3VzLWVhc3QtMScsXG4gICAgZGVwZW5kZW5jaWVzOiBbJ3N0YWNrMmFzc2V0cycsICdzdGFjazEnXSxcbiAgfSk7XG59XG5cbi8qKlxuICogV2UgY2FuJ3QgZG8gYXJyYXlDb250YWluaW5nIG9uIHRoZSBzZXQgdGhhdCBhIE5vZGUgaGFzLCBzbyBjb252ZXJ0IGl0IHRvIGFuIGFycmF5IGZvciBhc3NlcnRpbmdcbiAqL1xuZnVuY3Rpb24gYXNzZXJ0YWJsZU5vZGU8QSBleHRlbmRzIFdvcmtOb2RlPih4OiBBKSB7XG4gIHJldHVybiB7XG4gICAgLi4ueCxcbiAgICBkZXBlbmRlbmNpZXM6IEFycmF5LmZyb20oeC5kZXBlbmRlbmNpZXMpLFxuICB9O1xufVxuXG5hc3luYyBmdW5jdGlvbiB0cmF2ZXJzZUFuZFJlY29yZChncmFwaDogV29ya0dyYXBoKSB7XG4gIGNvbnN0IHJldDogc3RyaW5nW10gPSBbXTtcbiAgYXdhaXQgZ3JhcGguZG9QYXJhbGxlbCgxLCB7XG4gICAgZGVwbG95U3RhY2s6IGFzeW5jIChub2RlKSA9PiB7IHJldC5wdXNoKG5vZGUuaWQpOyB9LFxuICAgIGJ1aWxkQXNzZXQ6IGFzeW5jIChub2RlKSA9PiB7IHJldC5wdXNoKG5vZGUuaWQpOyB9LFxuICAgIHB1Ymxpc2hBc3NldDogYXN5bmMgKG5vZGUpID0+IHsgcmV0LnB1c2gobm9kZS5pZCk7IH0sXG4gIH0pO1xuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBpc0l0ZXJhYmxlKHg6IHVua25vd24pOiB4IGlzIEl0ZXJhYmxlPGFueT4ge1xuICByZXR1cm4geCAmJiB0eXBlb2YgeCA9PT0gJ29iamVjdCcgJiYgKHggYXMgYW55KVtTeW1ib2wuaXRlcmF0b3JdO1xufSJdfQ==