@aws/cloudfront-hosting-toolkit
Version:
CloudFront Hosting Toolkit offers the convenience of a managed frontend hosting service while retaining full control over the hosting and deployment infrastructure to make it your own.
368 lines (365 loc) • 51.2 kB
JavaScript
"use strict";
/*
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.PipelineInfrastructure = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const helper_1 = require("../bin/cli/utils/helper");
const constructs_1 = require("constructs");
const yaml = __importStar(require("yaml"));
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const aws_codepipeline_actions_1 = require("aws-cdk-lib/aws-codepipeline-actions");
const aws_logs_1 = require("aws-cdk-lib/aws-logs");
const constants_1 = require("../bin/cli/shared/constants");
const cfn_nag_utils_1 = require("./cfn_nag/cfn_nag_utils");
const cdk_nag_1 = require("cdk-nag");
const deployment_workflow_sf_1 = require("./deployment_workflow_sf");
class PipelineInfrastructure extends constructs_1.Construct {
constructor(scope, id, params) {
super(scope, id);
var ssmCommitIdParam, ssmS3KeyParam;
if ((0, helper_1.isS3Config)(params.hostingConfiguration)) {
const ssmCommitId = `/hosting/${params.hostingConfiguration.s3bucket}/buildId`;
const ssmSrcKey = `/hosting/${params.hostingConfiguration.s3bucket}/s3key`;
ssmCommitIdParam = new aws_cdk_lib_1.aws_ssm.StringParameter(this, "CommitIdParam", {
parameterName: ssmCommitId,
stringValue: "init",
description: "Commit Id",
tier: aws_cdk_lib_1.aws_ssm.ParameterTier.STANDARD,
});
ssmS3KeyParam = new aws_cdk_lib_1.aws_ssm.StringParameter(this, "S3KeyParam", {
parameterName: ssmSrcKey,
stringValue: "init",
description: "S3 Key",
});
}
const deploymentWorkflowStepFunction = new deployment_workflow_sf_1.DeploymentWorkflowStepFunction(this, "UpdateCFF", {
changeUri: params.changeUri,
kvsArn: params.kvsArn,
hostingBucket: params.hostingBucket,
ssmCommitIdParam: ssmCommitIdParam,
ssmS3KeyParam: ssmS3KeyParam,
});
const sourceOutput = new aws_cdk_lib_1.aws_codepipeline.Artifact();
var pipelineName, buildName;
var dummySourceBucket;
var buildSrcBucket = null; // Initialize with null
var sourceAction;
var stepFunctionInput = {};
var codeBuildEnvVars;
var s3upload;
if ((0, helper_1.isRepoConfig)(params.hostingConfiguration)) {
s3upload = new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, "InitialPage", {
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(path.join(__dirname, "..", "resources/initial_repository"))],
destinationBucket: params.hostingBucket,
});
codeBuildEnvVars = {
DEST_BUCKET_NAME: { value: params.hostingBucket.bucketName },
};
const parsedUrl = (0, helper_1.parseRepositoryUrl)(params.hostingConfiguration.repoUrl);
const { repoOwner, repoName } = parsedUrl;
//the pipeline is triggered from code repository
pipelineName = `${repoOwner}-${repoName}-${params.hostingConfiguration.branchName}`;
pipelineName = (0, helper_1.cleanPipelineNameStr)(pipelineName);
buildName = "Build-And-Copy-to-S3-" + repoName;
buildName = (0, helper_1.cleanBuildNameStr)(buildName);
const sourceActionName = (0, helper_1.cleanActionNameStr)("GitHub-Source-" + repoName);
sourceAction = new aws_cdk_lib_1.aws_codepipeline_actions.CodeStarConnectionsSourceAction({
actionName: sourceActionName,
owner: repoOwner,
repo: repoName,
branch: params.hostingConfiguration.branchName,
output: sourceOutput,
connectionArn: params.connectionArn,
});
stepFunctionInput = { commitId: sourceAction.variables.commitId };
}
else if (params.hostingConfiguration.s3bucket) {
//the pipeline is triggered from s3 bucket
s3upload = new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, "InitialPage", {
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(path.join(__dirname, "..", "resources/initial_s3"))],
destinationBucket: params.hostingBucket,
});
pipelineName = params.hostingConfiguration.s3bucket;
pipelineName = (0, helper_1.cleanPipelineNameStr)(pipelineName);
buildName = "Unzip-And-Copy-to-S3";
const pipelineArn = `arn:aws:codepipeline:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:${pipelineName}`;
const cloudWatchPolicyStatement = new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
actions: [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
],
resources: ["arn:aws:logs:*:*:*"],
});
const paramPolicyStatement = new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
actions: ["ssm:PutParameter"],
resources: [
ssmCommitIdParam.parameterArn,
ssmS3KeyParam.parameterArn,
],
});
const pipelinePolicyStatement = new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
actions: ["codepipeline:StartPipelineExecution"],
resources: [pipelineArn],
});
buildSrcBucket = aws_cdk_lib_1.aws_s3.Bucket.fromBucketName(this, "BuildSrcBucket", params.hostingConfiguration.s3bucket);
buildSrcBucket.enableEventBridgeNotification();
const newBuild = new aws_cdk_lib_1.aws_lambda.Function(this, "NewBuildProcess", {
runtime: aws_cdk_lib_1.aws_lambda.Runtime.NODEJS_18_X,
code: aws_cdk_lib_1.aws_lambda.Code.fromAsset(path.join(__dirname, "../lambda/new_build")),
handler: "index.handler",
environment: {
SSM_PARAM_COMMITID: ssmCommitIdParam.parameterName,
SSM_PARAM_S3_KEY: ssmS3KeyParam === null || ssmS3KeyParam === void 0 ? void 0 : ssmS3KeyParam.parameterName,
PIPELINE_NAME: pipelineName,
},
logRetention: aws_cdk_lib_1.aws_logs.RetentionDays.ONE_WEEK,
});
newBuild.addToRolePolicy(cloudWatchPolicyStatement);
newBuild.addToRolePolicy(paramPolicyStatement);
newBuild.addToRolePolicy(pipelinePolicyStatement);
const rule = new aws_cdk_lib_1.aws_events.Rule(this, "rule", {
eventPattern: {
source: ["aws.s3"],
detailType: ["Object Created"],
detail: {
bucket: {
name: [buildSrcBucket.bucketName],
},
object: {
key: [
{
prefix: params.hostingConfiguration.s3path + '/',
},
{
suffix: ".zip",
},
],
},
},
},
});
(0, cfn_nag_utils_1.addCfnSuppressRules)(newBuild, [
{
id: "W58",
reason: "Lambda has CloudWatch permissions by using service role AWSLambdaBasicExecutionRole",
},
]);
(0, cfn_nag_utils_1.addCfnSuppressRules)(newBuild, [
{
id: "W89",
reason: "We don t have any VPC in the stack, we only use serverless services",
},
]);
(0, cfn_nag_utils_1.addCfnSuppressRules)(newBuild, [
{
id: "W92",
reason: "No need for ReservedConcurrentExecutions, some are used only for the demo website, and others are not used in a concurrent mode.",
},
]);
rule.addTarget(new aws_cdk_lib_1.aws_events_targets.LambdaFunction(newBuild, {
maxEventAge: aws_cdk_lib_1.Duration.hours(1),
retryAttempts: 3,
}));
codeBuildEnvVars = {
DEST_BUCKET_NAME: { value: params.hostingBucket.bucketName },
SSM_PARAM_COMMITID: { value: ssmCommitIdParam.parameterName },
SSM_PARAM_S3_KEY: { value: ssmS3KeyParam === null || ssmS3KeyParam === void 0 ? void 0 : ssmS3KeyParam.parameterName },
SRC_BUCKET_NAME: { value: buildSrcBucket.bucketName },
};
dummySourceBucket = new aws_cdk_lib_1.aws_s3.Bucket(this, "DummySourceBucket", {
versioned: true,
encryption: aws_cdk_lib_1.aws_s3.BucketEncryption.S3_MANAGED,
blockPublicAccess: aws_cdk_lib_1.aws_s3.BlockPublicAccess.BLOCK_ALL,
autoDeleteObjects: true,
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
//encryption: s3.BucketEncryption.S3_MANAGED,
enforceSSL: true,
});
(0, cfn_nag_utils_1.addCfnSuppressRules)(dummySourceBucket, [
{
id: "W35",
reason: "The bucket has a deny all policy, so no access is allowed",
},
]);
new aws_cdk_lib_1.aws_s3_deployment.BucketDeployment(this, "DeployWebsite", {
sources: [aws_cdk_lib_1.aws_s3_deployment.Source.asset(path.join(__dirname, "..", "resources/s3_trigger"))],
destinationBucket: dummySourceBucket,
});
sourceAction = new aws_codepipeline_actions_1.S3SourceAction({
bucket: dummySourceBucket,
bucketKey: "dummy.zip",
output: sourceOutput,
actionName: "Dummy-S3-Source",
trigger: aws_codepipeline_actions_1.S3Trigger.EVENTS,
});
}
else {
console.log("Missing required information. Exit.");
process.exit(1);
}
const artifactBucket = new aws_cdk_lib_1.aws_s3.Bucket(this, "ArtifactBucket", {
encryption: aws_cdk_lib_1.aws_s3.BucketEncryption.S3_MANAGED,
blockPublicAccess: aws_cdk_lib_1.aws_s3.BlockPublicAccess.BLOCK_ALL,
autoDeleteObjects: true,
removalPolicy: aws_cdk_lib_1.RemovalPolicy.DESTROY,
enforceSSL: true,
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(artifactBucket, [
{
id: "AwsSolutions-S1",
reason: "Bucket used by CodePipeline, no need for access logs.",
},
]);
const pipeline = new aws_cdk_lib_1.aws_codepipeline.Pipeline(this, "MyPipeline", {
artifactBucket: artifactBucket,
pipelineName: pipelineName,
crossAccountKeys: false,
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(pipeline, [
{
id: "AwsSolutions-S2",
reason: "Demonstrate a resource level suppression.",
},
]);
artifactBucket.addToResourcePolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
actions: ["s3:GetObject"],
resources: [`${artifactBucket.bucketArn}/*`],
principals: [new aws_cdk_lib_1.aws_iam.ArnPrincipal(pipeline.role.roleArn)],
}));
(0, cfn_nag_utils_1.addCfnSuppressRules)(artifactBucket, [
{
id: "W35",
reason: "The bucket can be read only by the pipeline",
},
]);
pipeline.node.addDependency(s3upload);
const stepFunctionAction = new aws_cdk_lib_1.aws_codepipeline_actions.StepFunctionInvokeAction({
actionName: "Invoke",
stateMachine: deploymentWorkflowStepFunction.stepFunction,
stateMachineInput: aws_cdk_lib_1.aws_codepipeline_actions.StateMachineInput.literal(stepFunctionInput),
});
const buildSpecObj = fs.readFileSync(params.buildFilePath, "utf8");
const buildSpecYaml = yaml.parse(buildSpecObj);
const codeBuildLogs = new aws_cdk_lib_1.aws_logs.LogGroup(this, `MyLogGroup`, {
retention: aws_logs_1.RetentionDays.ONE_WEEK,
});
const myCodeBuild = new aws_cdk_lib_1.aws_codebuild.PipelineProject(this, "Project", {
environment: {
buildImage: aws_cdk_lib_1.aws_codebuild.LinuxBuildImage.STANDARD_7_0,
computeType: aws_cdk_lib_1.aws_codebuild.ComputeType.MEDIUM,
},
buildSpec: aws_cdk_lib_1.aws_codebuild.BuildSpec.fromObject(buildSpecYaml),
environmentVariables: codeBuildEnvVars,
logging: {
cloudWatch: {
logGroup: codeBuildLogs,
},
},
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(myCodeBuild, [
{
id: "AwsSolutions-CB4",
reason: "Artifact bucket is using Server-side encryption with a master key managed by S3",
},
], true);
cdk_nag_1.NagSuppressions.addResourceSuppressions(myCodeBuild, [
{
id: "AwsSolutions-IAM5",
reason: "Read permissions for CodeBuild",
},
], true);
(0, cfn_nag_utils_1.addCfnSuppressRules)(codeBuildLogs, [
{
id: "W84",
reason: "CloudWatch log group is always encrypted by default.",
},
]);
if ((0, helper_1.isS3Config)(params.hostingConfiguration)) {
myCodeBuild.addToRolePolicy(new aws_cdk_lib_1.aws_iam.PolicyStatement({
effect: aws_cdk_lib_1.aws_iam.Effect.ALLOW,
actions: ["ssm:Describe*", "ssm:Get*", "ssm:List*"],
resources: [
ssmCommitIdParam.parameterArn,
ssmS3KeyParam.parameterArn,
],
}));
buildSrcBucket.grantRead(myCodeBuild);
}
const deploy = new aws_cdk_lib_1.aws_codepipeline_actions.CodeBuildAction({
actionName: buildName,
project: myCodeBuild,
input: sourceOutput,
runOrder: 2,
});
pipeline.addStage({
stageName: "Sources",
actions: [sourceAction],
});
pipeline.addStage({
stageName: "Build",
actions: [deploy],
});
params.hostingBucket.grantReadWrite(myCodeBuild);
params.hostingBucket.grantRead(myCodeBuild);
pipeline.addStage({
stageName: "ChangeUri",
actions: [stepFunctionAction],
});
cdk_nag_1.NagSuppressions.addResourceSuppressions(pipeline, [
{
id: "AwsSolutions-IAM5",
reason: "Read permissions for the Pipeline",
},
], true);
new aws_cdk_lib_1.CfnOutput(this, "PipelineName", {
value: pipeline.pipelineName,
});
const stackName = (0, helper_1.calculateMainStackName)(params.hostingConfiguration);
new aws_cdk_lib_1.aws_ssm.StringParameter(this, 'SSMPipelineName', {
parameterName: '/' + stackName + '/' + constants_1.SSM_PIPELINENAME_STR,
stringValue: pipeline.pipelineName
});
}
}
exports.PipelineInfrastructure = PipelineInfrastructure;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGlwZWxpbmVfaW5mcmFzdHJ1Y3R1cmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwaXBlbGluZV9pbmZyYXN0cnVjdHVyZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7O0dBY0c7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUgsNkNBb0JxQjtBQUVyQixvREFBNEs7QUFFNUssMkNBQXVDO0FBRXZDLDJDQUE2QjtBQUM3Qix1Q0FBeUI7QUFDekIsMkNBQTZCO0FBRTdCLG1GQUc4QztBQUM5QyxtREFBcUQ7QUFDckQsMkRBQW9GO0FBQ3BGLDJEQUE4RDtBQUM5RCxxQ0FBMEM7QUFDMUMscUVBQTBFO0FBZTFFLE1BQWEsc0JBQXVCLFNBQVEsc0JBQVM7SUFDbkQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxNQUFvQjtRQUM1RCxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLElBQUksZ0JBQWdCLEVBQUUsYUFBYSxDQUFDO1FBRXBDLElBQUcsSUFBQSxtQkFBVSxFQUFDLE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxFQUFDLENBQUM7WUFFMUMsTUFBTSxXQUFXLEdBQUcsWUFBWSxNQUFNLENBQUMsb0JBQW9CLENBQUMsUUFBUSxVQUFVLENBQUM7WUFDL0UsTUFBTSxTQUFTLEdBQUcsWUFBWSxNQUFNLENBQUMsb0JBQW9CLENBQUMsUUFBUSxRQUFRLENBQUM7WUFFM0UsZ0JBQWdCLEdBQUcsSUFBSSxxQkFBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUsZUFBZSxFQUFFO2dCQUNoRSxhQUFhLEVBQUUsV0FBVztnQkFDMUIsV0FBVyxFQUFFLE1BQU07Z0JBQ25CLFdBQVcsRUFBRSxXQUFXO2dCQUN4QixJQUFJLEVBQUUscUJBQUcsQ0FBQyxhQUFhLENBQUMsUUFBUTthQUNqQyxDQUFDLENBQUM7WUFFSCxhQUFhLEdBQUcsSUFBSSxxQkFBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLEVBQUUs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IENvcHlyaWdodCBBbWF6b24uY29tLCBJbmMuIG9yIGl0cyBhZmZpbGlhdGVzLiBBbGwgUmlnaHRzIFJlc2VydmVkLlxuICBcbiAgTGljZW5zZWQgdW5kZXIgdGhlIEFwYWNoZSBMaWNlbnNlLCBWZXJzaW9uIDIuMCAodGhlIFwiTGljZW5zZVwiKS5cbiAgWW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuICBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbiAgXG4gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbiAgXG4gIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbiAgZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gXCJBUyBJU1wiIEJBU0lTLFxuICBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbiAgU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuICBsaW1pdGF0aW9ucyB1bmRlciB0aGUgTGljZW5zZS5cbiAqL1xuXG5pbXBvcnQge1xuICBhd3Nfc3RlcGZ1bmN0aW9ucyBhcyBzZm4sXG4gIGF3c19zMyBhcyBzMyxcbiAgYXdzX2xvZ3MgYXMgbG9ncyxcbiAgYXdzX2NvZGVwaXBlbGluZSBhcyBjb2RlcGlwZWxpbmUsXG4gIGF3c19jb2RlYnVpbGQgYXMgY29kZWJ1aWxkLFxuICBhd3NfZXZlbnRzIGFzIGV2ZW50cyxcbiAgYXdzX2V2ZW50c190YXJnZXRzIGFzIHRhcmdldHMsXG4gIGF3c19jb2RlcGlwZWxpbmVfYWN0aW9ucyBhcyBjb2RlcGlwZWxpbmVfYWN0aW9ucyxcbiAgYXdzX3MzX2RlcGxveW1lbnQgYXMgczNkZXBsb3ksXG4gIGF3c19zM19ub3RpZmljYXRpb25zIGFzIHMzbixcbiAgYXdzX2lhbSBhcyBpYW0sXG4gIGF3c19sYW1iZGEgYXMgbGFtYmRhLFxuICBhd3Nfc3NtIGFzIHNzbSxcbiAgYXdzX2Nsb3VkZnJvbnQgYXMgY2xvdWRmcm9udCxcbiAgRHVyYXRpb24sXG4gIFJlbW92YWxQb2xpY3ksXG4gIEF3cywgICAgXG4gIFN0YWNrLFxuICBDZm5PdXRwdXQsXG59IGZyb20gXCJhd3MtY2RrLWxpYlwiO1xuXG5pbXBvcnQgeyBjYWxjdWxhdGVNYWluU3RhY2tOYW1lLCBjbGVhbkFjdGlvbk5hbWVTdHIsIGNsZWFuQnVpbGROYW1lU3RyLCBjbGVhblBpcGVsaW5lTmFtZVN0ciwgaXNSZXBvQ29uZmlnLCBpc1MzQ29uZmlnLCBwYXJzZVJlcG9zaXRvcnlVcmwgfSBmcm9tIFwiLi4vYmluL2NsaS91dGlscy9oZWxwZXJcIjtcblxuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSBcImNvbnN0cnVjdHNcIjtcbmltcG9ydCB7IElCdWNrZXQgfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLXMzXCI7XG5pbXBvcnQgKiBhcyB5YW1sIGZyb20gXCJ5YW1sXCI7XG5pbXBvcnQgKiBhcyBmcyBmcm9tIFwiZnNcIjtcbmltcG9ydCAqIGFzIHBhdGggZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IElBY3Rpb24gfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWNvZGVwaXBlbGluZVwiO1xuaW1wb3J0IHtcbiAgUzNTb3VyY2VBY3Rpb24sXG4gIFMzVHJpZ2dlcixcbn0gZnJvbSBcImF3cy1jZGstbGliL2F3cy1jb2RlcGlwZWxpbmUtYWN0aW9uc1wiO1xuaW1wb3J0IHsgUmV0ZW50aW9uRGF5cyB9IGZyb20gXCJhd3MtY2RrLWxpYi9hd3MtbG9nc1wiO1xuaW1wb3J0IHsgQlVJTERfRklMRV9OQU1FLCBTU01fUElQRUxJTkVOQU1FX1NUUiB9IGZyb20gXCIuLi9iaW4vY2xpL3NoYXJlZC9jb25zdGFudHNcIjtcbmltcG9ydCB7IGFkZENmblN1cHByZXNzUnVsZXMgfSBmcm9tIFwiLi9jZm5fbmFnL2Nmbl9uYWdfdXRpbHNcIjtcbmltcG9ydCB7IE5hZ1N1cHByZXNzaW9ucyB9IGZyb20gXCJjZGstbmFnXCI7XG5pbXBvcnQgeyBEZXBsb3ltZW50V29ya2Zsb3dTdGVwRnVuY3Rpb24gfSBmcm9tIFwiLi9kZXBsb3ltZW50X3dvcmtmbG93X3NmXCI7XG5pbXBvcnQgeyBIb3N0aW5nQ29uZmlndXJhdGlvbiB9IGZyb20gXCIuLi9iaW4vY2xpL3NoYXJlZC90eXBlc1wiO1xuaW1wb3J0IHsgTm9kZWpzRnVuY3Rpb24gfSBmcm9tIFwiYXdzLWNkay1saWIvYXdzLWxhbWJkYS1ub2RlanNcIjtcbmltcG9ydCB7IExheWVyVmVyc2lvbn0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5cblxuaW50ZXJmYWNlIElDb25maWdQcm9wcyB7XG4gIGhvc3RpbmdDb25maWd1cmF0aW9uOiBIb3N0aW5nQ29uZmlndXJhdGlvbjtcbiAgY29ubmVjdGlvbkFybj86IHN0cmluZztcbiAga3ZzQXJuOiBzdHJpbmc7XG4gIGhvc3RpbmdCdWNrZXQ6IElCdWNrZXQ7XG4gIGNoYW5nZVVyaTogY2xvdWRmcm9udC5GdW5jdGlvbjtcbiAgYnVpbGRGaWxlUGF0aDogc3RyaW5nXG59XG5cbmV4cG9ydCBjbGFzcyBQaXBlbGluZUluZnJhc3RydWN0dXJlIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcGFyYW1zOiBJQ29uZmlnUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgdmFyIHNzbUNvbW1pdElkUGFyYW0sIHNzbVMzS2V5UGFyYW07XG5cbiAgICBpZihpc1MzQ29uZmlnKHBhcmFtcy5ob3N0aW5nQ29uZmlndXJhdGlvbikpe1xuICAgIFxuICAgICAgY29uc3Qgc3NtQ29tbWl0SWQgPSBgL2hvc3RpbmcvJHtwYXJhbXMuaG9zdGluZ0NvbmZpZ3VyYXRpb24uczNidWNrZXR9L2J1aWxkSWRgO1xuICAgICAgY29uc3Qgc3NtU3JjS2V5ID0gYC9ob3N0aW5nLyR7cGFyYW1zLmhvc3RpbmdDb25maWd1cmF0aW9uLnMzYnVja2V0fS9zM2tleWA7XG5cbiAgICAgIHNzbUNvbW1pdElkUGFyYW0gPSBuZXcgc3NtLlN0cmluZ1BhcmFtZXRlcih0aGlzLCBcIkNvbW1pdElkUGFyYW1cIiwge1xuICAgICAgICBwYXJhbWV0ZXJOYW1lOiBzc21Db21taXRJZCxcbiAgICAgICAgc3RyaW5nVmFsdWU6IFwiaW5pdFwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJDb21taXQgSWRcIixcbiAgICAgICAgdGllcjogc3NtLlBhcmFtZXRlclRpZXIuU1RBTkRBUkQsXG4gICAgICB9KTtcblxuICAgICAgc3NtUzNLZXlQYXJhbSA9IG5ldyBzc20uU3RyaW5nUGFyYW1ldGVyKHRoaXMsIFwiUzNLZXlQYXJhbVwiLCB7XG4gICAgICAgIHBhcmFtZXRlck5hbWU6IHNzbVNyY0tleSxcbiAgICAgICAgc3RyaW5nVmFsdWU6IFwiaW5pdFwiLFxuICAgICAgICBkZXNjcmlwdGlvbjogXCJTMyBLZXlcIixcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IGRlcGxveW1lbnRXb3JrZmxvd1N0ZXBGdW5jdGlvbiA9IG5ldyBEZXBsb3ltZW50V29ya2Zsb3dTdGVwRnVuY3Rpb24odGhpcywgXCJVcGRhdGVDRkZcIiwge1xuICAgICAgY2hhbmdlVXJpOiBwYXJhbXMuY2hhbmdlVXJpLFxuICAgICAga3ZzQXJuOiBwYXJhbXMua3ZzQXJuLFxuICAgICAgaG9zdGluZ0J1Y2tldDogcGFyYW1zLmhvc3RpbmdCdWNrZXQsXG4gICAgICBzc21Db21taXRJZFBhcmFtOiBzc21Db21taXRJZFBhcmFtLFxuICAgICAgc3NtUzNLZXlQYXJhbTogc3NtUzNLZXlQYXJhbSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHNvdXJjZU91dHB1dCA9IG5ldyBjb2RlcGlwZWxpbmUuQXJ0aWZhY3QoKTtcblxuICAgIHZhciBwaXBlbGluZU5hbWUsIGJ1aWxkTmFtZTtcbiAgICB2YXIgZHVtbXlTb3VyY2VCdWNrZXQ7XG4gICAgdmFyIGJ1aWxkU3JjQnVja2V0OiBJQnVja2V0IHwgbnVsbCA9IG51bGw7IC8vIEluaXRpYWxpemUgd2l0aCBudWxsXG5cbiAgICB2YXIgc291cmNlQWN0aW9uOlxuICAgICAgfCBjb2RlcGlwZWxpbmVfYWN0aW9ucy5Db2RlU3RhckNvbm5lY3Rpb25zU291cmNlQWN0aW9uXG4gICAgICB8IFMzU291cmNlQWN0aW9uO1xuICAgIHZhciBzdGVwRnVuY3Rpb25JbnB1dCA9IHt9O1xuICAgIHZhciBjb2RlQnVpbGRFbnZWYXJzO1xuICAgIHZhciBzM3VwbG9hZDtcbiAgICBpZiAoaXNSZXBvQ29uZmlnKHBhcmFtcy5ob3N0aW5nQ29uZmlndXJhdGlvbikpIHtcbiAgICAgIHMzdXBsb2FkID0gbmV3IHMzZGVwbG95LkJ1Y2tldERlcGxveW1lbnQodGhpcywgXCJJbml0aWFsUGFnZVwiLCB7XG4gICAgICAgIHNvdXJjZXM6IFtzM2RlcGxveS5Tb3VyY2UuYXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcInJlc291cmNlcy9pbml0aWFsX3JlcG9zaXRvcnlcIikpXSxcbiAgICAgICAgZGVzdGluYXRpb25CdWNrZXQ6IHBhcmFtcy5ob3N0aW5nQnVja2V0LFxuICAgICAgfSk7XG5cbiAgICAgIGNvZGVCdWlsZEVudlZhcnMgPSB7XG4gICAgICAgIERFU1RfQlVDS0VUX05BTUU6IHsgdmFsdWU6IHBhcmFtcy5ob3N0aW5nQnVja2V0LmJ1Y2tldE5hbWUgfSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IHBhcnNlZFVybCA9IHBhcnNlUmVwb3NpdG9yeVVybChwYXJhbXMuaG9zdGluZ0NvbmZpZ3VyYXRpb24ucmVwb1VybCk7XG5cbiAgICAgIGNvbnN0IHsgcmVwb093bmVyLCByZXBvTmFtZSB9ID0gcGFyc2VkVXJsO1xuICAgICAgLy90aGUgcGlwZWxpbmUgaXMgdHJpZ2dlcmVkIGZyb20gY29kZSByZXBvc2l0b3J5XG4gICAgICBwaXBlbGluZU5hbWUgPSBgJHtyZXBvT3duZXJ9LSR7cmVwb05hbWV9LSR7cGFyYW1zLmhvc3RpbmdDb25maWd1cmF0aW9uLmJyYW5jaE5hbWV9YDtcbiAgICAgIFxuICAgICAgcGlwZWxpbmVOYW1lID0gY2xlYW5QaXBlbGluZU5hbWVTdHIocGlwZWxpbmVOYW1lKTtcblxuXG4gICAgICBidWlsZE5hbWUgPSBcIkJ1aWxkLUFuZC1Db3B5LXRvLVMzLVwiICsgcmVwb05hbWU7XG4gICAgICBidWlsZE5hbWUgPSBjbGVhbkJ1aWxkTmFtZVN0cihidWlsZE5hbWUpO1xuICAgICAgY29uc3Qgc291cmNlQWN0aW9uTmFtZSA9IGNsZWFuQWN0aW9uTmFtZVN0cihcIkdpdEh1Yi1Tb3VyY2UtXCIgKyByZXBvTmFtZSk7XG5cblxuICAgICAgc291cmNlQWN0aW9uID0gbmV3IGNvZGVwaXBlbGluZV9hY3Rpb25zLkNvZGVTdGFyQ29ubmVjdGlvbnNTb3VyY2VBY3Rpb24oe1xuICAgICAgICBhY3Rpb25OYW1lOiBzb3VyY2VBY3Rpb25OYW1lLFxuICAgICAgICBvd25lcjogcmVwb093bmVyLFxuICAgICAgICByZXBvOiByZXBvTmFtZSxcbiAgICAgICAgYnJhbmNoOiBwYXJhbXMuaG9zdGluZ0NvbmZpZ3VyYXRpb24uYnJhbmNoTmFtZSxcbiAgICAgICAgb3V0cHV0OiBzb3VyY2VPdXRwdXQsXG4gICAgICAgIGNvbm5lY3Rpb25Bcm46IHBhcmFtcy5jb25uZWN0aW9uQXJuISxcbiAgICAgIH0pO1xuXG4gICAgICBzdGVwRnVuY3Rpb25JbnB1dCA9IHsgY29tbWl0SWQ6IHNvdXJjZUFjdGlvbi52YXJpYWJsZXMuY29tbWl0SWQgfTtcbiAgICB9IGVsc2UgaWYgKHBhcmFtcy5ob3N0aW5nQ29uZmlndXJhdGlvbi5zM2J1Y2tldCkge1xuICAgICAgLy90aGUgcGlwZWxpbmUgaXMgdHJpZ2dlcmVkIGZyb20gczMgYnVja2V0XG5cbiAgICAgIHMzdXBsb2FkID0gbmV3IHMzZGVwbG95LkJ1Y2tldERlcGxveW1lbnQodGhpcywgXCJJbml0aWFsUGFnZVwiLCB7XG4gICAgICAgIHNvdXJjZXM6IFtzM2RlcGxveS5Tb3VyY2UuYXNzZXQocGF0aC5qb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcInJlc291cmNlcy9pbml0aWFsX3MzXCIpKV0sXG4gICAgICAgIGRlc3RpbmF0aW9uQnVja2V0OiBwYXJhbXMuaG9zdGluZ0J1Y2tldCxcbiAgICAgIH0pO1xuXG4gICAgICBwaXBlbGluZU5hbWUgPSBwYXJhbXMuaG9zdGluZ0NvbmZpZ3VyYXRpb24uczNidWNrZXQ7XG4gICAgICBwaXBlbGluZU5hbWUgPSBjbGVhblBpcGVsaW5lTmFtZVN0cihwaXBlbGluZU5hbWUpO1xuICAgICAgYnVpbGROYW1lID0gXCJVbnppcC1BbmQtQ29weS10by1TM1wiO1xuXG4gICAgICBjb25zdCBwaXBlbGluZUFybiA9IGBhcm46YXdzOmNvZGVwaXBlbGluZToke0F3cy5SRUdJT059OiR7QXdzLkFDQ09VTlRfSUR9OiR7cGlwZWxpbmVOYW1lfWA7XG5cbiAgICAgIGNvbnN0IGNsb3VkV2F0Y2hQb2xpY3lTdGF0ZW1lbnQgPVxuICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgIFwibG9nczpDcmVhdGVMb2dHcm91cFwiLFxuICAgICAgICAgICAgXCJsb2dzOkNyZWF0ZUxvZ1N0cmVhbVwiLFxuICAgICAgICAgICAgXCJsb2dzOlB1dExvZ0V2ZW50c1wiLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbXCJhcm46YXdzOmxvZ3M6KjoqOipcIl0sXG4gICAgICAgIH0pO1xuICAgICAgXG4gICAgICBjb25zdCBwYXJhbVBvbGljeVN0YXRlbWVudCA9IG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICBhY3Rpb25zOiBbXCJzc206UHV0UGFyYW1ldGVyXCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICBzc21Db21taXRJZFBhcmFtIS5wYXJhbWV0ZXJBcm4sXG4gICAgICAgICAgc3NtUzNLZXlQYXJhbSEucGFyYW1ldGVyQXJuLFxuICAgICAgICBdLFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IHBpcGVsaW5lUG9saWN5U3RhdGVtZW50ID0gbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIGFjdGlvbnM6IFtcImNvZGVwaXBlbGluZTpTdGFydFBpcGVsaW5lRXhlY3V0aW9uXCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtwaXBlbGluZUFybl0sXG4gICAgICB9KTtcblxuICAgICAgYnVpbGRTcmNCdWNrZXQgPSBzMy5CdWNrZXQuZnJvbUJ1Y2tldE5hbWUoXG4gICAgICAgIHRoaXMsXG4gICAgICAgIFwiQnVpbGRTcmNCdWNrZXRcIixcbiAgICAgICAgcGFyYW1zLmhvc3RpbmdDb25maWd1cmF0aW9uLnMzYnVja2V0XG4gICAgICApO1xuICAgICAgYnVpbGRTcmNCdWNrZXQuZW5hYmxlRXZlbnRCcmlkZ2VOb3RpZmljYXRpb24oKTtcblxuICBcbiAgICAgIGNvbnN0IG5ld0J1aWxkID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCBcIk5ld0J1aWxkUHJvY2Vzc1wiLCB7XG4gICAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18xOF9YLFxuICAgICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tQXNzZXQoXG4gICAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgXCIuLi9sYW1iZGEvbmV3X2J1aWxkXCIpXG4gICAgICAgICksXG4gICAgICAgIGhhbmRsZXI6IFwiaW5kZXguaGFuZGxlclwiLFxuICAgICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICAgIFNTTV9QQVJBTV9DT01NSVRJRDogc3NtQ29tbWl0SWRQYXJhbSEucGFyYW1ldGVyTmFtZSxcbiAgICAgICAgICBTU01fUEFSQU1fUzNfS0VZOiBzc21TM0tleVBhcmFtPy5wYXJhbWV0ZXJOYW1lISxcbiAgICAgICAgICBQSVBFTElORV9OQU1FOiBwaXBlbGluZU5hbWUsXG4gICAgICAgIH0sXG4gICAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9XRUVLLFxuICAgICAgfSk7XG5cblxuICAgICAgbmV3QnVpbGQuYWRkVG9Sb2xlUG9saWN5KGNsb3VkV2F0Y2hQb2xpY3lTdGF0ZW1lbnQpO1xuICAgICAgbmV3QnVpbGQuYWRkVG9Sb2xlUG9saWN5KHBhcmFtUG9saWN5U3RhdGVtZW50KTtcbiAgICAgIG5ld0J1aWxkLmFkZFRvUm9sZVBvbGljeShwaXBlbGluZVBvbGljeVN0YXRlbWVudCk7XG5cbiAgICAgIGNvbnN0IHJ1bGUgPSBuZXcgZXZlbnRzLlJ1bGUodGhpcywgXCJydWxlXCIsIHtcbiAgICAgICAgZXZlbnRQYXR0ZXJuOiB7XG4gICAgICAgICAgc291cmNlOiBbXCJhd3MuczNcIl0sXG4gICAgICAgICAgZGV0YWlsVHlwZTogW1wiT2JqZWN0IENyZWF0ZWRcIl0sXG4gICAgICAgICAgZGV0YWlsOiB7XG4gICAgICAgICAgICBidWNrZXQ6IHtcbiAgICAgICAgICAgICAgbmFtZTogW2J1aWxkU3JjQnVja2V0LmJ1Y2tldE5hbWVdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9iamVjdDoge1xuICAgICAgICAgICAgICBrZXk6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBwcmVmaXg6IHBhcmFtcy5ob3N0aW5nQ29uZmlndXJhdGlvbi5zM3BhdGggKyAnLycsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBzdWZmaXg6IFwiLnppcFwiLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgYWRkQ2ZuU3VwcHJlc3NSdWxlcyhuZXdCdWlsZCwgW1xuICAgICAgICB7XG4gICAgICAgICAgaWQ6IFwiVzU4XCIsXG4gICAgICAgICAgcmVhc29uOlxuICAgICAgICAgICAgXCJMYW1iZGEgaGFzIENsb3VkV2F0Y2ggcGVybWlzc2lvbnMgYnkgdXNpbmcgc2VydmljZSByb2xlIEFXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZVwiLFxuICAgICAgICB9LFxuICAgICAgXSk7XG4gICAgICBhZGRDZm5TdXBwcmVzc1J1bGVzKG5ld0J1aWxkLCBbXG4gICAgICAgIHtcbiAgICAgICAgICBpZDogXCJXODlcIixcbiAgICAgICAgICByZWFzb246XG4gICAgICAgICAgICBcIldlIGRvbiB0IGhhdmUgYW55IFZQQyBpbiB0aGUgc3RhY2ssIHdlIG9ubHkgdXNlIHNlcnZlcmxlc3Mgc2VydmljZXNcIixcbiAgICAgICAgfSxcbiAgICAgIF0pO1xuICAgICAgYWRkQ2ZuU3VwcHJlc3NSdWxlcyhuZXdCdWlsZCwgW1xuICAgICAgICB7XG4gICAgICAgICAgaWQ6IFwiVzkyXCIsXG4gICAgICAgICAgcmVhc29uOlxuICAgICAgICAgICAgXCJObyBuZWVkIGZvciBSZXNlcnZlZENvbmN1cnJlbnRFeGVjdXRpb25zLCBzb21lIGFyZSB1c2VkIG9ubHkgZm9yIHRoZSBkZW1vIHdlYnNpdGUsIGFuZCBvdGhlcnMgYXJlIG5vdCB1c2VkIGluIGEgY29uY3VycmVudCBtb2RlLlwiLFxuICAgICAgICB9LFxuICAgICAgXSk7XG5cbiAgICAgIHJ1bGUuYWRkVGFyZ2V0KFxuICAgICAgICBuZXcgdGFyZ2V0cy5MYW1iZGFGdW5jdGlvbihuZXdCdWlsZCwge1xuICAgICAgICAgIG1heEV2ZW50QWdlOiBEdXJhdGlvbi5ob3VycygxKSxcbiAgICAgICAgICByZXRyeUF0dGVtcHRzOiAzLFxuICAgICAgICB9KVxuICAgICAgKTtcblxuICAgICAgY29kZUJ1aWxkRW52VmFycyA9IHtcbiAgICAgICAgREVTVF9CVUNLRVRfTkFNRTogeyB2YWx1ZTogcGFyYW1zLmhvc3RpbmdCdWNrZXQuYnVja2V0TmFtZSB9LFxuICAgICAgICBTU01fUEFSQU1fQ09NTUlUSUQ6IHsgdmFsdWU6IHNzbUNvbW1pdElkUGFyYW0hLnBhcmFtZXRlck5hbWUgfSxcbiAgICAgICAgU1NNX1BBUkFNX1MzX0tFWTogeyB2YWx1ZTogc3NtUzNLZXlQYXJhbT8ucGFyYW1ldGVyTmFtZSEgfSxcbiAgICAgICAgU1JDX0JVQ0tFVF9OQU1FOiB7IHZhbHVlOiBidWlsZFNyY0J1Y2tldC5idWNrZXROYW1lIH0sXG4gICAgICB9O1xuXG4gICAgICBkdW1teVNvdXJjZUJ1Y2tldCA9IG5ldyBzMy5CdWNrZXQodGhpcywgXCJEdW1teVNvdXJjZUJ1Y2tldFwiLCB7XG4gICAgICAgIHZlcnNpb25lZDogdHJ1ZSxcbiAgICAgICAgZW5jcnlwdGlvbjogczMuQnVja2V0RW5jcnlwdGlvbi5TM19NQU5BR0VELFxuICAgICAgICBibG9ja1B1YmxpY0FjY2VzczogczMuQmxvY2tQdWJsaWNBY2Nlc3MuQkxPQ0tfQUxMLFxuICAgICAgICBhdXRvRGVsZXRlT2JqZWN0czogdHJ1ZSxcbiAgICAgICAgcmVtb3ZhbFBvbGljeTogUmVtb3ZhbFBvbGljeS5ERVNUUk9ZLFxuICAgICAgICAvL2VuY3J5cHRpb246IHMzLkJ1Y2tldEVuY3J5cHRpb24uUzNfTUFOQUdFRCxcbiAgICAgICAgZW5mb3JjZVNTTDogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBhZGRDZm5TdXBwcmVzc1J1bGVzKGR1bW15U291cmNlQnVja2V0LCBbXG4gICAgICAgIHtcbiAgICAgICAgICBpZDogXCJXMzVcIixcbiAgICAgICAgICByZWFzb246IFwiVGhlIGJ1Y2tldCBoYXMgYSBkZW55IGFsbCBwb2xpY3ksIHNvIG5vIGFjY2VzcyBpcyBhbGxvd2VkXCIsXG4gICAgICAgIH0sXG4gICAgICBdKTtcblxuICAgICAgbmV3IHMzZGVwbG95LkJ1Y2tldERlcGxveW1lbnQodGhpcywgXCJEZXBsb3lXZWJzaXRlXCIsIHtcbiAgICAgICAgc291cmNlczogW3MzZGVwbG95LlNvdXJjZS5hc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCBcIi4uXCIsIFwicmVzb3VyY2VzL3MzX3RyaWdnZXJcIikpXSxcbiAgICAgICAgZGVzdGluYXRpb25CdWNrZXQ6IGR1bW15U291cmNlQnVja2V0LFxuICAgICAgfSk7XG5cbiAgICAgIHNvdXJjZUFjdGlvbiA9IG5ldyBTM1NvdXJjZUFjdGlvbih7XG4gICAgICAgIGJ1Y2tldDogZHVtbXlTb3VyY2VCdWNrZXQsXG4gICAgICAgIGJ1Y2tldEtleTogXCJkdW1teS56aXBcIixcbiAgICAgICAgb3V0cHV0OiBzb3VyY2VPdXRwdXQsXG4gICAgICAgIGFjdGlvbk5hbWU6IFwiRHVtbXktUzMtU291cmNlXCIsXG4gICAgICAgIHRyaWdnZXI6IFMzVHJpZ2dlci5FVkVOVFMsXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5sb2coXCJNaXNzaW5nIHJlcXVpcmVkIGluZm9ybWF0aW9uLiBFeGl0LlwiKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBjb25zdCBhcnRpZmFjdEJ1Y2tldCA9IG5ldyBzMy5CdWNrZXQodGhpcywgXCJBcnRpZmFjdEJ1Y2tldFwiLCB7XG4gICAgICBlbmNyeXB0aW9uOiBzMy5CdWNrZXRFbmNyeXB0aW9uLlMzX01BTkFHRUQsXG4gICAgICBibG9ja1B1YmxpY0FjY2VzczogczMuQmxvY2tQdWJsaWNBY2Nlc3MuQkxPQ0tfQUxMLFxuICAgICAgYXV0b0RlbGV0ZU9iamVjdHM6IHRydWUsXG4gICAgICByZW1vdmFsUG9saWN5OiBSZW1vdmFsUG9saWN5LkRFU1RST1ksXG4gICAgICBlbmZvcmNlU1NMOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKGFydGlmYWN0QnVja2V0LCBbXG4gICAgICB7XG4gICAgICAgIGlkOiBcIkF3c1NvbHV0aW9ucy1TMVwiLFxuICAgICAgICByZWFzb246IFwiQnVja2V0IHVzZWQgYnkgQ29kZVBpcGVsaW5lLCBubyBuZWVkIGZvciBhY2Nlc3MgbG9ncy5cIixcbiAgICAgIH0sXG4gICAgXSk7XG5cbiAgICBjb25zdCBwaXBlbGluZSA9IG5ldyBjb2RlcGlwZWxpbmUuUGlwZWxpbmUodGhpcywgXCJNeVBpcGVsaW5lXCIsIHtcbiAgICAgIGFydGlmYWN0QnVja2V0OiBhcnRpZmFjdEJ1Y2tldCxcbiAgICAgIHBpcGVsaW5lTmFtZTogcGlwZWxpbmVOYW1lLFxuICAgICAgY3Jvc3NBY2NvdW50S2V5czogZmFsc2UsXG4gICAgfSk7XG5cbiAgICBOYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMocGlwZWxpbmUsIFtcbiAgICAgIHtcbiAgICAgICAgaWQ6IFwiQXdzU29sdXRpb25zLVMyXCIsXG4gICAgICAgIHJlYXNvbjogXCJEZW1vbnN0cmF0ZSBhIHJlc291cmNlIGxldmVsIHN1cHByZXNzaW9uLlwiLFxuICAgICAgfSxcbiAgICBdKTtcblxuICAgIGFydGlmYWN0QnVja2V0LmFkZFRvUmVzb3VyY2VQb2xpY3koXG4gICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgYWN0aW9uczogW1wiczM6R2V0T2JqZWN0XCJdLFxuICAgICAgICByZXNvdXJjZXM6IFtgJHthcnRpZmFjdEJ1Y2tldC5idWNrZXRBcm59LypgXSxcbiAgICAgICAgcHJpbmNpcGFsczogW25ldyBpYW0uQXJuUHJpbmNpcGFsKHBpcGVsaW5lLnJvbGUucm9sZUFybildLFxuICAgICAgfSlcbiAgICApO1xuXG4gICAgYWRkQ2ZuU3VwcHJlc3NSdWxlcyhhcnRpZmFjdEJ1Y2tldCwgW1xuICAgICAge1xuICAgICAgICBpZDogXCJXMzVcIixcbiAgICAgICAgcmVhc29uOiBcIlRoZSBidWNrZXQgY2FuIGJlIHJlYWQgb25seSBieSB0aGUgcGlwZWxpbmVcIixcbiAgICAgIH0sXG4gICAgXSk7XG5cbiAgICBwaXBlbGluZS5ub2RlLmFkZERlcGVuZGVuY3koczN1cGxvYWQpO1xuXG4gICAgY29uc3Qgc3RlcEZ1bmN0aW9uQWN0aW9uID1cbiAgICAgIG5ldyBjb2RlcGlwZWxpbmVfYWN0aW9ucy5TdGVwRnVuY3Rpb25JbnZva2VBY3Rpb24oe1xuICAgICAgICBhY3Rpb25OYW1lOiBcIkludm9rZVwiLFxuICAgICAgICBzdGF0ZU1hY2hpbmU6IGRlcGxveW1lbnRXb3JrZmxvd1N0ZXBGdW5jdGlvbi5zdGVwRnVuY3Rpb24sXG4gICAgICAgIHN0YXRlTWFjaGluZUlucHV0OlxuICAgICAgICAgIGNvZGVwaXBlbGluZV9hY3Rpb25zLlN0YXRlTWFjaGluZUlucHV0LmxpdGVyYWwoc3RlcEZ1bmN0aW9uSW5wdXQpLFxuICAgICAgfSk7XG5cbiAgICBjb25zdCBidWlsZFNwZWNPYmogPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICBwYXJhbXMuYnVpbGRGaWxlUGF0aCxcbiAgICAgIFwidXRmOFwiXG4gICAgKTtcbiAgICBjb25zdCBidWlsZFNwZWNZYW1sID0geWFtbC5wYXJzZShidWlsZFNwZWNPYmopO1xuICAgIGNvbnN0IGNvZGVCdWlsZExvZ3MgPSBuZXcgbG9ncy5Mb2dHcm91cCh0aGlzLCBgTXlMb2dHcm91cGAsIHtcbiAgICAgIHJldGVudGlvbjogUmV0ZW50aW9uRGF5cy5PTkVfV0VFSyxcbiAgICB9KTtcblxuICAgIGNvbnN0IG15Q29kZUJ1aWxkID0gbmV3IGNvZGVidWlsZC5QaXBlbGluZVByb2plY3QodGhpcywgXCJQcm9qZWN0XCIsIHtcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIGJ1aWxkSW1hZ2U6IGNvZGVidWlsZC5MaW51eEJ1aWxkSW1hZ2UuU1RBTkRBUkRfN18wLFxuICAgICAgICBjb21wdXRlVHlwZTogY29kZWJ1aWxkLkNvbXB1dGVUeXBlLk1FRElVTSxcbiAgICAgIH0sXG4gICAgICBidWlsZFNwZWM6IGNvZGVidWlsZC5CdWlsZFNwZWMuZnJvbU9iamVjdChidWlsZFNwZWNZYW1sKSxcbiAgICAgIGVudmlyb25tZW50VmFyaWFibGVzOiBjb2RlQnVpbGRFbnZWYXJzLFxuICAgICAgbG9nZ2luZzoge1xuICAgICAgICBjbG91ZFdhdGNoOiB7XG4gICAgICAgICAgbG9nR3JvdXA6IGNvZGVCdWlsZExvZ3MsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgTmFnU3VwcHJlc3Npb25zLmFkZFJlc291cmNlU3VwcHJlc3Npb25zKFxuICAgICAgbXlDb2RlQnVpbGQsXG4gICAgICBbXG4gICAgICAgIHtcbiAgICAgICAgICBpZDogXCJBd3NTb2x1dGlvbnMtQ0I0XCIsXG4gICAgICAgICAgcmVhc29uOlxuICAgICAgICAgICAgXCJBcnRpZmFjdCBidWNrZXQgaXMgdXNpbmcgU2VydmVyLXNpZGUgZW5jcnlwdGlvbiB3aXRoIGEgbWFzdGVyIGtleSBtYW5hZ2VkIGJ5IFMzXCIsXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgICAgdHJ1ZVxuICAgICk7XG5cbiAgICBOYWdTdXBwcmVzc2lvbnMuYWRkUmVzb3VyY2VTdXBwcmVzc2lvbnMoXG4gICAgICBteUNvZGVCdWlsZCxcbiAgICAgIFtcbiAgICAgICAge1xuICAgICAgICAgIGlkOiBcIkF3c1NvbHV0aW9ucy1JQU01XCIsXG4gICAgICAgICAgcmVhc29uOiBcIlJlYWQgcGVybWlzc2lvbnMgZm9yIENvZGVCdWlsZFwiLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICAgIHRydWVcbiAgICApO1xuXG4gICAgYWRkQ2ZuU3VwcHJlc3NSdWxlcyhjb2RlQnVpbGRMb2dzLCBbXG4gICAgICB7XG4gICAgICAgIGlkOiBcIlc4NFwiLFxuICAgICAgICByZWFzb246IFwiQ2xvdWRXYXRjaCBsb2cgZ3JvdXAgaXMgYWx3YXlzIGVuY3J5cHRlZCBieSBkZWZhdWx0LlwiLFxuICAgICAgfSxcbiAgICBdKTtcblxuICAgIGlmIChpc1MzQ29uZmlnKHBhcmFtcy5ob3N0aW5nQ29uZmlndXJhdGlvbikpIHtcbiAgICAgIG15Q29kZUJ1aWxkLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgICBhY3Rpb25zOiBbXCJzc206RGVzY3JpYmUqXCIsIFwic3NtOkdldCpcIiwgXCJzc206TGlzdCpcIl0sXG4gICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICBzc21Db21taXRJZFBhcmFtIS5wYXJhbWV0ZXJBcm4sXG4gICAgICAgICAgICBzc21TM0tleVBhcmFtIS5wYXJhbWV0ZXJBcm4sXG4gICAgICAgICAgXSxcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgICBidWlsZFNyY0J1Y2tldCEuZ3JhbnRSZWFkKG15Q29kZUJ1aWxkKTtcbiAgICB9XG5cbiAgICBjb25zdCBkZXBsb3kgPSBuZXcgY29kZXBpcGVsaW5lX2FjdGlvbnMuQ29kZUJ1aWxkQWN0aW9uKHtcbiAgICAgIGFjdGlvbk5hbWU6IGJ1aWxkTmFtZSxcbiAgICAgIHByb2plY3Q6IG15Q29kZUJ1aWxkLFxuICAgICAgaW5wdXQ6IHNvdXJjZU91dHB1dCxcbiAgICAgIHJ1bk9yZGVyOiAyLFxuICAgIH0pO1xuXG4gICAgcGlwZWxpbmUuYWRkU3RhZ2Uoe1xuICAgICAgc3RhZ2VOYW1lOiBcIlNvdXJjZXNcIixcbiAgICAgICAgICAgIFxuICAgICAgYWN0aW9uczogW3NvdXJjZUFjdGlvbiEgYXMgSUFjdGlvbl