cdk-serverless-clamscan
Version:
Serverless architecture to virus scan objects in Amazon S3.
409 lines (403 loc) • 65.3 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.ServerlessClamscan = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
const path = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_ec2_1 = require("aws-cdk-lib/aws-ec2");
const aws_efs_1 = require("aws-cdk-lib/aws-efs");
const aws_events_1 = require("aws-cdk-lib/aws-events");
const aws_events_targets_1 = require("aws-cdk-lib/aws-events-targets");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_lambda_destinations_1 = require("aws-cdk-lib/aws-lambda-destinations");
const aws_s3_1 = require("aws-cdk-lib/aws-s3");
const aws_s3_notifications_1 = require("aws-cdk-lib/aws-s3-notifications");
const aws_sqs_1 = require("aws-cdk-lib/aws-sqs");
const constructs_1 = require("constructs");
/**
An [aws-cdk](https://github.com/aws/aws-cdk) construct that uses [ClamAV®](https://www.clamav.net/).
to scan objects in Amazon S3 for viruses. The construct provides a flexible interface for a system
to act based on the results of a ClamAV virus scan.
The construct creates a Lambda function with EFS integration to support larger files.
A VPC with isolated subnets, a S3 Gateway endpoint will also be created.
Additionally creates an twice-daily job to download the latest ClamAV definition files to the
Virus Definitions S3 Bucket by utilizing an EventBridge rule and a Lambda function and
publishes CloudWatch Metrics to the 'serverless-clamscan' namespace.
__Important O&M__:
When ClamAV publishes updates to the scanner you will see “Your ClamAV installation is OUTDATED” in your scan results.
While the construct creates a system to keep the database definitions up to date, you must update the scanner to
detect all the latest Viruses.
Update the docker images of the Lambda functions with the latest version of ClamAV by re-running `cdk deploy`.
Successful Scan Event format
```json
{
"source": "serverless-clamscan",
"input_bucket": <input_bucket_name>,
"input_key": <object_key>,
"status": <"CLEAN"|"INFECTED"|"N/A">,
"message": <scan_summary>,
}
```
Note: The Virus Definitions bucket policy will likely cause a deletion error if you choose to delete
the stack associated in the construct. However since the bucket itself gets deleted, you can delete
the stack again to resolve the error.
*/
class ServerlessClamscan extends constructs_1.Construct {
/**
* Creates a ServerlessClamscan construct.
* @param scope The parent creating construct (usually `this`).
* @param id The construct's name.
* @param props A `ServerlessClamscanProps` interface.
*/
constructor(scope, id, props) {
super(scope, id);
this._efsRootPath = '/lambda';
this._efsMountPath = `/mnt${this._efsRootPath}`;
this._efsDefsPath = 'virus_database/';
this.useImportedBuckets = props.acceptResponsibilityForUsingImportedBucket;
if (!props.onResult) {
this.resultBus = new aws_events_1.EventBus(this, 'ScanResultBus');
this.resultDest = new aws_lambda_destinations_1.EventBridgeDestination(this.resultBus);
this.infectedRule = new aws_events_1.Rule(this, 'InfectedRule', {
eventBus: this.resultBus,
description: 'Event for when a file is marked INFECTED',
eventPattern: {
detail: {
responsePayload: {
source: ['serverless-clamscan'],
status: ['INFECTED'],
},
},
},
});
this.cleanRule = new aws_events_1.Rule(this, 'CleanRule', {
eventBus: this.resultBus,
description: 'Event for when a file is marked CLEAN',
eventPattern: {
detail: {
responsePayload: {
source: ['serverless-clamscan'],
status: ['CLEAN'],
},
},
},
});
}
else {
this.resultDest = props.onResult;
}
if (!props.onError) {
this.errorDeadLetterQueue = new aws_sqs_1.Queue(this, 'ScanErrorDeadLetterQueue', {
encryption: aws_sqs_1.QueueEncryption.KMS_MANAGED,
});
this.errorDeadLetterQueue.addToResourcePolicy(new aws_iam_1.PolicyStatement({
actions: ['sqs:*'],
effect: aws_iam_1.Effect.DENY,
principals: [new aws_iam_1.AnyPrincipal()],
conditions: { Bool: { 'aws:SecureTransport': false } },
resources: [this.errorDeadLetterQueue.queueArn],
}));
this.errorQueue = new aws_sqs_1.Queue(this, 'ScanErrorQueue', {
encryption: aws_sqs_1.QueueEncryption.KMS_MANAGED,
deadLetterQueue: {
maxReceiveCount: 3,
queue: this.errorDeadLetterQueue,
},
});
this.errorQueue.addToResourcePolicy(new aws_iam_1.PolicyStatement({
actions: ['sqs:*'],
effect: aws_iam_1.Effect.DENY,
principals: [new aws_iam_1.AnyPrincipal()],
conditions: { Bool: { 'aws:SecureTransport': false } },
resources: [this.errorQueue.queueArn],
}));
this.errorDest = new aws_lambda_destinations_1.SqsDestination(this.errorQueue);
}
else {
this.errorDest = props.onError;
}
const vpc = new aws_ec2_1.Vpc(this, 'ScanVPC', {
subnetConfiguration: [
{
subnetType: aws_ec2_1.SubnetType.PRIVATE_ISOLATED,
name: 'Isolated',
},
],
});
vpc.addFlowLog('FlowLogs');
this._s3Gw = vpc.addGatewayEndpoint('S3Endpoint', {
service: aws_ec2_1.GatewayVpcEndpointAwsService.S3,
});
const fileSystem = new aws_efs_1.FileSystem(this, 'ScanFileSystem', {
vpc: vpc,
encrypted: props.efsEncryption === false ? false : true,
lifecyclePolicy: aws_efs_1.LifecyclePolicy.AFTER_7_DAYS,
performanceMode: props.efsPerformanceMode ?? aws_efs_1.PerformanceMode.GENERAL_PURPOSE,
throughputMode: props.efsThroughputMode ?? aws_efs_1.ThroughputMode.BURSTING,
provisionedThroughputPerSecond: props.efsProvisionedThroughputPerSecond,
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
securityGroup: new aws_ec2_1.SecurityGroup(this, 'ScanFileSystemSecurityGroup', {
vpc: vpc,
allowAllOutbound: false,
}),
});
const lambda_ap = fileSystem.addAccessPoint('ScanLambdaAP', {
createAcl: {
ownerGid: '0',
ownerUid: '0',
permissions: '755',
},
posixUser: {
gid: '0',
uid: '0',
},
path: this._efsRootPath,
});
const logs_bucket = props.defsBucketAccessLogsConfig?.logsBucket;
const logs_bucket_prefix = props.defsBucketAccessLogsConfig?.logsPrefix;
if (logs_bucket === true || logs_bucket === undefined) {
this.defsAccessLogsBucket = new aws_s3_1.Bucket(this, 'VirusDefsAccessLogsBucket', {
encryption: aws_s3_1.BucketEncryption.S3_MANAGED,
removalPolicy: aws_cdk_lib_1.RemovalPolicy.RETAIN,
blockPublicAccess: {
blockPublicAcls: true,
blockPublicPolicy: true,
ignorePublicAcls: true,
restrictPublicBuckets: true,
},
objectOwnership: aws_s3_1.ObjectOwnership.OBJECT_WRITER,
});
this.defsAccessLogsBucket.addToResourcePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.DENY,
actions: ['s3:*'],
resources: [
this.defsAccessLogsBucket.arnForObjects('*'),
this.defsAccessLogsBucket.bucketArn,
],
principals: [new aws_iam_1.AnyPrincipal()],
conditions: {
Bool: {
'aws:SecureTransport': false,
},
},
}));
}
else if (logs_bucket != false) {
this.defsAccessLogsBucket = logs_bucket;
}
const defs_bucket = new aws_s3_1.Bucket(this, 'VirusDefsBucket', {
encryption: aws_s3_1.BucketEncryption.S3_MANAGED,
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
autoDeleteObjects: true,
serverAccessLogsBucket: this.defsAccessLogsBucket,
serverAccessLogsPrefix: logs_bucket === false ? undefined : logs_bucket_prefix,
blockPublicAccess: {
blockPublicAcls: true,
blockPublicPolicy: true,
ignorePublicAcls: true,
restrictPublicBuckets: true,
},
});
defs_bucket.addToResourcePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.DENY,
actions: ['s3:*'],
resources: [defs_bucket.arnForObjects('*'), defs_bucket.bucketArn],
principals: [new aws_iam_1.AnyPrincipal()],
conditions: {
Bool: {
'aws:SecureTransport': false,
},
},
}));
defs_bucket.addToResourcePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: ['s3:GetObject', 's3:ListBucket'],
resources: [defs_bucket.arnForObjects('*'), defs_bucket.bucketArn],
principals: [new aws_iam_1.AnyPrincipal()],
conditions: {
StringEquals: {
'aws:SourceVpce': this._s3Gw.vpcEndpointId,
},
},
}));
if (props.defsBucketAllowPolicyMutation !== true) {
defs_bucket.addToResourcePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.DENY,
actions: ['s3:PutBucketPolicy', 's3:DeleteBucketPolicy'],
resources: [defs_bucket.bucketArn],
notPrincipals: [new aws_iam_1.AccountRootPrincipal()],
}));
}
this._s3Gw.addToPolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: ['s3:GetObject', 's3:ListBucket'],
resources: [defs_bucket.arnForObjects('*'), defs_bucket.bucketArn],
principals: [new aws_iam_1.AnyPrincipal()],
}));
this._scanFunction = new aws_lambda_1.DockerImageFunction(this, 'ServerlessClamscan', {
code: aws_lambda_1.DockerImageCode.fromImageAsset(path.join(__dirname, '../assets/lambda/code/scan'), {
buildArgs: {
// Only force update the docker layer cache once a day
CACHE_DATE: new Date().toDateString(),
},
extraHash: Date.now().toString(),
}),
onSuccess: this.resultDest,
onFailure: this.errorDest,
filesystem: aws_lambda_1.FileSystem.fromEfsAccessPoint(lambda_ap, this._efsMountPath),
vpc: vpc,
vpcSubnets: { subnets: vpc.isolatedSubnets },
allowAllOutbound: false,
timeout: props.scanFunctionTimeout ?? aws_cdk_lib_1.Duration.minutes(15),
memorySize: props.scanFunctionMemorySize ?? 10240,
reservedConcurrentExecutions: props.reservedConcurrency,
environment: {
EFS_MOUNT_PATH: this._efsMountPath,
EFS_DEF_PATH: this._efsDefsPath,
DEFS_URL: defs_bucket.virtualHostedUrlForObject(),
POWERTOOLS_METRICS_NAMESPACE: 'serverless-clamscan',
POWERTOOLS_SERVICE_NAME: 'virus-scan',
},
});
this._scanFunction.connections.allowToAnyIpv4(aws_ec2_1.Port.tcp(443), 'Allow outbound HTTPS traffic for S3 access.');
defs_bucket.grantRead(this._scanFunction);
const download_defs = new aws_lambda_1.DockerImageFunction(this, 'DownloadDefs', {
code: aws_lambda_1.DockerImageCode.fromImageAsset(path.join(__dirname, '../assets/lambda/code/download_defs'), {
buildArgs: {
// Only force update the docker layer cache once a day
CACHE_DATE: new Date().toDateString(),
},
extraHash: Date.now().toString(),
}),
timeout: aws_cdk_lib_1.Duration.minutes(5),
memorySize: 1024,
environment: {
DEFS_BUCKET: defs_bucket.bucketName,
POWERTOOLS_SERVICE_NAME: 'freshclam-update',
},
});
const stack = aws_cdk_lib_1.Stack.of(this);
if (download_defs.role) {
const download_defs_role = `arn:${stack.partition}:sts::${stack.account}:assumed-role/${download_defs.role.roleName}/${download_defs.functionName}`;
const download_defs_assumed_principal = new aws_iam_1.ArnPrincipal(download_defs_role);
defs_bucket.addToResourcePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.DENY,
actions: ['s3:PutObject*'],
resources: [defs_bucket.arnForObjects('*')],
notPrincipals: [download_defs.role, download_defs_assumed_principal],
}));
defs_bucket.grantReadWrite(download_defs);
}
new aws_events_1.Rule(this, 'VirusDefsUpdateRule', {
schedule: aws_events_1.Schedule.rate(aws_cdk_lib_1.Duration.hours(12)),
targets: [new aws_events_targets_1.LambdaFunction(download_defs)],
});
const init_defs_cr = new aws_lambda_1.Function(this, 'InitDefs', {
runtime: aws_lambda_1.Runtime.PYTHON_3_9,
code: aws_lambda_1.Code.fromAsset(path.join(__dirname, '../assets/lambda/code/initialize_defs_cr')),
handler: 'lambda.lambda_handler',
timeout: aws_cdk_lib_1.Duration.minutes(5),
});
download_defs.grantInvoke(init_defs_cr);
new aws_cdk_lib_1.CustomResource(this, 'InitDefsCr', {
serviceToken: init_defs_cr.functionArn,
properties: {
FnName: download_defs.functionName,
},
});
if (props.buckets) {
props.buckets.forEach((bucket) => {
this.addSourceBucket(bucket);
});
}
}
/**
* @returns ArnPrincipal the ARN of the assumed role principal for the scan function
*/
get scanAssumedPrincipal() {
if (this._scanFunction.role) {
const stack = aws_cdk_lib_1.Stack.of(this);
const scan_assumed_role = `arn:${stack.partition}:sts::${stack.account}:assumed-role/${this._scanFunction.role.roleName}/${this._scanFunction.functionName}`;
return new aws_iam_1.ArnPrincipal(scan_assumed_role);
}
else {
throw new Error('The scan function role is undefined');
}
}
/**
* Returns the statement that should be added to the bucket policy
in order to prevent objects to be accessed when they are not clean
or there have been scanning errors: this policy should be added
manually if external buckets are passed to addSourceBucket()
* @param bucket The bucket which you need to protect with the policy
* @returns PolicyStatement the policy statement if available
*/
getPolicyStatementForBucket(bucket) {
if (this._scanFunction.role) {
const scan_assumed_principal = this.scanAssumedPrincipal;
return new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.DENY,
actions: ['s3:GetObject'],
resources: [bucket.arnForObjects('*')],
principals: [new aws_iam_1.AnyPrincipal()],
conditions: {
StringEquals: {
's3:ExistingObjectTag/scan-status': [
'IN PROGRESS',
'INFECTED',
'ERROR',
],
},
ArnNotEquals: {
'aws:PrincipalArn': [this._scanFunction.role.roleArn, scan_assumed_principal.arn],
},
},
});
}
else {
throw new Error("Can't generate a valid S3 bucket policy, the scan function role is undefined");
}
}
/**
* Sets the specified S3 Bucket as a s3:ObjectCreate* for the ClamAV function.
Grants the ClamAV function permissions to get and tag objects.
Adds a bucket policy to disallow GetObject operations on files that are tagged 'IN PROGRESS', 'INFECTED', or 'ERROR'.
* @param bucket The bucket to add the scanning bucket policy and s3:ObjectCreate* trigger to.
*/
addSourceBucket(bucket) {
bucket.addEventNotification(aws_s3_1.EventType.OBJECT_CREATED, new aws_s3_notifications_1.LambdaDestination(this._scanFunction));
bucket.grantRead(this._scanFunction);
this._scanFunction.addToRolePolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: ['s3:GetObjectTagging', 's3:GetObjectVersionTagging', 's3:PutObjectTagging', 's3:PutObjectVersionTagging'],
resources: [bucket.arnForObjects('*')],
}));
if (this._scanFunction.role) {
const scan_assumed_principal = this.scanAssumedPrincipal;
this._s3Gw.addToPolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: ['s3:GetObject*', 's3:GetBucket*', 's3:List*'],
resources: [bucket.bucketArn, bucket.arnForObjects('*')],
principals: [this._scanFunction.role, scan_assumed_principal],
}));
this._s3Gw.addToPolicy(new aws_iam_1.PolicyStatement({
effect: aws_iam_1.Effect.ALLOW,
actions: ['s3:GetObjectTagging', 's3:GetObjectVersionTagging', 's3:PutObjectTagging', 's3:PutObjectVersionTagging'],
resources: [bucket.arnForObjects('*')],
principals: [this._scanFunction.role, scan_assumed_principal],
}));
const result = bucket.addToResourcePolicy(this.getPolicyStatementForBucket(bucket));
if (!result.statementAdded && !this.useImportedBuckets) {
throw new Error('acceptResponsibilityForUsingImportedBucket must be set when adding an imported bucket. When using imported buckets the user is responsible for adding the required policy statement to the bucket policy: `getPolicyStatementForBucket()` can be used to retrieve the policy statement required by the solution');
}
}
}
}
exports.ServerlessClamscan = ServerlessClamscan;
_a = JSII_RTTI_SYMBOL_1;
ServerlessClamscan[_a] = { fqn: "cdk-serverless-clamscan.ServerlessClamscan", version: "2.12.1" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSxxRUFBcUU7QUFDckUsc0NBQXNDO0FBRXRDLDZCQUE2QjtBQUM3Qiw2Q0FHcUI7QUFDckIsaURBSzZCO0FBQzdCLGlEQUFtRztBQUNuRyx1REFBa0U7QUFDbEUsdUVBQWdFO0FBQ2hFLGlEQUk2QjtBQUM3Qix1REFPZ0M7QUFDaEMsaUZBRzZDO0FBQzdDLCtDQUFtRztBQUNuRywyRUFBcUU7QUFDckUsaURBQTZEO0FBRTdELDJDQUF1QztBQThFdkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWlDRztBQUNILE1BQWEsa0JBQW1CLFNBQVEsc0JBQVM7SUFvRC9DOzs7OztPQUtHO0lBQ0gsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUE4QjtRQUN0RSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBWFgsaUJBQVksR0FBRyxTQUFTLENBQUM7UUFDekIsa0JBQWEsR0FBRyxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztRQUMzQyxpQkFBWSxHQUFHLGlCQUFpQixDQUFDO1FBV3ZDLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxLQUFLLENBQUMsMENBQTBDLENBQUM7UUFFM0UsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNwQixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUkscUJBQVEsQ0FBQyxJQUFJLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDckQsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLGdEQUFzQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUM3RCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksaUJBQUksQ0FBQyxJQUFJLEVBQUUsY0FBYyxFQUFFO2dCQUNqRCxRQUFRLEVBQUUsSUFBSSxDQUFDLFNBQVM7Z0JBQ3hCLFdBQVcs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QUUsQ0FBQyxxQkFBcUIsRUFBRSw0QkFBNEIsRUFBRSxxQkFBcUIsRUFBRSw0QkFBNEIsQ0FBQztnQkFDbkgsU0FBUyxFQUFFLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDdEMsVUFBVSxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLEVBQUUsc0JBQXNCLENBQUM7YUFDOUQsQ0FBQyxDQUNILENBQUM7WUFFRixNQUFNLE1BQU0sR0FBOEIsTUFBTSxDQUFDLG1CQUFtQixDQUNsRSxJQUFJLENBQUMsMkJBQTJCLENBQUMsTUFBTSxDQUFDLENBQ3pDLENBQUM7WUFFRixJQUFJLENBQUMsTUFBTSxDQUFDLGNBQWMsSUFBSSxDQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO2dCQUN2RCxNQUFNLElBQUksS0FBSyxDQUFDLGlUQUFpVCxDQUFDLENBQUM7WUFDclUsQ0FBQztRQUNILENBQUM7SUFDSCxDQUFDOztBQTdjSCxnREE4Y0MiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgQW1hem9uLmNvbSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cbi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wXG5cbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQge1xuICBDdXN0b21SZXNvdXJjZSwgRHVyYXRpb24sIFJlbW92YWxQb2xpY3ksXG4gIFN0YWNrLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQge1xuICBHYXRld2F5VnBjRW5kcG9pbnQsXG4gIEdhdGV3YXlWcGNFbmRwb2ludEF3c1NlcnZpY2UsXG4gIFBvcnQsXG4gIFNlY3VyaXR5R3JvdXAsIFN1Ym5ldFR5cGUsIFZwYyxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWVjMic7XG5pbXBvcnQgeyBGaWxlU3lzdGVtLCBMaWZlY3ljbGVQb2xpY3ksIFBlcmZvcm1hbmNlTW9kZSwgVGhyb3VnaHB1dE1vZGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWZzJztcbmltcG9ydCB7IEV2ZW50QnVzLCBSdWxlLCBTY2hlZHVsZSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1ldmVudHMnO1xuaW1wb3J0IHsgTGFtYmRhRnVuY3Rpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZXZlbnRzLXRhcmdldHMnO1xuaW1wb3J0IHtcbiAgQWNjb3VudFJvb3RQcmluY2lwYWwsXG4gIEFkZFRvUmVzb3VyY2VQb2xpY3lSZXN1bHQsIEFueVByaW5jaXBhbCwgQXJuUHJpbmNpcGFsLCBFZmZlY3QsXG4gIFBvbGljeVN0YXRlbWVudCxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQge1xuICBDb2RlLCBEb2NrZXJJbWFnZUNvZGUsXG4gIERvY2tlckltYWdlRnVuY3Rpb24sXG4gIEZ1bmN0aW9uLFxuICBJRGVzdGluYXRpb24sXG4gIEZpbGVTeXN0ZW0gYXMgTGFtYmRhRmlsZVN5c3RlbSxcbiAgUnVudGltZSxcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQge1xuICBFdmVudEJyaWRnZURlc3RpbmF0aW9uLFxuICBTcXNEZXN0aW5hdGlvbixcbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYS1kZXN0aW5hdGlvbnMnO1xuaW1wb3J0IHsgQnVja2V0LCBCdWNrZXRFbmNyeXB0aW9uLCBFdmVudFR5cGUsIElCdWNrZXQsIE9iamVjdE93bmVyc2hpcCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBMYW1iZGFEZXN0aW5hdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMy1ub3RpZmljYXRpb25zJztcbmltcG9ydCB7IFF1ZXVlLCBRdWV1ZUVuY3J5cHRpb24gfSBmcm9tICdhd3MtY2RrLWxpYi9hd3Mtc3FzJztcbmltcG9ydCB7IFNpemUgfSBmcm9tICdhd3MtY2RrLWxpYi9jb3JlJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG4vKipcbiAqIEludGVyZmFjZSBmb3IgU2VydmVybGVzc0NsYW1zY2FuIFZpcnVzIERlZmluaXRpb25zIFMzIEJ1Y2tldCBMb2dnaW5nLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFNlcnZlcmxlc3NDbGFtc2NhbkxvZ2dpbmdQcm9wcyB7XG4gIC8qKlxuICAgKiBEZXN0aW5hdGlvbiBidWNrZXQgZm9yIHRoZSBzZXJ2ZXIgYWNjZXNzIGxvZ3MgKERlZmF1bHQ6IENyZWF0ZXMgYSBuZXcgUzMgQnVja2V0IGZvciBhY2Nlc3MgbG9ncykuXG4gICAqL1xuICByZWFkb25seSBsb2dzQnVja2V0PzogYm9vbGVhbiB8IElCdWNrZXQ7XG4gIC8qKlxuICAgKiBPcHRpb25hbCBsb2cgZmlsZSBwcmVmaXggdG8gdXNlIGZvciB0aGUgYnVja2V0J3MgYWNjZXNzIGxvZ3MsIG9wdGlvbiBpcyBpZ25vcmVkIGlmIGxvZ3NfYnVja2V0IGlzIHNldCB0byBmYWxzZS5cbiAgICovXG4gIHJlYWRvbmx5IGxvZ3NQcmVmaXg/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogSW50ZXJmYWNlIGZvciBjcmVhdGluZyBhIFNlcnZlcmxlc3NDbGFtc2Nhbi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBTZXJ2ZXJsZXNzQ2xhbXNjYW5Qcm9wcyB7XG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCBsaXN0IG9mIFMzIGJ1Y2tldHMgdG8gY29uZmlndXJlIGZvciBDbGFtQVYgVmlydXMgU2Nhbm5pbmc7IGJ1Y2tldHMgY2FuIGJlIGFkZGVkIGxhdGVyIGJ5IGNhbGxpbmcgYWRkU291cmNlQnVja2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0cz86IElCdWNrZXRbXTtcbiAgLyoqXG4gICAqIE9wdGlvbmFsbHkgc2V0IGEgcmVzZXJ2ZWQgY29uY3VycmVuY3kgZm9yIHRoZSB2aXJ1cyBzY2FubmluZyBMYW1iZGEuXG4gICAqIEBzZWUgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL2xhbWJkYS9sYXRlc3Qvb3BlcmF0b3JndWlkZS9yZXNlcnZlZC1jb25jdXJyZW5jeS5odG1sXG4gICAqL1xuICByZWFkb25seSByZXNlcnZlZENvbmN1cnJlbmN5PzogbnVtYmVyO1xuICAvKipcbiAgICogT3B0aW9uYWxseSBzZXQgdGhlIG1lbW9yeSBhbGxvY2F0aW9uIGZvciB0aGUgc2NhbiBmdW5jdGlvbi4gTm90ZSB0aGF0IGxvdyBtZW1vcnkgYWxsb2NhdGlvbnMgbWF5IGNhdXNlIGVycm9ycy4gKERlZmF1bHQ6IDEwMjQwKS5cbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2xhdGVzdC9vcGVyYXRvcmd1aWRlL2NvbXB1dGluZy1wb3dlci5odG1sXG4gICAqL1xuICByZWFkb25seSBzY2FuRnVuY3Rpb25NZW1vcnlTaXplPzogbnVtYmVyO1xuICAvKipcbiAgICogT3B0aW9uYWxseSBzZXQgdGhlIHRpbWVvdXQgZm9yIHRoZSBzY2FuIGZ1bmN0aW9uLiAoRGVmYXVsdDogMTUgbWludXRlcykuXG4gICAqL1xuICByZWFkb25seSBzY2FuRnVuY3Rpb25UaW1lb3V0PzogRHVyYXRpb247XG4gIC8qKlxuICAgKiBUaGUgTGFtYmRhIERlc3RpbmF0aW9uIGZvciBmaWxlcyBtYXJrZWQgJ0NMRUFOJyBvciAnSU5GRUNURUQnIGJhc2VkIG9uIHRoZSBDbGFtQVYgVmlydXMgc2NhbiBvciAnTi9BJyBmb3Igc2NhbnMgdHJpZ2dlcmVkIGJ5IFMzIGZvbGRlciBjcmVhdGlvbiBldmVudHMgbWFya2VkIChEZWZhdWx0OiBDcmVhdGVzIGFuZCBwdWJsaXNoZXMgdG8gYSBuZXcgRXZlbnQgQnJpZGdlIEJ1cyBpZiB1bnNwZWNpZmllZCkuXG4gICAqL1xuICByZWFkb25seSBvblJlc3VsdD86IElEZXN0aW5hdGlvbjtcbiAgLyoqXG4gICAqIFRoZSBMYW1iZGEgRGVzdGluYXRpb24gZm9yIGZpbGVzIHRoYXQgZmFpbCB0byBzY2FuIGFuZCBhcmUgbWFya2VkICdFUlJPUicgb3Igc3R1Y2sgJ0lOIFBST0dSRVNTJyBkdWUgdG8gYSBMYW1iZGEgdGltZW91dCAoRGVmYXVsdDogQ3JlYXRlcyBhbmQgcHVibGlzaGVzIHRvIGEgbmV3IFNRUyBxdWV1ZSBpZiB1bnNwZWNpZmllZCkuXG4gICAqL1xuICByZWFkb25seSBvbkVycm9yPzogSURlc3RpbmF0aW9uO1xuICAvKipcbiAgICogV2hldGhlciBvciBub3QgdG8gZW5hYmxlIGVuY3J5cHRpb24gb24gRUZTIGZpbGVzeXN0ZW0gKERlZmF1bHQ6IGVuYWJsZWQpLlxuICAgKi9cbiAgcmVhZG9ubHkgZWZzRW5jcnlwdGlvbj86IGJvb2xlYW47XG4gIC8qKlxuICAgKiBTZXQgdGhlIHBlcmZvcm1hbmNlIG1vZGUgb2YgdGhlIEVGUyBmaWxlIHN5c3RlbSAoRGVmYXVsdDogR0VORVJBTF9QVVJQT1NFKS5cbiAgICovXG4gIHJlYWRvbmx5IGVmc1BlcmZvcm1hbmNlTW9kZT86IFBlcmZvcm1hbmNlTW9kZTtcbiAgLyoqXG4gICAqIFNldCB0aGUgdGhyb3VnaHB1dCBtb2RlIG9mIHRoZSBFRlMgZmlsZSBzeXN0ZW0gKERlZmF1bHQ6IEJVUlNUSU5HKS5cbiAgICovXG4gIHJlYWRvbmx5IGVmc1Rocm91Z2hwdXRNb2RlPzogVGhyb3VnaHB1dE1vZGU7XG4gIC8qKlxuICAgKiBQcm92aXNpb25lZCB0aHJvdWdocHV0IGZvciB0aGUgRUZTIGZpbGUgc3lzdGVtLiBUaGlzIGlzIGEgcmVxdWlyZWQgcHJvcGVydHkgaWYgdGhlIHRocm91Z2hwdXQgbW9kZSBpcyBzZXQgdG8gUFJPVklTSU9ORUQuIE11c3QgYmUgYXQgbGVhc3QgMU1pQi9zIChEZWZhdWx0OiBub25lKS5cbiAgICovXG4gIHJlYWRvbmx5IGVmc1Byb3Zpc2lvbmVkVGhyb3VnaHB1dFBlclNlY29uZD86IFNpemU7XG4gIC8qKlxuICAgKiBXaGV0aGVyIG9yIG5vdCB0byBlbmFibGUgQWNjZXNzIExvZ2dpbmcgZm9yIHRoZSBWaXJ1cyBEZWZpbml0aW9ucyBidWNrZXQsIHlvdSBjYW4gc3BlY2lmeSBhbiBleGlzdGluZyBidWNrZXQgYW5kIHByZWZpeCAoRGVmYXVsdDogQ3JlYXRlcyBhIG5ldyBTMyBCdWNrZXQgZm9yIGFjY2VzcyBsb2dzKS5cbiAgICovXG4gIHJlYWRvbmx5IGRlZnNCdWNrZXRBY2Nlc3NMb2dzQ29uZmlnPzogU2VydmVybGVzc0NsYW1zY2FuTG9nZ2luZ1Byb3BzO1xuICAvKipcbiAgICogQWxsb3dzIHRoZSB1c2Ugb2YgaW1wb3J0ZWQgYnVja2V0cy4gV2hlbiB1c2luZyBpbXBvcnRlZCBidWNrZXRzIHRoZSB1c2VyIGlzIHJlc3BvbnNpYmxlIGZvciBhZGRpbmcgdGhlIHJlcXVpcmVkIHBvbGljeSBzdGF0ZW1lbnQgdG8gdGhlIGJ1Y2tldCBwb2xpY3k6IGBnZXRQb2xpY3lTdGF0ZW1lbnRGb3JCdWNrZXQoKWAgY2FuIGJlIHVzZWQgdG8gcmV0cmlldmUgdGhlIHBvbGljeSBzdGF0ZW1lbnQgcmVxdWlyZWQgYnkgdGhlIHNvbHV0aW9uLlxuICAgKi9cbiAgcmVhZG9ubHkgYWNjZXB0UmVzcG9uc2liaWxpdHlGb3JVc2luZ0ltcG9ydGVkQnVja2V0PzogYm9vbGVhbjtcbiAgLyoqXG4gICAqIEFsbG93IGZvciBub24tcm9vdCB1c2VycyB0byBtb2RpZnkvZGVsZXRlIHRoZSBidWNrZXQgcG9saWN5IG9uIHRoZSBWaXJ1cyBEZWZpbml0aW9ucyBidWNrZXQuXG4gICAqIFdhcm5pbmc6IGNoYW5naW5nIHRoaXMgZmxhZyBmcm9tICdmYWxzZScgdG8gJ3RydWUnIG9uIGV4aXN0aW5nIGRlcGxveW1lbnRzIHdpbGwgY2F1c2UgdXBkYXRlcyB0byBmYWlsLlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgZGVmc0J1Y2tldEFsbG93UG9saWN5TXV0YXRpb24/OiBib29sZWFuO1xufVxuXG4vKipcbiAgQW4gW2F3cy1jZGtdKGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkaykgY29uc3RydWN0IHRoYXQgdXNlcyBbQ2xhbUFWwq5dKGh0dHBzOi8vd3d3LmNsYW1hdi5uZXQvKS5cbiAgdG8gc2NhbiBvYmplY3RzIGluIEFtYXpvbiBTMyBmb3IgdmlydXNlcy4gVGhlIGNvbnN0cnVjdCBwcm92aWRlcyBhIGZsZXhpYmxlIGludGVyZmFjZSBmb3IgYSBzeXN0ZW1cbiAgdG8gYWN0IGJhc2VkIG9uIHRoZSByZXN1bHRzIG9mIGEgQ2xhbUFWIHZpcnVzIHNjYW4uXG5cbiAgVGhlIGNvbnN0cnVjdCBjcmVhdGVzIGEgTGFtYmRhIGZ1bmN0aW9uIHdpdGggRUZTIGludGVncmF0aW9uIHRvIHN1cHBvcnQgbGFyZ2VyIGZpbGVzLlxuICBBIFZQQyB3aXRoIGlzb2xhdGVkIHN1Ym5ldHMsIGEgUzMgR2F0ZXdheSBlbmRwb2ludCB3aWxsIGFsc28gYmUgY3JlYXRlZC5cblxuICBBZGRpdGlvbmFsbHkgY3JlYXRlcyBhbiB0d2ljZS1kYWlseSBqb2IgdG8gZG93bmxvYWQgdGhlIGxhdGVzdCBDbGFtQVYgZGVmaW5pdGlvbiBmaWxlcyB0byB0aGVcbiAgVmlydXMgRGVmaW5pdGlvbnMgUzMgQnVja2V0IGJ5IHV0aWxpemluZyBhbiBFdmVudEJyaWRnZSBydWxlIGFuZCBhIExhbWJkYSBmdW5jdGlvbiBhbmRcbiAgcHVibGlzaGVzIENsb3VkV2F0Y2ggTWV0cmljcyB0byB0aGUgJ3NlcnZlcmxlc3MtY2xhbXNjYW4nIG5hbWVzcGFjZS5cblxuICBfX0ltcG9ydGFudCBPJk1fXzpcbiAgV2hlbiBDbGFtQVYgcHVibGlzaGVzIHVwZGF0ZXMgdG8gdGhlIHNjYW5uZXIgeW91IHdpbGwgc2VlIOKAnFlvdXIgQ2xhbUFWIGluc3RhbGxhdGlvbiBpcyBPVVREQVRFROKAnSBpbiB5b3VyIHNjYW4gcmVzdWx0cy5cbiAgV2hpbGUgdGhlIGNvbnN0cnVjdCBjcmVhdGVzIGEgc3lzdGVtIHRvIGtlZXAgdGhlIGRhdGFiYXNlIGRlZmluaXRpb25zIHVwIHRvIGRhdGUsIHlvdSBtdXN0IHVwZGF0ZSB0aGUgc2Nhbm5lciB0b1xuICBkZXRlY3QgYWxsIHRoZSBsYXRlc3QgVmlydXNlcy5cblxuICBVcGRhdGUgdGhlIGRvY2tlciBpbWFnZXMgb2YgdGhlIExhbWJkYSBmdW5jdGlvbnMgd2l0aCB0aGUgbGF0ZXN0IHZlcnNpb24gb2YgQ2xhbUFWIGJ5IHJlLXJ1bm5pbmcgYGNkayBkZXBsb3lgLlxuXG4gIFN1Y2Nlc3NmdWwgU2NhbiBFdmVudCBmb3JtYXRcbiAgYGBganNvblxuICB7XG4gICAgIFwic291cmNlXCI6IFwic2VydmVybGVzcy1jbGFtc2NhblwiLFxuICAgICBcImlucHV0X2J1Y2tldFwiOiA8aW5wdXRfYnVja2V0X25hbWU+LFxuICAgICBcImlucHV0X2tleVwiOiA8b2JqZWN0X2tleT4sXG4gICAgIFwic3RhdHVzXCI6IDxcIkNMRUFOXCJ8XCJJTkZFQ1RFRFwifFwiTi9BXCI+LFxuICAgICBcIm1lc3NhZ2VcIjogPHNjYW5fc3VtbWFyeT4sXG4gICB9XG4gIGBgYFxuXG4gIE5vdGU6IFRoZSBWaXJ1cyBEZWZpbml0aW9ucyBidWNrZXQgcG9saWN5IHdpbGwgbGlrZWx5IGNhdXNlIGEgZGVsZXRpb24gZXJyb3IgaWYgeW91IGNob29zZSB0byBkZWxldGVcbiAgdGhlIHN0YWNrIGFzc29jaWF0ZWQgaW4gdGhlIGNvbnN0cnVjdC4gSG93ZXZlciBzaW5jZSB0aGUgYnVja2V0IGl0c2VsZiBnZXRzIGRlbGV0ZWQsIHlvdSBjYW4gZGVsZXRlXG4gIHRoZSBzdGFjayBhZ2FpbiB0byByZXNvbHZlIHRoZSBlcnJvci5cbiAqL1xuZXhwb3J0IGNsYXNzIFNlcnZlcmxlc3NDbGFtc2NhbiBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgIFRoZSBMYW1iZGEgRGVzdGluYXRpb24gZm9yIGZhaWxlZCBvbiBlcnJlZCBzY2FucyBbRVJST1IsIElOIFBST0dSRVNTIChJZiBlcnJvciBpcyBkdWUgdG8gTGFtYmRhIHRpbWVvdXQpXS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBlcnJvckRlc3Q6IElEZXN0aW5hdGlvbjtcblxuICAvKipcbiAgICBUaGUgTGFtYmRhIERlc3RpbmF0aW9uIGZvciBjb21wbGV0ZWQgQ2xhbUFWIHNjYW5zIFtDTEVBTiwgSU5GRUNURURdLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJlc3VsdERlc3Q6IElEZXN0aW5hdGlvbjtcblxuICAvKipcbiAgICBDb25kaXRpb25hbDogVGhlIFNRUyBRdWV1ZSBmb3IgZXJyZWQgc2NhbnMgaWYgYSBmYWlsdXJlIChvbkVycm9yKSBkZXN0aW5hdGlvbiB3YXMgbm90IHNwZWNpZmllZC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBlcnJvclF1ZXVlPzogUXVldWU7XG5cbiAgLyoqXG4gICAgQ29uZGl0aW9uYWw6IFRoZSBTUVMgRGVhZCBMZXR0ZXIgUXVldWUgZm9yIHRoZSBlcnJvclF1ZXVlIGlmIGEgZmFpbHVyZSAob25FcnJvcikgZGVzdGluYXRpb24gd2FzIG5vdCBzcGVjaWZpZWQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZXJyb3JEZWFkTGV0dGVyUXVldWU/OiBRdWV1ZTtcblxuICAvKipcbiAgICBDb25kaXRpb25hbDogVGhlIEV2ZW50IEJyaWRnZSBCdXMgZm9yIGNvbXBsZXRlZCBDbGFtQVYgc2NhbnMgaWYgYSBzdWNjZXNzIChvblJlc3VsdCkgZGVzdGluYXRpb24gd2FzIG5vdCBzcGVjaWZpZWQuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVzdWx0QnVzPzogRXZlbnRCdXM7XG5cbiAgLyoqXG4gICAgQ29uZGl0aW9uYWw6IEFuIEV2ZW50IEJyaWRnZSBSdWxlIGZvciBmaWxlcyB0aGF0IGFyZSBtYXJrZWQgJ0NMRUFOJyBieSBDbGFtQVYgaWYgYSBzdWNjZXNzIGRlc3RpbmF0aW9uIHdhcyBub3Qgc3BlY2lmaWVkLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGNsZWFuUnVsZT86IFJ1bGU7XG5cbiAgLyoqXG4gICAgQ29uZGl0aW9uYWw6IEFuIEV2ZW50IEJyaWRnZSBSdWxlIGZvciBmaWxlcyB0aGF0IGFyZSBtYXJrZWQgJ0lORkVDVEVEJyBieSBDbGFtQVYgaWYgYSBzdWNjZXNzIGRlc3RpbmF0aW9uIHdhcyBub3Qgc3BlY2lmaWVkLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGluZmVjdGVkUnVsZT86IFJ1bGU7XG5cbiAgLyoqXG4gICAgQ29uZGl0aW9uYWw6IFRoZSBCdWNrZXQgZm9yIGFjY2VzcyBsb2dzIGZvciB0aGUgdmlydXMgZGVmaW5pdGlvbnMgYnVja2V0IGlmIGxvZ2dpbmcgaXMgZW5hYmxlZCAoZGVmc0J1Y2tldEFjY2Vzc0xvZ3NDb25maWcpLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGRlZnNBY2Nlc3NMb2dzQnVja2V0PzogSUJ1Y2tldDtcblxuICAvKipcbiAgICBDb25kaXRpb25hbDogV2hlbiB0cnVlLCB0aGUgdXNlciBhY2NlcHRlZCB0aGUgcmVzcG9uc2liaWxpdHkgZm9yIHVzaW5nIGltcG9ydGVkIGJ1Y2tldHMuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdXNlSW1wb3J0ZWRCdWNrZXRzPzogYm9vbGVhbjtcblxuICBwcml2YXRlIF9zY2FuRnVuY3Rpb246IERvY2tlckltYWdlRnVuY3Rpb247XG4gIHByaXZhdGUgX3MzR3c6IEdhdGV3YXlWcGNFbmRwb2ludDtcbiAgcHJpdmF0ZSBfZWZzUm9vdFBhdGggPSAnL2xhbWJkYSc7XG4gIHByaXZhdGUgX2Vmc01vdW50UGF0aCA9IGAvbW50JHt0aGlzLl9lZnNSb290UGF0aH1gO1xuICBwcml2YXRlIF9lZnNEZWZzUGF0aCA9ICd2aXJ1c19kYXRhYmFzZS8nO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgU2VydmVybGVzc0NsYW1zY2FuIGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIHNjb3BlIFRoZSBwYXJlbnQgY3JlYXRpbmcgY29uc3RydWN0ICh1c3VhbGx5IGB0aGlzYCkuXG4gICAqIEBwYXJhbSBpZCBUaGUgY29uc3RydWN0J3MgbmFtZS5cbiAgICogQHBhcmFtIHByb3BzIEEgYFNlcnZlcmxlc3NDbGFtc2NhblByb3BzYCBpbnRlcmZhY2UuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogU2VydmVybGVzc0NsYW1zY2FuUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdGhpcy51c2VJbXBvcnRlZEJ1Y2tldHMgPSBwcm9wcy5hY2NlcHRSZXNwb25zaWJpbGl0eUZvclVzaW5nSW1wb3J0ZWRCdWNrZXQ7XG5cbiAgICBpZiAoIXByb3BzLm9uUmVzdWx0KSB7XG4gICAgICB0aGlzLnJlc3VsdEJ1cyA9IG5ldyBFdmVudEJ1cyh0aGlzLCAnU2NhblJlc3VsdEJ1cycpO1xuICAgICAgdGhpcy5yZXN1bHREZXN0ID0gbmV3IEV2ZW50QnJpZGdlRGVzdGluYXRpb24odGhpcy5yZXN1bHRCdXMpO1xuICAgICAgdGhpcy5pbmZlY3RlZFJ1bGUgPSBuZXcgUnVsZSh0aGlzLCAnSW5mZWN0ZWRSdWxlJywge1xuICAgICAgICBldmVudEJ1czogdGhpcy5yZXN1bHRCdXMsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRXZlbnQgZm9yIHdoZW4gYSBmaWxlIGlzIG1hcmtlZCBJTkZFQ1RFRCcsXG4gICAgICAgIGV2ZW50UGF0dGVybjoge1xuICAgICAgICAgIGRldGFpbDoge1xuICAgICAgICAgICAgcmVzcG9uc2VQYXlsb2FkOiB7XG4gICAgICAgICAgICAgIHNvdXJjZTogWydzZXJ2ZXJsZXNzLWNsYW1zY2FuJ10sXG4gICAgICAgICAgICAgIHN0YXR1czogWydJTkZFQ1RFRCddLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICB0aGlzLmNsZWFuUnVsZSA9IG5ldyBSdWxlKHRoaXMsICdDbGVhblJ1bGUnLCB7XG4gICAgICAgIGV2ZW50QnVzOiB0aGlzLnJlc3VsdEJ1cyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFdmVudCBmb3Igd2hlbiBhIGZpbGUgaXMgbWFya2VkIENMRUFOJyxcbiAgICAgICAgZXZlbnRQYXR0ZXJuOiB7XG4gICAgICAgICAgZGV0YWlsOiB7XG4gICAgICAgICAgICByZXNwb25zZVBheWxvYWQ6IHtcbiAgICAgICAgICAgICAgc291cmNlOiBbJ3NlcnZlcmxlc3MtY2xhbXNjYW4nXSxcbiAgICAgICAgICAgICAgc3RhdHVzOiBbJ0NMRUFOJ10sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5yZXN1bHREZXN0ID0gcHJvcHMub25SZXN1bHQ7XG4gICAgfVxuXG4gICAgaWYgKCFwcm9wcy5vbkVycm9yKSB7XG4gICAgICB0aGlzLmVycm9yRGVhZExldHRlclF1ZXVlID0gbmV3IFF1ZXVlKHRoaXMsICdTY2FuRXJyb3JEZWFkTGV0dGVyUXVldWUnLCB7XG4gICAgICAgIGVuY3J5cHRpb246IFF1ZXVlRW5jcnlwdGlvbi5LTVNfTUFOQUdFRCxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5lcnJvckRlYWRMZXR0ZXJRdWV1ZS5hZGRUb1Jlc291cmNlUG9saWN5KG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbJ3NxczoqJ10sXG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkRFTlksXG4gICAgICAgIHByaW5jaXBhbHM6IFtuZXcgQW55UHJpbmNpcGFsKCldLFxuICAgICAgICBjb25kaXRpb25zOiB7IEJvb2w6IHsgJ2F3czpTZWN1cmVUcmFuc3BvcnQnOiBmYWxzZSB9IH0sXG4gICAgICAgIHJlc291cmNlczogW3RoaXMuZXJyb3JEZWFkTGV0dGVyUXVldWUucXVldWVBcm5dLFxuICAgICAgfSkpO1xuICAgICAgdGhpcy5lcnJvclF1ZXVlID0gbmV3IFF1ZXVlKHRoaXMsICdTY2FuRXJyb3JRdWV1ZScsIHtcbiAgICAgICAgZW5jcnlwdGlvbjogUXVldWVFbmNyeXB0aW9uLktNU19NQU5BR0VELFxuICAgICAgICBkZWFkTGV0dGVyUXVldWU6IHtcbiAgICAgICAgICBtYXhSZWNlaXZlQ291bnQ6IDMsXG4gICAgICAgICAgcXVldWU6IHRoaXMuZXJyb3JEZWFkTGV0dGVyUXVldWUsXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIHRoaXMuZXJyb3JRdWV1ZS5hZGRUb1Jlc291cmNlUG9saWN5KG5ldyBQb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBhY3Rpb25zOiBbJ3NxczoqJ10sXG4gICAgICAgIGVmZmVjdDogRWZmZWN0LkRFTlksXG4gICAgICAgIHByaW5jaXBhbHM6IFtuZXcgQW55UHJpbmNpcGFsKCldLFxuICAgICAgICBjb25kaXRpb25zOiB7IEJvb2w6IHsgJ2F3czpTZWN1cmVUcmFuc3BvcnQnOiBmYWxzZSB9IH0sXG4gICAgICAgIHJlc291cmNlczogW3RoaXMuZXJyb3JRdWV1ZS5xdWV1ZUFybl0sXG4gICAgICB9KSk7XG4gICAgICB0aGlzLmVycm9yRGVzdCA9IG5ldyBTcXNEZXN0aW5hdGlvbih0aGlzLmVycm9yUXVldWUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmVycm9yRGVzdCA9IHByb3BzLm9uRXJyb3I7XG4gICAgfVxuXG4gICAgY29uc3QgdnBjID0gbmV3IFZwYyh0aGlzLCAnU2NhblZQQycsIHtcbiAgICAgIHN1Ym5ldENvbmZpZ3VyYXRpb246IFtcbiAgICAgICAge1xuICAgICAgICAgIHN1Ym5ldFR5cGU6IFN1Ym5ldFR5cGUuUFJJVkFURV9JU09MQVRFRCxcbiAgICAgICAgICBuYW1lOiAnSXNvbGF0ZWQnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIHZwYy5hZGRGbG93TG9nKCdGbG93TG9ncycpO1xuXG4gICAgdGhpcy5fczNHdyA9IHZwYy5hZGRHYXRld2F5RW5kcG9pbnQoJ1MzRW5kcG9pbnQnLCB7XG4gICAgICBzZXJ2aWNlOiBHYXRld2F5VnBjRW5kcG9pbnRBd3NTZXJ2aWNlLlMzLFxuICAgIH0pO1xuXG4gICAgY29uc3QgZmlsZVN5c3RlbSA9IG5ldyBGaWxlU3lzdGVtKHRoaXMsICdTY2FuRmlsZVN5c3RlbScsIHtcbiAgICAgIHZwYzogdnBjLFxuICAgICAgZW5jcnlwdGVkOiBwcm9wcy5lZnNFbmNyeXB0aW9uID09PSBmYWxzZSA/IGZhbHNlIDogdHJ1ZSxcbiAgICAgIGxpZmVjeWNsZVBvbGljeTogTGlmZWN5Y2xlUG9saWN5LkFGVEVSXzdfREFZUyxcbiAgICAgIHBlcmZvcm1hbmNlTW9kZTogcHJvcHMuZWZzUGVyZm9ybWFuY2VNb2RlID8/IFBlcmZvcm1hbmNlTW9kZS5HRU5FUkFMX1BVUlBPU0UsXG4gICAgICB0aHJv