aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
580 lines • 71.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const client_ec2_1 = require("@aws-sdk/client-ec2");
const vpcs_1 = require("../../lib/context-providers/vpcs");
const mock_sdk_1 = require("../util/mock-sdk");
const mockSDK = new mock_sdk_1.MockSdkProvider();
beforeEach(() => {
(0, mock_sdk_1.restoreSdkMocksToDefault)();
mock_sdk_1.mockEC2Client
.on(client_ec2_1.DescribeVpcsCommand)
.resolves({
Vpcs: [{ VpcId: 'vpc-1234567', CidrBlock: '1.1.1.1/16', OwnerId: '123456789012' }],
})
.on(client_ec2_1.DescribeSubnetsCommand)
.resolves({
Subnets: [
{ SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: true },
{ SubnetId: 'sub-789012', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false },
],
})
.on(client_ec2_1.DescribeRouteTablesCommand)
.resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '1.1.1.1/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
GatewayId: 'igw-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
{
Associations: [{ SubnetId: 'sub-789012' }],
RouteTableId: 'rtb-789012',
Routes: [
{
DestinationCidrBlock: '1.1.2.1/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
NatGatewayId: 'nat-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
],
})
.on(client_ec2_1.DescribeVpnGatewaysCommand)
.resolves({
VpnGateways: [{ VpnGatewayId: 'gw-abcdef' }],
});
});
test('looks up the requested VPC', async () => {
// GIVEN
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
privateSubnetIds: ['sub-789012'],
privateSubnetNames: ['Private'],
privateSubnetRouteTableIds: ['rtb-789012'],
publicSubnetIds: ['sub-123456'],
publicSubnetNames: ['Public'],
publicSubnetRouteTableIds: ['rtb-123456'],
vpnGatewayId: 'gw-abcdef',
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('throws when no such VPC is found', async () => {
// GIVEN
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
mock_sdk_1.mockEC2Client.on(client_ec2_1.DescribeVpcsCommand).resolves({});
// WHEN
await expect(provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
})).rejects.toThrow(/Could not find any VPCs matching/);
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
});
test('throws when subnet with subnetGroupNameTag not found', async () => {
// GIVEN
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
await expect(provider.getValue({
account: '123456789012',
region: 'us-east-1',
subnetGroupNameTag: 'DOES_NOT_EXIST',
filter,
})).rejects.toThrow(/Invalid subnetGroupNameTag: Subnet .* does not have an associated tag with Key='DOES_NOT_EXIST'/);
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
});
test('does not throw when subnet with subnetGroupNameTag is found', async () => {
// GIVEN
mock_sdk_1.mockEC2Client.on(client_ec2_1.DescribeSubnetsCommand).resolves({
Subnets: [
{
SubnetId: 'sub-123456',
AvailabilityZone: 'bermuda-triangle-1337',
MapPublicIpOnLaunch: true,
Tags: [{ Key: 'DOES_EXIST', Value: 'SubnetName1' }],
},
{
SubnetId: 'sub-789012',
AvailabilityZone: 'bermuda-triangle-1337',
MapPublicIpOnLaunch: false,
Tags: [{ Key: 'DOES_EXIST', Value: 'SubnetName2' }],
},
],
});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
subnetGroupNameTag: 'DOES_EXIST',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
privateSubnetIds: ['sub-789012'],
privateSubnetNames: ['SubnetName2'],
privateSubnetRouteTableIds: ['rtb-789012'],
publicSubnetIds: ['sub-123456'],
publicSubnetNames: ['SubnetName1'],
publicSubnetRouteTableIds: ['rtb-123456'],
vpnGatewayId: 'gw-abcdef',
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('throws when multiple VPCs are found', async () => {
// GIVEN
mock_sdk_1.mockEC2Client.on(client_ec2_1.DescribeVpcsCommand).resolves({
Vpcs: [{ VpcId: 'vpc-1' }, { VpcId: 'vpc-2' }],
});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
await expect(provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
})).rejects.toThrow(/Found 2 VPCs matching/);
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
});
test('uses the VPC main route table when a subnet has no specific association', async () => {
// GIVEN
mock_sdk_1.mockEC2Client.on(client_ec2_1.DescribeRouteTablesCommand).resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '1.1.1.1/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
GatewayId: 'igw-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
{
Associations: [{ Main: true }],
RouteTableId: 'rtb-789012',
Routes: [
{
DestinationCidrBlock: '1.1.2.1/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
NatGatewayId: 'nat-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
],
});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
privateSubnetIds: ['sub-789012'],
privateSubnetNames: ['Private'],
privateSubnetRouteTableIds: ['rtb-789012'],
publicSubnetIds: ['sub-123456'],
publicSubnetNames: ['Public'],
publicSubnetRouteTableIds: ['rtb-123456'],
vpnGatewayId: 'gw-abcdef',
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('Recognize public subnet by route table', async () => {
// GIVEN
mock_sdk_1.mockEC2Client
.on(client_ec2_1.DescribeSubnetsCommand)
.resolves({
Subnets: [{ SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }],
})
.on(client_ec2_1.DescribeRouteTablesCommand)
.resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '10.0.2.0/26',
Origin: 'CreateRoute',
State: 'active',
VpcPeeringConnectionId: 'pcx-xxxxxx',
},
{
DestinationCidrBlock: '10.0.1.0/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
GatewayId: 'igw-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
],
})
.on(client_ec2_1.DescribeVpnGatewaysCommand)
.resolves({});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
publicSubnetIds: ['sub-123456'],
publicSubnetNames: ['Public'],
publicSubnetRouteTableIds: ['rtb-123456'],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('Recognize private subnet by route table with NAT Gateway', async () => {
// GIVEN
mock_sdk_1.mockEC2Client
.on(client_ec2_1.DescribeSubnetsCommand)
.resolves({
Subnets: [{ SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }],
})
.on(client_ec2_1.DescribeRouteTablesCommand)
.resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '10.0.2.0/26',
Origin: 'CreateRoute',
State: 'active',
VpcPeeringConnectionId: 'pcx-xxxxxx',
},
{
DestinationCidrBlock: '10.0.1.0/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
NatGatewayId: 'nat-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
],
})
.on(client_ec2_1.DescribeVpnGatewaysCommand)
.resolves({});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
privateSubnetIds: ['sub-123456'],
privateSubnetNames: ['Private'],
privateSubnetRouteTableIds: ['rtb-123456'],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('Recognize private subnet by route table with Transit Gateway', async () => {
// GIVEN
mock_sdk_1.mockEC2Client
.on(client_ec2_1.DescribeSubnetsCommand)
.resolves({
Subnets: [{ SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }],
})
.on(client_ec2_1.DescribeRouteTablesCommand)
.resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '10.0.2.0/26',
Origin: 'CreateRoute',
State: 'active',
VpcPeeringConnectionId: 'pcx-xxxxxx',
},
{
DestinationCidrBlock: '10.0.1.0/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
{
DestinationCidrBlock: '0.0.0.0/0',
TransitGatewayId: 'tgw-xxxxxx',
Origin: 'CreateRoute',
State: 'active',
},
],
},
],
})
.on(client_ec2_1.DescribeVpnGatewaysCommand)
.resolves({});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
privateSubnetIds: ['sub-123456'],
privateSubnetNames: ['Private'],
privateSubnetRouteTableIds: ['rtb-123456'],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
test('Recognize isolated subnet by route table', async () => {
// GIVEN
mock_sdk_1.mockEC2Client
.on(client_ec2_1.DescribeSubnetsCommand)
.resolves({
Subnets: [{ SubnetId: 'sub-123456', AvailabilityZone: 'bermuda-triangle-1337', MapPublicIpOnLaunch: false }],
})
.on(client_ec2_1.DescribeRouteTablesCommand)
.resolves({
RouteTables: [
{
Associations: [{ SubnetId: 'sub-123456' }],
RouteTableId: 'rtb-123456',
Routes: [
{
DestinationCidrBlock: '10.0.1.0/24',
GatewayId: 'local',
Origin: 'CreateRouteTable',
State: 'active',
},
],
},
],
})
.on(client_ec2_1.DescribeVpnGatewaysCommand)
.resolves({});
const filter = { foo: 'bar' };
const provider = new vpcs_1.VpcNetworkContextProviderPlugin(mockSDK);
// WHEN
const result = await provider.getValue({
account: '123456789012',
region: 'us-east-1',
filter,
});
// THEN
expect(result).toEqual({
vpcId: 'vpc-1234567',
vpcCidrBlock: '1.1.1.1/16',
ownerAccountId: '123456789012',
availabilityZones: ['bermuda-triangle-1337'],
isolatedSubnetIds: ['sub-123456'],
isolatedSubnetNames: ['Isolated'],
isolatedSubnetRouteTableIds: ['rtb-123456'],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpcsCommand, {
Filters: [{ Name: 'foo', Values: ['bar'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeSubnetsCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeRouteTablesCommand, {
Filters: [{ Name: 'vpc-id', Values: ['vpc-1234567'] }],
});
expect(mock_sdk_1.mockEC2Client).toHaveReceivedCommandWith(client_ec2_1.DescribeVpnGatewaysCommand, {
Filters: [
{ Name: 'attachment.vpc-id', Values: ['vpc-1234567'] },
{ Name: 'attachment.state', Values: ['attached'] },
{ Name: 'state', Values: ['available'] },
],
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnBjcy50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidnBjcy50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsb0RBSzZCO0FBQzdCLDJEQUFtRjtBQUNuRiwrQ0FBNEY7QUFFNUYsTUFBTSxPQUFPLEdBQUcsSUFBSSwwQkFBZSxFQUFFLENBQUM7QUFFdEMsVUFBVSxDQUFDLEdBQUcsRUFBRTtJQUNkLElBQUEsbUNBQXdCLEdBQUUsQ0FBQztJQUMzQix3QkFBYTtTQUNWLEVBQUUsQ0FBQyxnQ0FBbUIsQ0FBQztTQUN2QixRQUFRLENBQUM7UUFDUixJQUFJLEVBQUUsQ0FBQyxFQUFFLEtBQUssRUFBRSxhQUFhLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxPQUFPLEVBQUUsY0FBYyxFQUFFLENBQUM7S0FDbkYsQ0FBQztTQUNELEVBQUUsQ0FBQyxtQ0FBc0IsQ0FBQztTQUMxQixRQUFRLENBQUM7UUFDUixPQUFPLEVBQUU7WUFDUCxFQUFFLFFBQVEsRUFBRSxZQUFZLEVBQUUsZ0JBQWdCLEVBQUUsdUJBQXVCLEVBQUUsbUJBQW1CLEVBQUUsSUFBSSxFQUFFO1lBQ2hHLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxnQkFBZ0IsRUFBRSx1QkFBdUIsRUFBRSxtQkFBbUIsRUFBRSxLQUFLLEVBQUU7U0FDbEc7S0FDRixDQUFDO1NBQ0QsRUFBRSxDQUFDLHVDQUEwQixDQUFDO1NBQzlCLFFBQVEsQ0FBQztRQUNSLFdBQVcsRUFBRTtZQUNYO2dCQUNFLFlBQVksRUFBRSxDQUFDLEVBQUUsUUFBUSxFQUFFLFlBQVksRUFBRSxDQUFDO2dCQUMxQyxZQUFZLEVBQUUsWUFBWTtnQkFDMUIsTUFBTSxFQUFFO29CQUNOO3dCQUNFLG9CQUFvQixFQUFFLFlBQVk7d0JBQ2xDLFNBQVMsRUFBRSxPQUFPO3dCQUNsQixNQUFNLEVBQUUsa0JBQWtCO3dCQUMxQixLQUFLLEVBQUUsUUFBUTtxQkFDaEI7b0JBQ0Q7d0JBQ0Usb0JBQW9CLEVBQUUs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LENBQUM7SUFDSCxNQUFNLENBQUMsd0JBQWEsQ0FBQyxDQUFDLHlCQUF5QixDQUFDLHVDQUEwQixFQUFFO1FBQzFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsQ0FBQyxhQUFhLENBQUMsRUFBRSxDQUFDO0tBQ3ZELENBQUMsQ0FBQztJQUNILE1BQU0sQ0FBQyx3QkFBYSxDQUFDLENBQUMseUJBQXlCLENBQUMsdUNBQTBCLEVBQUU7UUFDMUUsT0FBTyxFQUFFO1lBQ1AsRUFBRSxJQUFJLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxFQUFFLENBQUMsYUFBYSxDQUFDLEVBQUU7WUFDdEQsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxFQUFFLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDbEQsRUFBRSxJQUFJLEVBQUUsT0FBTyxFQUFFLE1BQU0sRUFBRSxDQUFDLFdBQVcsQ0FBQyxFQUFFO1NBQ3pDO0tBQ0YsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBEZXNjcmliZVJvdXRlVGFibGVzQ29tbWFuZCxcbiAgRGVzY3JpYmVTdWJuZXRzQ29tbWFuZCxcbiAgRGVzY3JpYmVWcGNzQ29tbWFuZCxcbiAgRGVzY3JpYmVWcG5HYXRld2F5c0NvbW1hbmQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lYzInO1xuaW1wb3J0IHsgVnBjTmV0d29ya0NvbnRleHRQcm92aWRlclBsdWdpbiB9IGZyb20gJy4uLy4uL2xpYi9jb250ZXh0LXByb3ZpZGVycy92cGNzJztcbmltcG9ydCB7IE1vY2tTZGtQcm92aWRlciwgbW9ja0VDMkNsaWVudCwgcmVzdG9yZVNka01vY2tzVG9EZWZhdWx0IH0gZnJvbSAnLi4vdXRpbC9tb2NrLXNkayc7XG5cbmNvbnN0IG1vY2tTREsgPSBuZXcgTW9ja1Nka1Byb3ZpZGVyKCk7XG5cbmJlZm9yZUVhY2goKCkgPT4ge1xuICByZXN0b3JlU2RrTW9ja3NUb0RlZmF1bHQoKTtcbiAgbW9ja0VDMkNsaWVudFxuICAgIC5vbihEZXNjcmliZVZwY3NDb21tYW5kKVxuICAgIC5yZXNvbHZlcyh7XG4gICAgICBWcGNzOiBbeyBWcGNJZDogJ3ZwYy0xMjM0NTY3JywgQ2lkckJsb2NrOiAnMS4xLjEuMS8xNicsIE93bmVySWQ6ICcxMjM0NTY3ODkwMTInIH1dLFxuICAgIH0pXG4gICAgLm9uKERlc2NyaWJlU3VibmV0c0NvbW1hbmQpXG4gICAgLnJlc29sdmVzKHtcbiAgICAgIFN1Ym5ldHM6IFtcbiAgICAgICAgeyBTdWJuZXRJZDogJ3N1Yi0xMjM0NTYnLCBBdmFpbGFiaWxpdHlab25lOiAnYmVybXVkYS10cmlhbmdsZS0xMzM3JywgTWFwUHVibGljSXBPbkxhdW5jaDogdHJ1ZSB9LFxuICAgICAgICB7IFN1Ym5ldElkOiAnc3ViLTc4OTAxMicsIEF2YWlsYWJpbGl0eVpvbmU6ICdiZXJtdWRhLXRyaWFuZ2xlLTEzMzcnLCBNYXBQdWJsaWNJcE9uTGF1bmNoOiBmYWxzZSB9LFxuICAgICAgXSxcbiAgICB9KVxuICAgIC5vbihEZXNjcmliZVJvdXRlVGFibGVzQ29tbWFuZClcbiAgICAucmVzb2x2ZXMoe1xuICAgICAgUm91dGVUYWJsZXM6IFtcbiAgICAgICAge1xuICAgICAgICAgIEFzc29jaWF0aW9uczogW3sgU3VibmV0SWQ6ICdzdWItMTIzNDU2JyB9XSxcbiAgICAgICAgICBSb3V0ZVRhYmxlSWQ6ICdydGItMTIzNDU2JyxcbiAgICAgICAgICBSb3V0ZXM6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRGVzdGluYXRpb25DaWRyQmxvY2s6ICcxLjEuMS4xLzI0JyxcbiAgICAgICAgICAgICAgR2F0ZXdheUlkOiAnbG9jYWwnLFxuICAgICAgICAgICAgICBPcmlnaW46ICdDcmVhdGVSb3V0ZVRhYmxlJyxcbiAgICAgICAgICAgICAgU3RhdGU6ICdhY3RpdmUnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgRGVzdGluYXRpb25DaWRyQmxvY2s6ICcwLjAuMC4wLzAnLFxuICAgICAgICAgICAgICBHYXRld2F5SWQ6ICdpZ3cteHh4eHh4JyxcbiAgICAgICAgICAgICAgT3JpZ2luOiAnQ3JlYXRlUm91dGUnLFxuICAgICAgICAgICAgICBTdGF0ZTogJ2FjdGl2ZScsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIHtcbiAgICAgICAgICBBc3NvY2lhdGlvbnM6IFt7IFN1Ym5ldElkOiAnc3ViLTc4OTAxMicgfV0sXG4gICAgICAgICAgUm91dGVUYWJsZUlkOiAncnRiLTc4OTAxMicsXG4gICAgICAgICAgUm91dGVzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIERlc3RpbmF0aW9uQ2lkckJsb2NrOiAnMS4xLjIuMS8yNCcsXG4gICAgICAgICAgICAgIEdhdGV3YXlJZDogJ2xvY2FsJyxcbiAgICAgICAgICAgICAgT3JpZ2luOiAnQ3JlYXRlUm91dGVUYWJsZScsXG4gICAgICAgICAgICAgIFN0YXRlOiAnYWN0aXZlJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIERlc3RpbmF0aW9uQ2lkckJsb2NrOiAnMC4wLjAuMC8wJyxcbiAgICAgICAgICAgICAgTmF0R2F0ZXdheUlkOiAnbmF0LXh4eHh4eCcsXG4gICAgICAgICAgICAgIE9yaWdpbjogJ0NyZWF0ZVJvdXRlJyxcbiAgICAgICAgICAgICAgU3RhdGU6ICdhY3RpdmUnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICBdLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KVxuICAgIC5vbihEZXNjcmliZVZwbkdhdGV3YXlzQ29tbWFuZClcbiAgICAucmVzb2x2ZXMoe1xuICAgICAgVnBuR2F0ZXdheXM6IFt7IFZwbkdhdGV3YXlJZDogJ2d3LWFiY2RlZicgfV0sXG4gICAgfSk7XG59KTtcblxudGVzdCgnbG9va3MgdXAgdGhlIHJlcXVlc3RlZCBWUEMnLCBhc3luYyAoKSA9PiB7XG4gIC8vIEdJVkVOXG4gIGNvbnN0IGZpbHRlciA9IHsgZm9vOiAnYmFyJyB9O1xuICBjb25zdCBwcm92aWRlciA9IG5ldyBWcGNOZXR3b3JrQ29udGV4dFByb3ZpZGVyUGx1Z2luKG1vY2tTREspO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHJvdmlkZXIuZ2V0VmFsdWUoe1xuICAgIGFjY291bnQ6ICcxMjM0NTY3ODkwMTInLFxuICAgIHJlZ2lvbjogJ3VzLWVhc3QtMScsXG4gICAgZmlsdGVyLFxuICB9KTtcblxuICAvLyBUSEVOXG4gIGV4cGVjdChyZXN1bHQpLnRvRXF1YWwoe1xuICAgIHZwY0lkOiAndnBjLTEyMzQ1NjcnLFxuICAgIHZwY0NpZHJCbG9jazogJzEuMS4xLjEvMTYnLFxuICAgIG93bmVyQWNjb3VudElkOiAnMTIzNDU2Nzg5MDEyJyxcbiAgICBhdmFpbGFiaWxpdHlab25lczogWydiZXJtdWRhLXRyaWFuZ2xlLTEzMzcnXSxcbiAgICBwcml2YXRlU3VibmV0SWRzOiBbJ3N1Yi03ODkwMTInXSxcbiAgICBwcml2YXRlU3VibmV0TmFtZXM6IFsnUHJpdmF0ZSddLFxuICAgIHByaXZhdGVTdWJuZXRSb3V0ZVRhYmxlSWRzOiBbJ3J0Yi03ODkwMTInXSxcbiAgICBwdWJsaWNTdWJuZXRJZHM6IFsnc3ViLTEyMzQ1NiddLFxuICAgIHB1YmxpY1N1Ym5ldE5hbWVzOiBbJ1B1YmxpYyddLFxuICAgIHB1YmxpY1N1Ym5ldFJvdXRlVGFibGVJZHM6IFsncnRiLTEyMzQ1NiddLFxuICAgIHZwbkdhdGV3YXlJZDogJ2d3LWFiY2RlZicsXG4gIH0pO1xuICBleHBlY3QobW9ja0VDMkNsaWVudCkudG9IYXZlUmVjZWl2ZWRDb21tYW5kV2l0aChEZXNjcmliZVZwY3NDb21tYW5kLCB7XG4gICAgRmlsdGVyczogW3sgTmFtZTogJ2ZvbycsIFZhbHVlczogWydiYXInXSB9XSxcbiAgfSk7XG4gIGV4cGVjdChtb2NrRUMyQ2xpZW50KS50b0hhdmVSZWNlaXZlZENvbW1hbmRXaXRoKERlc2NyaWJlU3VibmV0c0NvbW1hbmQsIHtcbiAgICBGaWx0ZXJzOiBbeyBOYW1lOiAndnBjLWlkJywgVmFsdWVzOiBbJ3ZwYy0xMjM0NTY3J10gfV0sXG4gIH0pO1xuICBleHBlY3QobW9ja0VDMkNsaWVudCkudG9IYXZlUmVjZWl2ZWRDb21tYW5kV2l0aChEZXNjcmliZVJvdXRlVGFibGVzQ29tbWFuZCwge1xuICAgIEZpbHRlcnM6IFt7IE5hbWU6ICd2cGMtaWQnLCBWYWx1ZXM6IFsndnBjLTEyMzQ1NjcnXSB9XSxcbiAgfSk7XG4gIGV4cGVjdChtb2NrRUMyQ2xpZW50KS50b0hhdmVSZWNlaXZlZENvbW1hbmRXaXRoKERlc2NyaWJlVnBuR2F0ZXdheXNDb21tYW5kLCB7XG4gICAgRmlsdGVyczogW1xuICAgICAgeyBOYW1lOiAnYXR0YWNobWVudC52cGMtaWQnLCBWYWx1ZXM6IFsndnBjLTEyMzQ1NjcnXSB9LFxuICAgICAgeyBOYW1lOiAnYXR0YWNobWVudC5zdGF0ZScsIFZhbHVlczogWydhdHRhY2hlZCddIH0sXG4gICAgICB7IE5hbWU6ICdzdGF0ZScsIFZhbHVlczogWydhdmFpbGFibGUnXSB9LFx