@aws-cdk/aws-ec2
Version:
The CDK Construct Library for AWS::EC2
419 lines • 73.5 kB
JavaScript
"use strict";
var _a, _b, _c, _d, _e, _f;
Object.defineProperty(exports, "__esModule", { value: true });
exports.InterfaceVpcEndpoint = exports.InterfaceVpcEndpointAwsService = exports.InterfaceVpcEndpointService = exports.GatewayVpcEndpoint = exports.GatewayVpcEndpointAwsService = exports.VpcEndpointType = exports.VpcEndpoint = void 0;
const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const iam = require("@aws-cdk/aws-iam");
const cxschema = require("@aws-cdk/cloud-assembly-schema");
const core_1 = require("@aws-cdk/core");
const connections_1 = require("./connections");
const ec2_generated_1 = require("./ec2.generated");
const peer_1 = require("./peer");
const port_1 = require("./port");
const security_group_1 = require("./security-group");
const util_1 = require("./util");
class VpcEndpoint extends core_1.Resource {
/**
* Adds a statement to the policy document of the VPC endpoint. The statement
* must have a Principal.
*
* Not all interface VPC endpoints support policy. For more information
* see https://docs.aws.amazon.com/vpc/latest/userguide/vpce-interface.html
*
* @param statement the IAM statement to add
*/
addToPolicy(statement) {
if (!statement.hasPrincipal) {
throw new Error('Statement must have a `Principal`.');
}
if (!this.policyDocument) {
this.policyDocument = new iam.PolicyDocument();
}
this.policyDocument.addStatements(statement);
}
}
exports.VpcEndpoint = VpcEndpoint;
_a = JSII_RTTI_SYMBOL_1;
VpcEndpoint[_a] = { fqn: "@aws-cdk/aws-ec2.VpcEndpoint", version: "1.204.0" };
/**
* The type of VPC endpoint.
*/
var VpcEndpointType;
(function (VpcEndpointType) {
/**
* Interface
*
* An interface endpoint is an elastic network interface with a private IP
* address that serves as an entry point for traffic destined to a supported
* service.
*/
VpcEndpointType["INTERFACE"] = "Interface";
/**
* Gateway
*
* A gateway endpoint is a gateway that is a target for a specified route in
* your route table, used for traffic destined to a supported AWS service.
*/
VpcEndpointType["GATEWAY"] = "Gateway";
})(VpcEndpointType = exports.VpcEndpointType || (exports.VpcEndpointType = {}));
/**
* An AWS service for a gateway VPC endpoint.
*/
class GatewayVpcEndpointAwsService {
constructor(name, prefix) {
this.name = `${prefix || 'com.amazonaws'}.${core_1.Aws.REGION}.${name}`;
}
}
exports.GatewayVpcEndpointAwsService = GatewayVpcEndpointAwsService;
_b = JSII_RTTI_SYMBOL_1;
GatewayVpcEndpointAwsService[_b] = { fqn: "@aws-cdk/aws-ec2.GatewayVpcEndpointAwsService", version: "1.204.0" };
GatewayVpcEndpointAwsService.DYNAMODB = new GatewayVpcEndpointAwsService('dynamodb');
GatewayVpcEndpointAwsService.S3 = new GatewayVpcEndpointAwsService('s3');
/**
* A gateway VPC endpoint.
* @resource AWS::EC2::VPCEndpoint
*/
class GatewayVpcEndpoint extends VpcEndpoint {
constructor(scope, id, props) {
super(scope, id);
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_GatewayVpcEndpointProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, GatewayVpcEndpoint);
}
throw error;
}
const subnets = props.subnets
? util_1.flatten(props.subnets.map(s => props.vpc.selectSubnets(s).subnets))
: [...props.vpc.privateSubnets, ...props.vpc.publicSubnets, ...props.vpc.isolatedSubnets];
const routeTableIds = util_1.allRouteTableIds(subnets);
if (routeTableIds.length === 0) {
throw new Error('Can\'t add a gateway endpoint to VPC; route table IDs are not available');
}
const endpoint = new ec2_generated_1.CfnVPCEndpoint(this, 'Resource', {
policyDocument: core_1.Lazy.any({ produce: () => this.policyDocument }),
routeTableIds,
serviceName: props.service.name,
vpcEndpointType: VpcEndpointType.GATEWAY,
vpcId: props.vpc.vpcId,
});
this.vpcEndpointId = endpoint.ref;
this.vpcEndpointCreationTimestamp = endpoint.attrCreationTimestamp;
this.vpcEndpointDnsEntries = endpoint.attrDnsEntries;
this.vpcEndpointNetworkInterfaceIds = endpoint.attrNetworkInterfaceIds;
}
static fromGatewayVpcEndpointId(scope, id, gatewayVpcEndpointId) {
class Import extends VpcEndpoint {
constructor() {
super(...arguments);
this.vpcEndpointId = gatewayVpcEndpointId;
}
}
return new Import(scope, id);
}
}
exports.GatewayVpcEndpoint = GatewayVpcEndpoint;
_c = JSII_RTTI_SYMBOL_1;
GatewayVpcEndpoint[_c] = { fqn: "@aws-cdk/aws-ec2.GatewayVpcEndpoint", version: "1.204.0" };
/**
* A custom-hosted service for an interface VPC endpoint.
*/
class InterfaceVpcEndpointService {
constructor(name, port) {
/**
* Whether Private DNS is supported by default.
*/
this.privateDnsDefault = false;
this.name = name;
this.port = port || 443;
}
}
exports.InterfaceVpcEndpointService = InterfaceVpcEndpointService;
_d = JSII_RTTI_SYMBOL_1;
InterfaceVpcEndpointService[_d] = { fqn: "@aws-cdk/aws-ec2.InterfaceVpcEndpointService", version: "1.204.0" };
/**
* An AWS service for an interface VPC endpoint.
*/
class InterfaceVpcEndpointAwsService {
constructor(name, prefix, port) {
/**
* Whether Private DNS is supported by default.
*/
this.privateDnsDefault = true;
const region = core_1.Lazy.uncachedString({
produce: (context) => core_1.Stack.of(context.scope).region,
});
const defaultEndpointPrefix = core_1.Lazy.uncachedString({
produce: (context) => {
const regionName = core_1.Stack.of(context.scope).region;
return this.getDefaultEndpointPrefix(name, regionName);
},
});
const defaultEndpointSuffix = core_1.Lazy.uncachedString({
produce: (context) => {
const regionName = core_1.Stack.of(context.scope).region;
return this.getDefaultEndpointSuffix(name, regionName);
},
});
this.name = `${prefix || defaultEndpointPrefix}.${region}.${name}${defaultEndpointSuffix}`;
this.port = port || 443;
}
/**
* Get the endpoint prefix for the service in the specified region
* because the prefix for some of the services in cn-north-1 and cn-northwest-1 are different
*
* For future maintenance, the vpc endpoint services could be fetched using AWS CLI Commmand:
* aws ec2 describe-vpc-endpoint-services
*/
getDefaultEndpointPrefix(name, region) {
const VPC_ENDPOINT_SERVICE_EXCEPTIONS = {
'cn-north-1': ['application-autoscaling', 'athena', 'autoscaling', 'awsconnector', 'cassandra',
'cloudformation', 'codedeploy-commands-secure', 'databrew', 'dms', 'ebs', 'ec2', 'ecr.api', 'ecr.dkr',
'elasticbeanstalk', 'elasticfilesystem', 'elasticfilesystem-fips', 'execute-api', 'imagebuilder',
'iotsitewise.api', 'iotsitewise.data', 'kinesis-streams', 'lambda', 'license-manager', 'monitoring',
'rds', 'redshift', 'redshift-data', 's3', 'sagemaker.api', 'sagemaker.featurestore-runtime',
'sagemaker.runtime', 'servicecatalog', 'sms', 'sqs', 'states', 'sts', 'synthetics', 'transcribe',
'transcribestreaming', 'transfer', 'xray'],
'cn-northwest-1': ['application-autoscaling', 'athena', 'autoscaling', 'awsconnector', 'cassandra',
'cloudformation', 'codedeploy-commands-secure', 'databrew', 'dms', 'ebs', 'ec2', 'ecr.api', 'ecr.dkr',
'elasticbeanstalk', 'elasticfilesystem', 'elasticfilesystem-fips', 'execute-api', 'imagebuilder',
'kinesis-streams', 'lambda', 'license-manager', 'monitoring', 'rds', 'redshift', 'redshift-data', 's3',
'sagemaker.api', 'sagemaker.featurestore-runtime', 'sagemaker.runtime', 'servicecatalog', 'sms', 'sqs',
'states', 'sts', 'synthetics', 'transcribe', 'transcribestreaming', 'transfer', 'workspaces', 'xray'],
};
if (VPC_ENDPOINT_SERVICE_EXCEPTIONS[region]?.includes(name)) {
return 'cn.com.amazonaws';
}
else {
return 'com.amazonaws';
}
}
/**
* Get the endpoint suffix for the service in the specified region.
* In cn-north-1 and cn-northwest-1, the vpc endpoint of transcribe is:
* cn.com.amazonaws.cn-north-1.transcribe.cn
* cn.com.amazonaws.cn-northwest-1.transcribe.cn
* so suffix '.cn' should be return in these scenarios.
*
* For future maintenance, the vpc endpoint services could be fetched using AWS CLI Commmand:
* aws ec2 describe-vpc-endpoint-services
*/
getDefaultEndpointSuffix(name, region) {
const VPC_ENDPOINT_SERVICE_EXCEPTIONS = {
'cn-north-1': ['transcribe'],
'cn-northwest-1': ['transcribe'],
};
return VPC_ENDPOINT_SERVICE_EXCEPTIONS[region]?.includes(name) ? '.cn' : '';
}
}
exports.InterfaceVpcEndpointAwsService = InterfaceVpcEndpointAwsService;
_e = JSII_RTTI_SYMBOL_1;
InterfaceVpcEndpointAwsService[_e] = { fqn: "@aws-cdk/aws-ec2.InterfaceVpcEndpointAwsService", version: "1.204.0" };
InterfaceVpcEndpointAwsService.SAGEMAKER_NOTEBOOK = new InterfaceVpcEndpointAwsService('notebook', 'aws.sagemaker');
InterfaceVpcEndpointAwsService.ATHENA = new InterfaceVpcEndpointAwsService('athena');
InterfaceVpcEndpointAwsService.CLOUDFORMATION = new InterfaceVpcEndpointAwsService('cloudformation');
InterfaceVpcEndpointAwsService.CLOUDTRAIL = new InterfaceVpcEndpointAwsService('cloudtrail');
InterfaceVpcEndpointAwsService.CODEBUILD = new InterfaceVpcEndpointAwsService('codebuild');
InterfaceVpcEndpointAwsService.CODEBUILD_FIPS = new InterfaceVpcEndpointAwsService('codebuild-fips');
InterfaceVpcEndpointAwsService.CODECOMMIT = new InterfaceVpcEndpointAwsService('codecommit');
InterfaceVpcEndpointAwsService.CODECOMMIT_FIPS = new InterfaceVpcEndpointAwsService('codecommit-fips');
InterfaceVpcEndpointAwsService.CODEGURU_PROFILER = new InterfaceVpcEndpointAwsService('codeguru-profiler');
InterfaceVpcEndpointAwsService.CODEGURU_REVIEWER = new InterfaceVpcEndpointAwsService('codeguru-reviewer');
InterfaceVpcEndpointAwsService.CODEPIPELINE = new InterfaceVpcEndpointAwsService('codepipeline');
InterfaceVpcEndpointAwsService.CONFIG = new InterfaceVpcEndpointAwsService('config');
InterfaceVpcEndpointAwsService.EC2 = new InterfaceVpcEndpointAwsService('ec2');
InterfaceVpcEndpointAwsService.EC2_MESSAGES = new InterfaceVpcEndpointAwsService('ec2messages');
InterfaceVpcEndpointAwsService.ECR = new InterfaceVpcEndpointAwsService('ecr.api');
InterfaceVpcEndpointAwsService.ECR_DOCKER = new InterfaceVpcEndpointAwsService('ecr.dkr');
InterfaceVpcEndpointAwsService.ECS = new InterfaceVpcEndpointAwsService('ecs');
InterfaceVpcEndpointAwsService.ECS_AGENT = new InterfaceVpcEndpointAwsService('ecs-agent');
InterfaceVpcEndpointAwsService.ECS_TELEMETRY = new InterfaceVpcEndpointAwsService('ecs-telemetry');
InterfaceVpcEndpointAwsService.ELASTIC_FILESYSTEM = new InterfaceVpcEndpointAwsService('elasticfilesystem');
InterfaceVpcEndpointAwsService.ELASTIC_FILESYSTEM_FIPS = new InterfaceVpcEndpointAwsService('elasticfilesystem-fips');
InterfaceVpcEndpointAwsService.ELASTIC_INFERENCE_RUNTIME = new InterfaceVpcEndpointAwsService('elastic-inference.runtime');
InterfaceVpcEndpointAwsService.ELASTIC_LOAD_BALANCING = new InterfaceVpcEndpointAwsService('elasticloadbalancing');
InterfaceVpcEndpointAwsService.CLOUDWATCH_EVENTS = new InterfaceVpcEndpointAwsService('events');
InterfaceVpcEndpointAwsService.APIGATEWAY = new InterfaceVpcEndpointAwsService('execute-api');
InterfaceVpcEndpointAwsService.CODECOMMIT_GIT = new InterfaceVpcEndpointAwsService('git-codecommit');
InterfaceVpcEndpointAwsService.CODECOMMIT_GIT_FIPS = new InterfaceVpcEndpointAwsService('git-codecommit-fips');
InterfaceVpcEndpointAwsService.GLUE = new InterfaceVpcEndpointAwsService('glue');
InterfaceVpcEndpointAwsService.KEYSPACES = new InterfaceVpcEndpointAwsService('cassandra', '', 9142);
InterfaceVpcEndpointAwsService.KINESIS_STREAMS = new InterfaceVpcEndpointAwsService('kinesis-streams');
InterfaceVpcEndpointAwsService.KINESIS_FIREHOSE = new InterfaceVpcEndpointAwsService('kinesis-firehose');
InterfaceVpcEndpointAwsService.KMS = new InterfaceVpcEndpointAwsService('kms');
InterfaceVpcEndpointAwsService.CLOUDWATCH_LOGS = new InterfaceVpcEndpointAwsService('logs');
InterfaceVpcEndpointAwsService.CLOUDWATCH = new InterfaceVpcEndpointAwsService('monitoring');
InterfaceVpcEndpointAwsService.RDS = new InterfaceVpcEndpointAwsService('rds');
InterfaceVpcEndpointAwsService.RDS_DATA = new InterfaceVpcEndpointAwsService('rds-data');
InterfaceVpcEndpointAwsService.SAGEMAKER_API = new InterfaceVpcEndpointAwsService('sagemaker.api');
InterfaceVpcEndpointAwsService.SAGEMAKER_RUNTIME = new InterfaceVpcEndpointAwsService('sagemaker.runtime');
InterfaceVpcEndpointAwsService.SAGEMAKER_RUNTIME_FIPS = new InterfaceVpcEndpointAwsService('sagemaker.runtime-fips');
InterfaceVpcEndpointAwsService.SECRETS_MANAGER = new InterfaceVpcEndpointAwsService('secretsmanager');
InterfaceVpcEndpointAwsService.SERVICE_CATALOG = new InterfaceVpcEndpointAwsService('servicecatalog');
InterfaceVpcEndpointAwsService.SNS = new InterfaceVpcEndpointAwsService('sns');
InterfaceVpcEndpointAwsService.SQS = new InterfaceVpcEndpointAwsService('sqs');
InterfaceVpcEndpointAwsService.SSM = new InterfaceVpcEndpointAwsService('ssm');
InterfaceVpcEndpointAwsService.SSM_MESSAGES = new InterfaceVpcEndpointAwsService('ssmmessages');
InterfaceVpcEndpointAwsService.STS = new InterfaceVpcEndpointAwsService('sts');
InterfaceVpcEndpointAwsService.TRANSFER = new InterfaceVpcEndpointAwsService('transfer.server');
InterfaceVpcEndpointAwsService.STORAGE_GATEWAY = new InterfaceVpcEndpointAwsService('storagegateway');
InterfaceVpcEndpointAwsService.REKOGNITION = new InterfaceVpcEndpointAwsService('rekognition');
InterfaceVpcEndpointAwsService.REKOGNITION_FIPS = new InterfaceVpcEndpointAwsService('rekognition-fips');
InterfaceVpcEndpointAwsService.STEP_FUNCTIONS = new InterfaceVpcEndpointAwsService('states');
InterfaceVpcEndpointAwsService.LAMBDA = new InterfaceVpcEndpointAwsService('lambda');
InterfaceVpcEndpointAwsService.TRANSCRIBE = new InterfaceVpcEndpointAwsService('transcribe');
InterfaceVpcEndpointAwsService.XRAY = new InterfaceVpcEndpointAwsService('xray');
/**
* A interface VPC endpoint.
* @resource AWS::EC2::VPCEndpoint
*/
class InterfaceVpcEndpoint extends VpcEndpoint {
constructor(scope, id, props) {
super(scope, id);
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_InterfaceVpcEndpointProps(props);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, InterfaceVpcEndpoint);
}
throw error;
}
const securityGroups = props.securityGroups || [new security_group_1.SecurityGroup(this, 'SecurityGroup', {
vpc: props.vpc,
})];
this.securityGroupId = securityGroups[0].securityGroupId;
this.connections = new connections_1.Connections({
defaultPort: port_1.Port.tcp(props.service.port),
securityGroups,
});
if (props.open !== false) {
this.connections.allowDefaultPortFrom(peer_1.Peer.ipv4(props.vpc.vpcCidrBlock));
}
// Determine which subnets to place the endpoint in
const subnetIds = this.endpointSubnets(props);
const endpoint = new ec2_generated_1.CfnVPCEndpoint(this, 'Resource', {
privateDnsEnabled: props.privateDnsEnabled ?? props.service.privateDnsDefault ?? true,
policyDocument: core_1.Lazy.any({ produce: () => this.policyDocument }),
securityGroupIds: securityGroups.map(s => s.securityGroupId),
serviceName: props.service.name,
vpcEndpointType: VpcEndpointType.INTERFACE,
subnetIds,
vpcId: props.vpc.vpcId,
});
this.vpcEndpointId = endpoint.ref;
this.vpcEndpointCreationTimestamp = endpoint.attrCreationTimestamp;
this.vpcEndpointDnsEntries = endpoint.attrDnsEntries;
this.vpcEndpointNetworkInterfaceIds = endpoint.attrNetworkInterfaceIds;
}
/**
* Imports an existing interface VPC endpoint.
*/
static fromInterfaceVpcEndpointAttributes(scope, id, attrs) {
try {
jsiiDeprecationWarnings._aws_cdk_aws_ec2_InterfaceVpcEndpointAttributes(attrs);
}
catch (error) {
if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
Error.captureStackTrace(error, this.fromInterfaceVpcEndpointAttributes);
}
throw error;
}
const securityGroups = attrs.securityGroupId
? [security_group_1.SecurityGroup.fromSecurityGroupId(scope, 'SecurityGroup', attrs.securityGroupId)]
: attrs.securityGroups;
class Import extends core_1.Resource {
constructor() {
super(...arguments);
this.vpcEndpointId = attrs.vpcEndpointId;
this.connections = new connections_1.Connections({
defaultPort: port_1.Port.tcp(attrs.port),
securityGroups,
});
}
}
return new Import(scope, id);
}
/**
* Determine which subnets to place the endpoint in. This is in its own function
* because there's a lot of code.
*/
endpointSubnets(props) {
const lookupSupportedAzs = props.lookupSupportedAzs ?? false;
const subnetSelection = props.vpc.selectSubnets({ ...props.subnets, onePerAz: true });
const subnets = subnetSelection.subnets;
// Sanity check the subnet count
if (!subnetSelection.isPendingLookup && subnetSelection.subnets.length == 0) {
throw new Error('Cannot create a VPC Endpoint with no subnets');
}
// If we aren't going to lookup supported AZs we'll exit early, returning the subnetIds from the provided subnet selection
if (!lookupSupportedAzs) {
return subnetSelection.subnetIds;
}
// Some service names, such as AWS service name references, use Tokens to automatically fill in the region
// If it is an InterfaceVpcEndpointAwsService, then the reference will be resolvable since it only references the region
const isAwsService = core_1.Token.isUnresolved(props.service.name) && props.service instanceof InterfaceVpcEndpointAwsService;
// Determine what service name gets pass to the context provider
// If it is an AWS service it will have a REGION token
const lookupServiceName = isAwsService ? core_1.Stack.of(this).resolve(props.service.name) : props.service.name;
// Check that the lookup will work
this.validateCanLookupSupportedAzs(subnets, lookupServiceName);
// Do the actual lookup for AZs
const availableAZs = this.availableAvailabilityZones(lookupServiceName);
const filteredSubnets = subnets.filter(s => availableAZs.includes(s.availabilityZone));
// Throw an error if the lookup filtered out all subnets
// VpcEndpoints must be created with at least one AZ
if (filteredSubnets.length == 0) {
throw new Error(`lookupSupportedAzs returned ${availableAZs} but subnets have AZs ${subnets.map(s => s.availabilityZone)}`);
}
return filteredSubnets.map(s => s.subnetId);
}
/**
* Sanity checking when looking up AZs for an endpoint service, to make sure it won't fail
*/
validateCanLookupSupportedAzs(subnets, serviceName) {
// Having any of these be true will cause the AZ lookup to fail at synthesis time
const agnosticAcct = core_1.Token.isUnresolved(this.env.account);
const agnosticRegion = core_1.Token.isUnresolved(this.env.region);
const agnosticService = core_1.Token.isUnresolved(serviceName);
// Having subnets with Token AZs can cause the endpoint to be created with no subnets, failing at deployment time
const agnosticSubnets = subnets.some(s => core_1.Token.isUnresolved(s.availabilityZone));
const agnosticSubnetList = core_1.Token.isUnresolved(subnets.map(s => s.availabilityZone));
// Context provider cannot make an AWS call without an account/region
if (agnosticAcct || agnosticRegion) {
throw new Error('Cannot look up VPC endpoint availability zones if account/region are not specified');
}
// The AWS call will fail if there is a Token in the service name
if (agnosticService) {
throw new Error(`Cannot lookup AZs for a service name with a Token: ${serviceName}`);
}
// The AWS call return strings for AZs, like us-east-1a, us-east-1b, etc
// If the subnet AZs are Tokens, a string comparison between the subnet AZs and the AZs from the AWS call
// will not match
if (agnosticSubnets || agnosticSubnetList) {
const agnostic = subnets.filter(s => core_1.Token.isUnresolved(s.availabilityZone));
throw new Error(`lookupSupportedAzs cannot filter on subnets with Token AZs: ${agnostic}`);
}
}
availableAvailabilityZones(serviceName) {
// Here we check what AZs the endpoint service is available in
// If for whatever reason we can't retrieve the AZs, and no context is set,
// we will fall back to all AZs
const availableAZs = core_1.ContextProvider.getValue(this, {
provider: cxschema.ContextProvider.ENDPOINT_SERVICE_AVAILABILITY_ZONE_PROVIDER,
dummyValue: this.stack.availabilityZones,
props: { serviceName },
}).value;
if (!Array.isArray(availableAZs)) {
throw new Error(`Discovered AZs for endpoint service ${serviceName} must be an array`);
}
return availableAZs;
}
}
exports.InterfaceVpcEndpoint = InterfaceVpcEndpoint;
_f = JSII_RTTI_SYMBOL_1;
InterfaceVpcEndpoint[_f] = { fqn: "@aws-cdk/aws-ec2.InterfaceVpcEndpoint", version: "1.204.0" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidnBjLWVuZHBvaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidnBjLWVuZHBvaW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHdDQUF3QztBQUN4QywyREFBMkQ7QUFDM0Qsd0NBQThGO0FBRTlGLCtDQUEwRDtBQUMxRCxtREFBaUQ7QUFDakQsaUNBQThCO0FBQzlCLGlDQUE4QjtBQUM5QixxREFBaUU7QUFDakUsaUNBQW1EO0FBY25ELE1BQXNCLFdBQVksU0FBUSxlQUFRO0lBS2hEOzs7Ozs7OztPQVFHO0lBQ0ksV0FBVyxDQUFDLFNBQThCO1FBQy9DLElBQUksQ0FBQyxTQUFTLENBQUMsWUFBWSxFQUFFO1lBQzNCLE1BQU0sSUFBSSxLQUFLLENBQUMsb0NBQW9DLENBQUMsQ0FBQztTQUN2RDtRQUVELElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFO1lBQ3hCLElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxHQUFHLENBQUMsY0FBYyxFQUFFLENBQUM7U0FDaEQ7UUFFRCxJQUFJLENBQUMsY0FBYyxDQUFDLGFBQWEsQ0FBQyxTQUFTLENBQUMsQ0FBQztLQUM5Qzs7QUF4Qkgsa0NBeUJDOzs7QUFRRDs7R0FFRztBQUNILElBQVksZUFpQlg7QUFqQkQsV0FBWSxlQUFlO0lBQ3pCOzs7Ozs7T0FNRztJQUNILDBDQUF1QixDQUFBO0lBRXZCOzs7OztPQUtHO0lBQ0gsc0NBQW1CLENBQUE7QUFDckIsQ0FBQyxFQWpCVyxlQUFlLEdBQWYsdUJBQWUsS0FBZix1QkFBZSxRQWlCMUI7QUFZRDs7R0FFRztBQUNILE1BQWEsNEJBQTRCO0lBU3ZDLFlBQVksSUFBWSxFQUFFLE1BQWU7UUFDdkMsSUFBSSxDQUFDLElBQUksR0FBRyxHQUFHLE1BQU0sSUFBSSxlQUFlLElBQUksVUFBRyxDQUFDLE1BQU0sSUFBSSxJQUFJLEVBQUUsQ0FBQztLQUNsRTs7QUFYSCxvRUFZQzs7O0FBWHdCLHFDQUFRLEdBQUcsSUFBSSw0QkFBNEIsQ0FB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LENBQUMsS0FBSyxDQUFDLGlCQUFpQjtZQUN4QyxLQUFLLEVBQUUsRUFBRSxXQUFXLEVBQUU7U0FDdkIsQ0FBQyxDQUFDLEtBQUssQ0FBQztRQUNULElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxFQUFFO1lBQ2hDLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLFdBQVcsbUJBQW1CLENBQUMsQ0FBQztTQUN4RjtRQUNELE9BQU8sWUFBWSxDQUFDO0tBQ3JCOztBQXBMSCxvREFxTEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBpYW0gZnJvbSAnQGF3cy1jZGsvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0IHsgQXdzLCBDb250ZXh0UHJvdmlkZXIsIElSZXNvdXJjZSwgTGF6eSwgUmVzb3VyY2UsIFN0YWNrLCBUb2tlbiB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBDb25uZWN0aW9ucywgSUNvbm5lY3RhYmxlIH0gZnJvbSAnLi9jb25uZWN0aW9ucyc7XG5pbXBvcnQgeyBDZm5WUENFbmRwb2ludCB9IGZyb20gJy4vZWMyLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBQZWVyIH0gZnJvbSAnLi9wZWVyJztcbmltcG9ydCB7IFBvcnQgfSBmcm9tICcuL3BvcnQnO1xuaW1wb3J0IHsgSVNlY3VyaXR5R3JvdXAsIFNlY3VyaXR5R3JvdXAgfSBmcm9tICcuL3NlY3VyaXR5LWdyb3VwJztcbmltcG9ydCB7IGFsbFJvdXRlVGFibGVJZHMsIGZsYXR0ZW4gfSBmcm9tICcuL3V0aWwnO1xuaW1wb3J0IHsgSVN1Ym5ldCwgSVZwYywgU3VibmV0U2VsZWN0aW9uIH0gZnJvbSAnLi92cGMnO1xuXG4vKipcbiAqIEEgVlBDIGVuZHBvaW50LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElWcGNFbmRwb2ludCBleHRlbmRzIElSZXNvdXJjZSB7XG4gIC8qKlxuICAgKiBUaGUgVlBDIGVuZHBvaW50IGlkZW50aWZpZXIuXG4gICAqIEBhdHRyaWJ1dGVcbiAgICovXG4gIHJlYWRvbmx5IHZwY0VuZHBvaW50SWQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIFZwY0VuZHBvaW50IGV4dGVuZHMgUmVzb3VyY2UgaW1wbGVtZW50cyBJVnBjRW5kcG9pbnQge1xuICBwdWJsaWMgYWJzdHJhY3QgcmVhZG9ubHkgdnBjRW5kcG9pbnRJZDogc3RyaW5nO1xuXG4gIHByb3RlY3RlZCBwb2xpY3lEb2N1bWVudD86IGlhbS5Qb2xpY3lEb2N1bWVudDtcblxuICAvKipcbiAgICogQWRkcyBhIHN0YXRlbWVudCB0byB0aGUgcG9saWN5IGRvY3VtZW50IG9mIHRoZSBWUEMgZW5kcG9pbnQuIFRoZSBzdGF0ZW1lbnRcbiAgICogbXVzdCBoYXZlIGEgUHJpbmNpcGFsLlxuICAgKlxuICAgKiBOb3QgYWxsIGludGVyZmFjZSBWUEMgZW5kcG9pbnRzIHN1cHBvcnQgcG9saWN5LiBGb3IgbW9yZSBpbmZvcm1hdGlvblxuICAgKiBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL3ZwYy9sYXRlc3QvdXNlcmd1aWRlL3ZwY2UtaW50ZXJmYWNlLmh0bWxcbiAgICpcbiAgICogQHBhcmFtIHN0YXRlbWVudCB0aGUgSUFNIHN0YXRlbWVudCB0byBhZGRcbiAgICovXG4gIHB1YmxpYyBhZGRUb1BvbGljeShzdGF0ZW1lbnQ6IGlhbS5Qb2xpY3lTdGF0ZW1lbnQpIHtcbiAgICBpZiAoIXN0YXRlbWVudC5oYXNQcmluY2lwYWwpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignU3RhdGVtZW50IG11c3QgaGF2ZSBhIGBQcmluY2lwYWxgLicpO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5wb2xpY3lEb2N1bWVudCkge1xuICAgICAgdGhpcy5wb2xpY3lEb2N1bWVudCA9IG5ldyBpYW0uUG9saWN5RG9jdW1lbnQoKTtcbiAgICB9XG5cbiAgICB0aGlzLnBvbGljeURvY3VtZW50LmFkZFN0YXRlbWVudHMoc3RhdGVtZW50KTtcbiAgfVxufVxuXG4vKipcbiAqIEEgZ2F0ZXdheSBWUEMgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUdhdGV3YXlWcGNFbmRwb2ludCBleHRlbmRzIElWcGNFbmRwb2ludCB7XG59XG5cbi8qKlxuICogVGhlIHR5cGUgb2YgVlBDIGVuZHBvaW50LlxuICovXG5leHBvcnQgZW51bSBWcGNFbmRwb2ludFR5cGUge1xuICAvKipcbiAgICogSW50ZXJmYWNlXG4gICAqXG4gICAqIEFuIGludGVyZmFjZSBlbmRwb2ludCBpcyBhbiBlbGFzdGljIG5ldHdvcmsgaW50ZXJmYWNlIHdpdGggYSBwcml2YXRlIElQXG4gICAqIGFkZHJlc3MgdGhhdCBzZXJ2ZXMgYXMgYW4gZW50cnkgcG9pbnQgZm9yIHRyYWZmaWMgZGVzdGluZWQgdG8gYSBzdXBwb3J0ZWRcbiAgICogc2VydmljZS5cbiAgICovXG4gIElOVEVSRkFDRSA9ICdJbnRlcmZhY2UnLFxuXG4gIC8qKlxuICAgKiBHYXRld2F5XG4gICAqXG4gICAqIEEgZ2F0ZXdheSBlbmRwb2ludCBpcyBhIGdhdGV3YXkgdGhhdCBpcyBhIHRhcmdldCBmb3IgYSBzcGVjaWZpZWQgcm91dGUgaW5cbiAgICogeW91ciByb3V0ZSB0YWJsZSwgdXNlZCBmb3IgdHJhZmZpYyBkZXN0aW5lZCB0byBhIHN1cHBvcnRlZCBBV1Mgc2VydmljZS5cbiAgICovXG4gIEdBVEVXQVkgPSAnR2F0ZXdheSdcbn1cblxuLyoqXG4gKiBBIHNlcnZpY2UgZm9yIGEgZ2F0ZXdheSBWUEMgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUdhdGV3YXlWcGNFbmRwb2ludFNlcnZpY2Uge1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIHNlcnZpY2UuXG4gICAqL1xuICByZWFkb25seSBuYW1lOiBzdHJpbmc7XG59XG5cbi8qKlxuICogQW4gQVdTIHNlcnZpY2UgZm9yIGEgZ2F0ZXdheSBWUEMgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBHYXRld2F5VnBjRW5kcG9pbnRBd3NTZXJ2aWNlIGltcGxlbWVudHMgSUdhdGV3YXlWcGNFbmRwb2ludFNlcnZpY2Uge1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IERZTkFNT0RCID0gbmV3IEdhdGV3YXlWcGNFbmRwb2ludEF3c1NlcnZpY2UoJ2R5bmFtb2RiJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgUzMgPSBuZXcgR2F0ZXdheVZwY0VuZHBvaW50QXdzU2VydmljZSgnczMnKTtcblxuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIHNlcnZpY2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKG5hbWU6IHN0cmluZywgcHJlZml4Pzogc3RyaW5nKSB7XG4gICAgdGhpcy5uYW1lID0gYCR7cHJlZml4IHx8ICdjb20uYW1hem9uYXdzJ30uJHtBd3MuUkVHSU9OfS4ke25hbWV9YDtcbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgdG8gYWRkIGEgZ2F0ZXdheSBlbmRwb2ludCB0byBhIFZQQy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHYXRld2F5VnBjRW5kcG9pbnRPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBzZXJ2aWNlIHRvIHVzZSBmb3IgdGhpcyBnYXRld2F5IFZQQyBlbmRwb2ludC5cbiAgICovXG4gIHJlYWRvbmx5IHNlcnZpY2U6IElHYXRld2F5VnBjRW5kcG9pbnRTZXJ2aWNlO1xuXG4gIC8qKlxuICAgKiBXaGVyZSB0byBhZGQgZW5kcG9pbnQgcm91dGluZy5cbiAgICpcbiAgICogQnkgZGVmYXVsdCwgdGhpcyBlbmRwb2ludCB3aWxsIGJlIHJvdXRhYmxlIGZyb20gYWxsIHN1Ym5ldHMgaW4gdGhlIFZQQy5cbiAgICogU3BlY2lmeSBhIGxpc3Qgb2Ygc3VibmV0IHNlbGVjdGlvbiBvYmplY3RzIGhlcmUgdG8gYmUgbW9yZSBzcGVjaWZpYy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBbGwgc3VibmV0cyBpbiB0aGUgVlBDXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIGRlY2xhcmUgY29uc3QgdnBjOiBlYzIuVnBjO1xuICAgKlxuICAgKiB2cGMuYWRkR2F0ZXdheUVuZHBvaW50KCdEeW5hbW9EYkVuZHBvaW50Jywge1xuICAgKiAgIHNlcnZpY2U6IGVjMi5HYXRld2F5VnBjRW5kcG9pbnRBd3NTZXJ2aWNlLkRZTkFNT0RCLFxuICAgKiAgIC8vIEFkZCBvbmx5IHRvIElTT0xBVEVEIHN1Ym5ldHNcbiAgICogICBzdWJuZXRzOiBbXG4gICAqICAgICB7IHN1Ym5ldFR5cGU6IGVjMi5TdWJuZXRUeXBlLlBSSVZBVEVfSVNPTEFURUQgfVxuICAgKiAgIF1cbiAgICogfSk7XG4gICAqXG4gICAqXG4gICAqL1xuICByZWFkb25seSBzdWJuZXRzPzogU3VibmV0U2VsZWN0aW9uW11cbn1cblxuLyoqXG4gKiBDb25zdHJ1Y3Rpb24gcHJvcGVydGllcyBmb3IgYSBHYXRld2F5VnBjRW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2F0ZXdheVZwY0VuZHBvaW50UHJvcHMgZXh0ZW5kcyBHYXRld2F5VnBjRW5kcG9pbnRPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBWUEMgbmV0d29yayBpbiB3aGljaCB0aGUgZ2F0ZXdheSBlbmRwb2ludCB3aWxsIGJlIHVzZWQuXG4gICAqL1xuICByZWFkb25seSB2cGM6IElWcGNcbn1cblxuLyoqXG4gKiBBIGdhdGV3YXkgVlBDIGVuZHBvaW50LlxuICogQHJlc291cmNlIEFXUzo6RUMyOjpWUENFbmRwb2ludFxuICovXG5leHBvcnQgY2xhc3MgR2F0ZXdheVZwY0VuZHBvaW50IGV4dGVuZHMgVnBjRW5kcG9pbnQgaW1wbGVtZW50cyBJR2F0ZXdheVZwY0VuZHBvaW50IHtcblxuICBwdWJsaWMgc3RhdGljIGZyb21HYXRld2F5VnBjRW5kcG9pbnRJZChzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBnYXRld2F5VnBjRW5kcG9pbnRJZDogc3RyaW5nKTogSUdhdGV3YXlWcGNFbmRwb2ludCB7XG4gICAgY2xhc3MgSW1wb3J0IGV4dGVuZHMgVnBjRW5kcG9pbnQge1xuICAgICAgcHVibGljIHZwY0VuZHBvaW50SWQgPSBnYXRld2F5VnBjRW5kcG9pbnRJZDtcbiAgICB9XG5cbiAgICByZXR1cm4gbmV3IEltcG9ydChzY29wZSwgaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBnYXRld2F5IFZQQyBlbmRwb2ludCBpZGVudGlmaWVyLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZwY0VuZHBvaW50SWQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRhdGUgYW5kIHRpbWUgdGhlIGdhdGV3YXkgVlBDIGVuZHBvaW50IHdhcyBjcmVhdGVkLlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdnBjRW5kcG9pbnRDcmVhdGlvblRpbWVzdGFtcDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdnBjRW5kcG9pbnROZXR3b3JrSW50ZXJmYWNlSWRzOiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZwY0VuZHBvaW50RG5zRW50cmllczogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEdhdGV3YXlWcGNFbmRwb2ludFByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGNvbnN0IHN1Ym5ldHM6IElTdWJuZXRbXSA9IHByb3BzLnN1Ym5ldHNcbiAgICAgID8gZmxhdHRlbihwcm9wcy5zdWJuZXRzLm1hcChzID0+IHByb3BzLnZwYy5zZWxlY3RTdWJuZXRzKHMpLnN1Ym5ldHMpKVxuICAgICAgOiBbLi4ucHJvcHMudnBjLnByaXZhdGVTdWJuZXRzLCAuLi5wcm9wcy52cGMucHVibGljU3VibmV0cywgLi4ucHJvcHMudnBjLmlzb2xhdGVkU3VibmV0c107XG4gICAgY29uc3Qgcm91dGVUYWJsZUlkcyA9IGFsbFJvdXRlVGFibGVJZHMoc3VibmV0cyk7XG5cbiAgICBpZiAocm91dGVUYWJsZUlkcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2FuXFwndCBhZGQgYSBnYXRld2F5IGVuZHBvaW50IHRvIFZQQzsgcm91dGUgdGFibGUgSURzIGFyZSBub3QgYXZhaWxhYmxlJyk7XG4gICAgfVxuXG4gICAgY29uc3QgZW5kcG9pbnQgPSBuZXcgQ2ZuVlBDRW5kcG9pbnQodGhpcywgJ1Jlc291cmNlJywge1xuICAgICAgcG9saWN5RG9jdW1lbnQ6IExhenkuYW55KHsgcHJvZHVjZTogKCkgPT4gdGhpcy5wb2xpY3lEb2N1bWVudCB9KSxcbiAgICAgIHJvdXRlVGFibGVJZHMsXG4gICAgICBzZXJ2aWNlTmFtZTogcHJvcHMuc2VydmljZS5uYW1lLFxuICAgICAgdnBjRW5kcG9pbnRUeXBlOiBWcGNFbmRwb2ludFR5cGUuR0FURVdBWSxcbiAgICAgIHZwY0lkOiBwcm9wcy52cGMudnBjSWQsXG4gICAgfSk7XG5cbiAgICB0aGlzLnZwY0VuZHBvaW50SWQgPSBlbmRwb2ludC5yZWY7XG4gICAgdGhpcy52cGNFbmRwb2ludENyZWF0aW9uVGltZXN0YW1wID0gZW5kcG9pbnQuYXR0ckNyZWF0aW9uVGltZXN0YW1wO1xuICAgIHRoaXMudnBjRW5kcG9pbnREbnNFbnRyaWVzID0gZW5kcG9pbnQuYXR0ckRuc0VudHJpZXM7XG4gICAgdGhpcy52cGNFbmRwb2ludE5ldHdvcmtJbnRlcmZhY2VJZHMgPSBlbmRwb2ludC5hdHRyTmV0d29ya0ludGVyZmFjZUlkcztcbiAgfVxufVxuXG4vKipcbiAqIEEgc2VydmljZSBmb3IgYW4gaW50ZXJmYWNlIFZQQyBlbmRwb2ludC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJSW50ZXJmYWNlVnBjRW5kcG9pbnRTZXJ2aWNlIHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBzZXJ2aWNlLlxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcG9ydCBvZiB0aGUgc2VydmljZS5cbiAgICovXG4gIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciBQcml2YXRlIEROUyBpcyBzdXBwb3J0ZWQgYnkgZGVmYXVsdC5cbiAgICovXG4gIHJlYWRvbmx5IHByaXZhdGVEbnNEZWZhdWx0PzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBBIGN1c3RvbS1ob3N0ZWQgc2VydmljZSBmb3IgYW4gaW50ZXJmYWNlIFZQQyBlbmRwb2ludC5cbiAqL1xuZXhwb3J0IGNsYXNzIEludGVyZmFjZVZwY0VuZHBvaW50U2VydmljZSBpbXBsZW1lbnRzIElJbnRlcmZhY2VWcGNFbmRwb2ludFNlcnZpY2Uge1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgc2VydmljZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwb3J0IG9mIHRoZSBzZXJ2aWNlLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHBvcnQ6IG51bWJlcjtcblxuICAvKipcbiAgICogV2hldGhlciBQcml2YXRlIEROUyBpcyBzdXBwb3J0ZWQgYnkgZGVmYXVsdC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwcml2YXRlRG5zRGVmYXVsdD86IGJvb2xlYW4gPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIHBvcnQ/OiBudW1iZXIpIHtcbiAgICB0aGlzLm5hbWUgPSBuYW1lO1xuICAgIHRoaXMucG9ydCA9IHBvcnQgfHwgNDQzO1xuICB9XG59XG5cbi8qKlxuICogQW4gQVdTIHNlcnZpY2UgZm9yIGFuIGludGVyZmFjZSBWUEMgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBjbGFzcyBJbnRlcmZhY2VWcGNFbmRwb2ludEF3c1NlcnZpY2UgaW1wbGVtZW50cyBJSW50ZXJmYWNlVnBjRW5kcG9pbnRTZXJ2aWNlIHtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBTQUdFTUFLRVJfTk9URUJPT0sgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdub3RlYm9vaycsICdhd3Muc2FnZW1ha2VyJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQVRIRU5BID0gbmV3IEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZSgnYXRoZW5hJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ0xPVURGT1JNQVRJT04gPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjbG91ZGZvcm1hdGlvbicpO1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IENMT1VEVFJBSUwgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjbG91ZHRyYWlsJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ09ERUJVSUxEID0gbmV3IEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZSgnY29kZWJ1aWxkJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ09ERUJVSUxEX0ZJUFMgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjb2RlYnVpbGQtZmlwcycpO1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IENPREVDT01NSVQgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjb2RlY29tbWl0Jyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ09ERUNPTU1JVF9GSVBTID0gbmV3IEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZSgnY29kZWNvbW1pdC1maXBzJyk7XG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQ09ERUdVUlVfUFJPRklMRVIgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjb2RlZ3VydS1wcm9maWxlcicpO1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IENPREVHVVJVX1JFVklFV0VSID0gbmV3IEludGVyZmFjZVZwY0VuZHBvaW50QXdzU2VydmljZSgnY29kZWd1cnUtcmV2aWV3ZXInKTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBDT0RFUElQRUxJTkUgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjb2RlcGlwZWxpbmUnKTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBDT05GSUcgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdjb25maWcnKTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBFQzIgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdlYzInKTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBFQzJfTUVTU0FHRVMgPSBuZXcgSW50ZXJmYWNlVnBjRW5kcG9pbnRBd3NTZXJ2aWNlKCdlYzJtZXNzYWdlcycpO1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IEVDUiA9IG5ldyBJbnRlcmZhY2VWcGNFbmRwb2ludEF3c1NlcnZpY2UoJ2Vjci5hcGknKTtcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBFQ1JfRE9DS0VSID0gbmV3IEludGVyZmF