@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
209 lines • 30.3 kB
JavaScript
"use strict";
const lib_1 = require("../lib");
const util_1 = require("./util");
function generateString(chars) {
let s = '';
for (let i = 0; i < chars; ++i) {
s += randomAlpha();
}
return s;
function randomAlpha() {
return String.fromCharCode('a'.charCodeAt(0) + Math.floor(Math.random() * 26));
}
}
function logicalForElementInPath(constructPath) {
const stack = new lib_1.Stack();
let scope = stack;
for (const component of constructPath) {
scope = new lib_1.CfnResource(scope, component, { type: 'Foo' });
}
return stack.resolve(scope.logicalId);
}
module.exports = {
'if the naming scheme uniquifies with a hash we can have the same concatenated identifier'(test) {
// GIVEN
const stack = new lib_1.Stack(undefined, 'TestStack');
const A = new lib_1.Construct(stack, 'A');
new lib_1.CfnResource(A, 'BC', { type: 'Resource' });
// WHEN
const AB = new lib_1.Construct(stack, 'AB');
new lib_1.CfnResource(AB, 'C', { type: 'Resource' });
// THEN: no exception
test.done();
},
'special case: if the resource is top-level, a hash is not added'(test) {
// GIVEN
const stack = new lib_1.Stack(undefined, 'TestStack');
// WHEN
const r = new lib_1.CfnResource(stack, 'MyAwesomeness', { type: 'Resource' });
// THEN
test.equal(stack.resolve(r.logicalId), 'MyAwesomeness');
test.done();
},
'Logical IDs can be renamed at the stack level'(test) {
// GIVEN
const stack = new lib_1.Stack();
// WHEN
const parent = new lib_1.Construct(stack, 'Parent');
new lib_1.CfnResource(parent, 'ThingResource', { type: 'AWS::TAAS::Thing' });
stack.renameLogicalId('ParentThingResource75D1D9CB', 'Renamed');
// THEN
const template = util_1.toCloudFormation(stack);
test.ok('Renamed' in template.Resources);
test.done();
},
'Renames for objects that don\'t exist fail'(test) {
// GIVEN
const stack = new lib_1.Stack();
new lib_1.Construct(stack, 'Parent');
// WHEN
stack.renameLogicalId('DOESNOTEXIST', 'Renamed');
// THEN
test.throws(() => util_1.toCloudFormation(stack));
test.done();
},
'ID Renames that collide with existing IDs should fail'(test) {
// GIVEN
const stack = new lib_1.Stack();
stack.renameLogicalId('ParentThingResource1916E7808', 'ParentThingResource2F19948CB');
// WHEN
const parent = new lib_1.Construct(stack, 'Parent');
new lib_1.CfnResource(parent, 'ThingResource1', { type: 'AWS::TAAS::Thing' });
new lib_1.CfnResource(parent, 'ThingResource2', { type: 'AWS::TAAS::Thing' });
// THEN
test.throws(() => util_1.toCloudFormation(stack), /Two objects have been assigned the same Logical ID/);
test.done();
},
'hashed naming scheme filters constructs named "Resource" from the human portion'(test) {
// GIVEN
const stack = new lib_1.Stack();
// WHEN
const parent = new lib_1.Construct(stack, 'Parent');
const child1 = new lib_1.Construct(parent, 'Child');
const child2 = new lib_1.Construct(child1, 'Resource');
new lib_1.CfnResource(child2, 'HeyThere', { type: 'AWS::TAAS::Thing' });
// THEN
const template = util_1.toCloudFormation(stack);
test.deepEqual(template, {
Resources: {
ParentChildHeyThere35220347: {
Type: 'AWS::TAAS::Thing'
}
}
});
test.done();
},
'can transparently wrap constructs using "Default" id'(test) {
// GIVEN
const stack1 = new lib_1.Stack();
const parent1 = new lib_1.Construct(stack1, 'Parent');
new lib_1.CfnResource(parent1, 'HeyThere', { type: 'AWS::TAAS::Thing' });
const template1 = util_1.toCloudFormation(stack1);
// AND
const theId1 = Object.keys(template1.Resources)[0];
test.equal('AWS::TAAS::Thing', template1.Resources[theId1].Type);
// WHEN
const stack2 = new lib_1.Stack();
const parent2 = new lib_1.Construct(stack2, 'Parent');
const invisibleWrapper = new lib_1.Construct(parent2, 'Default');
new lib_1.CfnResource(invisibleWrapper, 'HeyThere', { type: 'AWS::TAAS::Thing' });
const template2 = util_1.toCloudFormation(stack1);
const theId2 = Object.keys(template2.Resources)[0];
test.equal('AWS::TAAS::Thing', template2.Resources[theId2].Type);
// THEN: same ID, same object
test.equal(theId1, theId2);
test.done();
},
'non-alphanumeric characters are removed from the human part of the logical ID'(test) {
const val1 = logicalForElementInPath(['Foo-bar', 'B00m', 'Hello_World', '&&Horray Horray.']);
const val2 = logicalForElementInPath(['Foobar', 'B00m', 'HelloWorld', 'HorrayHorray']);
// same human part, different hash
test.deepEqual(val1, 'FoobarB00mHelloWorldHorrayHorray640E99FB');
test.deepEqual(val2, 'FoobarB00mHelloWorldHorrayHorray744334FD');
test.done();
},
'non-alphanumeric characters are removed even if the ID has only one component'(test) {
const val1 = logicalForElementInPath(['Foo-bar']);
// same human part, different hash
test.deepEqual(val1, 'Foobar');
test.done();
},
'empty identifiers are not allowed'(test) {
// GIVEN
const stack = new lib_1.Stack();
// WHEN
new lib_1.CfnResource(stack, '.', { type: 'R' });
// THEN
test.throws(() => util_1.toCloudFormation(stack), /Logical ID must adhere to the regular expression/);
test.done();
},
'too large identifiers are truncated yet still remain unique'(test) {
// GIVEN
const stack = new lib_1.Stack();
const A = new lib_1.Construct(stack, generateString(100));
const B = new lib_1.Construct(A, generateString(100));
// WHEN
const firstPart = generateString(60);
// The shared part has now exceeded the maximum length of CloudFormation identifiers
// so the identity generator will have to something smart
const C1 = new lib_1.CfnResource(B, firstPart + generateString(40), { type: 'Resource' });
const C2 = new lib_1.CfnResource(B, firstPart + generateString(40), { type: 'Resource' });
// THEN
test.ok(C1.logicalId.length <= 255);
test.ok(C2.logicalId.length <= 255);
test.notEqual(C1, C2);
test.done();
},
'Refs and dependencies will correctly reflect renames done at the stack level'(test) {
// GIVEN
const stack = new lib_1.Stack();
stack.renameLogicalId('OriginalName', 'NewName');
// WHEN
const c1 = new lib_1.CfnResource(stack, 'OriginalName', { type: 'R1' });
const ref = c1.ref;
const c2 = new lib_1.CfnResource(stack, 'Construct2', { type: 'R2', properties: { ReferenceToR1: ref } });
c2.node.addDependency(c1);
// THEN
test.deepEqual(util_1.toCloudFormation(stack), {
Resources: {
NewName: { Type: 'R1' },
Construct2: {
Type: 'R2',
Properties: { ReferenceToR1: { Ref: 'NewName' } },
DependsOn: ['NewName']
}
}
});
test.done();
},
'customize logical id allocation behavior by overriding `Stack.allocateLogicalId`'(test) {
class MyStack extends lib_1.Stack {
allocateLogicalId(element) {
if (element.node.id === 'A') {
return 'LogicalIdOfA';
}
if (element.node.id === 'B') {
return 'LogicalIdOfB';
}
throw new Error(`Invalid element ID`);
}
}
const stack = new MyStack();
new lib_1.CfnResource(stack, 'A', { type: 'Type::Of::A' });
const group = new lib_1.Construct(stack, 'Group');
new lib_1.CfnResource(group, 'B', { type: 'Type::Of::B' });
// renames can also be applied on custom logical IDs.
stack.renameLogicalId('LogicalIdOfB', 'BoomBoomB');
const c = new lib_1.CfnResource(stack, 'B', { type: 'Type::Of::C' });
c.overrideLogicalId('TheC');
test.deepEqual(util_1.toCloudFormation(stack), {
Resources: {
LogicalIdOfA: { Type: 'Type::Of::A' },
BoomBoomB: { Type: 'Type::Of::B' },
TheC: { Type: 'Type::Of::C' }
}
});
test.done();
}
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdC5sb2dpY2FsLWlkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGVzdC5sb2dpY2FsLWlkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFDQSxnQ0FBbUU7QUFDbkUsaUNBQTBDO0FBaVAxQyxTQUFTLGNBQWMsQ0FBQyxLQUFhO0lBQ25DLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztJQUNYLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxLQUFLLEVBQUUsRUFBRSxDQUFDLEVBQUU7UUFDOUIsQ0FBQyxJQUFJLFdBQVcsRUFBRSxDQUFDO0tBQ3BCO0lBQ0QsT0FBTyxDQUFDLENBQUM7SUFFVCxTQUFTLFdBQVc7UUFDbEIsT0FBTyxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNqRixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMsdUJBQXVCLENBQUMsYUFBdUI7SUFDdEQsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFLLEVBQUUsQ0FBQztJQUMxQixJQUFJLEtBQUssR0FBYyxLQUFLLENBQUM7SUFDN0IsS0FBSyxNQUFNLFNBQVMsSUFBSSxhQUFhLEVBQUU7UUFDckMsS0FBSyxHQUFHLElBQUksaUJBQVcsQ0FBQyxLQUFLLEVBQUUsU0FBUyxFQUFFLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7S0FDNUQ7SUFFRCxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUUsS0FBcUIsQ0FBQyxTQUFTLENBQUMsQ0FBQztBQUN6RCxDQUFDO0FBaFFELGlCQUFTO0lBQ1AsMEZBQTBGLENBQUMsSUFBVTtRQUNuRyxRQUFRO1FBQ1IsTUFBTSxLQUFLLEdBQUcsSUFBSSxXQUFLLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBRWhELE1B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QUFHLElBQUksZUFBUyxDQUFDLEtBQUssRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM1QyxJQUFJLGlCQUFXLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBRXJELHFEQUFxRDtRQUNyRCxLQUFLLENBQUMsZUFBZSxDQUFDLGNBQWMsRUFBRSxXQUFXLENBQUMsQ0FBQztRQUVuRCxNQUFNLENBQUMsR0FBRyxJQUFJLGlCQUFXLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxFQUFFLElBQUksRUFBRSxhQUFhLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELENBQUMsQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUU1QixJQUFJLENBQUMsU0FBUyxDQUFDLHVCQUFnQixDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ3RDLFNBQVMsRUFBRTtnQkFDVCxZQUFZLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUNyQyxTQUFTLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2dCQUNsQyxJQUFJLEVBQUUsRUFBRSxJQUFJLEVBQUUsYUFBYSxFQUFFO2FBQzlCO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO0lBQ2QsQ0FBQztDQUNGLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBUZXN0IH0gZnJvbSAnbm9kZXVuaXQnO1xuaW1wb3J0IHsgQ2ZuRWxlbWVudCwgQ2ZuUmVzb3VyY2UsIENvbnN0cnVjdCwgU3RhY2sgfSBmcm9tICcuLi9saWInO1xuaW1wb3J0IHsgdG9DbG91ZEZvcm1hdGlvbiB9IGZyb20gJy4vdXRpbCc7XG5cbi8qKlxuICogVGhlc2UgdGVzdHMgYXJlIGV4ZWN1dGVkIG9uY2UgKGZvciBzcGVjaWZpYyBJRCBzY2hlbWVzKVxuICovXG5leHBvcnQgPSB7XG4gICdpZiB0aGUgbmFtaW5nIHNjaGVtZSB1bmlxdWlmaWVzIHdpdGggYSBoYXNoIHdlIGNhbiBoYXZlIHRoZSBzYW1lIGNvbmNhdGVuYXRlZCBpZGVudGlmaWVyJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsICdUZXN0U3RhY2snKTtcblxuICAgIGNvbnN0IEEgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnQScpO1xuICAgIG5ldyBDZm5SZXNvdXJjZShBLCAnQkMnLCB7IHR5cGU6ICdSZXNvdXJjZScgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgQUIgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnQUInKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UoQUIsICdDJywgeyB0eXBlOiAnUmVzb3VyY2UnIH0pO1xuXG4gICAgLy8gVEhFTjogbm8gZXhjZXB0aW9uXG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnc3BlY2lhbCBjYXNlOiBpZiB0aGUgcmVzb3VyY2UgaXMgdG9wLWxldmVsLCBhIGhhc2ggaXMgbm90IGFkZGVkJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjayh1bmRlZmluZWQsICdUZXN0U3RhY2snKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCByID0gbmV3IENmblJlc291cmNlKHN0YWNrLCAnTXlBd2Vzb21lbmVzcycsIHsgdHlwZTogJ1Jlc291cmNlJyB9KTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LmVxdWFsKHN0YWNrLnJlc29sdmUoci5sb2dpY2FsSWQpLCAnTXlBd2Vzb21lbmVzcycpO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ0xvZ2ljYWwgSURzIGNhbiBiZSByZW5hbWVkIGF0IHRoZSBzdGFjayBsZXZlbCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBwYXJlbnQgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnUGFyZW50Jyk7XG4gICAgbmV3IENmblJlc291cmNlKHBhcmVudCwgJ1RoaW5nUmVzb3VyY2UnLCB7IHR5cGU6ICdBV1M6OlRBQVM6OlRoaW5nJyB9KTtcbiAgICBzdGFjay5yZW5hbWVMb2dpY2FsSWQoJ1BhcmVudFRoaW5nUmVzb3VyY2U3NUQxRDlDQicsICdSZW5hbWVkJyk7XG5cbiAgICAvLyBUSEVOXG4gICAgY29uc3QgdGVtcGxhdGUgPSB0b0Nsb3VkRm9ybWF0aW9uKHN0YWNrKTtcbiAgICB0ZXN0Lm9rKCdSZW5hbWVkJyBpbiB0ZW1wbGF0ZS5SZXNvdXJjZXMpO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ1JlbmFtZXMgZm9yIG9iamVjdHMgdGhhdCBkb25cXCd0IGV4aXN0IGZhaWwnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gICAgbmV3IENvbnN0cnVjdChzdGFjaywgJ1BhcmVudCcpO1xuXG4gICAgLy8gV0hFTlxuICAgIHN0YWNrLnJlbmFtZUxvZ2ljYWxJZCgnRE9FU05PVEVYSVNUJywgJ1JlbmFtZWQnKTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0LnRocm93cygoKSA9PiB0b0Nsb3VkRm9ybWF0aW9uKHN0YWNrKSk7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnSUQgUmVuYW1lcyB0aGF0IGNvbGxpZGUgd2l0aCBleGlzdGluZyBJRHMgc2hvdWxkIGZhaWwnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG4gICAgc3RhY2sucmVuYW1lTG9naWNhbElkKCdQYXJlbnRUaGluZ1Jlc291cmNlMTkxNkU3ODA4JywgJ1BhcmVudFRoaW5nUmVzb3VyY2UyRjE5OTQ4Q0InKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBwYXJlbnQgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnUGFyZW50Jyk7XG4gICAgbmV3IENmblJlc291cmNlKHBhcmVudCwgJ1RoaW5nUmVzb3VyY2UxJywgeyB0eXBlOiAnQVdTOjpUQUFTOjpUaGluZycgfSk7XG4gICAgbmV3IENmblJlc291cmNlKHBhcmVudCwgJ1RoaW5nUmVzb3VyY2UyJywgeyB0eXBlOiAnQVdTOjpUQUFTOjpUaGluZycgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgdGVzdC50aHJvd3MoKCkgPT4gdG9DbG91ZEZvcm1hdGlvbihzdGFjayksIC9Ud28gb2JqZWN0cyBoYXZlIGJlZW4gYXNzaWduZWQgdGhlIHNhbWUgTG9naWNhbCBJRC8pO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdoYXNoZWQgbmFtaW5nIHNjaGVtZSBmaWx0ZXJzIGNvbnN0cnVjdHMgbmFtZWQgXCJSZXNvdXJjZVwiIGZyb20gdGhlIGh1bWFuIHBvcnRpb24nKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgcGFyZW50ID0gbmV3IENvbnN0cnVjdChzdGFjaywgJ1BhcmVudCcpO1xuICAgIGNvbnN0IGNoaWxkMSA9IG5ldyBDb25zdHJ1Y3QocGFyZW50LCAnQ2hpbGQnKTtcbiAgICBjb25zdCBjaGlsZDIgPSBuZXcgQ29uc3RydWN0KGNoaWxkMSwgJ1Jlc291cmNlJyk7XG5cbiAgICBuZXcgQ2ZuUmVzb3VyY2UoY2hpbGQyLCAnSGV5VGhlcmUnLCB7IHR5cGU6ICdBV1M6OlRBQVM6OlRoaW5nJyB9KTtcblxuICAgIC8vIFRIRU5cbiAgICBjb25zdCB0ZW1wbGF0ZSA9IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2spO1xuICAgIHRlc3QuZGVlcEVxdWFsKHRlbXBsYXRlLCB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgUGFyZW50Q2hpbGRIZXlUaGVyZTM1MjIwMzQ3OiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6VEFBUzo6VGhpbmcnXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdjYW4gdHJhbnNwYXJlbnRseSB3cmFwIGNvbnN0cnVjdHMgdXNpbmcgXCJEZWZhdWx0XCIgaWQnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrMSA9IG5ldyBTdGFjaygpO1xuICAgIGNvbnN0IHBhcmVudDEgPSBuZXcgQ29uc3RydWN0KHN0YWNrMSwgJ1BhcmVudCcpO1xuICAgIG5ldyBDZm5SZXNvdXJjZShwYXJlbnQxLCAnSGV5VGhlcmUnLCB7IHR5cGU6ICdBV1M6OlRBQVM6OlRoaW5nJyB9KTtcbiAgICBjb25zdCB0ZW1wbGF0ZTEgPSB0b0Nsb3VkRm9ybWF0aW9uKHN0YWNrMSk7XG5cbiAgICAvLyBBTkRcbiAgICBjb25zdCB0aGVJZDEgPSBPYmplY3Qua2V5cyh0ZW1wbGF0ZTEuUmVzb3VyY2VzKVswXTtcbiAgICB0ZXN0LmVxdWFsKCdBV1M6OlRBQVM6OlRoaW5nJywgdGVtcGxhdGUxLlJlc291cmNlc1t0aGVJZDFdLlR5cGUpO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IHN0YWNrMiA9IG5ldyBTdGFjaygpO1xuICAgIGNvbnN0IHBhcmVudDIgPSBuZXcgQ29uc3RydWN0KHN0YWNrMiwgJ1BhcmVudCcpO1xuICAgIGNvbnN0IGludmlzaWJsZVdyYXBwZXIgPSBuZXcgQ29uc3RydWN0KHBhcmVudDIsICdEZWZhdWx0Jyk7XG4gICAgbmV3IENmblJlc291cmNlKGludmlzaWJsZVdyYXBwZXIsICdIZXlUaGVyZScsIHsgdHlwZTogJ0FXUzo6VEFBUzo6VGhpbmcnIH0pO1xuICAgIGNvbnN0IHRlbXBsYXRlMiA9IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2sxKTtcblxuICAgIGNvbnN0IHRoZUlkMiA9IE9iamVjdC5rZXlzKHRlbXBsYXRlMi5SZXNvdXJjZXMpWzBdO1xuICAgIHRlc3QuZXF1YWwoJ0FXUzo6VEFBUzo6VGhpbmcnLCB0ZW1wbGF0ZTIuUmVzb3VyY2VzW3RoZUlkMl0uVHlwZSk7XG5cbiAgICAvLyBUSEVOOiBzYW1lIElELCBzYW1lIG9iamVjdFxuICAgIHRlc3QuZXF1YWwodGhlSWQxLCB0aGVJZDIpO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ25vbi1hbHBoYW51bWVyaWMgY2hhcmFjdGVycyBhcmUgcmVtb3ZlZCBmcm9tIHRoZSBodW1hbiBwYXJ0IG9mIHRoZSBsb2dpY2FsIElEJyh0ZXN0OiBUZXN0KSB7XG4gICAgY29uc3QgdmFsMSA9IGxvZ2ljYWxGb3JFbGVtZW50SW5QYXRoKFsgJ0Zvby1iYXInLCAnQjAwbScsICdIZWxsb19Xb3JsZCcsICcmJkhvcnJheSBIb3JyYXkuJyBdKTtcbiAgICBjb25zdCB2YWwyID0gbG9naWNhbEZvckVsZW1lbnRJblBhdGgoWyAnRm9vYmFyJywgJ0IwMG0nLCAnSGVsbG9Xb3JsZCcsICdIb3JyYXlIb3JyYXknIF0pO1xuXG4gICAgLy8gc2FtZSBodW1hbiBwYXJ0LCBkaWZmZXJlbnQgaGFzaFxuICAgIHRlc3QuZGVlcEVxdWFsKHZhbDEsICdGb29iYXJCMDBtSGVsbG9Xb3JsZEhvcnJheUhvcnJheTY0MEU5OUZCJyk7XG4gICAgdGVzdC5kZWVwRXF1YWwodmFsMiwgJ0Zvb2JhckIwMG1IZWxsb1dvcmxkSG9ycmF5SG9ycmF5NzQ0MzM0RkQnKTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnbm9uLWFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIGFyZSByZW1vdmVkIGV2ZW4gaWYgdGhlIElEIGhhcyBvbmx5IG9uZSBjb21wb25lbnQnKHRlc3Q6IFRlc3QpIHtcbiAgICBjb25zdCB2YWwxID0gbG9naWNhbEZvckVsZW1lbnRJblBhdGgoWyAnRm9vLWJhcicgXSk7XG5cbiAgICAvLyBzYW1lIGh1bWFuIHBhcnQsIGRpZmZlcmVudCBoYXNoXG4gICAgdGVzdC5kZWVwRXF1YWwodmFsMSwgJ0Zvb2JhcicpO1xuICAgIHRlc3QuZG9uZSgpO1xuICB9LFxuXG4gICdlbXB0eSBpZGVudGlmaWVycyBhcmUgbm90IGFsbG93ZWQnKHRlc3Q6IFRlc3QpIHtcbiAgICAvLyBHSVZFTlxuICAgIGNvbnN0IHN0YWNrID0gbmV3IFN0YWNrKCk7XG5cbiAgICAvLyBXSEVOXG4gICAgbmV3IENmblJlc291cmNlKHN0YWNrLCAnLicsIHsgdHlwZTogJ1InIH0pO1xuXG4gICAgLy8gVEhFTlxuICAgIHRlc3QudGhyb3dzKCgpID0+IHRvQ2xvdWRGb3JtYXRpb24oc3RhY2spLCAvTG9naWNhbCBJRCBtdXN0IGFkaGVyZSB0byB0aGUgcmVndWxhciBleHByZXNzaW9uLyk7XG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ3RvbyBsYXJnZSBpZGVudGlmaWVycyBhcmUgdHJ1bmNhdGVkIHlldCBzdGlsbCByZW1haW4gdW5pcXVlJyh0ZXN0OiBUZXN0KSB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzdGFjayA9IG5ldyBTdGFjaygpO1xuICAgIGNvbnN0IEEgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCBnZW5lcmF0ZVN0cmluZygxMDApKTtcbiAgICBjb25zdCBCID0gbmV3IENvbnN0cnVjdChBLCBnZW5lcmF0ZVN0cmluZygxMDApKTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBmaXJzdFBhcnQgPSBnZW5lcmF0ZVN0cmluZyg2MCk7XG4gICAgLy8gVGhlIHNoYXJlZCBwYXJ0IGhhcyBub3cgZXhjZWVkZWQgdGhlIG1heGltdW0gbGVuZ3RoIG9mIENsb3VkRm9ybWF0aW9uIGlkZW50aWZpZXJzXG4gICAgLy8gc28gdGhlIGlkZW50aXR5IGdlbmVyYXRvciB3aWxsIGhhdmUgdG8gc29tZXRoaW5nIHNtYXJ0XG5cbiAgICBjb25zdCBDMSA9IG5ldyBDZm5SZXNvdXJjZShCLCBmaXJzdFBhcnQgKyBnZW5lcmF0ZVN0cmluZyg0MCksIHsgdHlwZTogJ1Jlc291cmNlJyB9KTtcbiAgICBjb25zdCBDMiA9IG5ldyBDZm5SZXNvdXJjZShCLCBmaXJzdFBhcnQgKyBnZW5lcmF0ZVN0cmluZyg0MCksIHsgdHlwZTogJ1Jlc291cmNlJyB9KTtcblxuICAgIC8vIFRIRU5cbiAgICB0ZXN0Lm9rKEMxLmxvZ2ljYWxJZC5sZW5ndGggPD0gMjU1KTtcbiAgICB0ZXN0Lm9rKEMyLmxvZ2ljYWxJZC5sZW5ndGggPD0gMjU1KTtcbiAgICB0ZXN0Lm5vdEVxdWFsKEMxLCBDMik7XG5cbiAgICB0ZXN0LmRvbmUoKTtcbiAgfSxcblxuICAnUmVmcyBhbmQgZGVwZW5kZW5jaWVzIHdpbGwgY29ycmVjdGx5IHJlZmxlY3QgcmVuYW1lcyBkb25lIGF0IHRoZSBzdGFjayBsZXZlbCcodGVzdDogVGVzdCkge1xuICAgIC8vIEdJVkVOXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcbiAgICBzdGFjay5yZW5hbWVMb2dpY2FsSWQoJ09yaWdpbmFsTmFtZScsICdOZXdOYW1lJyk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgYzEgPSBuZXcgQ2ZuUmVzb3VyY2Uoc3RhY2ssICdPcmlnaW5hbE5hbWUnLCB7IHR5cGU6ICdSMScgfSk7XG4gICAgY29uc3QgcmVmID0gYzEucmVmO1xuXG4gICAgY29uc3QgYzIgPSBuZXcgQ2ZuUmVzb3VyY2Uoc3RhY2ssICdDb25zdHJ1Y3QyJywgeyB0eXBlOiAnUjInLCBwcm9wZXJ0aWVzOiB7IFJlZmVyZW5jZVRvUjE6IHJlZiB9IH0pO1xuICAgIGMyLm5vZGUuYWRkRGVwZW5kZW5jeShjMSk7XG5cbiAgICAvLyBUSEVOXG4gICAgdGVzdC5kZWVwRXF1YWwodG9DbG91ZEZvcm1hdGlvbihzdGFjayksIHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBOZXdOYW1lOiB7IFR5cGU6ICdSMScgfSxcbiAgICAgICAgQ29uc3RydWN0Mjoge1xuICAgICAgICAgIFR5cGU6ICdSMicsXG4gICAgICAgICAgUHJvcGVydGllczogeyBSZWZlcmVuY2VUb1IxOiB7IFJlZjogJ05ld05hbWUnIH0gfSxcbiAgICAgICAgICBEZXBlbmRzT246IFsgJ05ld05hbWUnIF1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgdGVzdC5kb25lKCk7XG4gIH0sXG5cbiAgJ2N1c3RvbWl6ZSBsb2dpY2FsIGlkIGFsbG9jYXRpb24gYmVoYXZpb3IgYnkgb3ZlcnJpZGluZyBgU3RhY2suYWxsb2NhdGVMb2dpY2FsSWRgJyh0ZXN0OiBUZXN0KSB7XG4gICAgY2xhc3MgTXlTdGFjayBleHRlbmRzIFN0YWNrIHtcbiAgICAgIHByb3RlY3RlZCBhbGxvY2F0ZUxvZ2ljYWxJZChlbGVtZW50OiBDZm5FbGVtZW50KTogc3RyaW5nIHtcbiAgICAgICAgaWYgKGVsZW1lbnQubm9kZS5pZCA9PT0gJ0EnKSB7IHJldHVybiAnTG9naWNhbElkT2ZBJzsgfVxuICAgICAgICBpZiAoZWxlbWVudC5ub2RlLmlkID09PSAnQicpIHsgcmV0dXJuICdMb2dpY2FsSWRPZkInOyB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBlbGVtZW50IElEYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3Qgc3RhY2sgPSBuZXcgTXlTdGFjaygpO1xuICAgIG5ldyBDZm5SZXNvdXJjZShzdGFjaywgJ0EnLCB7IHR5cGU6ICdUeXBlOjpPZjo6QScgfSk7XG4gICAgY29uc3QgZ3JvdXAgPSBuZXcgQ29uc3RydWN0KHN0YWNrLCAnR3JvdXAnKTtcbiAgICBuZXcgQ2ZuUmVzb3VyY2UoZ3JvdXAsICdCJywgeyB0eXBlOiAnVHlwZTo6T2Y6OkInIH0pO1xuXG4gICAgLy8gcmVuYW1lcyBjYW4gYWxzbyBiZSBhcHBsaWVkIG9uIGN1c3RvbSBsb2dpY2FsIElEcy5cbiAgICBzdGFjay5yZW5hbWVMb2dpY2FsSWQoJ0xvZ2ljYWxJZE9mQicsICdCb29tQm9vbUInKTtcblxuICAgIGNvbnN0IGMgPSBuZXcgQ2ZuUmVzb3VyY2Uoc3RhY2ssICdCJywgeyB0eXBlOiAnVHlwZTo6T2Y6OkMnIH0pO1xuICAgIGMub3ZlcnJpZGVMb2dpY2FsSWQoJ1RoZUMnKTtcblxuICAgIHRlc3QuZGVlcEVxdWFsKHRvQ2xvdWRGb3JtYXRpb24oc3RhY2spLCB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgTG9naWNhbElkT2ZBOiB7IFR5cGU6ICdUeXBlOjpPZjo6QScgfSxcbiAgICAgICAgQm9vbUJvb21COiB7IFR5cGU6ICdUeXBlOjpPZjo6QicgfSxcbiAgICAgICAgVGhlQzogeyBUeXBlOiAnVHlwZTo6T2Y6OkMnIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB0ZXN0LmRvbmUoKTtcbiAgfVxufTtcblxuZnVuY3Rpb24gZ2VuZXJhdGVTdHJpbmcoY2hhcnM6IG51bWJlcikge1xuICBsZXQgcyA9ICcnO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGNoYXJzOyArK2kpIHtcbiAgICBzICs9IHJhbmRvbUFscGhhKCk7XG4gIH1cbiAgcmV0dXJuIHM7XG5cbiAgZnVuY3Rpb24gcmFuZG9tQWxwaGEoKSB7XG4gICAgcmV0dXJuIFN0cmluZy5mcm9tQ2hhckNvZGUoJ2EnLmNoYXJDb2RlQXQoMCkgKyBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAyNikpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGxvZ2ljYWxGb3JFbGVtZW50SW5QYXRoKGNvbnN0cnVjdFBhdGg6IHN0cmluZ1tdKTogc3RyaW5nIHtcbiAgY29uc3Qgc3RhY2sgPSBuZXcgU3RhY2soKTtcbiAgbGV0IHNjb3BlOiBDb25zdHJ1Y3QgPSBzdGFjaztcbiAgZm9yIChjb25zdCBjb21wb25lbnQgb2YgY29uc3RydWN0UGF0aCkge1xuICAgIHNjb3BlID0gbmV3IENmblJlc291cmNlKHNjb3BlLCBjb21wb25lbnQsIHsgdHlwZTogJ0ZvbycgfSk7XG4gIH1cblxuICByZXR1cm4gc3RhY2sucmVzb2x2ZSgoc2NvcGUgYXMgQ2ZuUmVzb3VyY2UpLmxvZ2ljYWxJZCk7XG59Il19