UNPKG

cdk-databrew-cicd

Version:
180 lines 42.7 kB
"use strict"; var _a, _b, _c; Object.defineProperty(exports, "__esModule", { value: true }); exports.FirstCommitHandler = exports.ProductionLambda = exports.PreProductionLambda = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cdk = require("aws-cdk-lib"); const iam = require("aws-cdk-lib/aws-iam"); const lambda = require("aws-cdk-lib/aws-lambda"); const logs = require("aws-cdk-lib/aws-logs"); const constructs_1 = require("constructs"); const functionScript = 'import os\r\nimport json\r\nimport zipfile\r\nimport boto3\r\nimport gzip\r\nfrom io import BytesIO\r\n\r\ndef get_clients():\r\n s3_client = boto3.resource(\'s3\')\r\n sts_connection = boto3.client(\'sts\')\r\n cross_account = sts_connection.assume_role(RoleArn=os.environ[\'role\'],RoleSessionName=\"session\")\r\n access_key = cross_account[\'Credentials\'][\'AccessKeyId\']\r\n secrect_key = cross_account[\'Credentials\'][\'SecretAccessKey\']\r\n session_token = cross_account[\'Credentials\'][\'SessionToken\']\r\n databrew_client = boto3.client(\r\n \'databrew\',\r\n aws_access_key_id=access_key,\r\n aws_secret_access_key=secrect_key,\r\n aws_session_token=session_token,\r\n )\r\n return s3_client, databrew_client\r\n\r\ndef get_name_contents(event, s3_client):\r\n s3_location = event[\'CodePipeline.job\'][\'data\'][\'inputArtifacts\'][0][\'location\'][\'s3Location\']\r\n s3_bucket = s3_location[\'bucketName\']\r\n s3_file = s3_location[\'objectKey\']\r\n zip_obj = s3_client.Object(bucket_name=s3_bucket, key=s3_file)\r\n # extracting compressed files\r\n buffer = BytesIO(zip_obj.get()[\"Body\"].read())\r\n file_name = \'\'\r\n z = zipfile.ZipFile(buffer)\r\n json_content = \'\'\r\n for filename in z.namelist():\r\n if filename.endswith(\'.json\'):\r\n file_name = filename\r\n with z.open(file_name) as content:\r\n json_content = json.load(content)\r\n return file_name.replace(\'.json\', \'\'), json_content\r\n\r\ndef lambda_handler(event, context):\r\n codepipeline_client = boto3.client(\'codepipeline\')\r\n job_id = event[\'CodePipeline.job\'][\'id\']\r\n try:\r\n # client creation\r\n clients = get_clients()\r\n s3_client = clients[0]\r\n databrew_client = clients[1]\r\n # getting file name and contents\r\n name_contents = get_name_contents(event, s3_client)\r\n recipe_lists = databrew_client.list_recipes(MaxResults=99)\r\n if name_contents[0] not in (x[\'Name\'] for x in recipe_lists[\'Recipes\']):\r\n databrew_client.create_recipe(Name=name_contents[0], Steps=name_contents[1])\r\n # updating recipe\r\n databrew_client.update_recipe(Description=\'updating recipe\',Name=name_contents[0],Steps= name_contents[1])\r\n # publishing a recipe\r\n databrew_client.publish_recipe(Description=\'publishing recipe\', Name=name_contents[0])\r\n # Notify AWS CodePipeline of a successful job\r\n codepipeline_client.put_job_success_result(jobId=job_id)\r\n except Exception as e:\r\n # Notifying pipeline of a failure\r\n codepipeline_client.put_job_failure_result(jobId=job_id,failureDetails={\'type\': \'JobFailed\',\'message\': str(e)})'; class PreProductionLambda extends constructs_1.Construct { constructor(scope, name, props) { super(scope, name); this.roleName = props.roleName ?? 'PreProd-DataBrew-Recipe-Deployer-role'; this.functionName = props.functionName ?? 'PreProd-DataBrew-Recipe-Deployer'; const lambdaRole = new iam.Role(this, 'PreproductionFunctionRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), description: 'An execution role for the pre-production Lambda funciton.', managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'), iam.ManagedPolicy.fromAwsManagedPolicyName('AWSXRayDaemonWriteAccess'), new iam.ManagedPolicy(this, 'PreProductionManagedPolicy', { managedPolicyName: 'PreProd-DataBrew-Recipe-Deployer-Policy', statements: [ new iam.PolicyStatement({ sid: 'CodePipelinePermissions', effect: iam.Effect.ALLOW, actions: [ 'codepipeline:PutJobFailureResult', 'codepipeline:PutJobSuccessResult', ], resources: ['*'], }), new iam.PolicyStatement({ sid: 'S3BucketPermissions', effect: iam.Effect.ALLOW, actions: ['s3:GetObject'], resources: [`${props.bucketArn}/*`], }), new iam.PolicyStatement({ sid: 'AssumeRolePermission', effect: iam.Effect.ALLOW, actions: ['sts:AssumeRole'], resources: [props.preproductionIamRoleArn], }), ], }), ], roleName: this.roleName, }); const preproductionFunction = new lambda.Function(this, 'PreProductionFunction', { functionName: this.functionName, description: 'Read from latest commit and publish AWS Glue DataBrew recipe to pre-prod account', logRetention: logs.RetentionDays.THREE_MONTHS, runtime: lambda.Runtime.PYTHON_3_12, architecture: lambda.Architecture.ARM_64, code: lambda.Code.fromInline(functionScript), handler: 'index.lambda_handler', environment: { role: props.preproductionIamRoleArn }, memorySize: 128, role: lambdaRole, timeout: cdk.Duration.seconds(20), tracing: lambda.Tracing.ACTIVE, }); this.function = preproductionFunction; } } exports.PreProductionLambda = PreProductionLambda; _a = JSII_RTTI_SYMBOL_1; PreProductionLambda[_a] = { fqn: "cdk-databrew-cicd.PreProductionLambda", version: "2.0.636" }; class ProductionLambda extends constructs_1.Construct { constructor(scope, name, props) { super(scope, name); this.roleName = props.roleName ?? 'Prod-DataBrew-Recipe-Deployer-role'; this.functionName = props.functionName ?? 'Prod-DataBrew-Recipe-Deployer'; const lambdaRole = new iam.Role(this, 'ProductionFunctionRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), description: 'An execution role for the production Lambda funciton.', managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'), iam.ManagedPolicy.fromAwsManagedPolicyName('AWSXRayDaemonWriteAccess'), new iam.ManagedPolicy(this, 'ProductionLambdaMangedPolicuy', { managedPolicyName: 'Prod-DataBrew-Recipe-Deployer-Policy', statements: [ new iam.PolicyStatement({ sid: 'CodePipelinePermissions', effect: iam.Effect.ALLOW, actions: [ 'codepipeline:PutJobFailureResult', 'codepipeline:PutJobSuccessResult', ], resources: ['*'], }), new iam.PolicyStatement({ sid: 'S3BucketPermissions', effect: iam.Effect.ALLOW, actions: ['s3:GetObject'], resources: [`${props.bucketArn}/*`], }), new iam.PolicyStatement({ sid: 'AssumeRolePermission', effect: iam.Effect.ALLOW, actions: ['sts:AssumeRole'], resources: [props.productionIamRoleArn], }), ], }), ], roleName: this.roleName, }); const productionFunction = new lambda.Function(this, 'ProductionFunction', { functionName: this.functionName, description: 'Read from latest commit and publish AWS Glue DataBrew recipe to production account', logRetention: logs.RetentionDays.THREE_MONTHS, architecture: lambda.Architecture.ARM_64, runtime: lambda.Runtime.PYTHON_3_12, code: lambda.Code.fromInline(functionScript), handler: 'index.lambda_handler', environment: { role: props.productionIamRoleArn }, memorySize: 128, role: lambdaRole, timeout: cdk.Duration.seconds(20), tracing: lambda.Tracing.ACTIVE, }); this.function = productionFunction; } } exports.ProductionLambda = ProductionLambda; _b = JSII_RTTI_SYMBOL_1; ProductionLambda[_b] = { fqn: "cdk-databrew-cicd.ProductionLambda", version: "2.0.636" }; class FirstCommitHandler extends constructs_1.Construct { constructor(scope, name, props) { super(scope, name); this.roleName = props.roleName ?? 'LambdaForInitialCommitRole'; this.functionName = props.functionName ?? 'FirstCommitHandler'; const lambdaRole = new iam.Role(this, 'FirstCommitFunctionRole', { assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'), description: 'An execution role for the Lambda function which deals with first commit via AWS CodeCommit.', managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'), iam.ManagedPolicy.fromAwsManagedPolicyName('AWSXRayDaemonWriteAccess'), ], roleName: this.roleName, inlinePolicies: { LambdaForBranchPolicy: new iam.PolicyDocument({ assignSids: true, statements: [new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: ['codecommit:CreateCommit'], resources: [props.codeCommitRepoArn], })], }), }, }); const commitHandlerFunction = new lambda.Function(this, 'CommitHandlerFunction', { functionName: this.functionName, description: 'Read from latest commit and publish AWS Glue DataBrew recipe to production account', logRetention: logs.RetentionDays.THREE_MONTHS, architecture: lambda.Architecture.ARM_64, runtime: lambda.Runtime.PYTHON_3_12, code: lambda.Code.fromInline('import os\r\nimport json\r\nimport boto3\r\nimport cfnresponse\r\n\r\ndef lambda_handler(event, context):\r\n if(event[\'RequestType\'] == \'Create\'):\r\n code_commit_client = boto3.client(\'codecommit\')\r\n code_commit_client.create_commit(repositoryName=os.environ[\'repo_name\'],branchName=os.environ[\'branch_name\'],commitMessage=\'Initial Commit\',putFiles=[{\'filePath\': \'README.md\',\'fileMode\': \'NORMAL\',\'fileContent\': os.environ[\'readme_contents\']}])\r\n responseValue = 120\r\n responseData = {}\r\n responseData[\'Data\'] = responseValue\r\n cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)'), handler: 'index.lambda_handler', memorySize: 128, role: lambdaRole, environment: { repo_name: props.repoName, branch_name: props.branchName, readme_contents: 'CONTENTS OF THIS FILE\r\n------------\r\n * Introduction\r\n * How to set up local access\r\nINTRODUCTION\r\n------------\r\nThis repository is used for storing recipes for AWSGlue DataBrew. DataBrew is a visual data preparation tool that makes it easy to profile and prepare data for analytics and machine learning (ML). \r\nHOW TO SET UP LOCAL ACCESS\r\n------------\r\nTo set up local developer access:\r\n1. Open a terminal window, and configure the AWS CLI.\r\n ```\r\n aws configure\r\n ```\r\n2. When prompted, provide the following information.\r\n ```\r\n > AWS Access Key ID [None]: User-Access-Key\r\n > AWS Secret Access Key ID [None]: User-Secret-Access-Key\r\n > Default region name ID [None]: us-east-1\r\n > Default output format [None]: json\r\n ```\r\n3. In a plain-text editor, open the config file, also known as the AWS CLI configuration file. Depending on your operating system, this file might be located at `~/.aws/config` on Linux, macOS, or Unix, or at `drive:\\Users\\USERNAME\\.aws\\config` on Windows.\r\n4. Update the file to include two entries, default for your account, and a second for cross account access. The resulting file should look as follows: \r\n ```\r\n [default]\r\n account = <user-account-id>\r\n region = us-east-1\r\n output = json\r\n \r\n [profile CrossAccountAccessProfile]\r\n account = <infra-account-id>\r\n region = us-east-1\r\n output = json\r\n role_arn = arn:aws:iam::<infra-account-id>:role/CrossAccountRepositoryContributorRole\r\n source_profile = default\r\n ```\r\n6. Save your changes, and close the plain-text editor.\r\n7. Run *git clone* to clone the shared repository.\r\n ```\r\n > git clone codecommit://CrossAccountAccessProfile@DataBrew-Recipes-Repo \r\n ```', }, timeout: cdk.Duration.seconds(20), tracing: lambda.Tracing.ACTIVE, }); this.function = commitHandlerFunction; } } exports.FirstCommitHandler = FirstCommitHandler; _c = JSII_RTTI_SYMBOL_1; FirstCommitHandler[_c] = { fqn: "cdk-databrew-cicd.FirstCommitHandler", version: "2.0.636" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2RrLWRhdGFicmV3LWxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jZGstZGF0YWJyZXctbGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsbUNBQW1DO0FBQ25DLDJDQUEyQztBQUMzQyxpREFBaUQ7QUFDakQsNkNBQTZDO0FBQzdDLDJDQUF1QztBQUd2QyxNQUFNLGNBQWMsR0FBRyxxeEZBQXF4RixDQUFDO0FBeUI3eUYsTUFBYSxtQkFBb0IsU0FBUSxzQkFBUztJQWFoRCxZQUFZLEtBQWdCLEVBQUUsSUFBWSxFQUFFLEtBQStCO1FBQ3pFLEtBQUssQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDbkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsUUFBUSxJQUFJLHVDQUF1QyxDQUFDO1FBQzFFLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDLFlBQVksSUFBSSxrQ0FBa0MsQ0FBQztRQUU3RSxNQUFNLFVBQVUsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLDJCQUEyQixFQUFFO1lBQ2pFLFNBQVMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQztZQUMzRCxXQUFXLEVBQUUsMkRBQTJEO1lBQ3hFLGVBQWUsRUFBRTtnQkFDZixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLDBDQUEwQyxDQUFDO2dCQUN0RixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLDBCQUEwQixDQUFDO2dCQUN0RSxJQUFJLEdBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxFQUFFLDRCQUE0QixFQUFFO29CQUN4RCxpQkFBaUIsRUFBRSx5Q0FBeUM7b0JBQzVELFVBQVUsRUFBRTt3QkFDVixJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUM7NEJBQ3RCLEdBQUcsRUFBRSx5QkFBeUI7NEJBQzlCLE1BQU0sRUFBRSxHQUFHLENBQUMs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Yic7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgKiBhcyBsb2dzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG5cbmNvbnN0IGZ1bmN0aW9uU2NyaXB0ID0gJ2ltcG9ydCBvc1xcclxcbmltcG9ydCBqc29uXFxyXFxuaW1wb3J0IHppcGZpbGVcXHJcXG5pbXBvcnQgYm90bzNcXHJcXG5pbXBvcnQgZ3ppcFxcclxcbmZyb20gaW8gaW1wb3J0IEJ5dGVzSU9cXHJcXG5cXHJcXG5kZWYgZ2V0X2NsaWVudHMoKTpcXHJcXG4gICAgczNfY2xpZW50ID0gYm90bzMucmVzb3VyY2UoXFwnczNcXCcpXFxyXFxuICAgIHN0c19jb25uZWN0aW9uID0gYm90bzMuY2xpZW50KFxcJ3N0c1xcJylcXHJcXG4gICAgY3Jvc3NfYWNjb3VudCA9IHN0c19jb25uZWN0aW9uLmFzc3VtZV9yb2xlKFJvbGVBcm49b3MuZW52aXJvbltcXCdyb2xlXFwnXSxSb2xlU2Vzc2lvbk5hbWU9XFxcInNlc3Npb25cXFwiKVxcclxcbiAgICBhY2Nlc3Nfa2V5ID0gY3Jvc3NfYWNjb3VudFtcXCdDcmVkZW50aWFsc1xcJ11bXFwnQWNjZXNzS2V5SWRcXCddXFxyXFxuICAgIHNlY3JlY3Rfa2V5ID0gY3Jvc3NfYWNjb3VudFtcXCdDcmVkZW50aWFsc1xcJ11bXFwnU2VjcmV0QWNjZXNzS2V5XFwnXVxcclxcbiAgICBzZXNzaW9uX3Rva2VuID0gY3Jvc3NfYWNjb3VudFtcXCdDcmVkZW50aWFsc1xcJ11bXFwnU2Vzc2lvblRva2VuXFwnXVxcclxcbiAgICBkYXRhYnJld19jbGllbnQgPSBib3RvMy5jbGllbnQoXFxyXFxuICAgICAgICBcXCdkYXRhYnJld1xcJyxcXHJcXG4gICAgICAgIGF3c19hY2Nlc3Nfa2V5X2lkPWFjY2Vzc19rZXksXFxyXFxuICAgICAgICBhd3Nfc2VjcmV0X2FjY2Vzc19rZXk9c2VjcmVjdF9rZXksXFxyXFxuICAgICAgICBhd3Nfc2Vzc2lvbl90b2tlbj1zZXNzaW9uX3Rva2VuLFxcclxcbiAgICApXFxyXFxuICAgIHJldHVybiBzM19jbGllbnQsIGRhdGFicmV3X2NsaWVudFxcclxcblxcclxcbmRlZiBnZXRfbmFtZV9jb250ZW50cyhldmVudCwgczNfY2xpZW50KTpcXHJcXG4gICAgczNfbG9jYXRpb24gPSBldmVudFtcXCdDb2RlUGlwZWxpbmUuam9iXFwnXVtcXCdkYXRhXFwnXVtcXCdpbnB1dEFydGlmYWN0c1xcJ11bMF1bXFwnbG9jYXRpb25cXCddW1xcJ3MzTG9jYXRpb25cXCddXFxyXFxuICAgIHMzX2J1Y2tldCA9IHMzX2xvY2F0aW9uW1xcJ2J1Y2tldE5hbWVcXCddXFxyXFxuICAgIHMzX2ZpbGUgPSBzM19sb2NhdGlvbltcXCdvYmplY3RLZXlcXCddXFxyXFxuICAgIHppcF9vYmogPSBzM19jbGllbnQuT2JqZWN0KGJ1Y2tldF9uYW1lPXMzX2J1Y2tldCwga2V5PXMzX2ZpbGUpXFxyXFxuICAgICMgZXh0cmFjdGluZyBjb21wcmVzc2VkIGZpbGVzXFxyXFxuICAgIGJ1ZmZlciA9IEJ5dGVzSU8oemlwX29iai5nZXQoKVtcXFwiQm9keVxcXCJdLnJlYWQoKSlcXHJcXG4gICAgZmlsZV9uYW1lID0gXFwnXFwnXFxyXFxuICAgIHogPSB6aXBmaWxlLlppcEZpbGUoYnVmZmVyKVxcclxcbiAgICBqc29uX2NvbnRlbnQgPSBcXCdcXCdcXHJcXG4gICAgZm9yIGZpbGVuYW1lIGluIHoubmFtZWxpc3QoKTpcXHJcXG4gICAgICAgIGlmIGZpbGVuYW1lLmVuZHN3aXRoKFxcJy5qc29uXFwnKTpcXHJcXG4gICAgICAgICAgICBmaWxlX25hbWUgPSBmaWxlbmFtZVxcclxcbiAgICAgICAgICAgIHdpdGggei5vcGVuKGZpbGVfbmFtZSkgYXMgY29udGVudDpcXHJcXG4gICAgICAgICAgICAgICAganNvbl9jb250ZW50ID0ganNvbi5sb2FkKGNvbnRlbnQpXFxyXFxuICAgIHJldHVybiBmaWxlX25hbWUucmVwbGFjZShcXCcuanNvblxcJywgXFwnXFwnKSwganNvbl9jb250ZW50XFxyXFxuXFxyXFxuZGVmIGxhbWJkYV9oYW5kbGVyKGV2ZW50LCBjb250ZXh0KTpcXHJcXG4gICAgY29kZXBpcGVsaW5lX2NsaWVudCA9IGJvdG8zLmNsaWVudChcXCdjb2RlcGlwZWxpbmVcXCcpXFxyXFxuICAgIGpvYl9pZCA9IGV2ZW50W1xcJ0NvZGVQaXBlbGluZS5qb2JcXCddW1xcJ2lkXFwnXVxcclxcbiAgICB0cnk6XFxyXFxuICAgICAgICAjIGNsaWVudCBjcmVhdGlvblxcclxcbiAgICAgICAgY2xpZW50cyA9IGdldF9jbGllbnRzKClcXHJcXG4gICAgICAgIHMzX2NsaWVudCA9IGNsaWVudHNbMF1cXHJcXG4gICAgICAgIGRhdGFicmV3X2NsaWVudCA9IGNsaWVudHNbMV1cXHJcXG4gICAgICAgICMgZ2V0dGluZyBmaWxlIG5hbWUgYW5kIGNvbnRlbnRzXFxyXFxuICAgICAgICBuYW1lX2NvbnRlbnRzID0gZ2V0X25hbWVfY29udGVudHMoZXZlbnQsIHMzX2NsaWVudClcXHJcXG4gICAgICAgIHJlY2lwZV9saXN0cyA9IGRhdGFicmV3X2NsaWVudC5saXN0X3JlY2lwZXMoTWF4UmVzdWx0cz05OSlcXHJcXG4gICAgICAgIGlmIG5hbWVfY29udGVudHNbMF0gbm90IGluICh4W1xcJ05hbWVcXCddIGZvciB4IGluIHJlY2lwZV9saXN0c1tcXCdSZWNpcGVzXFwnXSk6XFxyXFxuICAgICAgICAgICAgZGF0YWJyZXdfY2xpZW50LmNyZWF0ZV9yZWNpcGUoTmFtZT1uYW1lX2NvbnRlbnRzWzBdLCBTdGVwcz1uYW1lX2NvbnRlbnRzWzFdKVxcclxcbiAgICAgICAgIyB1cGRhdGluZyByZWNpcGVcXHJcXG4gICAgICAgIGRhdGFicmV3X2NsaWVudC51cGRhdGVfcmVjaXBlKERlc2NyaXB0aW9uPVxcJ3VwZGF0aW5nIHJlY2lwZVxcJyxOYW1lPW5hbWVfY29udGVudHNbMF0sU3RlcHM9IG5hbWVfY29udGVudHNbMV0pXFxyXFxuICAgICAgICAjIHB1Ymxpc2hpbmcgYSByZWNpcGVcXHJcXG4gICAgICAgIGRhdGFicmV3X2NsaWVudC5wdWJsaXNoX3JlY2lwZShEZXNjcmlwdGlvbj1cXCdwdWJsaXNoaW5nIHJlY2lwZVxcJywgTmFtZT1uYW1lX2NvbnRlbnRzWzBdKVxcclxcbiAgICAgICAgIyBOb3RpZnkgQVdTIENvZGVQaXBlbGluZSBvZiBhIHN1Y2Nlc3NmdWwgam9iXFxyXFxuICAgICAgICBjb2RlcGlwZWxpbmVfY2xpZW50LnB1dF9qb2Jfc3VjY2Vzc19yZXN1bHQoam9iSWQ9am9iX2lkKVxcclxcbiAgICBleGNlcHQgRXhjZXB0aW9uIGFzIGU6XFxyXFxuICAgICAgICAjIE5vdGlmeWluZyBwaXBlbGluZSBvZiBhIGZhaWx1cmVcXHJcXG4gICAgICAgIGNvZGVwaXBlbGluZV9jbGllbnQucHV0X2pvYl9mYWlsdXJlX3Jlc3VsdChqb2JJZD1qb2JfaWQsZmFpbHVyZURldGFpbHM9e1xcJ3R5cGVcXCc6IFxcJ0pvYkZhaWxlZFxcJyxcXCdtZXNzYWdlXFwnOiBzdHIoZSl9KSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJlUHJvZHVjdGlvbkxhbWJkYVByb3BzIHtcbiAgLyoqXG4gICAgICogVGhlIEFSTiBvZiB0aGUgUzMgYnVja2V0IGZvciB0aGUgRGF0YUJyZXcgQ0lDRCBwaXBlbGluZS5cbiAgICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0QXJuOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgQVJOIG9mIHRoZSBJQU0gcm9sZSBpbiB0aGUgcHJlLXByb2R1Y3Rpb24gYWNjb3VudC5cbiAgICovXG4gIHJlYWRvbmx5IHByZXByb2R1Y3Rpb25JYW1Sb2xlQXJuOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgSUFNIHJvbGUgZm9yIHRoZSBwcmUtcHJvZHVjaXRvbiBMYW1iZGEgZnVuY3Rpb24uXG4gICAqXG4gICAqIEBkZWZhdWx0ICdQcmVQcm9kLURhdGFCcmV3LVJlY2lwZS1EZXBsb3llci1yb2xlJ1xuICAgKiAqL1xuICByZWFkb25seSByb2xlTmFtZT86IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBMYW1iZGEgZnVuY2l0b24gbmFtZSBmb3IgdGhlIHByZS1wcm9kdWN0aW9uIGFjY291bnRcbiAgICpcbiAgICogQGRlZmF1bHQgJ1ByZVByb2QtRGF0YUJyZXctUmVjaXBlLURlcGxveWVyJ1xuICAgKiAqL1xuICByZWFkb25seSBmdW5jdGlvbk5hbWU/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBjbGFzcyBQcmVQcm9kdWN0aW9uTGFtYmRhIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAgICogVGhlIG5hbWUgb2YgdGhlIElBTSByb2xlIGZvciB0aGUgcHJlLXByb2R1Y2l0b24gTGFtYmRhIGZ1bmN0aW9uLlxuICAgICAqL1xuICByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuICAvKipcbiAgICAgKiBUaGUgTGFtYmRhIGZ1bmNpdG9uIG5hbWUgZm9yIHRoZSBwcmUtcHJvZHVjdGlvbiBhY2NvdW50LlxuICAgICAqL1xuICByZWFkb25seSBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAgICogVGhlIHJlcHJlc2VudGF0aXZlIG9mIExhbWJkYSBmdW5jdGlvbiBmb3IgdGhlIHByZS1wcm9kdWN0aW9uIGFjY291bnQuXG4gICAgICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uOiBsYW1iZGEuSUZ1bmN0aW9uO1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBuYW1lOiBzdHJpbmcsIHByb3BzOiBQcmVQcm9kdWN0aW9uTGFtYmRhUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgbmFtZSk7XG4gICAgdGhpcy5yb2xlTmFtZSA9IHByb3BzLnJvbGVOYW1lID8/ICdQcmVQcm9kLURhdGFCcmV3LVJlY2lwZS1EZXBsb3llci1yb2xlJztcbiAgICB0aGlzLmZ1bmN0aW9uTmFtZSA9IHByb3BzLmZ1bmN0aW9uTmFtZSA/PyAnUHJlUHJvZC1EYXRhQnJldy1SZWNpcGUtRGVwbG95ZXInO1xuXG4gICAgY29uc3QgbGFtYmRhUm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCAnUHJlcHJvZHVjdGlvbkZ1bmN0aW9uUm9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpLFxuICAgICAgZGVzY3JpcHRpb246ICdBbiBleGVjdXRpb24gcm9sZSBmb3IgdGhlIHByZS1wcm9kdWN0aW9uIExhbWJkYSBmdW5jaXRvbi4nLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpLFxuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ0FXU1hSYXlEYWVtb25Xcml0ZUFjY2VzcycpLFxuICAgICAgICBuZXcgaWFtLk1hbmFnZWRQb2xpY3kodGhpcywgJ1ByZVByb2R1Y3Rpb25NYW5hZ2VkUG9saWN5Jywge1xuICAgICAgICAgIG1hbmFnZWRQb2xpY3lOYW1lOiAnUHJlUHJvZC1EYXRhQnJldy1SZWNpcGUtRGVwbG95ZXItUG9saWN5JyxcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBbXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ0NvZGVQaXBlbGluZVBlcm1pc3Npb25zJyxcbiAgICAgICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgJ2NvZGVwaXBlbGluZTpQdXRKb2JGYWlsdXJlUmVzdWx0JyxcbiAgICAgICAgICAgICAgICAnY29kZXBpcGVsaW5lOlB1dEpvYlN1Y2Nlc3NSZXN1bHQnLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ1MzQnVja2V0UGVybWlzc2lvbnMnLFxuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0J10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2Ake3Byb3BzLmJ1Y2tldEFybn0vKmBdLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ0Fzc3VtZVJvbGVQZXJtaXNzaW9uJyxcbiAgICAgICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbJ3N0czpBc3N1bWVSb2xlJ10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW3Byb3BzLnByZXByb2R1Y3Rpb25JYW1Sb2xlQXJuXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgXSxcbiAgICAgIHJvbGVOYW1lOiB0aGlzLnJvbGVOYW1lLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcHJlcHJvZHVjdGlvbkZ1bmN0aW9uID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCAnUHJlUHJvZHVjdGlvbkZ1bmN0aW9uJywge1xuICAgICAgZnVuY3Rpb25OYW1lOiB0aGlzLmZ1bmN0aW9uTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiAnUmVhZCBmcm9tIGxhdGVzdCBjb21taXQgYW5kIHB1Ymxpc2ggQVdTIEdsdWUgRGF0YUJyZXcgcmVjaXBlIHRvIHByZS1wcm9kIGFjY291bnQnLFxuICAgICAgbG9nUmV0ZW50aW9uOiBsb2dzLlJldGVudGlvbkRheXMuVEhSRUVfTU9OVEhTLFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTIsXG4gICAgICBhcmNoaXRlY3R1cmU6IGxhbWJkYS5BcmNoaXRlY3R1cmUuQVJNXzY0LFxuICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUlubGluZShmdW5jdGlvblNjcmlwdCksXG4gICAgICBoYW5kbGVyOiAnaW5kZXgubGFtYmRhX2hhbmRsZXInLFxuICAgICAgZW52aXJvbm1lbnQ6IHsgcm9sZTogcHJvcHMucHJlcHJvZHVjdGlvbklhbVJvbGVBcm4gfSxcbiAgICAgIG1lbW9yeVNpemU6IDEyOCxcbiAgICAgIHJvbGU6IGxhbWJkYVJvbGUsXG4gICAgICB0aW1lb3V0OiBjZGsuRHVyYXRpb24uc2Vjb25kcygyMCksXG4gICAgICB0cmFjaW5nOiBsYW1iZGEuVHJhY2luZy5BQ1RJVkUsXG4gICAgfSk7XG4gICAgdGhpcy5mdW5jdGlvbiA9IHByZXByb2R1Y3Rpb25GdW5jdGlvbjtcbiAgfVxufVxuXG5cbmV4cG9ydCBpbnRlcmZhY2UgUHJvZHVjdGlvbkxhbWJkYVByb3BzIHtcbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIFMzIGJ1Y2tldCBmb3IgdGhlIERhdGFCcmV3IENJQ0QgcGlwZWxpbmUuXG4gICAqL1xuICByZWFkb25seSBidWNrZXRBcm46IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIElBTSByb2xlIGluIHRoZSBwcm9kdWN0aW9uIGFjY291bnQuXG4gICAqICovXG4gIHJlYWRvbmx5IHByb2R1Y3Rpb25JYW1Sb2xlQXJuOiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgSUFNIHJvbGUgZm9yIHRoZSBwcm9kdWNpdG9uIExhbWJkYSBmdW5jdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgJ1Byb2QtRGF0YUJyZXctUmVjaXBlLURlcGxveWVyLXJvbGUnXG4gICAqICovXG4gIHJlYWRvbmx5IHJvbGVOYW1lPzogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIExhbWJkYSBmdW5jaXRvbiBuYW1lIGZvciB0aGUgcHJvZHVjdGlvbiBhY2NvdW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAnUHJvZC1EYXRhQnJldy1SZWNpcGUtRGVwbG95ZXInXG4gICAqICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uTmFtZT86IHN0cmluZztcbn1cblxuXG5leHBvcnQgY2xhc3MgUHJvZHVjdGlvbkxhbWJkYSBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgICAqIFRoZSBuYW1lIG9mIHRoZSBJQU0gcm9sZSBmb3IgdGhlIHByb2R1Y2l0b24gTGFtYmRhIGZ1bmN0aW9uLlxuICAgICAqL1xuICByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuICAvKipcbiAgICAgKiBUaGUgTGFtYmRhIGZ1bmNpdG9uIG5hbWUgZm9yIHRoZSBwcm9kdWN0aW9uIGFjY291bnQuXG4gICAgICovXG4gIHJlYWRvbmx5IGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICAvKipcbiAgICAgKiBUaGUgcmVwcmVzZW50YXRpdmUgb2YgTGFtYmRhIGZ1bmN0aW9uIGZvciB0aGUgcHJvZHVjdGlvbiBhY2NvdW50LlxuICAgICAqL1xuICByZWFkb25seSBmdW5jdGlvbjogbGFtYmRhLklGdW5jdGlvbjtcbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgbmFtZTogc3RyaW5nLCBwcm9wczogUHJvZHVjdGlvbkxhbWJkYVByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIG5hbWUpO1xuICAgIHRoaXMucm9sZU5hbWUgPSBwcm9wcy5yb2xlTmFtZSA/PyAnUHJvZC1EYXRhQnJldy1SZWNpcGUtRGVwbG95ZXItcm9sZSc7XG4gICAgdGhpcy5mdW5jdGlvbk5hbWUgPSBwcm9wcy5mdW5jdGlvbk5hbWUgPz8gJ1Byb2QtRGF0YUJyZXctUmVjaXBlLURlcGxveWVyJztcblxuICAgIGNvbnN0IGxhbWJkYVJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ1Byb2R1Y3Rpb25GdW5jdGlvblJvbGUnLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnbGFtYmRhLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gZXhlY3V0aW9uIHJvbGUgZm9yIHRoZSBwcm9kdWN0aW9uIExhbWJkYSBmdW5jaXRvbi4nLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpLFxuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ0FXU1hSYXlEYWVtb25Xcml0ZUFjY2VzcycpLFxuICAgICAgICBuZXcgaWFtLk1hbmFnZWRQb2xpY3kodGhpcywgJ1Byb2R1Y3Rpb25MYW1iZGFNYW5nZWRQb2xpY3V5Jywge1xuICAgICAgICAgIG1hbmFnZWRQb2xpY3lOYW1lOiAnUHJvZC1EYXRhQnJldy1SZWNpcGUtRGVwbG95ZXItUG9saWN5JyxcbiAgICAgICAgICBzdGF0ZW1lbnRzOiBbXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ0NvZGVQaXBlbGluZVBlcm1pc3Npb25zJyxcbiAgICAgICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgJ2NvZGVwaXBlbGluZTpQdXRKb2JGYWlsdXJlUmVzdWx0JyxcbiAgICAgICAgICAgICAgICAnY29kZXBpcGVsaW5lOlB1dEpvYlN1Y2Nlc3NSZXN1bHQnLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ1MzQnVja2V0UGVybWlzc2lvbnMnLFxuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFsnczM6R2V0T2JqZWN0J10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2Ake3Byb3BzLmJ1Y2tldEFybn0vKmBdLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIHNpZDogJ0Fzc3VtZVJvbGVQZXJtaXNzaW9uJyxcbiAgICAgICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICAgICAgICBhY3Rpb25zOiBbJ3N0czpBc3N1bWVSb2xlJ10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW3Byb3BzLnByb2R1Y3Rpb25JYW1Sb2xlQXJuXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgXSxcbiAgICAgIHJvbGVOYW1lOiB0aGlzLnJvbGVOYW1lLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcHJvZHVjdGlvbkZ1bmN0aW9uID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCAnUHJvZHVjdGlvbkZ1bmN0aW9uJywge1xuICAgICAgZnVuY3Rpb25OYW1lOiB0aGlzLmZ1bmN0aW9uTmFtZSxcbiAgICAgIGRlc2NyaXB0aW9uOiAnUmVhZCBmcm9tIGxhdGVzdCBjb21taXQgYW5kIHB1Ymxpc2ggQVdTIEdsdWUgRGF0YUJyZXcgcmVjaXBlIHRvIHByb2R1Y3Rpb24gYWNjb3VudCcsXG4gICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5USFJFRV9NT05USFMsXG4gICAgICBhcmNoaXRlY3R1cmU6IGxhbWJkYS5BcmNoaXRlY3R1cmUuQVJNXzY0LFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuUFlUSE9OXzNfMTIsXG4gICAgICBjb2RlOiBsYW1iZGEuQ29kZS5mcm9tSW5saW5lKGZ1bmN0aW9uU2NyaXB0KSxcbiAgICAgIGhhbmRsZXI6ICdpbmRleC5sYW1iZGFfaGFuZGxlcicsXG4gICAgICBlbnZpcm9ubWVudDogeyByb2xlOiBwcm9wcy5wcm9kdWN0aW9uSWFtUm9sZUFybiB9LFxuICAgICAgbWVtb3J5U2l6ZTogMTI4LFxuICAgICAgcm9sZTogbGFtYmRhUm9sZSxcbiAgICAgIHRpbWVvdXQ6IGNkay5EdXJhdGlvbi5zZWNvbmRzKDIwKSxcbiAgICAgIHRyYWNpbmc6IGxhbWJkYS5UcmFjaW5nLkFDVElWRSxcbiAgICB9KTtcbiAgICB0aGlzLmZ1bmN0aW9uID0gcHJvZHVjdGlvbkZ1bmN0aW9uO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRmlyc3RDb21taXRIYW5kbGVyUHJvcHMge1xuICAvKipcbiAgICogVGhlIEFSTiBvZiB0aGUgQ29kZUNvbW1pdCByZXBvc2l0b3J5LlxuICAgKi9cbiAgcmVhZG9ubHkgY29kZUNvbW1pdFJlcG9Bcm46IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBDb2RlQ29tbWl0IHJlcG8uXG4gICAqL1xuICByZWFkb25seSByZXBvTmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIGJyYW5jaCBuYW1lIHVzZWQgaW4gdGhlIENvZGVDb21taXQgcmVwby5cbiAgICovXG4gIHJlYWRvbmx5IGJyYW5jaE5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBJQU0gcm9sZSBmb3IgdGhlIExhbWJkYSBmdW5jdGlvbiB3aGljaCBkZWFscyB3aXRoIGZpcnN0IGNvbW1pdCB2aWEgQVdTIENvZGVDb21taXQuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdMYW1iZGFGb3JJbml0aWFsQ29tbWl0Um9sZSdcbiAgICogKi9cbiAgcmVhZG9ubHkgcm9sZU5hbWU/OiBzdHJpbmc7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgTGFtYmRhIGZ1bmN0aW9uIHdoaWNoIGRlYWxzIHdpdGggZmlyc3QgY29tbWl0IHZpYSBBV1MgQ29kZUNvbW1pdC5cbiAgICogQGRlZmF1bHQgJ0ZpcnN0Q29tbWl0SGFuZGxlcidcbiAgICogKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb25OYW1lPzogc3RyaW5nO1xufVxuXG5leHBvcnQgY2xhc3MgRmlyc3RDb21taXRIYW5kbGVyIGV4dGVuZHMgQ29uc3RydWN0IHtcbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBJQU0gcm9sZSBmb3IgdGhlIExhbWJkYSBmdW5jdGlvbiB3aGljaCBkZWFscyB3aXRoIGZpcnN0IGNvbW1pdCB2aWEgQVdTIENvZGVDb21taXQuXG4gICAqL1xuICByZWFkb25seSByb2xlTmFtZTogc3RyaW5nO1xuICAvKipcbiAgICogVGhlIG5hbWUgb2YgdGhlIExhbWJkYSBmdW5jdGlvbiB3aGljaCBkZWFscyB3aXRoIGZpcnN0IGNvbW1pdCB2aWEgQVdTIENvZGVDb21taXQuXG4gICAqL1xuICByZWFkb25seSBmdW5jdGlvbk5hbWU6IHN0cmluZztcbiAgLyoqXG4gICAqIFRoZSByZXByZXNlbnRhdGl2ZSBvZiBMYW1iZGEgZnVuY3Rpb24gd2hpY2ggZGVhbHMgd2l0aCBmaXJzdCBjb21taXQgdmlhIEFXUyBDb2RlQ29tbWl0LlxuICAgKi9cbiAgcmVhZG9ubHkgZnVuY3Rpb246IGxhbWJkYS5JRnVuY3Rpb247XG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIG5hbWU6IHN0cmluZywgcHJvcHM6IEZpcnN0Q29tbWl0SGFuZGxlclByb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIG5hbWUpO1xuICAgIHRoaXMucm9sZU5hbWUgPSBwcm9wcy5yb2xlTmFtZSA/PyAnTGFtYmRhRm9ySW5pdGlhbENvbW1pdFJvbGUnO1xuICAgIHRoaXMuZnVuY3Rpb25OYW1lID0gcHJvcHMuZnVuY3Rpb25OYW1lID8/ICdGaXJzdENvbW1pdEhhbmRsZXInO1xuICAgIGNvbnN0IGxhbWJkYVJvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ0ZpcnN0Q29tbWl0RnVuY3Rpb25Sb2xlJywge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2xhbWJkYS5hbWF6b25hd3MuY29tJyksXG4gICAgICBkZXNjcmlwdGlvbjogJ0FuIGV4ZWN1dGlvbiByb2xlIGZvciB0aGUgTGFtYmRhIGZ1bmN0aW9uIHdoaWNoIGRlYWxzIHdpdGggZmlyc3QgY29tbWl0IHZpYSBBV1MgQ29kZUNvbW1pdC4nLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpLFxuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ0FXU1hSYXlEYWVtb25Xcml0ZUFjY2VzcycpLFxuICAgICAgXSxcbiAgICAgIHJvbGVOYW1lOiB0aGlzLnJvbGVOYW1lLFxuICAgICAgaW5saW5lUG9saWNpZXM6IHtcbiAgICAgICAgTGFtYmRhRm9yQnJhbmNoUG9saWN5OiBuZXcgaWFtLlBvbGljeURvY3VtZW50KHtcbiAgICAgICAgICBhc3NpZ25TaWRzOiB0cnVlLFxuICAgICAgICAgIHN0YXRlbWVudHM6IFtuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICBhY3Rpb25zOiBbJ2NvZGVjb21taXQ6Q3JlYXRlQ29tbWl0J10sXG4gICAgICAgICAgICByZXNvdXJjZXM6IFtwcm9wcy5jb2RlQ29tbWl0UmVwb0Fybl0sXG4gICAgICAgICAgfSldLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBjb21taXRIYW5kbGVyRnVuY3Rpb24gPSBuZXcgbGFtYmRhLkZ1bmN0aW9uKHRoaXMsICdDb21taXRIYW5kbGVyRnVuY3Rpb24nLCB7XG4gICAgICBmdW5jdGlvbk5hbWU6IHRoaXMuZnVuY3Rpb25OYW1lLFxuICAgICAgZGVzY3JpcHRpb246ICdSZWFkIGZyb20gbGF0ZXN0IGNvbW1pdCBhbmQgcHVibGlzaCBBV1MgR2x1ZSBEYXRhQnJldyByZWNpcGUgdG8gcHJvZHVjdGlvbiBhY2NvdW50JyxcbiAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLlRIUkVFX01PTlRIUyxcbiAgICAgIGFyY2hpdGVjdHVyZTogbGFtYmRhLkFyY2hpdGVjdHVyZS5BUk1fNjQsXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5QWVRIT05fM18xMixcbiAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21JbmxpbmUoJ2ltcG9ydCBvc1xcclxcbmltcG9ydCBqc29uXFxyXFxuaW1wb3J0IGJvdG8zXFxyXFxuaW1wb3J0IGNmbnJlc3BvbnNlXFxyXFxuXFxyXFxuZGVmIGxhbWJkYV9oYW5kbGVyKGV2ZW50LCBjb250ZXh0KTpcXHJcXG4gICAgaWYoZXZlbnRbXFwnUmVxdWVzdFR5cGVcXCddID09IFxcJ0NyZWF0ZVxcJyk6XFxyXFxuICAgICAgICBjb2RlX2NvbW1pdF9jbGllbnQgPSBib3RvMy5jbGllbnQoXFwnY29kZWNvbW1pdFxcJylcXHJcXG4gICAgICAgIGNvZGVfY29tbWl0X2NsaWVudC5jcmVhdGVfY29tbWl0KHJlcG9zaXRvcnlOYW1lPW9zLmVudmlyb25bXFwncmVwb19uYW1lXFwnXSxicmFuY2hOYW1lPW9zLmVudmlyb25bXFwnYnJhbmNoX25hbWVcXCddLGNvbW1pdE1lc3NhZ2U9XFwnSW5pdGlhbCBDb21taXRcXCcscHV0RmlsZXM9W3tcXCdmaWxlUGF0aFxcJzogXFwnUkVBRE1FLm1kXFwnLFxcJ2ZpbGVNb2RlXFwnOiBcXCdOT1JNQUxcXCcsXFwnZmlsZUNvbnRlbnRcXCc6IG9zLmVudmlyb25bXFwncmVhZG1lX2NvbnRlbnRzXFwnXX1dKVxcclxcbiAgICByZXNwb25zZVZhbHVlID0gMTIwXFxyXFxuICAgIHJlc3BvbnNlRGF0YSA9IHt9XFxyXFxuICAgIHJlc3BvbnNlRGF0YVtcXCdEYXRhXFwnXSA9IHJlc3BvbnNlVmFsdWVcXHJcXG4gICAgY2ZucmVzcG9uc2Uuc2VuZChldmVudCwgY29udGV4dCwgY2ZucmVzcG9uc2UuU1VDQ0VTUywgcmVzcG9uc2VEYXRhKScpLFxuICAgICAgaGFuZGxlcjogJ2luZGV4LmxhbWJkYV9oYW5kbGVyJyxcbiAgICAgIG1lbW9yeVNpemU6IDEyOCxcbiAgICAgIHJvbGU6IGxhbWJkYVJvbGUsXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICByZXBvX25hbWU6IHByb3BzLnJlcG9OYW1lLFxuICAgICAgICBicmFuY2hfbmFtZTogcHJvcHMuYnJhbmNoTmFtZSxcbiAgICAgICAgcmVhZG1lX2NvbnRlbnRzOiAnQ09OVEVOVFMgT0YgVEhJUyBGSUxFXFxyXFxuLS0tLS0tLS0tLS0tXFxyXFxuICogSW50cm9kdWN0aW9uXFxyXFxuICogSG93IHRvIHNldCB1cCBsb2NhbCBhY2Nlc3NcXHJcXG5JTlRST0RVQ1RJT05cXHJcXG4tLS0tLS0tLS0tLS1cXHJcXG5UaGlzIHJlcG9zaXRvcnkgaXMgdXNlZCBmb3Igc3RvcmluZyByZWNpcGVzIGZvciBBV1NHbHVlIERhdGFCcmV3LiBEYXRhQnJldyBpcyBhIHZpc3VhbCBkYXRhIHByZXBhcmF0aW9uIHRvb2wgdGhhdCBtYWtlcyBpdCBlYXN5IHRvIHByb2ZpbGUgYW5kIHByZXBhcmUgZGF0YSBmb3IgYW5hbHl0aWNzIGFuZCBtYWNoaW5lIGxlYXJuaW5nIChNTCkuIFxcclxcbkhPVyBUTyBTRVQgVVAgTE9DQUwgQUNDRVNTXFxyXFxuLS0tLS0tLS0tLS0tXFxyXFxuVG8gc2V0IHVwIGxvY2FsIGRldmVsb3BlciBhY2Nlc3M6XFxyXFxuMS4gT3BlbiBhIHRlcm1pbmFsIHdpbmRvdywgYW5kIGNvbmZpZ3VyZSB0aGUgQVdTIENMSS5cXHJcXG4gICBgYGBcXHJcXG4gICBhd3MgY29uZmlndXJlXFxyXFxuICAgYGBgXFxyXFxuMi4gV2hlbiBwcm9tcHRlZCwgcHJvdmlkZSB0aGUgZm9sbG93aW5nIGluZm9ybWF0aW9uLlxcclxcbiAgIGBgYFxcclxcbiAgID4gQVdTIEFjY2VzcyBLZXkgSUQgW05vbmVdOiBVc2VyLUFjY2Vzcy1LZXlcXHJcXG4gICA+IEFXUyBTZWNyZXQgQWNjZXNzIEtleSBJRCBbTm9uZV06IFVzZXItU2VjcmV0LUFjY2Vzcy1LZXlcXHJcXG4gICA+IERlZmF1bHQgcmVnaW9uIG5hbWUgSUQgW05vbmVdOiB1cy1lYXN0LTFcXHJcXG4gICA+IERlZmF1bHQgb3V0cHV0IGZvcm1hdCBbTm9uZV06IGpzb25cXHJcXG4gICBgYGBcXHJcXG4zLiBJbiBhIHBsYWluLXRleHQgZWRpdG9yLCBvcGVuIHRoZSBjb25maWcgZmlsZSwgYWxzbyBrbm93biBhcyB0aGUgQVdTIENMSSBjb25maWd1cmF0aW9uIGZpbGUuIERlcGVuZGluZyBvbiB5b3VyIG9wZXJhdGluZyBzeXN0ZW0sIHRoaXMgZmlsZSBtaWdodCBiZSBsb2NhdGVkIGF0IGB+Ly5hd3MvY29uZmlnYCBvbiBMaW51eCwgbWFjT1MsIG9yIFVuaXgsIG9yIGF0IGBkcml2ZTpcXFxcVXNlcnNcXFxcVVNFUk5BTUVcXFxcLmF3c1xcXFxjb25maWdgIG9uIFdpbmRvd3MuXFxyXFxuNC4gVXBkYXRlIHRoZSBmaWxlIHRvIGluY2x1ZGUgdHdvIGVudHJpZXMsIGRlZmF1bHQgZm9yIHlvdXIgYWNjb3VudCwgYW5kIGEgc2Vjb25kIGZvciBjcm9zcyBhY2NvdW50IGFjY2Vzcy4gVGhlIHJlc3VsdGluZyBmaWxlIHNob3VsZCBsb29rIGFzIGZvbGxvd3M6IFxcclxcbiAgIGBgYFxcclxcbiAgIFtkZWZhdWx0XVxcclxcbiAgIGFjY291bnQgPSA8dXNlci1hY2NvdW50LWlkPlxcclxcbiAgIHJlZ2lvbiA9IHVzLWVhc3QtMVxcclxcbiAgIG91dHB1dCA9IGpzb25cXHJcXG4gICAgXFxyXFxuICAgW3Byb2ZpbGUgQ3Jvc3NBY2NvdW50QWNjZXNzUHJvZmlsZV1cXHJcXG4gICBhY2NvdW50ID0gPGluZnJhLWFjY291bnQtaWQ+XFxyXFxuICAgcmVnaW9uID0gdXMtZWFzdC0xXFxyXFxuICAgb3V0cHV0ID0ganNvblxcclxcbiAgIHJvbGVfYXJuID0gYXJuOmF3czppYW06OjxpbmZyYS1hY2NvdW50LWlkPjpyb2xlL0Nyb3NzQWNjb3VudFJlcG9zaXRvcnlDb250cmlidXRvclJvbGVcXHJcXG4gICBzb3VyY2VfcHJvZmlsZSA9IGRlZmF1bHRcXHJcXG4gICBgYGBcXHJcXG42LiBTYXZlIHlvdXIgY2hhbmdlcywgYW5kIGNsb3NlIHRoZSBwbGFpbi10ZXh0IGVkaXRvci5cXHJcXG43LiBSdW4gKmdpdCBjbG9uZSogdG8gY2xvbmUgdGhlIHNoYXJlZCByZXBvc2l0b3J5LlxcclxcbiAgIGBgYFxcclxcbiAgID4gZ2l0IGNsb25lIGNvZGVjb21taXQ6Ly9Dcm9zc0FjY291bnRBY2Nlc3NQcm9maWxlQERhdGFCcmV3LVJlY2lwZXMtUmVwbyBcXHJcXG4gICBgYGAnLFxuICAgICAgfSxcbiAgICAgIHRpbWVvdXQ6IGNkay5EdXJhdGlvbi5zZWNvbmRzKDIwKSxcbiAgICAgIHRyYWNpbmc6IGxhbWJkYS5UcmFjaW5nLkFDVElWRSxcbiAgICB9KTtcbiAgICB0aGlzLmZ1bmN0aW9uID0gY29tbWl0SGFuZGxlckZ1bmN0aW9uO1xuICB9XG59Il19