UNPKG

cdk-iot-greengrass-fleet-provisioning

Version:

CDK Construct for AWS IoT Greengrass Fleet Provisioning (with AWS IoT Certificates)

351 lines 49.6 kB
#!/usr/bin/env node "use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.GreengrassFleetProvisioning = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const cdk = require("aws-cdk-lib"); const cfn = require("aws-cdk-lib/aws-cloudformation"); const iam = require("aws-cdk-lib/aws-iam"); const iot = require("aws-cdk-lib/aws-iot"); const lambda = require("aws-cdk-lib/aws-lambda"); const nodejs = require("aws-cdk-lib/aws-lambda-nodejs"); const logs = require("aws-cdk-lib/aws-logs"); const cr = require("aws-cdk-lib/custom-resources"); const constructs_1 = require("constructs"); /** * A CDK Construct for creating an AWS IoT Greengrass Fleet Provisioning assets (including certificate via Custom Resource) */ class GreengrassFleetProvisioning extends constructs_1.Construct { constructor(scope, id, props) { super(scope, id); this.props = props; this.tokenExchangeRole = this.addTokenExchangeRole(); this.fleetProvisioningRole = this.addFleetProvisioningRole(); this.provisioningClaimPolicy = this.addProvisioningClaimPolicy(); this.tokenExchangeRoleAlias = this.addTokenExchangeRoleAlias(); this.deviceDefaultPolicy = this.addDeviceDefaultPolicy(); this.fleetProvisionTemplate = this.addFleetProvisioningTemplate(); this.fleetProvisionCustomResource = this.addFleetProvisioningCustomResource(); this.certificateId = this.addFleetProvisioningCertificateId(); this.certificateArn = this.addFleetProvisioningCertificateArn(); this.credentialEndpoint = this.addIoTCredentialEndpoint(); this.dataEndpoint = this.addIoTDataEndpoint(); new iot.CfnPolicyPrincipalAttachment(this, 'greengrass-provisioning-claim-policy-attachment', { policyName: `${this.addProvisioningClaimPolicy().policyName}`, principal: this.addFleetProvisioningCertificateArn(), }); } addFleetProvisioningCustomResource() { if (this.fleetProvisionCustomResource === undefined) { const lambdaFunction = new nodejs.NodejsFunction(this, 'function', { functionName: `${this.props.resourcePrefix}-gg-fleet-provisioning`, runtime: lambda.Runtime.NODEJS_LATEST, // entry: path.join(__dirname, 'lambda/greengrass-fleet-provisioning.handler.ts'), handler: 'handler', bundling: { minify: true, // minify code, defaults to false sourceMap: true, // include source maps, defaults to false sourceMapMode: nodejs.SourceMapMode.INLINE, // defaults to SourceMapMode.DEFAULT sourcesContent: false, // whether to include original source codes in source maps, defaults to true target: 'es2020', // target environment for the generated JavaScript code, defaults to es2020 }, timeout: cdk.Duration.seconds(30), logRetention: logs.RetentionDays.ONE_DAY, }); lambdaFunction.addToRolePolicy(new iam.PolicyStatement({ actions: [ 'iot:CreateKeysAndCertificate', 'iot:DescribeEndpoint', ], resources: [ '*', ], })); lambdaFunction.addToRolePolicy(new iam.PolicyStatement({ actions: [ 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', 'iam:PassRole', 'iot:DeleteCertificate', 'iot:UpdateCertificate', 'kms:GenerateDataKey', 's3:DeleteObject', 's3:PutObject', 'ssm:DeleteParameter', 'ssm:GetParameter', 'ssm:PutParameter', ], resources: [ 'arn:aws:logs:*:*:*', `arn:aws:s3:::${this.props.certificateBucket.bucketName}/${this.props.certificatePrefix}*`, `arn:aws:iam::${this.props.env.account}:role/${this.props.resourcePrefix}-*`, `arn:aws:iot:${this.props.env.region}:${this.props.env.account}:cert/*`, `arn:aws:ssm:${this.props.env.region}:${this.props.env.account}:parameter/${this.props.resourcePrefix}*`, `arn:aws:kms:${this.props.env.region}:${this.props.env.account}:key/*`, ], })); const { serviceToken } = new cr.Provider(this, `${this.props.resourcePrefix}-cr-lambda-provider`, { onEventHandler: lambdaFunction, providerFunctionName: `${lambdaFunction.functionName}-provider`, logRetention: logs.RetentionDays.ONE_DAY, }); this.fleetProvisionCustomResource = new cfn.CfnCustomResource(this, `${this.props.resourcePrefix}-cr`, { serviceToken: serviceToken, serviceTimeout: 60, }); this.fleetProvisionCustomResource.addPropertyOverride('ResourcePrefix', this.props.resourcePrefix); this.fleetProvisionCustomResource.addPropertyOverride('CertificateBucketName', this.props.certificateBucket.bucketName); this.fleetProvisionCustomResource.addPropertyOverride('CertificatePrefix', this.props.certificatePrefix); } return this.fleetProvisionCustomResource; } addFleetProvisioningCertificateId() { if (this.certificateId === undefined) { const _customResource = this.addFleetProvisioningCustomResource(); this.certificateId = _customResource.getAtt('certificateId').toString(); } return this.certificateId; } addFleetProvisioningCertificateArn() { if (this.certificateArn === undefined) { const _customResource = this.addFleetProvisioningCustomResource(); this.certificateArn = _customResource.getAtt('certificateArn').toString(); } return this.certificateArn; } addFleetProvisioningRole() { if (this.fleetProvisioningRole === undefined) { this.fleetProvisioningRole = new iam.Role(this, `${this.props.resourcePrefix}-gg-fleet-provisioning-role`, { roleName: `${this.props.resourcePrefix}-gg-fleet-provisioning`, assumedBy: new iam.ServicePrincipal('iot.amazonaws.com'), path: '/', }); this.fleetProvisioningRole.assumeRolePolicy?.addStatements(new iam.PolicyStatement({ principals: [ new iam.ServicePrincipal('iot.amazonaws.com'), ], actions: [ 'sts:AssumeRole', ], effect: iam.Effect.ALLOW, })); this.fleetProvisioningRole.addManagedPolicy({ managedPolicyArn: 'arn:aws:iam::aws:policy/service-role/AWSIoTThingsRegistration', }); this.fleetProvisioningRole.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, resources: ['*'], // #TODO: - !Sub arn:aws:s3:::${S3BucketName} or !Sub arn:aws:s3:::${S3BucketName}/${S3BucketPrefixPattern} actions: [ 'iot:DescribeCertificate', 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', 'logs:DescribeLogStreams', 's3:GetBucketLocation', 's3:GetObject', 's3:ListBucket', 's3:PutObject', 's3:PutObjectAcl', ], })); } return this.fleetProvisioningRole; } addFleetProvisioningTemplate() { if (this.fleetProvisionTemplate === undefined) { this.fleetProvisionTemplate = new iot.CfnProvisioningTemplate(this, `${this.props.resourcePrefix}-gg-provisioning-template`, { templateName: `${this.props.resourcePrefix}-gg-fleet-provisioning`, description: 'Fleet Provisioning template for AWS IoT Greengrass.', enabled: true, provisioningRoleArn: this.addFleetProvisioningRole().roleArn, templateBody: ` { "Parameters": { "ThingName": { "Type": "String" }, "ThingGroupName": { "Type": "String" }, "AWS::IoT::Certificate::Id": { "Type": "String" } }, "Resources": { "MyGreengrassThing": { "OverrideSettings": { "AttributePayload": "REPLACE", "ThingGroups": "REPLACE", "ThingTypeName": "REPLACE" }, "Properties": { "AttributePayload": {}, "ThingGroups": [ { "Ref": "ThingGroupName" } ], "ThingName": { "Ref": "ThingName" } }, "Type": "AWS::IoT::Thing" }, "MyGreengrassPolicy": { "Properties": { "PolicyName": "${this.addDeviceDefaultPolicy().policyName}" }, "Type": "AWS::IoT::Policy" }, "MyGreengrassCertificate": { "Properties": { "CertificateId": { "Ref": "AWS::IoT::Certificate::Id" }, "Status": "Active" }, "Type": "AWS::IoT::Certificate" } } }`, }); } return this.fleetProvisionTemplate; } addIoTCredentialEndpoint() { if (this.credentialEndpoint === undefined) { const _customResource = this.addFleetProvisioningCustomResource(); this.credentialEndpoint = _customResource.getAtt('credentialEndpointAddress').toString(); } return this.credentialEndpoint; } addIoTDataEndpoint() { if (this.dataEndpoint === undefined) { const _customResource = this.addFleetProvisioningCustomResource(); this.dataEndpoint = _customResource.getAtt('dataEndpointAddress').toString(); } return this.dataEndpoint; } addTokenExchangeRole() { if (this.tokenExchangeRole === undefined) { this.tokenExchangeRole = new iam.Role(this, `${this.props.resourcePrefix}-gg-token-exchange-role`, { roleName: `${this.props.resourcePrefix}-gg-token-exchange`, description: 'Greengrass core devices token exchange role', assumedBy: new iam.ServicePrincipal('credentials.iot.amazonaws.com'), path: '/', }); this.tokenExchangeRole.assumeRolePolicy?.addStatements(new iam.PolicyStatement({ principals: [ new iam.ServicePrincipal('credentials.iot.amazonaws.com'), ], actions: [ 'sts:AssumeRole', ], effect: iam.Effect.ALLOW, })); this.tokenExchangeRole.addToPolicy(new iam.PolicyStatement({ effect: iam.Effect.ALLOW, resources: ['*'], // #TODO: - !Sub arn:aws:s3:::${S3BucketName} or !Sub arn:aws:s3:::${S3BucketName}/${S3BucketPrefixPattern} actions: [ 'iot:DescribeCertificate', 'logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents', 'logs:DescribeLogStreams', 's3:GetBucketLocation', 's3:GetObject', 's3:ListBucket', 's3:PutObject', 's3:PutObjectAcl', ], })); } return this.tokenExchangeRole; } addTokenExchangeRoleAlias() { if (this.tokenExchangeRoleAlias === undefined) { this.tokenExchangeRoleAlias = new iot.CfnRoleAlias(this, `${this.props.resourcePrefix}-gg-token-exchange-alias`, { roleAlias: `${this.props.resourcePrefix}-gg-token-exchange`, roleArn: this.addTokenExchangeRole().roleArn, }); } return this.tokenExchangeRoleAlias; } addDeviceDefaultPolicy() { if (this.deviceDefaultPolicy === undefined) { this.deviceDefaultPolicy = new iot.CfnPolicy(this, `${this.props.resourcePrefix}-gg-thing-policy`, { policyName: `${this.props.resourcePrefix}-gg-thing`, policyDocument: new iam.PolicyDocument({ statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'iot:Connect', 'iot:Publish', 'iot:Subscribe', 'iot:Receive', 'iot:Connect', 'greengrass:*', ], resources: ['*'], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'iot:AssumeRoleWithCertificate', ], resources: [this.addTokenExchangeRoleAlias().attrRoleAliasArn], }), ], }), }); } return this.deviceDefaultPolicy; } addProvisioningClaimPolicy() { if (this.provisioningClaimPolicy === undefined) { this.provisioningClaimPolicy = new iot.CfnPolicy(this, `${this.props.resourcePrefix}-gg-provisioning-claim-policy`, { policyName: `${this.props.resourcePrefix}-gg-fleet-provisioning`, policyDocument: new iam.PolicyDocument({ statements: [ new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'iot:Connect', ], resources: ['*'], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'iot:Publish', 'iot:Receive', ], resources: [ `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/$aws/certificates/create/*`, `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topic/$aws/provisioning-templates/${this.addFleetProvisioningTemplate().templateName}/provision/*`, ], }), new iam.PolicyStatement({ effect: iam.Effect.ALLOW, actions: [ 'iot:Subscribe', ], resources: [ `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topicfilter/$aws/certificates/create/*`, `arn:aws:iot:${cdk.Aws.REGION}:${cdk.Aws.ACCOUNT_ID}:topicfilter/$aws/provisioning-templates/${this.addFleetProvisioningTemplate().templateName}/provision/*`, ], }), ], }), }); } return this.provisioningClaimPolicy; } } exports.GreengrassFleetProvisioning = GreengrassFleetProvisioning; _a = JSII_RTTI_SYMBOL_1; GreengrassFleetProvisioning[_a] = { fqn: "cdk-iot-greengrass-fleet-provisioning.GreengrassFleetProvisioning", version: "1.0.3" }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQ0EsbUNBQW1DO0FBQ25DLHNEQUFzRDtBQUN0RCwyQ0FBMkM7QUFDM0MsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCx3REFBd0Q7QUFDeEQsNkNBQTZDO0FBRTdDLG1EQUFtRDtBQUNuRCwyQ0FBdUM7QUFtQnZDOztHQUVHO0FBQ0gsTUFBYSwyQkFBNEIsU0FBUSxzQkFBUztJQWlCeEQsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUF1QztRQUMvRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2pCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDO1FBRW5CLElBQUksQ0FBQyxpQkFBaUIsR0FBRyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUNyRCxJQUFJLENBQUMscUJBQXFCLEdBQUcsSUFBSSxDQUFDLHdCQUF3QixFQUFFLENBQUM7UUFDN0QsSUFBSSxDQUFDLHVCQUF1QixHQUFHLElBQUksQ0FBQywwQkFBMEIsRUFBRSxDQUFDO1FBQ2pFLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxJQUFJLENBQUMseUJBQXlCLEVBQUUsQ0FBQztRQUMvRCxJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSxDQUFDLHNCQUFzQixFQUFFLENBQUM7UUFDekQsSUFBSSxDQUFDLHNCQUFzQixHQUFHLElBQUksQ0FBQyw0QkFBNEIsRUFBRSxDQUFDO1FBQ2xFLElBQUksQ0FBQyw0QkFBNEIsR0FBRyxJQUFJLENBQUMsa0NBQWtDLEVBQUUsQ0FBQztRQUU5RSxJQUFJLENBQUMsYUFBYSxHQUFHLElBQUksQ0FBQyxpQ0FBaUMsRUFBRSxDQUFDO1FBQzlELElBQUksQ0FBQyxjQUFjLEdBQUcsSUFBSSxDQUFDLGtDQUFrQyxFQUFFLENBQUM7UUFDaEUsSUFBSSxDQUFDLGtCQUFrQixHQUFHLElB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QztRQUNMLENBQUM7UUFDRCxPQUFPLElBQUksQ0FBQyx1QkFBdUIsQ0FBQztJQUN0QyxDQUFDOztBQTNYSCxrRUE0WEMiLCJzb3VyY2VzQ29udGVudCI6WyIjIS91c3IvYmluL2VudiBub2RlXG5pbXBvcnQgKiBhcyBjZGsgZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgY2ZuIGZyb20gJ2F3cy1jZGstbGliL2F3cy1jbG91ZGZvcm1hdGlvbic7XG5pbXBvcnQgKiBhcyBpYW0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWlhbSc7XG5pbXBvcnQgKiBhcyBpb3QgZnJvbSAnYXdzLWNkay1saWIvYXdzLWlvdCc7XG5pbXBvcnQgKiBhcyBsYW1iZGEgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYSc7XG5pbXBvcnQgKiBhcyBub2RlanMgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxhbWJkYS1ub2RlanMnO1xuaW1wb3J0ICogYXMgbG9ncyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbG9ncyc7XG5pbXBvcnQgKiBhcyBzMyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtczMnO1xuaW1wb3J0ICogYXMgY3IgZnJvbSAnYXdzLWNkay1saWIvY3VzdG9tLXJlc291cmNlcyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIG9mIEdyZWVuZ3Jhc3NGbGVldFByb3Zpc2lvbmluZyBjb25zdHJ1Y3RcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHcmVlbmdyYXNzRmxlZXRQcm92aXNpb25pbmdQcm9wcyBleHRlbmRzIGNkay5SZXNvdXJjZVByb3BzIHtcbiAgLy8gVGhlIHJlc291cmNlIHByZWZpeFxuICByZWFkb25seSByZXNvdXJjZVByZWZpeDogc3RyaW5nO1xuXG4gIC8vIFRoZSBBV1MgZW52aXJvbm1lbnQgKGFjY291bnQvcmVnaW9uKSB3aGVyZSB0aGlzIHN0YWNrIHdpbGwgYmUgZGVwbG95ZWQuXG4gIHJlYWRvbmx5IGVudjogY2RrLkVudmlyb25tZW50O1xuXG4gIC8vIFRoZSBidWNrZXQgdG8gc2F2ZSB0aGUgY2VydGlmaWNhdGUgYW5kIHByaXZhdGUga2V5IGZpbGVzXG4gIHJlYWRvbmx5IGNlcnRpZmljYXRlQnVja2V0OiBzMy5JQnVja2V0O1xuXG4gIC8vIFRoZSBwcmVmaXggdG8gc2F2ZSB0aGUgY2VydGlmaWNhdGUgYW5kIHByaXZhdGUga2V5IGZpbGVzIGluIFNTTSBhbmQgUzNcbiAgcmVhZG9ubHkgY2VydGlmaWNhdGVQcmVmaXg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIENESyBDb25zdHJ1Y3QgZm9yIGNyZWF0aW5nIGFuIEFXUyBJb1QgR3JlZW5ncmFzcyBGbGVldCBQcm92aXNpb25pbmcgYXNzZXRzIChpbmNsdWRpbmcgY2VydGlmaWNhdGUgdmlhIEN1c3RvbSBSZXNvdXJjZSlcbiAqL1xuZXhwb3J0IGNsYXNzIEdyZWVuZ3Jhc3NGbGVldFByb3Zpc2lvbmluZyBleHRlbmRzIENvbnN0cnVjdCB7XG5cbiAgcHJpdmF0ZSBwcm9wczogR3JlZW5ncmFzc0ZsZWV0UHJvdmlzaW9uaW5nUHJvcHM7XG5cbiAgcHVibGljIHRva2VuRXhjaGFuZ2VSb2xlOiBpYW0uUm9sZTtcbiAgcHVibGljIGZsZWV0UHJvdmlzaW9uaW5nUm9sZTogaWFtLlJvbGU7XG4gIHB1YmxpYyBwcm92aXNpb25pbmdDbGFpbVBvbGljeTogaW90LkNmblBvbGljeTtcbiAgcHVibGljIHRva2VuRXhjaGFuZ2VSb2xlQWxpYXM6IGlvdC5DZm5Sb2xlQWxpYXM7XG4gIHB1YmxpYyBkZXZpY2VEZWZhdWx0UG9saWN5OiBpb3QuQ2ZuUG9saWN5O1xuICBwdWJsaWMgZmxlZXRQcm92aXNpb25UZW1wbGF0ZTogaW90LkNmblByb3Zpc2lvbmluZ1RlbXBsYXRlO1xuICBwdWJsaWMgZmxlZXRQcm92aXNpb25DdXN0b21SZXNvdXJjZTogY2ZuLkNmbkN1c3RvbVJlc291cmNlO1xuXG4gIHB1YmxpYyBjZXJ0aWZpY2F0ZUlkOiBzdHJpbmc7XG4gIHB1YmxpYyBjZXJ0aWZpY2F0ZUFybjogc3RyaW5nO1xuICBwdWJsaWMgY3JlZGVudGlhbEVuZHBvaW50OiBzdHJpbmc7XG4gIHB1YmxpYyBkYXRhRW5kcG9pbnQ6IHN0cmluZztcblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogR3JlZW5ncmFzc0ZsZWV0UHJvdmlzaW9uaW5nUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuICAgIHRoaXMucHJvcHMgPSBwcm9wcztcblxuICAgIHRoaXMudG9rZW5FeGNoYW5nZVJvbGUgPSB0aGlzLmFkZFRva2VuRXhjaGFuZ2VSb2xlKCk7XG4gICAgdGhpcy5mbGVldFByb3Zpc2lvbmluZ1JvbGUgPSB0aGlzLmFkZEZsZWV0UHJvdmlzaW9uaW5nUm9sZSgpO1xuICAgIHRoaXMucHJvdmlzaW9uaW5nQ2xhaW1Qb2xpY3kgPSB0aGlzLmFkZFByb3Zpc2lvbmluZ0NsYWltUG9saWN5KCk7XG4gICAgdGhpcy50b2tlbkV4Y2hhbmdlUm9sZUFsaWFzID0gdGhpcy5hZGRUb2tlbkV4Y2hhbmdlUm9sZUFsaWFzKCk7XG4gICAgdGhpcy5kZXZpY2VEZWZhdWx0UG9saWN5ID0gdGhpcy5hZGREZXZpY2VEZWZhdWx0UG9saWN5KCk7XG4gICAgdGhpcy5mbGVldFByb3Zpc2lvblRlbXBsYXRlID0gdGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ1RlbXBsYXRlKCk7XG4gICAgdGhpcy5mbGVldFByb3Zpc2lvbkN1c3RvbVJlc291cmNlID0gdGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ0N1c3RvbVJlc291cmNlKCk7XG5cbiAgICB0aGlzLmNlcnRpZmljYXRlSWQgPSB0aGlzLmFkZEZsZWV0UHJvdmlzaW9uaW5nQ2VydGlmaWNhdGVJZCgpO1xuICAgIHRoaXMuY2VydGlmaWNhdGVBcm4gPSB0aGlzLmFkZEZsZWV0UHJvdmlzaW9uaW5nQ2VydGlmaWNhdGVBcm4oKTtcbiAgICB0aGlzLmNyZWRlbnRpYWxFbmRwb2ludCA9IHRoaXMuYWRkSW9UQ3JlZGVudGlhbEVuZHBvaW50KCk7XG4gICAgdGhpcy5kYXRhRW5kcG9pbnQgPSB0aGlzLmFkZElvVERhdGFFbmRwb2ludCgpO1xuXG4gICAgbmV3IGlvdC5DZm5Qb2xpY3lQcmluY2lwYWxBdHRhY2htZW50KHRoaXMsICdncmVlbmdyYXNzLXByb3Zpc2lvbmluZy1jbGFpbS1wb2xpY3ktYXR0YWNobWVudCcsIHtcbiAgICAgIHBvbGljeU5hbWU6IGAke3RoaXMuYWRkUHJvdmlzaW9uaW5nQ2xhaW1Qb2xpY3koKS5wb2xpY3lOYW1lfWAsXG4gICAgICBwcmluY2lwYWw6IHRoaXMuYWRkRmxlZXRQcm92aXNpb25pbmdDZXJ0aWZpY2F0ZUFybigpLFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRGbGVldFByb3Zpc2lvbmluZ0N1c3RvbVJlc291cmNlKCkge1xuICAgIGlmICh0aGlzLmZsZWV0UHJvdmlzaW9uQ3VzdG9tUmVzb3VyY2UgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgbGFtYmRhRnVuY3Rpb24gPSBuZXcgbm9kZWpzLk5vZGVqc0Z1bmN0aW9uKHRoaXMsICdmdW5jdGlvbicsIHtcbiAgICAgICAgZnVuY3Rpb25OYW1lOiBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1nZy1mbGVldC1wcm92aXNpb25pbmdgLFxuICAgICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfTEFURVNULFxuICAgICAgICAvLyBlbnRyeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJ2xhbWJkYS9ncmVlbmdyYXNzLWZsZWV0LXByb3Zpc2lvbmluZy5oYW5kbGVyLnRzJyksXG4gICAgICAgIGhhbmRsZXI6ICdoYW5kbGVyJyxcbiAgICAgICAgYnVuZGxpbmc6IHtcbiAgICAgICAgICBtaW5pZnk6IHRydWUsIC8vIG1pbmlmeSBjb2RlLCBkZWZhdWx0cyB0byBmYWxzZVxuICAgICAgICAgIHNvdXJjZU1hcDogdHJ1ZSwgLy8gaW5jbHVkZSBzb3VyY2UgbWFwcywgZGVmYXVsdHMgdG8gZmFsc2VcbiAgICAgICAgICBzb3VyY2VNYXBNb2RlOiBub2RlanMuU291cmNlTWFwTW9kZS5JTkxJTkUsIC8vIGRlZmF1bHRzIHRvIFNvdXJjZU1hcE1vZGUuREVGQVVMVFxuICAgICAgICAgIHNvdXJjZXNDb250ZW50OiBmYWxzZSwgLy8gd2hldGhlciB0byBpbmNsdWRlIG9yaWdpbmFsIHNvdXJjZSBjb2RlcyBpbiBzb3VyY2UgbWFwcywgZGVmYXVsdHMgdG8gdHJ1ZVxuICAgICAgICAgIHRhcmdldDogJ2VzMjAyMCcsIC8vIHRhcmdldCBlbnZpcm9ubWVudCBmb3IgdGhlIGdlbmVyYXRlZCBKYXZhU2NyaXB0IGNvZGUsIGRlZmF1bHRzIHRvIGVzMjAyMFxuICAgICAgICB9LFxuICAgICAgICB0aW1lb3V0OiBjZGsuRHVyYXRpb24uc2Vjb25kcygzMCksXG4gICAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9EQVksXG4gICAgICB9KTtcbiAgICAgIGxhbWJkYUZ1bmN0aW9uLmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICdpb3Q6Q3JlYXRlS2V5c0FuZENlcnRpZmljYXRlJyxcbiAgICAgICAgICAgICdpb3Q6RGVzY3JpYmVFbmRwb2ludCcsXG4gICAgICAgICAgXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICAgICcqJyxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgICBsYW1iZGFGdW5jdGlvbi5hZGRUb1JvbGVQb2xpY3koXG4gICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAnbG9nczpDcmVhdGVMb2dHcm91cCcsXG4gICAgICAgICAgICAnbG9nczpDcmVhdGVMb2dTdHJlYW0nLFxuICAgICAgICAgICAgJ2xvZ3M6UHV0TG9nRXZlbnRzJyxcbiAgICAgICAgICAgICdpYW06UGFzc1JvbGUnLFxuICAgICAgICAgICAgJ2lvdDpEZWxldGVDZXJ0aWZpY2F0ZScsXG4gICAgICAgICAgICAnaW90OlVwZGF0ZUNlcnRpZmljYXRlJyxcbiAgICAgICAgICAgICdrbXM6R2VuZXJhdGVEYXRhS2V5JyxcbiAgICAgICAgICAgICdzMzpEZWxldGVPYmplY3QnLFxuICAgICAgICAgICAgJ3MzOlB1dE9iamVjdCcsXG4gICAgICAgICAgICAnc3NtOkRlbGV0ZVBhcmFtZXRlcicsXG4gICAgICAgICAgICAnc3NtOkdldFBhcmFtZXRlcicsXG4gICAgICAgICAgICAnc3NtOlB1dFBhcmFtZXRlcicsXG4gICAgICAgICAgXSxcbiAgICAgICAgICByZXNvdXJjZXM6IFtcbiAgICAgICAgICAgICdhcm46YXdzOmxvZ3M6KjoqOionLFxuICAgICAgICAgICAgYGFybjphd3M6czM6Ojoke3RoaXMucHJvcHMuY2VydGlmaWNhdGVCdWNrZXQuYnVja2V0TmFtZX0vJHt0aGlzLnByb3BzLmNlcnRpZmljYXRlUHJlZml4fSpgLFxuICAgICAgICAgICAgYGFybjphd3M6aWFtOjoke3RoaXMucHJvcHMuZW52LmFjY291bnR9OnJvbGUvJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS0qYCxcbiAgICAgICAgICAgIGBhcm46YXdzOmlvdDoke3RoaXMucHJvcHMuZW52LnJlZ2lvbn06JHt0aGlzLnByb3BzLmVudi5hY2NvdW50fTpjZXJ0LypgLFxuICAgICAgICAgICAgYGFybjphd3M6c3NtOiR7dGhpcy5wcm9wcy5lbnYucmVnaW9ufToke3RoaXMucHJvcHMuZW52LmFjY291bnR9OnBhcmFtZXRlci8ke3RoaXMucHJvcHMucmVzb3VyY2VQcmVmaXh9KmAsXG4gICAgICAgICAgICBgYXJuOmF3czprbXM6JHt0aGlzLnByb3BzLmVudi5yZWdpb259OiR7dGhpcy5wcm9wcy5lbnYuYWNjb3VudH06a2V5LypgLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgY29uc3QgeyBzZXJ2aWNlVG9rZW4gfSA9IG5ldyBjci5Qcm92aWRlcih0aGlzLCBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1jci1sYW1iZGEtcHJvdmlkZXJgLCB7XG4gICAgICAgIG9uRXZlbnRIYW5kbGVyOiBsYW1iZGFGdW5jdGlvbixcbiAgICAgICAgcHJvdmlkZXJGdW5jdGlvbk5hbWU6IGAke2xhbWJkYUZ1bmN0aW9uLmZ1bmN0aW9uTmFtZX0tcHJvdmlkZXJgLFxuICAgICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfREFZLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuZmxlZXRQcm92aXNpb25DdXN0b21SZXNvdXJjZSA9IG5ldyBjZm4uQ2ZuQ3VzdG9tUmVzb3VyY2UodGhpcywgYCR7dGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeH0tY3JgLCB7XG4gICAgICAgIHNlcnZpY2VUb2tlbjogc2VydmljZVRva2VuLFxuICAgICAgICBzZXJ2aWNlVGltZW91dDogNjAsXG4gICAgICB9KTtcblxuICAgICAgdGhpcy5mbGVldFByb3Zpc2lvbkN1c3RvbVJlc291cmNlLmFkZFByb3BlcnR5T3ZlcnJpZGUoJ1Jlc291cmNlUHJlZml4JywgdGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeCk7XG4gICAgICB0aGlzLmZsZWV0UHJvdmlzaW9uQ3VzdG9tUmVzb3VyY2UuYWRkUHJvcGVydHlPdmVycmlkZSgnQ2VydGlmaWNhdGVCdWNrZXROYW1lJywgdGhpcy5wcm9wcy5jZXJ0aWZpY2F0ZUJ1Y2tldC5idWNrZXROYW1lKTtcbiAgICAgIHRoaXMuZmxlZXRQcm92aXNpb25DdXN0b21SZXNvdXJjZS5hZGRQcm9wZXJ0eU92ZXJyaWRlKCdDZXJ0aWZpY2F0ZVByZWZpeCcsIHRoaXMucHJvcHMuY2VydGlmaWNhdGVQcmVmaXgpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLmZsZWV0UHJvdmlzaW9uQ3VzdG9tUmVzb3VyY2U7XG4gIH1cblxuICBwcml2YXRlIGFkZEZsZWV0UHJvdmlzaW9uaW5nQ2VydGlmaWNhdGVJZCgpOiBhbnkge1xuICAgIGlmICh0aGlzLmNlcnRpZmljYXRlSWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgX2N1c3RvbVJlc291cmNlID0gdGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ0N1c3RvbVJlc291cmNlKCk7XG4gICAgICB0aGlzLmNlcnRpZmljYXRlSWQgPSBfY3VzdG9tUmVzb3VyY2UuZ2V0QXR0KCdjZXJ0aWZpY2F0ZUlkJykudG9TdHJpbmcoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2VydGlmaWNhdGVJZDtcbiAgfVxuXG4gIHByaXZhdGUgYWRkRmxlZXRQcm92aXNpb25pbmdDZXJ0aWZpY2F0ZUFybigpOiBhbnkge1xuICAgIGlmICh0aGlzLmNlcnRpZmljYXRlQXJuID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IF9jdXN0b21SZXNvdXJjZSA9IHRoaXMuYWRkRmxlZXRQcm92aXNpb25pbmdDdXN0b21SZXNvdXJjZSgpO1xuICAgICAgdGhpcy5jZXJ0aWZpY2F0ZUFybiA9IF9jdXN0b21SZXNvdXJjZS5nZXRBdHQoJ2NlcnRpZmljYXRlQXJuJykudG9TdHJpbmcoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuY2VydGlmaWNhdGVBcm47XG4gIH1cblxuICBwcml2YXRlIGFkZEZsZWV0UHJvdmlzaW9uaW5nUm9sZSgpIHtcbiAgICBpZiAodGhpcy5mbGVldFByb3Zpc2lvbmluZ1JvbGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5mbGVldFByb3Zpc2lvbmluZ1JvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgYCR7dGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeH0tZ2ctZmxlZXQtcHJvdmlzaW9uaW5nLXJvbGVgLCB7XG4gICAgICAgIHJvbGVOYW1lOiBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1nZy1mbGVldC1wcm92aXNpb25pbmdgLFxuICAgICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnaW90LmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgcGF0aDogJy8nLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMuZmxlZXRQcm92aXNpb25pbmdSb2xlLmFzc3VtZVJvbGVQb2xpY3k/LmFkZFN0YXRlbWVudHMoXG4gICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBwcmluY2lwYWxzOiBbXG4gICAgICAgICAgICBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2lvdC5hbWF6b25hd3MuY29tJyksXG4gICAgICAgICAgXSxcbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAnc3RzOkFzc3VtZVJvbGUnLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgICB9KSxcbiAgICAgICk7XG5cbiAgICAgIHRoaXMuZmxlZXRQcm92aXNpb25pbmdSb2xlLmFkZE1hbmFnZWRQb2xpY3koe1xuICAgICAgICBtYW5hZ2VkUG9saWN5QXJuOiAnYXJuOmF3czppYW06OmF3czpwb2xpY3kvc2VydmljZS1yb2xlL0FXU0lvVFRoaW5nc1JlZ2lzdHJhdGlvbicsXG4gICAgICB9KTtcblxuICAgICAgdGhpcy5mbGVldFByb3Zpc2lvbmluZ1JvbGUuYWRkVG9Qb2xpY3koXG4gICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgcmVzb3VyY2VzOiBbJyonXSwgLy8gI1RPRE86IC0gIVN1YiBhcm46YXdzOnMzOjo6JHtTM0J1Y2tldE5hbWV9IG9yICFTdWIgYXJuOmF3czpzMzo6OiR7UzNCdWNrZXROYW1lfS8ke1MzQnVja2V0UHJlZml4UGF0dGVybn1cbiAgICAgICAgICBhY3Rpb25zOiBbXG4gICAgICAgICAgICAnaW90OkRlc2NyaWJlQ2VydGlmaWNhdGUnLFxuICAgICAgICAgICAgJ2xvZ3M6Q3JlYXRlTG9nR3JvdXAnLFxuICAgICAgICAgICAgJ2xvZ3M6Q3JlYXRlTG9nU3RyZWFtJyxcbiAgICAgICAgICAgICdsb2dzOlB1dExvZ0V2ZW50cycsXG4gICAgICAgICAgICAnbG9nczpEZXNjcmliZUxvZ1N0cmVhbXMnLFxuICAgICAgICAgICAgJ3MzOkdldEJ1Y2tldExvY2F0aW9uJyxcbiAgICAgICAgICAgICdzMzpHZXRPYmplY3QnLFxuICAgICAgICAgICAgJ3MzOkxpc3RCdWNrZXQnLFxuICAgICAgICAgICAgJ3MzOlB1dE9iamVjdCcsXG4gICAgICAgICAgICAnczM6UHV0T2JqZWN0QWNsJyxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgICk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmZsZWV0UHJvdmlzaW9uaW5nUm9sZTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkRmxlZXRQcm92aXNpb25pbmdUZW1wbGF0ZSgpIHtcbiAgICBpZiAodGhpcy5mbGVldFByb3Zpc2lvblRlbXBsYXRlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuZmxlZXRQcm92aXNpb25UZW1wbGF0ZSA9IG5ldyBpb3QuQ2ZuUHJvdmlzaW9uaW5nVGVtcGxhdGUodGhpcywgYCR7dGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeH0tZ2ctcHJvdmlzaW9uaW5nLXRlbXBsYXRlYCwge1xuICAgICAgICB0ZW1wbGF0ZU5hbWU6IGAke3RoaXMucHJvcHMucmVzb3VyY2VQcmVmaXh9LWdnLWZsZWV0LXByb3Zpc2lvbmluZ2AsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRmxlZXQgUHJvdmlzaW9uaW5nIHRlbXBsYXRlIGZvciBBV1MgSW9UIEdyZWVuZ3Jhc3MuJyxcbiAgICAgICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgcHJvdmlzaW9uaW5nUm9sZUFybjogdGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ1JvbGUoKS5yb2xlQXJuLFxuICAgICAgICB0ZW1wbGF0ZUJvZHk6IGBcbiAgICAgICAge1xuICAgICAgICAgIFwiUGFyYW1ldGVyc1wiOiB7XG4gICAgICAgICAgICBcIlRoaW5nTmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiVHlwZVwiOiBcIlN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJUaGluZ0dyb3VwTmFtZVwiOiB7XG4gICAgICAgICAgICAgIFwiVHlwZVwiOiBcIlN0cmluZ1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJBV1M6OklvVDo6Q2VydGlmaWNhdGU6OklkXCI6IHtcbiAgICAgICAgICAgICAgXCJUeXBlXCI6IFwiU3RyaW5nXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIFwiUmVzb3VyY2VzXCI6IHtcbiAgICAgICAgICAgIFwiTXlHcmVlbmdyYXNzVGhpbmdcIjoge1xuICAgICAgICAgICAgICBcIk92ZXJyaWRlU2V0dGluZ3NcIjoge1xuICAgICAgICAgICAgICAgIFwiQXR0cmlidXRlUGF5bG9hZFwiOiBcIlJFUExBQ0VcIixcbiAgICAgICAgICAgICAgICBcIlRoaW5nR3JvdXBzXCI6IFwiUkVQTEFDRVwiLFxuICAgICAgICAgICAgICAgIFwiVGhpbmdUeXBlTmFtZVwiOiBcIlJFUExBQ0VcIlxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBcIlByb3BlcnRpZXNcIjoge1xuICAgICAgICAgICAgICAgIFwiQXR0cmlidXRlUGF5bG9hZFwiOiB7fSxcbiAgICAgICAgICAgICAgICBcIlRoaW5nR3JvdXBzXCI6IFtcbiAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgXCJSZWZcIjogXCJUaGluZ0dyb3VwTmFtZVwiXG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBcIlRoaW5nTmFtZVwiOiB7XG4gICAgICAgICAgICAgICAgICBcIlJlZlwiOiBcIlRoaW5nTmFtZVwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBcIlR5cGVcIjogXCJBV1M6OklvVDo6VGhpbmdcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwiTXlHcmVlbmdyYXNzUG9saWN5XCI6IHtcbiAgICAgICAgICAgICAgXCJQcm9wZXJ0aWVzXCI6IHtcbiAgICAgICAgICAgICAgICBcIlBvbGljeU5hbWVcIjogXCIke3RoaXMuYWRkRGV2aWNlRGVmYXVsdFBvbGljeSgpLnBvbGljeU5hbWV9XCJcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgXCJUeXBlXCI6IFwiQVdTOjpJb1Q6OlBvbGljeVwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJNeUdyZWVuZ3Jhc3NDZXJ0aWZpY2F0ZVwiOiB7XG4gICAgICAgICAgICAgIFwiUHJvcGVydGllc1wiOiB7XG4gICAgICAgICAgICAgICAgXCJDZXJ0aWZpY2F0ZUlkXCI6IHtcbiAgICAgICAgICAgICAgICAgIFwiUmVmXCI6IFwiQVdTOjpJb1Q6OkNlcnRpZmljYXRlOjpJZFwiXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBcIlN0YXR1c1wiOiBcIkFjdGl2ZVwiXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIFwiVHlwZVwiOiBcIkFXUzo6SW9UOjpDZXJ0aWZpY2F0ZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9YCxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5mbGVldFByb3Zpc2lvblRlbXBsYXRlO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRJb1RDcmVkZW50aWFsRW5kcG9pbnQoKTogYW55IHtcbiAgICBpZiAodGhpcy5jcmVkZW50aWFsRW5kcG9pbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgX2N1c3RvbVJlc291cmNlID0gdGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ0N1c3RvbVJlc291cmNlKCk7XG4gICAgICB0aGlzLmNyZWRlbnRpYWxFbmRwb2ludCA9IF9jdXN0b21SZXNvdXJjZS5nZXRBdHQoJ2NyZWRlbnRpYWxFbmRwb2ludEFkZHJlc3MnKS50b1N0cmluZygpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5jcmVkZW50aWFsRW5kcG9pbnQ7XG4gIH1cblxuICBwcml2YXRlIGFkZElvVERhdGFFbmRwb2ludCgpOiBhbnkge1xuICAgIGlmICh0aGlzLmRhdGFFbmRwb2ludCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBfY3VzdG9tUmVzb3VyY2UgPSB0aGlzLmFkZEZsZWV0UHJvdmlzaW9uaW5nQ3VzdG9tUmVzb3VyY2UoKTtcbiAgICAgIHRoaXMuZGF0YUVuZHBvaW50ID0gX2N1c3RvbVJlc291cmNlLmdldEF0dCgnZGF0YUVuZHBvaW50QWRkcmVzcycpLnRvU3RyaW5nKCk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmRhdGFFbmRwb2ludDtcbiAgfVxuXG4gIHByaXZhdGUgYWRkVG9rZW5FeGNoYW5nZVJvbGUoKSB7XG4gICAgaWYgKHRoaXMudG9rZW5FeGNoYW5nZVJvbGUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy50b2tlbkV4Y2hhbmdlUm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1nZy10b2tlbi1leGNoYW5nZS1yb2xlYCwge1xuICAgICAgICByb2xlTmFtZTogYCR7dGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeH0tZ2ctdG9rZW4tZXhjaGFuZ2VgLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0dyZWVuZ3Jhc3MgY29yZSBkZXZpY2VzIHRva2VuIGV4Y2hhbmdlIHJvbGUnLFxuICAgICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnY3JlZGVudGlhbHMuaW90LmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgcGF0aDogJy8nLFxuICAgICAgfSk7XG5cbiAgICAgIHRoaXMudG9rZW5FeGNoYW5nZVJvbGUuYXNzdW1lUm9sZVBvbGljeT8uYWRkU3RhdGVtZW50cyhcbiAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIHByaW5jaXBhbHM6IFtcbiAgICAgICAgICAgIG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnY3JlZGVudGlhbHMuaW90LmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgICBdLFxuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICdzdHM6QXNzdW1lUm9sZScsXG4gICAgICAgICAgXSxcbiAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgIH0pLFxuICAgICAgKTtcblxuICAgICAgdGhpcy50b2tlbkV4Y2hhbmdlUm9sZS5hZGRUb1BvbGljeShcbiAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgICByZXNvdXJjZXM6IFsnKiddLCAvLyAjVE9ETzogLSAhU3ViIGFybjphd3M6czM6Ojoke1MzQnVja2V0TmFtZX0gb3IgIVN1YiBhcm46YXdzOnMzOjo6JHtTM0J1Y2tldE5hbWV9LyR7UzNCdWNrZXRQcmVmaXhQYXR0ZXJufVxuICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICdpb3Q6RGVzY3JpYmVDZXJ0aWZpY2F0ZScsXG4gICAgICAgICAgICAnbG9nczpDcmVhdGVMb2dHcm91cCcsXG4gICAgICAgICAgICAnbG9nczpDcmVhdGVMb2dTdHJlYW0nLFxuICAgICAgICAgICAgJ2xvZ3M6UHV0TG9nRXZlbnRzJyxcbiAgICAgICAgICAgICdsb2dzOkRlc2NyaWJlTG9nU3RyZWFtcycsXG4gICAgICAgICAgICAnczM6R2V0QnVja2V0TG9jYXRpb24nLFxuICAgICAgICAgICAgJ3MzOkdldE9iamVjdCcsXG4gICAgICAgICAgICAnczM6TGlzdEJ1Y2tldCcsXG4gICAgICAgICAgICAnczM6UHV0T2JqZWN0JyxcbiAgICAgICAgICAgICdzMzpQdXRPYmplY3RBY2wnLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudG9rZW5FeGNoYW5nZVJvbGU7XG5cbiAgfVxuXG4gIHByaXZhdGUgYWRkVG9rZW5FeGNoYW5nZVJvbGVBbGlhcygpIHtcbiAgICBpZiAodGhpcy50b2tlbkV4Y2hhbmdlUm9sZUFsaWFzID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMudG9rZW5FeGNoYW5nZVJvbGVBbGlhcyA9IG5ldyBpb3QuQ2ZuUm9sZUFsaWFzKHRoaXMsIGAke3RoaXMucHJvcHMucmVzb3VyY2VQcmVmaXh9LWdnLXRva2VuLWV4Y2hhbmdlLWFsaWFzYCwge1xuICAgICAgICByb2xlQWxpYXM6IGAke3RoaXMucHJvcHMucmVzb3VyY2VQcmVmaXh9LWdnLXRva2VuLWV4Y2hhbmdlYCxcbiAgICAgICAgcm9sZUFybjogdGhpcy5hZGRUb2tlbkV4Y2hhbmdlUm9sZSgpLnJvbGVBcm4sXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMudG9rZW5FeGNoYW5nZVJvbGVBbGlhcztcbiAgfVxuXG4gIHByaXZhdGUgYWRkRGV2aWNlRGVmYXVsdFBvbGljeSgpIHtcbiAgICBpZiAodGhpcy5kZXZpY2VEZWZhdWx0UG9saWN5ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMuZGV2aWNlRGVmYXVsdFBvbGljeSA9IG5ldyBpb3QuQ2ZuUG9saWN5KHRoaXMsIGAke3RoaXMucHJvcHMucmVzb3VyY2VQcmVmaXh9LWdnLXRoaW5nLXBvbGljeWAsIHtcbiAgICAgICAgcG9saWN5TmFtZTogYCR7dGhpcy5wcm9wcy5yZXNvdXJjZVByZWZpeH0tZ2ctdGhpbmdgLFxuICAgICAgICBwb2xpY3lEb2N1bWVudDogbmV3IGlhbS5Qb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAnaW90OkNvbm5lY3QnLFxuICAgICAgICAgICAgICAgICdpb3Q6UHVibGlzaCcsXG4gICAgICAgICAgICAgICAgJ2lvdDpTdWJzY3JpYmUnLFxuICAgICAgICAgICAgICAgICdpb3Q6UmVjZWl2ZScsXG4gICAgICAgICAgICAgICAgJ2lvdDpDb25uZWN0JyxcbiAgICAgICAgICAgICAgICAnZ3JlZW5ncmFzczoqJyxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgcmVzb3VyY2VzOiBbJyonXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAnaW90OkFzc3VtZVJvbGVXaXRoQ2VydGlmaWNhdGUnLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFt0aGlzLmFkZFRva2VuRXhjaGFuZ2VSb2xlQWxpYXMoKS5hdHRyUm9sZUFsaWFzQXJuXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0pLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmRldmljZURlZmF1bHRQb2xpY3k7XG4gIH1cblxuICBwcml2YXRlIGFkZFByb3Zpc2lvbmluZ0NsYWltUG9saWN5KCkge1xuICAgIGlmICh0aGlzLnByb3Zpc2lvbmluZ0NsYWltUG9saWN5ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRoaXMucHJvdmlzaW9uaW5nQ2xhaW1Qb2xpY3kgPSBuZXcgaW90LkNmblBvbGljeSh0aGlzLCBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1nZy1wcm92aXNpb25pbmctY2xhaW0tcG9saWN5YCwge1xuICAgICAgICBwb2xpY3lOYW1lOiBgJHt0aGlzLnByb3BzLnJlc291cmNlUHJlZml4fS1nZy1mbGVldC1wcm92aXNpb25pbmdgLFxuICAgICAgICBwb2xpY3lEb2N1bWVudDogbmV3IGlhbS5Qb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAnaW90OkNvbm5lY3QnLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICByZXNvdXJjZXM6IFsnKiddLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgICAgICAgICAgYWN0aW9uczogW1xuICAgICAgICAgICAgICAgICdpb3Q6UHVibGlzaCcsXG4gICAgICAgICAgICAgICAgJ2lvdDpSZWNlaXZlJyxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAgICAgICAgYGFybjphd3M6aW90OiR7Y2RrLkF3cy5SRUdJT059OiR7Y2RrLkF3cy5BQ0NPVU5UX0lEfTp0b3BpYy8kYXdzL2NlcnRpZmljYXRlcy9jcmVhdGUvKmAsXG4gICAgICAgICAgICAgICAgYGFybjphd3M6aW90OiR7Y2RrLkF3cy5SRUdJT059OiR7Y2RrLkF3cy5BQ0NPVU5UX0lEfTp0b3BpYy8kYXdzL3Byb3Zpc2lvbmluZy10ZW1wbGF0ZXMvJHt0aGlzLmFkZEZsZWV0UHJvdmlzaW9uaW5nVGVtcGxhdGUoKS50ZW1wbGF0ZU5hbWV9L3Byb3Zpc2lvbi8qYCxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICBlZmZlY3Q6IGlhbS5FZmZlY3QuQUxMT1csXG4gICAgICAgICAgICAgIGFjdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAnaW90OlN1YnNjcmliZScsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW1xuICAgICAgICAgICAgICAgIGBhcm46YXdzOmlvdDoke2Nkay5Bd3MuUkVHSU9OfToke2Nkay5Bd3MuQUNDT1VOVF9JRH06dG9waWNmaWx0ZXIvJGF3cy9jZXJ0aWZpY2F0ZXMvY3JlYXRlLypgLFxuICAgICAgICAgICAgICAgIGBhcm46YXdzOmlvdDoke2Nkay5Bd3MuUkVHSU9OfToke2Nkay5Bd3MuQUNDT1VOVF9JRH06dG9waWNmaWx0ZXIvJGF3cy9wcm92aXNpb25pbmctdGVtcGxhdGVzLyR7dGhpcy5hZGRGbGVldFByb3Zpc2lvbmluZ1RlbXBsYXRlKCkudGVtcGxhdGVOYW1lfS9wcm92aXNpb24vKmAsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5wcm92aXNpb25pbmdDbGFpbVBvbGljeTtcbiAgfVxufVxuXG4iXX0=