aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
287 lines • 45.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VpcNetworkContextProviderPlugin = void 0;
const cx_api_1 = require("@aws-cdk/cx-api");
const sdk_provider_1 = require("../api/aws-auth/sdk-provider");
const logging_1 = require("../logging");
const error_1 = require("../toolkit/error");
class VpcNetworkContextProviderPlugin {
constructor(aws) {
this.aws = aws;
}
async getValue(args) {
const ec2 = (await (0, sdk_provider_1.initContextProviderSdk)(this.aws, args)).ec2();
const vpcId = await this.findVpc(ec2, args);
return this.readVpcProps(ec2, vpcId, args);
}
async findVpc(ec2, args) {
// Build request filter (map { Name -> Value } to list of [{ Name, Values }])
const filters = Object.entries(args.filter).map(([tag, value]) => ({ Name: tag, Values: [value] }));
(0, logging_1.debug)(`Listing VPCs in ${args.account}:${args.region}`);
const response = await ec2.describeVpcs({ Filters: filters });
const vpcs = response.Vpcs || [];
if (vpcs.length === 0) {
throw new error_1.ContextProviderError(`Could not find any VPCs matching ${JSON.stringify(args)}`);
}
if (vpcs.length > 1) {
throw new error_1.ContextProviderError(`Found ${vpcs.length} VPCs matching ${JSON.stringify(args)}; please narrow the search criteria`);
}
return vpcs[0];
}
async readVpcProps(ec2, vpc, args) {
const vpcId = vpc.VpcId;
(0, logging_1.debug)(`Describing VPC ${vpcId}`);
const filters = { Filters: [{ Name: 'vpc-id', Values: [vpcId] }] };
const subnetsResponse = await ec2.describeSubnets(filters);
const listedSubnets = subnetsResponse.Subnets || [];
const routeTablesResponse = await ec2.describeRouteTables(filters);
const routeTables = new RouteTables(routeTablesResponse.RouteTables || []);
// Now comes our job to separate these subnets out into AZs and subnet groups (Public, Private, Isolated)
// We have the following attributes to go on:
// - Type tag, we tag subnets with their type. In absence of this tag, we
// determine the subnet must be Public if either:
// a) it has the property MapPublicIpOnLaunch
// b) it has a route to an Internet Gateway
// If both of the above is false but the subnet has a route to a NAT Gateway
// and the destination CIDR block is "0.0.0.0/0", we assume it to be a Private subnet.
// Anything else is considered Isolated.
// - Name tag, we tag subnets with their subnet group name. In absence of this tag,
// we use the type as the name.
const azs = Array.from(new Set(listedSubnets.map((s) => s.AvailabilityZone)));
azs.sort();
const subnets = listedSubnets.map((subnet) => {
let type = getTag('aws-cdk:subnet-type', subnet.Tags);
if (type === undefined && subnet.MapPublicIpOnLaunch) {
type = SubnetType.Public;
}
if (type === undefined && routeTables.hasRouteToIgw(subnet.SubnetId)) {
type = SubnetType.Public;
}
if (type === undefined && routeTables.hasRouteToNatGateway(subnet.SubnetId)) {
type = SubnetType.Private;
}
if (type === undefined && routeTables.hasRouteToTransitGateway(subnet.SubnetId)) {
type = SubnetType.Private;
}
if (type === undefined) {
type = SubnetType.Isolated;
}
if (!isValidSubnetType(type)) {
// eslint-disable-next-line max-len
throw new error_1.ContextProviderError(`Subnet ${subnet.SubnetArn} has invalid subnet type ${type} (must be ${SubnetType.Public}, ${SubnetType.Private} or ${SubnetType.Isolated})`);
}
if (args.subnetGroupNameTag && !getTag(args.subnetGroupNameTag, subnet.Tags)) {
throw new error_1.ContextProviderError(`Invalid subnetGroupNameTag: Subnet ${subnet.SubnetArn} does not have an associated tag with Key='${args.subnetGroupNameTag}'`);
}
const name = getTag(args.subnetGroupNameTag || 'aws-cdk:subnet-name', subnet.Tags) || type;
const routeTableId = routeTables.routeTableIdForSubnetId(subnet.SubnetId);
if (!routeTableId) {
throw new error_1.ContextProviderError(`Subnet ${subnet.SubnetArn} does not have an associated route table (and there is no "main" table)`);
}
return {
az: subnet.AvailabilityZone,
cidr: subnet.CidrBlock,
type,
name,
subnetId: subnet.SubnetId,
routeTableId,
};
});
let grouped;
let assymetricSubnetGroups;
if (args.returnAsymmetricSubnets) {
grouped = { azs: [], groups: [] };
assymetricSubnetGroups = groupAsymmetricSubnets(subnets);
}
else {
grouped = groupSubnets(subnets);
assymetricSubnetGroups = undefined;
}
// Find attached+available VPN gateway for this VPC
const vpnGatewayResponse = (args.returnVpnGateways ?? true)
? await ec2.describeVpnGateways({
Filters: [
{
Name: 'attachment.vpc-id',
Values: [vpcId],
},
{
Name: 'attachment.state',
Values: ['attached'],
},
{
Name: 'state',
Values: ['available'],
},
],
})
: undefined;
const vpnGatewayId = vpnGatewayResponse?.VpnGateways?.length === 1 ? vpnGatewayResponse.VpnGateways[0].VpnGatewayId : undefined;
return {
vpcId,
vpcCidrBlock: vpc.CidrBlock,
ownerAccountId: vpc.OwnerId,
availabilityZones: grouped.azs,
isolatedSubnetIds: collapse(flatMap(findGroups(SubnetType.Isolated, grouped), (group) => group.subnets.map((s) => s.subnetId))),
isolatedSubnetNames: collapse(flatMap(findGroups(SubnetType.Isolated, grouped), (group) => (group.name ? [group.name] : []))),
isolatedSubnetRouteTableIds: collapse(flatMap(findGroups(SubnetType.Isolated, grouped), (group) => group.subnets.map((s) => s.routeTableId))),
privateSubnetIds: collapse(flatMap(findGroups(SubnetType.Private, grouped), (group) => group.subnets.map((s) => s.subnetId))),
privateSubnetNames: collapse(flatMap(findGroups(SubnetType.Private, grouped), (group) => (group.name ? [group.name] : []))),
privateSubnetRouteTableIds: collapse(flatMap(findGroups(SubnetType.Private, grouped), (group) => group.subnets.map((s) => s.routeTableId))),
publicSubnetIds: collapse(flatMap(findGroups(SubnetType.Public, grouped), (group) => group.subnets.map((s) => s.subnetId))),
publicSubnetNames: collapse(flatMap(findGroups(SubnetType.Public, grouped), (group) => (group.name ? [group.name] : []))),
publicSubnetRouteTableIds: collapse(flatMap(findGroups(SubnetType.Public, grouped), (group) => group.subnets.map((s) => s.routeTableId))),
vpnGatewayId,
subnetGroups: assymetricSubnetGroups,
};
}
}
exports.VpcNetworkContextProviderPlugin = VpcNetworkContextProviderPlugin;
class RouteTables {
constructor(tables) {
this.tables = tables;
this.mainRouteTable = this.tables.find((table) => !!table.Associations && table.Associations.some((assoc) => !!assoc.Main));
}
routeTableIdForSubnetId(subnetId) {
const table = this.tableForSubnet(subnetId);
return (table && table.RouteTableId) || (this.mainRouteTable && this.mainRouteTable.RouteTableId);
}
/**
* Whether the given subnet has a route to a NAT Gateway
*/
hasRouteToNatGateway(subnetId) {
const table = this.tableForSubnet(subnetId) || this.mainRouteTable;
return (!!table &&
!!table.Routes &&
table.Routes.some((route) => !!route.NatGatewayId && route.DestinationCidrBlock === '0.0.0.0/0'));
}
/**
* Whether the given subnet has a route to a Transit Gateway
*/
hasRouteToTransitGateway(subnetId) {
const table = this.tableForSubnet(subnetId) || this.mainRouteTable;
return (!!table &&
!!table.Routes &&
table.Routes.some((route) => !!route.TransitGatewayId && route.DestinationCidrBlock === '0.0.0.0/0'));
}
/**
* Whether the given subnet has a route to an IGW
*/
hasRouteToIgw(subnetId) {
const table = this.tableForSubnet(subnetId) || this.mainRouteTable;
return (!!table && !!table.Routes && table.Routes.some((route) => !!route.GatewayId && route.GatewayId.startsWith('igw-')));
}
tableForSubnet(subnetId) {
return this.tables.find((table) => !!table.Associations && table.Associations.some((assoc) => assoc.SubnetId === subnetId));
}
}
/**
* Return the value of a tag from a set of tags
*/
function getTag(name, tags) {
for (const tag of tags || []) {
if (tag.Key === name) {
return tag.Value;
}
}
return undefined;
}
/**
* Group subnets of the same type together, and order by AZ
*/
function groupSubnets(subnets) {
const grouping = {};
for (const subnet of subnets) {
const key = [subnet.type, subnet.name].toString();
if (!(key in grouping)) {
grouping[key] = [];
}
grouping[key].push(subnet);
}
const groups = Object.values(grouping).map((sns) => {
sns.sort((a, b) => a.az.localeCompare(b.az));
return {
type: sns[0].type,
name: sns[0].name,
subnets: sns,
};
});
const azs = groups[0].subnets.map((s) => s.az);
for (const group of groups) {
const groupAZs = group.subnets.map((s) => s.az);
if (!arraysEqual(groupAZs, azs)) {
throw new error_1.ContextProviderError(`Not all subnets in VPC have the same AZs: ${groupAZs} vs ${azs}`);
}
}
return { azs, groups };
}
function groupAsymmetricSubnets(subnets) {
const grouping = {};
for (const subnet of subnets) {
const key = [subnet.type, subnet.name].toString();
if (!(key in grouping)) {
grouping[key] = [];
}
grouping[key].push(subnet);
}
return Object.values(grouping).map((subnetArray) => {
subnetArray.sort((subnet1, subnet2) => subnet1.az.localeCompare(subnet2.az));
return {
name: subnetArray[0].name,
type: subnetTypeToVpcSubnetType(subnetArray[0].type),
subnets: subnetArray.map((subnet) => ({
subnetId: subnet.subnetId,
cidr: subnet.cidr,
availabilityZone: subnet.az,
routeTableId: subnet.routeTableId,
})),
};
});
}
function subnetTypeToVpcSubnetType(type) {
switch (type) {
case SubnetType.Isolated:
return cx_api_1.VpcSubnetGroupType.ISOLATED;
case SubnetType.Private:
return cx_api_1.VpcSubnetGroupType.PRIVATE;
case SubnetType.Public:
return cx_api_1.VpcSubnetGroupType.PUBLIC;
}
}
var SubnetType;
(function (SubnetType) {
SubnetType["Public"] = "Public";
SubnetType["Private"] = "Private";
SubnetType["Isolated"] = "Isolated";
})(SubnetType || (SubnetType = {}));
function isValidSubnetType(val) {
return val === SubnetType.Public || val === SubnetType.Private || val === SubnetType.Isolated;
}
function arraysEqual(as, bs) {
if (as.length !== bs.length) {
return false;
}
for (let i = 0; i < as.length; i++) {
if (as[i] !== bs[i]) {
return false;
}
}
return true;
}
function findGroups(type, groups) {
return groups.groups.filter((g) => g.type === type);
}
function flatMap(xs, fn) {
const ret = new Array();
for (const x of xs) {
ret.push(...fn(x));
}
return ret;
}
function collapse(xs) {
if (xs.length > 0) {
return xs;
}
return undefined;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnBjcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInZwY3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsNENBQW1HO0FBR25HLCtEQUF3RjtBQUV4Rix3Q0FBbUM7QUFDbkMsNENBQXdEO0FBQ3hELE1BQWEsK0JBQStCO0lBQzFDLFlBQTZCLEdBQWdCO1FBQWhCLFFBQUcsR0FBSCxHQUFHLENBQWE7SUFBRyxDQUFDO0lBRTFDLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBcUI7UUFDekMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxNQUFNLElBQUEscUNBQXNCLEVBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDO1FBRWpFLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFNUMsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLEdBQUcsRUFBRSxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQUVPLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBZSxFQUFFLElBQXFCO1FBQzFELDZFQUE2RTtRQUM3RSxNQUFNLE9BQU8sR0FBYSxNQUFNLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFOUcsSUFBQSxlQUFLLEVBQUMsbUJBQW1CLElBQUksQ0FBQyxPQUFPLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDeEQsTUFBTSxRQUFRLEdBQUcsTUFBTSxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxD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QUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDbEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBQ0QsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgVnBjQ29udGV4dFF1ZXJ5IH0gZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCB7IHR5cGUgVnBjQ29udGV4dFJlc3BvbnNlLCB0eXBlIFZwY1N1Ym5ldEdyb3VwLCBWcGNTdWJuZXRHcm91cFR5cGUgfSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHR5cGUgeyBGaWx0ZXIsIFJvdXRlVGFibGUsIFRhZywgVnBjIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWVjMic7XG5pbXBvcnQgdHlwZSB7IElFQzJDbGllbnQgfSBmcm9tICcuLi9hcGknO1xuaW1wb3J0IHsgdHlwZSBTZGtQcm92aWRlciwgaW5pdENvbnRleHRQcm92aWRlclNkayB9IGZyb20gJy4uL2FwaS9hd3MtYXV0aC9zZGstcHJvdmlkZXInO1xuaW1wb3J0IHsgQ29udGV4dFByb3ZpZGVyUGx1Z2luIH0gZnJvbSAnLi4vYXBpL3BsdWdpbic7XG5pbXBvcnQgeyBkZWJ1ZyB9IGZyb20gJy4uL2xvZ2dpbmcnO1xuaW1wb3J0IHsgQ29udGV4dFByb3ZpZGVyRXJyb3IgfSBmcm9tICcuLi90b29sa2l0L2Vycm9yJztcbmV4cG9ydCBjbGFzcyBWcGNOZXR3b3JrQ29udGV4dFByb3ZpZGVyUGx1Z2luIGltcGxlbWVudHMgQ29udGV4dFByb3ZpZGVyUGx1Z2luIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBhd3M6IFNka1Byb3ZpZGVyKSB7fVxuXG4gIHB1YmxpYyBhc3luYyBnZXRWYWx1ZShhcmdzOiBWcGNDb250ZXh0UXVlcnkpIHtcbiAgICBjb25zdCBlYzIgPSAoYXdhaXQgaW5pdENvbnRleHRQcm92aWRlclNkayh0aGlzLmF3cywgYXJncykpLmVjMigpO1xuXG4gICAgY29uc3QgdnBjSWQgPSBhd2FpdCB0aGlzLmZpbmRWcGMoZWMyLCBhcmdzKTtcblxuICAgIHJldHVybiB0aGlzLnJlYWRWcGNQcm9wcyhlYzIsIHZwY0lkLCBhcmdzKTtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmluZFZwYyhlYzI6IElFQzJDbGllbnQsIGFyZ3M6IFZwY0NvbnRleHRRdWVyeSk6IFByb21pc2U8VnBjPiB7XG4gICAgLy8gQnVpbGQgcmVxdWVzdCBmaWx0ZXIgKG1hcCB7IE5hbWUgLT4gVmFsdWUgfSB0byBsaXN0IG9mIFt7IE5hbWUsIFZhbHVlcyB9XSlcbiAgICBjb25zdCBmaWx0ZXJzOiBGaWx0ZXJbXSA9IE9iamVjdC5lbnRyaWVzKGFyZ3MuZmlsdGVyKS5tYXAoKFt0YWcsIHZhbHVlXSkgPT4gKHsgTmFtZTogdGFnLCBWYWx1ZXM6IFt2YWx1ZV0gfSkpO1xuXG4gICAgZGVidWcoYExpc3RpbmcgVlBDcyBpbiAke2FyZ3MuYWNjb3VudH06JHthcmdzLnJlZ2lvbn1gKTtcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGVjMi5kZXNjcmliZVZwY3MoeyBGaWx0ZXJzOiBmaWx0ZXJzIH0pO1xuXG4gICAgY29uc3QgdnBjcyA9IHJlc3BvbnNlLlZwY3MgfHwgW107XG4gICAgaWYgKHZwY3MubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgQ29udGV4dFByb3ZpZGVyRXJyb3IoYENvdWxkIG5vdCBmaW5kIGFueSBWUENzIG1hdGNoaW5nICR7SlNPTi5zdHJpbmdpZnkoYXJncyl9YCk7XG4gICAgfVxuICAgIGlmICh2cGNzLmxlbmd0aCA+IDEpIHtcbiAgICAgIHRocm93IG5ldyBDb250ZXh0UHJvdmlkZXJFcnJvcihgRm91bmQgJHt2cGNzLmxlbmd0aH0gVlBDcyBtYXRjaGluZyAke0pTT04uc3RyaW5naWZ5KGFyZ3MpfTsgcGxlYXNlIG5hcnJvdyB0aGUgc2VhcmNoIGNyaXRlcmlhYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHZwY3NbMF07XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIHJlYWRWcGNQcm9wcyhlYzI6IElFQzJDbGllbnQsIHZwYzogVnBjLCBhcmdzOiBWcGNDb250ZXh0UXVlcnkpOiBQcm9taXNlPFZwY0NvbnRleHRSZXNwb25zZT4ge1xuICAgIGNvbnN0IHZwY0lkID0gdnBjLlZwY0lkITtcblxuICAgIGRlYnVnKGBEZXNjcmliaW5nIFZQQyAke3ZwY0lkfWApO1xuXG4gICAgY29uc3QgZmlsdGVycyA9IHsgRmlsdGVyczogW3sgTmFtZTogJ3ZwYy1pZCcsIFZhbHVlczogW3ZwY0lkXSB9XSB9O1xuXG4gICAgY29uc3Qgc3VibmV0c1Jlc3BvbnNlID0gYXdhaXQgZWMyLmRlc2NyaWJlU3VibmV0cyhmaWx0ZXJzKTtcbiAgICBjb25zdCBsaXN0ZWRTdWJuZXRzID0gc3VibmV0c1Jlc3BvbnNlLlN1Ym5ldHMgfHwgW107XG5cbiAgICBjb25zdCByb3V0ZVRhYmxlc1Jlc3BvbnNlID0gYXdhaXQgZWMyLmRlc2NyaWJlUm91dGVUYWJsZXMoZmlsdGVycyk7XG4gICAgY29uc3Qgcm91dGVUYWJsZXMgPSBuZXcgUm91dGVUYWJsZXMocm91dGVUYWJsZXNSZXNwb25zZS5Sb3V0ZVRhYmxlcyB8fCBbXSk7XG5cbiAgICAvLyBOb3cgY29tZXMgb3VyIGpvYiB0byBzZXBhcmF0ZSB0aGVzZSBzdWJuZXRzIG91dCBpbnRvIEFacyBhbmQgc3VibmV0IGdyb3VwcyAoUHVibGljLCBQcml2YXRlLCBJc29sYXRlZClcbiAgICAvLyBXZSBoYXZlIHRoZSBmb2xsb3dpbmcgYXR0cmlidXRlcyB0byBnbyBvbjpcbiAgICAvLyAtIFR5cGUgdGFnLCB3ZSB0YWcgc3VibmV0cyB3aXRoIHRoZWlyIHR5cGUuIEluIGFic2VuY2Ugb2YgdGhpcyB0YWcsIHdlXG4gICAgLy8gICBkZXRlcm1pbmUgdGhlIHN1Ym5ldCBtdXN0IGJlIFB1YmxpYyBpZiBlaXRoZXI6XG4gICAgLy8gICBhKSBpdCBoYXMgdGhlIHByb3BlcnR5IE1hcFB1YmxpY0lwT25MYXVuY2hcbiAgICAvLyAgIGIpIGl0IGhhcyBhIHJvdXRlIHRvIGFuIEludGVybmV0IEdhdGV3YXlcbiAgICAvLyAgIElmIGJvdGggb2YgdGhlIGFib3ZlIGlzIGZhbHNlIGJ1dCB0aGUgc3VibmV0IGhhcyBhIHJvdXRlIHRvIGEgTkFUIEdhdGV3YXlcbiAgICAvLyAgIGFuZCB0aGUgZGVzdGluYXRpb24gQ0lEUiBibG9jayBpcyBcIjAuMC4wLjAvMFwiLCB3ZSBhc3N1bWUgaXQgdG8gYmUgYSBQcml2YXRlIHN1Ym5ldC5cbiAgICAvLyAgIEFueXRoaW5nIGVsc2UgaXMgY29uc2lkZXJlZCBJc29sYXRlZC5cbiAgICAvLyAtIE5hbWUgdGFnLCB3ZSB0YWcgc3VibmV0cyB3aXRoIHRoZWlyIHN1Ym5ldCBncm91cCBuYW1lLiBJbiBhYnNlbmNlIG9mIHRoaXMgdGFnLFxuICAgIC8vICAgd2UgdXNlIHRoZSB0eXBlIGFzIHRoZSBuYW1lLlxuXG4gICAgY29uc3QgYXpzID0gQXJyYXkuZnJvbShuZXcgU2V0PHN0cmluZz4obGlzdGVkU3VibmV0cy5tYXAoKHMpID0+IHMuQXZhaWxhYmlsaXR5Wm9uZSEpKSk7XG4gICAgYXpzLnNvcnQoKTtcblxuICAgIGNvbnN0IHN1Ym5ldHM6IFN1Ym5ldFtdID0gbGlzdGVkU3VibmV0cy5tYXAoKHN1Ym5ldCkgPT4ge1xuICAgICAgbGV0IHR5cGUgPSBnZXRUYWcoJ2F3cy1jZGs6c3VibmV0LXR5cGUnLCBzdWJuZXQuVGFncyk7XG4gICAgICBpZiAodHlwZSA9PT0gdW5kZWZpbmVkICYmIHN1Ym5ldC5NYXBQdWJsaWNJcE9uTGF1bmNoKSB7XG4gICAgICAgIHR5cGUgPSBTdWJuZXRUeXBlLlB1YmxpYztcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlID09PSB1bmRlZmluZWQgJiYgcm91dGVUYWJsZXMuaGFzUm91dGVUb0lndyhzdWJuZXQuU3VibmV0SWQpKSB7XG4gICAgICAgIHR5cGUgPSBTdWJuZXRUeXBlLlB1YmxpYztcbiAgICAgIH1cbiAgICAgIGlmICh0eXBlID09PSB1bmRlZmluZWQgJiYgcm91dGVUYWJsZXMuaGFzUm91dGVUb05hdEdhdGV3YXkoc3VibmV0LlN1Ym5ldElkKSkge1xuICAgICAgICB0eXBlID0gU3VibmV0VHlwZS5Qcml2YXRlO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGUgPT09IHVuZGVmaW5lZCAmJiByb3V0ZVRhYmxlcy5oYXNSb3V0ZVRvVHJhbnNpdEdhdGV3YXkoc3VibmV0LlN1Ym5ldElkKSkge1xuICAgICAgICB0eXBlID0gU3VibmV0VHlwZS5Qcml2YXRlO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICB0eXBlID0gU3VibmV0VHlwZS5Jc29sYXRlZDtcbiAgICAgIH1cblxuICAgICAgaWYgKCFpc1ZhbGlkU3VibmV0VHlwZSh0eXBlKSkge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWxlblxuICAgICAgICB0aHJvdyBuZXcgQ29udGV4dFByb3ZpZGVyRXJyb3IoXG4gICAgICAgICAgYFN1Ym5ldCAke3N1Ym5ldC5TdWJuZXRBcm59IGhhcyBpbnZhbGlkIHN1Ym5ldCB0eXBlICR7dHlwZX0gKG11c3QgYmUgJHtTdWJuZXRUeXBlLlB1YmxpY30sICR7U3VibmV0VHlwZS5Qcml2YXRlfSBvciAke1N1Ym5ldFR5cGUuSXNvbGF0ZWR9KWAsXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGlmIChhcmdzLnN1Ym5ldEdyb3VwTmFtZVRhZyAmJiAhZ2V0VGFnKGFyZ3Muc3VibmV0R3JvdXBOYW1lVGFnLCBzdWJuZXQuVGFncykpIHtcbiAgICAgICAgdGhyb3cgbmV3IENvbnRleHRQcm92aWRlckVycm9yKFxuICAgICAgICAgIGBJbnZhbGlkIHN1Ym5ldEdyb3VwTmFtZVRhZzogU3VibmV0ICR7c3VibmV0LlN1Ym5ldEFybn0gZG9lcyBub3QgaGF2ZSBhbiBhc3NvY2lhdGVkIHRhZyB3aXRoIEtleT0nJHthcmdzLnN1Ym5ldEdyb3VwTmFtZVRhZ30nYCxcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgbmFtZSA9IGdldFRhZyhhcmdzLnN1Ym5ldEdyb3VwTmFtZVRhZyB8fCAnYXdzLWNkazpzdWJuZXQtbmFtZScsIHN1Ym5ldC5UYWdzKSB8fCB0eXBlO1xuICAgICAgY29uc3Qgcm91dGVUYWJsZUlkID0gcm91dGVUYWJsZXMucm91dGVUYWJsZUlkRm9yU3VibmV0SWQoc3VibmV0LlN1Ym5ldElkKTtcblxuICAgICAgaWYgKCFyb3V0ZVRhYmxlSWQpIHtcbiAgICAgICAgdGhyb3cgbmV3IENvbnRleHRQcm92aWRlckVycm9yKFxuICAgICAgICAgIGBTdWJuZXQgJHtzdWJuZXQuU3VibmV0QXJufSBkb2VzIG5vdCBoYXZlIGFuIGFzc29jaWF0ZWQgcm91dGUgdGFibGUgKGFuZCB0aGVyZSBpcyBubyBcIm1haW5cIiB0YWJsZSlgLFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICBhejogc3VibmV0LkF2YWlsYWJpbGl0eVpvbmUhLFxuICAgICAgICBjaWRyOiBzdWJuZXQuQ2lkckJsb2NrISxcbiAgICAgICAgdHlwZSxcbiAgICAgICAgbmFtZSxcbiAgICAgICAgc3VibmV0SWQ6IHN1Ym5ldC5TdWJuZXRJZCEsXG4gICAgICAgIHJvdXRlVGFibGVJZCxcbiAgICAgIH07XG4gICAgfSk7XG5cbiAgICBsZXQgZ3JvdXBlZDogU3VibmV0R3JvdXBzO1xuICAgIGxldCBhc3N5bWV0cmljU3VibmV0R3JvdXBzOiBWcGNTdWJuZXRHcm91cFtdIHwgdW5kZWZpbmVkO1xuICAgIGlmIChhcmdzLnJldHVybkFzeW1tZXRyaWNTdWJuZXRzKSB7XG4gICAgICBncm91cGVkID0geyBhenM6IFtdLCBncm91cHM6IFtdIH07XG4gICAgICBhc3N5bWV0cmljU3VibmV0R3JvdXBzID0gZ3JvdXBBc3ltbWV0cmljU3VibmV0cyhzdWJuZXRzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZ3JvdXBlZCA9IGdyb3VwU3VibmV0cyhzdWJuZXRzKTtcbiAgICAgIGFzc3ltZXRyaWNTdWJuZXRHcm91cHMgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgLy8gRmluZCBhdHRhY2hlZCthdmFpbGFibGUgVlBOIGdhdGV3YXkgZm9yIHRoaXMgVlBDXG4gICAgY29uc3QgdnBuR2F0ZXdheVJlc3BvbnNlID1cbiAgICAgIChhcmdzLnJldHVyblZwbkdhdGV3YXlzID8/IHRydWUpXG4gICAgICAgID8gYXdhaXQgZWMyLmRlc2NyaWJlVnBuR2F0ZXdheXMoe1xuICAgICAgICAgIEZpbHRlcnM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgTmFtZTogJ2F0dGFjaG1lbnQudnBjLWlkJyxcbiAgICAgICAgICAgICAgVmFsdWVzOiBbdnBjSWRdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgTmFtZTogJ2F0dGFjaG1lbnQuc3RhdGUnLFxuICAgICAgICAgICAgICBWYWx1ZXM6IFsnYXR0YWNoZWQnXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIE5hbWU6ICdzdGF0ZScsXG4gICAgICAgICAgICAgIFZhbHVlczogWydhdmFpbGFibGUnXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSlcbiAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgdnBuR2F0ZXdheUlkID1cbiAgICAgIHZwbkdhdGV3YXlSZXNwb25zZT8uVnBuR2F0ZXdheXM/Lmxlbmd0aCA9PT0gMSA/IHZwbkdhdGV3YXlSZXNwb25zZS5WcG5HYXRld2F5c1swXS5WcG5HYXRld2F5SWQgOiB1bmRlZmluZWQ7XG5cbiAgICByZXR1cm4ge1xuICAgICAgdnBjSWQsXG4gICAgICB2cGNDaWRyQmxvY2s6IHZwYy5DaWRyQmxvY2shLFxuICAgICAgb3duZXJBY2NvdW50SWQ6IHZwYy5Pd25lcklkLFxuICAgICAgYXZhaWxhYmlsaXR5Wm9uZXM6IGdyb3VwZWQuYXpzLFxuICAgICAgaXNvbGF0ZWRTdWJuZXRJZHM6IGNvbGxhcHNlKFxuICAgICAgICBmbGF0TWFwKGZpbmRHcm91cHMoU3VibmV0VHlwZS5Jc29sYXRlZCwgZ3JvdXBlZCksIChncm91cCkgPT4gZ3JvdXAuc3VibmV0cy5tYXAoKHMpID0+IHMuc3VibmV0SWQpKSxcbiAgICAgICksXG4gICAgICBpc29sYXRlZFN1Ym5ldE5hbWVzOiBjb2xsYXBzZShcbiAgICAgICAgZmxhdE1hcChmaW5kR3JvdXBzKFN1Ym5ldFR5cGUuSXNvbGF0ZWQsIGdyb3VwZWQpLCAoZ3JvdXApID0+IChncm91cC5uYW1lID8gW2dyb3VwLm5hbWVdIDogW10pKSxcbiAgICAgICksXG4gICAgICBpc29sYXRlZFN1Ym5ldFJvdXRlVGFibGVJZHM6IGNvbGxhcHNlKFxuICAgICAgICBmbGF0TWFwKGZpbmRHcm91cHMoU3VibmV0VHlwZS5Jc29sYXRlZCwgZ3JvdXBlZCksIChncm91cCkgPT4gZ3JvdXAuc3VibmV0cy5tYXAoKHMpID0+IHMucm91dGVUYWJsZUlkKSksXG4gICAgICApLFxuICAgICAgcHJpdmF0ZVN1Ym5ldElkczogY29sbGFwc2UoXG4gICAgICAgIGZsYXRNYXAoZmluZEdyb3VwcyhTdWJuZXRUeXBlLlByaXZhdGUsIGdyb3VwZWQpLCAoZ3JvdXApID0+IGdyb3VwLnN1Ym5ldHMubWFwKChzKSA9PiBzLnN1Ym5ldElkKSksXG4gICAgICApLFxuICAgICAgcHJpdmF0ZVN1Ym5ldE5hbWVzOiBjb2xsYXBzZShcbiAgICAgICAgZmxhdE1hcChmaW5kR3JvdXBzKFN1Ym5ldFR5cGUuUHJpdmF0ZSwgZ3JvdXBlZCksIChncm91cCkgPT4gKGdyb3VwLm5hbWUgPyBbZ3JvdXAubmFtZV0gOiBbXSkpLFxuICAgICAgKSxcbiAgICAgIHByaXZhdGVTdWJuZXRSb3V0ZVRhYmxlSWRzOiBjb2xsYXBzZShcbiAgICAgICAgZmxhdE1hcChmaW5kR3JvdXBzKFN1Ym5ldFR5cGUuUHJpdmF0ZSwgZ3JvdXBlZCksIChncm91cCkgPT4gZ3JvdXAuc3VibmV0cy5tYXAoKHMpID0+IHMucm91dGVUYWJsZUlkKSksXG4gICAgICApLFxuICAgICAgcHVibGljU3VibmV0SWRzOiBjb2xsYXBzZShcbiAgICAgICAgZmxhdE1hcChmaW5kR3JvdXBzKFN1Ym5ldFR5cGUuUHVibGljLCBncm91cGVkKSwgKGdyb3VwKSA9PiBncm91cC5zdWJuZXRzLm1hcCgocykgPT4gcy5zdWJuZXRJZCkpLFxuICAgICAgKSxcbiAgICAgIHB1YmxpY1N1Ym5ldE5hbWVzOiBjb2xsYXBzZShcbiAgICAgICAgZmxhdE1hcChmaW5kR3JvdXBzKFN1Ym5ldFR5cGUuUHVibGljLCBncm91cGVkKSwgKGdyb3VwKSA9PiAoZ3JvdXAubmFtZSA/IFtncm91cC5uYW1lXSA6IFtdKSksXG4gICAgICApLFxuICAgICAgcHVibGljU3VibmV0Um91dGVUYWJsZUlkczogY29sbGFwc2UoXG4gICAgICAgIGZsYXRNYXAoZmluZEdyb3VwcyhTdWJuZXRUeXBlLlB1YmxpYywgZ3JvdXBlZCksIChncm91cCkgPT4gZ3JvdXAuc3VibmV0cy5tYXAoKHMpID0+IHMucm91dGVUYWJsZUlkKSksXG4gICAgICApLFxuICAgICAgdnBuR2F0ZXdheUlkLFxuICAgICAgc3VibmV0R3JvdXBzOiBhc3N5bWV0cmljU3VibmV0R3JvdXBzLFxuICAgIH07XG4gIH1cbn1cblxuY2xhc3MgUm91dGVUYWJsZXMge1xuICBwdWJsaWMgcmVhZG9ubHkgbWFpblJvdXRlVGFibGU/OiBSb3V0ZVRhYmxlO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgdGFibGVzOiBSb3V0ZVRhYmxlW10pIHtcbiAgICB0aGlzLm1haW5Sb3V0ZVRhYmxlID0gdGhpcy50YWJsZXMuZmluZChcbiAgICAgICh0YWJsZSkgPT4gISF0YWJsZS5Bc3NvY2lhdGlvbnMgJiYgdGFibGUuQXNzb2NpYXRpb25zLnNvbWUoKGFzc29jKSA9PiAhIWFzc29jLk1haW4pLFxuICAgICk7XG4gIH1cblxuICBwdWJsaWMgcm91dGVUYWJsZUlkRm9yU3VibmV0SWQoc3VibmV0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgY29uc3QgdGFibGUgPSB0aGlzLnRhYmxlRm9yU3VibmV0KHN1Ym5ldElkKTtcbiAgICByZXR1cm4gKHRhYmxlICYmIHRhYmxlLlJvdXRlVGFibGVJZCkgfHwgKHRoaXMubWFpblJvdXRlVGFibGUgJiYgdGhpcy5tYWluUm91dGVUYWJsZS5Sb3V0ZVRhYmxlSWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdGhlIGdpdmVuIHN1Ym5ldCBoYXMgYSByb3V0ZSB0byBhIE5BVCBHYXRld2F5XG4gICAqL1xuICBwdWJsaWMgaGFzUm91dGVUb05hdEdhdGV3YXkoc3VibmV0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHRhYmxlID0gdGhpcy50YWJsZUZvclN1Ym5ldChzdWJuZXRJZCkgfHwgdGhpcy5tYWluUm91dGVUYWJsZTtcblxuICAgIHJldHVybiAoXG4gICAgICAhIXRhYmxlICYmXG4gICAgICAhIXRhYmxlLlJvdXRlcyAmJlxuICAgICAgdGFibGUuUm91dGVzLnNvbWUoKHJvdXRlKSA9PiAhIXJvdXRlLk5hdEdhdGV3YXlJZCAmJiByb3V0ZS5EZXN0aW5hdGlvbkNpZHJCbG9jayA9PT0gJzAuMC4wLjAvMCcpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBnaXZlbiBzdWJuZXQgaGFzIGEgcm91dGUgdG8gYSBUcmFuc2l0IEdhdGV3YXlcbiAgICovXG4gIHB1YmxpYyBoYXNSb3V0ZVRvVHJhbnNpdEdhdGV3YXkoc3VibmV0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHRhYmxlID0gdGhpcy50YWJsZUZvclN1Ym5ldChzdWJuZXRJZCkgfHwgdGhpcy5tYWluUm91dGVUYWJsZTtcblxuICAgIHJldHVybiAoXG4gICAgICAhIXRhYmxlICYmXG4gICAgICAhIXRhYmxlLlJvdXRlcyAmJlxuICAgICAgdGFibGUuUm91dGVzLnNvbWUoKHJvdXRlKSA9PiAhIXJvdXRlLlRyYW5zaXRHYXRld2F5SWQgJiYgcm91dGUuRGVzdGluYXRpb25DaWRyQmxvY2sgPT09ICcwLjAuMC4wLzAnKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogV2hldGhlciB0aGUgZ2l2ZW4gc3VibmV0IGhhcyBhIHJvdXRlIHRvIGFuIElHV1xuICAgKi9cbiAgcHVibGljIGhhc1JvdXRlVG9JZ3coc3VibmV0SWQ6IHN0cmluZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIGNvbnN0IHRhYmxlID0gdGhpcy50YWJsZUZvclN1Ym5ldChzdWJuZXRJZCkgfHwgdGhpcy5tYWluUm91dGVUYWJsZTtcblxuICAgIHJldHVybiAoXG4gICAgICAhIXRhYmxlICYmICEhdGFibGUuUm91dGVzICYmIHRhYmxlLlJvdXRlcy5zb21lKChyb3V0ZSkgPT4gISFyb3V0ZS5HYXRld2F5SWQgJiYgcm91dGUuR2F0ZXdheUlkLnN0YXJ0c1dpdGgoJ2lndy0nKSlcbiAgICApO1xuICB9XG5cbiAgcHVibGljIHRhYmxlRm9yU3VibmV0KHN1Ym5ldElkOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdGhpcy50YWJsZXMuZmluZChcbiAgICAgICh0YWJsZSkgPT4gISF0YWJsZS5Bc3NvY2lhdGlvbnMgJiYgdGFibGUuQXNzb2NpYXRpb25zLnNvbWUoKGFzc29jKSA9PiBhc3NvYy5TdWJuZXRJZCA9PT0gc3VibmV0SWQpLFxuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIHZhbHVlIG9mIGEgdGFnIGZyb20gYSBzZXQgb2YgdGFnc1xuICovXG5mdW5jdGlvbiBnZXRUYWcobmFtZTogc3RyaW5nLCB0YWdzPzogVGFnW10pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBmb3IgKGNvbnN0IHRhZyBvZiB0YWdzIHx8IFtdKSB7XG4gICAgaWYgKHRhZy5LZXkgPT09IG5hbWUpIHtcbiAgICAgIHJldHVybiB0YWcuVmFsdWU7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogR3JvdXAgc3VibmV0cyBvZiB0aGUgc2FtZSB0eXBlIHRvZ2V0aGVyLCBhbmQgb3JkZXIgYnkgQVpcbiAqL1xuZnVuY3Rpb24gZ3JvdXBTdWJuZXRzKHN1Ym5ldHM6IFN1Ym5ldFtdKTogU3VibmV0R3JvdXBzIHtcbiAgY29uc3QgZ3JvdXBpbmc6IHsgW2tleTogc3RyaW5nXTogU3VibmV0W10gfSA9IHt9O1xuICBmb3IgKGNvbnN0IHN1Ym5ldCBvZiBzdWJuZXRzKSB7XG4gICAgY29uc3Qga2V5ID0gW3N1Ym5ldC50eXBlLCBzdWJuZXQubmFtZV0udG9TdHJpbmcoKTtcbiAgICBpZiAoIShrZXkgaW4gZ3JvdXBpbmcpKSB7XG4gICAgICBncm91cGluZ1trZXldID0gW107XG4gICAgfVxuICAgIGdyb3VwaW5nW2tleV0ucHVzaChzdWJuZXQpO1xuICB9XG5cbiAgY29uc3QgZ3JvdXBzID0gT2JqZWN0LnZhbHVlcyhncm91cGluZykubWFwKChzbnMpID0+IHtcbiAgICBzbnMuc29ydCgoYTogU3VibmV0LCBiOiBTdWJuZXQpID0+IGEuYXoubG9jYWxlQ29tcGFyZShiLmF6KSk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHR5cGU6IHNuc1swXS50eXBlLFxuICAgICAgbmFtZTogc25zWzBdLm5hbWUsXG4gICAgICBzdWJuZXRzOiBzbnMsXG4gICAgfTtcbiAgfSk7XG5cbiAgY29uc3QgYXpzID0gZ3JvdXBzWzBdLnN1Ym5ldHMubWFwKChzKSA9PiBzLmF6KTtcblxuICBmb3IgKGNvbnN0IGdyb3VwIG9mIGdyb3Vwcykge1xuICAgIGNvbnN0IGdyb3VwQVpzID0gZ3JvdXAuc3VibmV0cy5tYXAoKHMpID0+IHMuYXopO1xuICAgIGlmICghYXJyYXlzRXF1YWwoZ3JvdXBBWnMsIGF6cykpIHtcbiAgICAgIHRocm93IG5ldyBDb250ZXh0UHJvdmlkZXJFcnJvcihgTm90IGFsbCBzdWJuZXRzIGluIFZQQyBoYXZlIHRoZSBzYW1lIEFaczogJHtncm91cEFac30gdnMgJHthenN9YCk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIHsgYXpzLCBncm91cHMgfTtcbn1cblxuZnVuY3Rpb24gZ3JvdXBBc3ltbWV0cmljU3VibmV0cyhzdWJuZXRzOiBTdWJuZXRbXSk6IFZwY1N1Ym5ldEdyb3VwW10ge1xuICBjb25zdCBncm91cGluZzogeyBba2V5OiBzdHJpbmddOiBTdWJuZXRbXSB9ID0ge307XG4gIGZvciAoY29uc3Qgc3VibmV0IG9mIHN1Ym5ldHMpIHtcbiAgICBjb25zdCBrZXkgPSBbc3VibmV0LnR5cGUsIHN1Ym5ldC5uYW1lXS50b1N0cmluZygpO1xuICAgIGlmICghKGtleSBpbiBncm91cGluZykpIHtcbiAgICAgIGdyb3VwaW5nW2tleV0gPSBbXTtcbiAgICB9XG4gICAgZ3JvdXBpbmdba2V5XS5wdXNoKHN1Ym5ldCk7XG4gIH1cblxuICByZXR1cm4gT2JqZWN0LnZhbHVlcyhncm91cGluZykubWFwKChzdWJuZXRBcnJheSkgPT4ge1xuICAgIHN1Ym5ldEFycmF5LnNvcnQoKHN1Ym5ldDE6IFN1Ym5ldCwgc3VibmV0MjogU3VibmV0KSA9PiBzdWJuZXQxLmF6LmxvY2FsZUNvbXBhcmUoc3VibmV0Mi5heikpO1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIG5hbWU6IHN1Ym5ldEFycmF5WzBdLm5hbWUsXG4gICAgICB0eXBlOiBzdWJuZXRUeXBlVG9WcGNTdWJuZXRUeXBlKHN1Ym5ldEFycmF5WzBdLnR5cGUpLFxuICAgICAgc3VibmV0czogc3VibmV0QXJyYXkubWFwKChzdWJuZXQpID0+ICh7XG4gICAgICAgIHN1Ym5ldElkOiBzdWJuZXQuc3VibmV0SWQsXG4gICAgICAgIGNpZHI6IHN1Ym5ldC5jaWRyLFxuICAgICAgICBhdmFpbGFiaWxpdHlab25lOiBzdWJuZXQuYXosXG4gICAgICAgIHJvdXRlVGFibGVJZDogc3VibmV0LnJvdXRlVGFibGVJZCxcbiAgICAgIH0pKSxcbiAgICB9O1xuICB9KTtcbn1cblxuZnVuY3Rpb24gc3VibmV0VHlwZVRvVnBjU3VibmV0VHlwZSh0eXBlOiBTdWJuZXRUeXBlKTogVnBjU3VibmV0R3JvdXBUeXBlIHtcbiAgc3dpdGNoICh0eXBlKSB7XG4gICAgY2FzZSBTdWJuZXRUeXBlLklzb2xhdGVkOlxuICAgICAgcmV0dXJuIFZwY1N1Ym5ldEdyb3VwVHlwZS5JU09MQVRFRDtcbiAgICBjYXNlIFN1Ym5ldFR5cGUuUHJpdmF0ZTpcbiAgICAgIHJldHVybiBWcGNTdWJuZXRHcm91cFR5cGUuUFJJVkFURTtcbiAgICBjYXNlIFN1Ym5ldFR5cGUuUHVibGljOlxuICAgICAgcmV0dXJuIFZwY1N1Ym5ldEdyb3VwVHlwZS5QVUJMSUM7XG4gIH1cbn1cblxuZW51bSBTdWJuZXRUeXBlIHtcbiAgUHVibGljID0gJ1B1YmxpYycsXG4gIFByaXZhdGUgPSAnUHJpdmF0ZScsXG4gIElzb2xhdGVkID0gJ0lzb2xhdGVkJyxcbn1cblxuZnVuY3Rpb24gaXNWYWxpZFN1Ym5ldFR5cGUodmFsOiBzdHJpbmcpOiB2YWwgaXMgU3VibmV0VHlwZSB7XG4gIHJldHVybiB2YWwgPT09IFN1Ym5ldFR5cGUuUHVibGljIHx8IHZhbCA9PT0gU3VibmV0VHlwZS5Qcml2YXRlIHx8IHZhbCA9PT0gU3VibmV0VHlwZS5Jc29sYXRlZDtcbn1cblxuaW50ZXJmYWNlIFN1Ym5ldCB7XG4gIGF6OiBzdHJpbmc7XG4gIGNpZHI6IHN0cmluZztcbiAgdHlwZTogU3VibmV0VHlwZTtcbiAgbmFtZTogc3RyaW5nO1xuICByb3V0ZVRhYmxlSWQ6IHN0cmluZztcbiAgc3VibmV0SWQ6IHN0cmluZztcbn1cblxuaW50ZXJmYWNlIFN1Ym5ldEdyb3VwIHtcbiAgdHlwZTogU3VibmV0VHlwZTtcbiAgbmFtZTogc3RyaW5nO1xuICBzdWJuZXRzOiBTdWJuZXRbXTtcbn1cblxuaW50ZXJmYWNlIFN1Ym5ldEdyb3VwcyB7XG4gIGF6czogc3RyaW5nW107XG4gIGdyb3VwczogU3VibmV0R3JvdXBbXTtcbn1cblxuZnVuY3Rpb24gYXJyYXlzRXF1YWwoYXM6IHN0cmluZ1tdLCBiczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgaWYgKGFzLmxlbmd0aCAhPT0gYnMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcy5sZW5ndGg7IGkrKykge1xuICAgIGlmIChhc1tpXSAhPT0gYnNbaV0pIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn1cblxuZnVuY3Rpb24gZmluZEdyb3Vwcyh0eXBlOiBTdWJuZXRUeXBlLCBncm91cHM6IFN1Ym5ldEdyb3Vwcyk6IFN1Ym5ldEdyb3VwW10ge1xuICByZXR1cm4gZ3JvdXBzLmdyb3Vwcy5maWx0ZXIoKGcpID0+IGcudHlwZSA9PT0gdHlwZSk7XG59XG5cbmZ1bmN0aW9uIGZsYXRNYXA8VCwgVT4oeHM6IFRbXSwgZm46ICh4OiBUKSA9PiBVW10pOiBVW10ge1xuICBjb25zdCByZXQgPSBuZXcgQXJyYXk8VT4oKTtcbiAgZm9yIChjb25zdCB4IG9mIHhzKSB7XG4gICAgcmV0LnB1c2goLi4uZm4oeCkpO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG5cbmZ1bmN0aW9uIGNvbGxhcHNlPFQ+KHhzOiBUW10pOiBUW10gfCB1bmRlZmluZWQge1xuICBpZiAoeHMubGVuZ3RoID4gMCkge1xuICAgIHJldHVybiB4cztcbiAgfVxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuIl19