UNPKG

@aws-cdk/aws-ec2

Version:

The CDK Construct Library for AWS::EC2

419 lines 73.5 kB
"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