@pwrdrvr/microapps-cdk
Version:
MicroApps framework, by PwrDrvr LLC, delivered as an AWS CDK construct that provides the DynamoDB, Router service, Deploy service, API Gateway, and CloudFront distribution.
342 lines • 58.3 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MicroAppsSvcs = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const fs_1 = require("fs");
const path = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const dynamodb = require("aws-cdk-lib/aws-dynamodb");
const iam = require("aws-cdk-lib/aws-iam");
const lambda = require("aws-cdk-lib/aws-lambda");
const lambdaNodejs = require("aws-cdk-lib/aws-lambda-nodejs");
const logs = require("aws-cdk-lib/aws-logs");
const s3 = require("aws-cdk-lib/aws-s3");
const constructs_1 = require("constructs");
/**
* Create a new MicroApps Services construct, including the Deployer
* and Router Lambda Functions, and the DynamoDB Table used by both.
*/
class MicroAppsSvcs extends constructs_1.Construct {
get table() {
return this._table;
}
get deployerFunc() {
return this._deployerFunc;
}
get routerFunc() {
return this._routerFunc;
}
constructor(scope, id, props) {
super(scope, id);
if (props === undefined) {
throw new Error('props cannot be undefined');
}
const { bucketApps, bucketAppsOAI, bucketAppsStaging, deployerTimeout = aws_cdk_lib_1.Duration.minutes(2), s3PolicyBypassAROAs = [], s3PolicyBypassPrincipalARNs = [], s3StrictBucketPolicy = false, appEnv, removalPolicy, assetNameRoot, assetNameSuffix, rootPathPrefix = '', requireIAMAuthorization = true, edgeToOriginRoleARN, } = props;
if (s3StrictBucketPolicy === true) {
if (s3PolicyBypassAROAs.length === 0 && s3PolicyBypassPrincipalARNs.length === 0) {
throw new Error('s3StrictBucketPolicy cannot be true without specifying at least one s3PolicyBypassAROAs or s3PolicyBypassPrincipalARNs');
}
}
//
// DynamoDB Table
//
if (props.table === undefined) {
// Create able if none passed
this._ownedTable = new dynamodb.Table(this, 'table', {
tableName: assetNameRoot
? `${assetNameRoot}${assetNameSuffix}`
: aws_cdk_lib_1.PhysicalName.GENERATE_IF_NEEDED,
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
partitionKey: {
name: 'PK',
type: dynamodb.AttributeType.STRING,
},
sortKey: {
name: 'SK',
type: dynamodb.AttributeType.STRING,
},
removalPolicy,
});
this._table = this._ownedTable;
}
else {
this._table = props.table;
}
//
// Deployer Lambda Function
//
// Create Deployer Lambda Function
const iamRoleUploadName = assetNameRoot
? `${assetNameRoot}-deployer-upload${assetNameSuffix}`
: undefined;
const iamRoleDeployerName = assetNameRoot
? `${assetNameRoot}-deployer${assetNameSuffix}`
: undefined;
const iamRoleDeployer = new iam.Role(this, 'deployer-role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
roleName: iamRoleDeployerName,
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
],
});
const deployerFuncName = assetNameRoot
? `${assetNameRoot}-deployer${assetNameSuffix}`
: undefined;
const deployerFuncProps = {
functionName: deployerFuncName,
role: iamRoleDeployer,
memorySize: 1769,
logRetention: logs.RetentionDays.ONE_MONTH,
runtime: lambda.Runtime.NODEJS_22_X,
timeout: deployerTimeout,
environment: {
NODE_ENV: appEnv,
DATABASE_TABLE_NAME: this._table.tableName,
FILESTORE_STAGING_BUCKET: bucketAppsStaging.bucketName,
FILESTORE_DEST_BUCKET: bucketApps.bucketName,
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
ROOT_PATH_PREFIX: rootPathPrefix,
REQUIRE_IAM_AUTHORIZATION: requireIAMAuthorization ? 'true' : 'false',
...(edgeToOriginRoleARN ? { EDGE_TO_ORIGIN_ROLE_ARN: edgeToOriginRoleARN.join(',') } : {}),
},
};
if (process.env.NODE_ENV === 'test' &&
(0, fs_1.existsSync)(path.join(__dirname, '..', '..', 'microapps-deployer', 'dist', 'index.js'))) {
// This is for local dev
this._deployerFunc = new lambda.Function(this, 'deployer-func', {
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'microapps-deployer', 'dist')),
handler: 'index.handler',
...deployerFuncProps,
});
}
else if ((0, fs_1.existsSync)(path.join(__dirname, 'microapps-deployer', 'index.js'))) {
// This is for built apps packaged with the CDK construct
this._deployerFunc = new lambda.Function(this, 'deployer-func', {
code: lambda.Code.fromAsset(path.join(__dirname, 'microapps-deployer')),
handler: 'index.handler',
...deployerFuncProps,
});
}
else {
this._deployerFunc = new lambdaNodejs.NodejsFunction(this, 'deployer-func', {
entry: path.join(__dirname, '..', '..', 'microapps-deployer', 'src', 'index.ts'),
handler: 'handler',
bundling: {
minify: true,
sourceMap: true,
},
...deployerFuncProps,
});
}
if (removalPolicy !== undefined) {
this._deployerFunc.applyRemovalPolicy(removalPolicy);
}
// Give the Deployer access to DynamoDB table
this._table.grantReadWriteData(this._deployerFunc);
this._table.grant(this._deployerFunc, 'dynamodb:DescribeTable');
// Add Tags to Deployer
aws_cdk_lib_1.Tags.of(this._deployerFunc).add('microapps-deployer', 'true');
//
// Deployer upload temp role
// Deployer assumes this role with a limited policy to generate
// an STS temp token to return to the `pwrdrvr` CLI for the upload.
//
const iamRoleUpload = new iam.Role(this, 'deployer-upload-role', {
roleName: iamRoleUploadName,
inlinePolicies: {
uploadPolicy: new iam.PolicyDocument({
statements: [
new iam.PolicyStatement({
actions: ['s3:ListBucket'],
resources: [bucketAppsStaging.bucketArn],
}),
new iam.PolicyStatement({
actions: ['s3:PutObject', 's3:GetObject', 's3:AbortMultipartUpload'],
resources: [`${bucketAppsStaging.bucketArn}/*`],
}),
],
}),
},
assumedBy: this._deployerFunc.grantPrincipal,
});
this._deployerFunc.addEnvironment('UPLOAD_ROLE_NAME', iamRoleUpload.roleName);
//
// Update S3 permissions
//
// Create PrincipalARN List
const s3PolicyBypassArnPrincipals = [];
for (const arnPrincipal of s3PolicyBypassPrincipalARNs) {
s3PolicyBypassArnPrincipals.push(new iam.ArnPrincipal(arnPrincipal));
}
// Create AROA List that matches assumed sessions
const s3PolicyBypassAROAMatches = [];
for (const aroa of s3PolicyBypassAROAs) {
s3PolicyBypassAROAMatches.push(`${aroa}:*`);
}
// Deny apps from reading:
// - If they are missing the microapp-name tag
// - Anything outside of the folder that matches their microapp-name tag
const policyDenyPrefixOutsideTag = new iam.PolicyStatement({
sid: 'deny-prefix-outside-microapp-name-tag',
effect: iam.Effect.DENY,
actions: ['s3:*'],
notPrincipals: [
new iam.CanonicalUserPrincipal(bucketAppsOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId),
new iam.AccountRootPrincipal(),
...s3PolicyBypassArnPrincipals,
this._deployerFunc.grantPrincipal,
],
notResources: [
`${bucketApps.bucketArn}/\${aws:PrincipalTag/microapp-name}/*`,
bucketApps.bucketArn,
],
conditions: {
Null: { 'aws:PrincipalTag/microapp-name': 'false' },
// StringNotLike: {'aws:'}
},
});
if (removalPolicy !== undefined) {
policyDenyPrefixOutsideTag.addCondition(
// Allows the DeletableBucket Lambda to delete items in the buckets
'StringNotLike', { 'aws:PrincipalTag/application': `${aws_cdk_lib_1.Stack.of(this).stackName}-core*` });
}
const policyDenyMissingTag = new iam.PolicyStatement({
sid: 'deny-missing-microapp-name-tag',
effect: iam.Effect.DENY,
actions: ['s3:*'],
notPrincipals: [
new iam.CanonicalUserPrincipal(bucketAppsOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId),
new iam.AccountRootPrincipal(),
// Exclude the Deployer Function directly
this._deployerFunc.grantPrincipal,
// 2021-12-04 - Not 100% sure that this is actually needed...
// Let's test this and remove if actually not necessary
new iam.ArnPrincipal(`arn:aws:sts::${aws_cdk_lib_1.Aws.ACCOUNT_ID}:assumed-role/${this._deployerFunc.role?.roleName}/${this._deployerFunc.functionName}`),
...s3PolicyBypassArnPrincipals,
],
resources: [`${bucketApps.bucketArn}/*`, bucketApps.bucketArn],
conditions: {
Null: { 'aws:PrincipalTag/microapp-name': 'true' },
// Note: This AROA must be specified to prevent this policy from locking
// out non-root sessions that have assumed the admin role.
// The notPrincipals will only match the role name exactly and will not match
// any session that has assumed the role since notPrincipals does not allow
// wildcard matches and does not do them implicitly either.
// The AROA must be used because there are only 3 Principal variables:
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_variables.html#principaltable
// aws:username, aws:userid, aws:PrincipalTag
// For an assumed role, aws:username is blank, aws:userid is:
// [unique id AKA AROA for Role]:[session name]
// Table of unique ID prefixes such as AROA:
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-prefixes
// The name of the role is simply not available and if it was
// we'd need to write a complicated comparison to make sure
// that we didn't exclude the Deny tag from roles in other accounts.
//
// To get the AROA with the AWS CLI:
// aws iam get-role --role-name ROLE-NAME
// aws iam get-user --user-name USER-NAME
StringNotLike: { 'aws:userid': [aws_cdk_lib_1.Aws.ACCOUNT_ID, ...s3PolicyBypassAROAMatches] },
},
});
if (removalPolicy !== undefined) {
policyDenyMissingTag.addCondition(
// Allows the DeletableBucket Lambda to delete items in the buckets
'StringNotLike', { 'aws:PrincipalTag/application': `${aws_cdk_lib_1.Stack.of(this).stackName}-core*` });
}
const policyCloudFrontAccess = new iam.PolicyStatement({
sid: 'cloudfront-oai-access',
effect: iam.Effect.ALLOW,
actions: ['s3:GetObject', 's3:ListBucket'],
principals: [
new iam.CanonicalUserPrincipal(bucketAppsOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId),
],
resources: [`${bucketApps.bucketArn}/*`, bucketApps.bucketArn],
});
if (bucketApps.policy === undefined) {
const document = new s3.BucketPolicy(this, 's3-policy', {
bucket: bucketApps,
}).document;
document.addStatements(policyCloudFrontAccess);
if (s3StrictBucketPolicy) {
document.addStatements(policyDenyPrefixOutsideTag);
document.addStatements(policyDenyMissingTag);
}
}
else {
bucketApps.policy.document.addStatements(policyCloudFrontAccess);
if (s3StrictBucketPolicy) {
bucketApps.policy.document.addStatements(policyDenyPrefixOutsideTag);
bucketApps.policy.document.addStatements(policyDenyMissingTag);
}
}
// Allow the Lambda to read from the staging bucket
const policyReadListStaging = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
// FIXME: Allow Deployer to delete from Staging bucket
actions: ['s3:DeleteObject', 's3:GetObject', 's3:ListBucket'],
resources: [`${bucketAppsStaging.bucketArn}/*`, bucketAppsStaging.bucketArn],
});
this._deployerFunc.addToRolePolicy(policyReadListStaging);
// Allow the Lambda to write to the target bucket and delete
const policyReadWriteListTarget = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['s3:DeleteObject', 's3:GetObject', 's3:PutObject', 's3:ListBucket'],
resources: [`${bucketApps.bucketArn}/*`, bucketApps.bucketArn],
});
this._deployerFunc.addToRolePolicy(policyReadWriteListTarget);
// Allow the deployer to get a temporary STS token
const policyGetSTSToken = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['sts:GetFederationToken'],
resources: ['*'],
});
this._deployerFunc.addToRolePolicy(policyGetSTSToken);
// Allow the deployer to assume the upload role
const policyAssumeUpload = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['sts:AssumeRole'],
resources: [iamRoleUpload.roleArn],
});
this._deployerFunc.addToRolePolicy(policyAssumeUpload);
//
// Give Deployer permissions to create routes and integrations
// on the API Gateway API.
//
// Grant the ability to List all APIs (we have to find it)
const policyAPIList = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['apigateway:GET'],
resources: [`arn:aws:apigateway:${aws_cdk_lib_1.Aws.REGION}::/apis`],
});
this._deployerFunc.addToRolePolicy(policyAPIList);
// Grant full control over lambdas that indicate they are microapps
const policyAPIManageLambdas = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['lambda:*'],
resources: [
`arn:aws:lambda:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:function:*`,
`arn:aws:lambda:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:function:*:*`,
],
conditions: {
StringEqualsIfExists: { 'aws:ResourceTag/microapp-managed': 'true' },
},
});
this._deployerFunc.addToRolePolicy(policyAPIManageLambdas);
this._deployerFunc.addToRolePolicy(policyAPIManageLambdas);
const policyReadonlyLambdas = new iam.PolicyStatement({
effect: iam.Effect.ALLOW,
actions: ['lambda:GetFunction', 'lambda:GetAlias'],
resources: [
`arn:aws:lambda:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:function:*`,
`arn:aws:lambda:${aws_cdk_lib_1.Aws.REGION}:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:function:*:*`,
],
});
this._deployerFunc.addToRolePolicy(policyReadonlyLambdas);
}
}
exports.MicroAppsSvcs = MicroAppsSvcs;
_a = JSII_RTTI_SYMBOL_1;
MicroAppsSvcs[_a] = { fqn: "@pwrdrvr/microapps-cdk.MicroAppsSvcs", version: "1.1.2" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWljcm9BcHBzU3Zjcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9NaWNyb0FwcHNTdmNzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsMkJBQWdDO0FBQ2hDLDZCQUE2QjtBQUM3Qiw2Q0FBc0Y7QUFFdEYscURBQXFEO0FBQ3JELDJDQUEyQztBQUMzQyxpREFBaUQ7QUFDakQsOERBQThEO0FBQzlELDZDQUE2QztBQUM3Qyx5Q0FBeUM7QUFDekMsMkNBQXVDO0FBNkx2Qzs7O0dBR0c7QUFDSCxNQUFhLGFBQWMsU0FBUSxzQkFBUztJQUcxQyxJQUFXLEtBQUs7UUFDZCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUM7SUFDckIsQ0FBQztJQUdELElBQVcsWUFBWTtRQUNyQixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUM7SUFDNUIsQ0FBQztJQUdELElBQVcsVUFBVTtRQUNuQixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUM7SUFDMUIsQ0FBQztJQUVELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMEI7UUFDbEUsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixJQUFJLEtBQUssS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7UUFDL0MsQ0FBQztRQUVELE1BQU0sRUFDSixVQUFVLEVBQ1YsYUFBYSxFQUNiLGlCQUFpQixFQUNqQixlQUFlLEdBQUcsc0JBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQ3JDLG1CQUFtQixHQUFHLEVBQUUsRUFDeEIsMkJBQTJCLEdBQUcsRUFBRSxFQUNoQyxvQkFBb0IsR0FBRyxLQUFLLEVBQzVCLE1BQU0sRUFDTixhQUFhLEVBQ2IsYUFBYSxFQUNiLGVBQWUsRUFDZixjQUFjLEdBQUcsRUFBRSxFQUNuQix1QkFBdUIsR0FBRyxJQUFJLEVBQzlCLG1CQUFtQixHQUNwQixHQUFHLEtBQUss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RCxNQUFNLHFCQUFxQixHQUFHLElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQztZQUNwRCxNQUFNLEVBQUUsR0FBRyxDQUFDLE1BQU0sQ0FBQyxLQUFLO1lBQ3hCLE9BQU8sRUFBRSxDQUFDLG9CQUFvQixFQUFFLGlCQUFpQixDQUFDO1lBQ2xELFNBQVMsRUFBRTtnQkFDVCxrQkFBa0IsaUJBQUcsQ0FBQyxNQUFNLElBQUksaUJBQUcsQ0FBQyxVQUFVLGFBQWE7Z0JBQzNELGtCQUFrQixpQkFBRyxDQUFDLE1BQU0sSUFBSSxpQkFBRyxDQUFDLFVBQVUsZUFBZTthQUM5RDtTQUNGLENBQUMsQ0FBQztRQUNILElBQUksQ0FBQyxhQUFhLENBQUMsZUFBZSxDQUFDLHFCQUFxQixDQUFDLENBQUM7SUFDNUQsQ0FBQzs7QUFsWEgsc0NBbVhDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgZXhpc3RzU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBBd3MsIER1cmF0aW9uLCBQaHlzaWNhbE5hbWUsIFJlbW92YWxQb2xpY3ksIFN0YWNrLCBUYWdzIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgY2YgZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQnO1xuaW1wb3J0ICogYXMgZHluYW1vZGIgZnJvbSAnYXdzLWNkay1saWIvYXdzLWR5bmFtb2RiJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGxhbWJkYU5vZGVqcyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLW5vZGVqcyc7XG5pbXBvcnQgKiBhcyBsb2dzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCAqIGFzIHMzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1zMyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIHRvIGluaXRpYWxpemUgYW4gaW5zdGFuY2Ugb2YgYE1pY3JvQXBwc1N2Y3NgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1pY3JvQXBwc1N2Y3NQcm9wcyB7XG4gIC8qKlxuICAgKiBSZW1vdmFsUG9saWN5IG92ZXJyaWRlIGZvciBjaGlsZCByZXNvdXJjZXNcbiAgICpcbiAgICogTm90ZTogaWYgc2V0IHRvIERFU1RST1kgdGhlIFMzIGJ1Y2tlcyB3aWxsIGhhdmUgYGF1dG9EZWxldGVPYmplY3RzYCBzZXQgdG8gYHRydWVgXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcGVyIHJlc291cmNlIGRlZmF1bHRcbiAgICovXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBSZW1vdmFsUG9saWN5O1xuXG4gIC8qKlxuICAgKiBTMyBidWNrZXQgZm9yIGRlcGxveWVkIGFwcGxpY2F0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0QXBwczogczMuSUJ1Y2tldDtcblxuICAvKipcbiAgICogQ2xvdWRGcm9udCBPcmlnaW4gQWNjZXNzIElkZW50aXR5IGZvciB0aGUgZGVwbG95ZWQgYXBwbGljYXRpb25zIGJ1Y2tldFxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0QXBwc09BSTogY2YuT3JpZ2luQWNjZXNzSWRlbnRpdHk7XG5cbiAgLyoqXG4gICAqIFMzIGJ1Y2tldCBmb3Igc3RhZ2VkIGFwcGxpY2F0aW9ucyAocHJpb3IgdG8gZGVwbG95KVxuICAgKi9cbiAgcmVhZG9ubHkgYnVja2V0QXBwc1N0YWdpbmc6IHMzLklCdWNrZXQ7XG5cbiAgLyoqXG4gICAqIEFwcGxpY2F0aW9uIGVudmlyb25tZW50LCBwYXNzZWQgYXMgYE5PREVfRU5WYFxuICAgKiB0byB0aGUgUm91dGVyIGFuZCBEZXBsb3llciBMYW1iZGEgZnVuY3Rpb25zXG4gICAqL1xuICByZWFkb25seSBhcHBFbnY6IHN0cmluZztcblxuICAvKipcbiAgICogT3B0aW9uYWwgYXNzZXQgbmFtZSByb290XG4gICAqXG4gICAqIEBleGFtcGxlIG1pY3JvYXBwc1xuICAgKiBAZGVmYXVsdCAtIHJlc291cmNlIG5hbWVzIGF1dG8gYXNzaWduZWRcbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0TmFtZVJvb3Q/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE9wdGlvbmFsIGFzc2V0IG5hbWUgc3VmZml4XG4gICAqXG4gICAqIEBleGFtcGxlIC1kZXYtcHItMTJcbiAgICogQGRlZmF1bHQgbm9uZVxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXROYW1lU3VmZml4Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBVc2UgYSBzdHJpY3QgUzMgQnVja2V0IFBvbGljeSB0aGF0IHByZXZlbnRzIGFwcGxpY2F0aW9uc1xuICAgKiBmcm9tIHJlYWRpbmcvd3JpdGluZy9tb2RpZnlpbmcvZGVsZXRpbmcgZmlsZXMgaW4gdGhlIFMzIEJ1Y2tldFxuICAgKiBvdXRzaWRlIG9mIHRoZSBwYXRoIHRoYXQgaXMgc3BlY2lmaWMgdG8gdGhlaXIgYXBwL3ZlcnNpb24uXG4gICAqXG4gICAqIFRoaXMgc2V0dGluZyBzaG91bGQgYmUgdXNlZCB3aGVuIGFwcGxpY2F0aW9ucyBhcmUgbGVzcyB0aGFuXG4gICAqIGZ1bGx5IHRydXN0ZWQuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBzM1N0cmljdEJ1Y2tldFBvbGljeT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgd2hlbiB1c2luZyBzM1N0cmljdEJ1Y2tldFBvbGljeSA9IHRydWVcbiAgICpcbiAgICogSUFNIFJvbGUgb3IgSUFNIFVzZXIgbmFtZXMgdG8gZXhjbHVkZSBmcm9tIHRoZSBERU5ZIHJ1bGVzIG9uIHRoZSBTMyBCdWNrZXQgUG9saWN5LlxuICAgKlxuICAgKiBSb2xlcyB0aGF0IGFyZSBBc3N1bWVkIG11c3QgaW5zdGVhZCBoYXZlIHRoZWlyIEFST0EgYWRkZWQgdG8gYHMzUG9saWN5QnlwYXNzQVJPQXNgLlxuICAgKlxuICAgKiBUeXBpY2FsbHkgYW55IGFkbWluIHJvbGVzIC8gdXNlcnMgdGhhdCBuZWVkIHRvIHZpZXcgb3IgbWFuYWdlIHRoZSBTMyBCdWNrZXRcbiAgICogd291bGQgYmUgYWRkZWQgdG8gdGhpcyBsaXN0LlxuICAgKlxuICAgKiBAZXhhbXBsZSBbJ2Fybjphd3M6aWFtOjoxMjM0NTY3ODkwMTIzOnJvbGUvQWRtaW5BY2Nlc3MnLCAnYXJuOmF3czppYW06OjEyMzQ1Njc4OTAxMjM6dXNlci9NeUFkbWluVXNlciddXG4gICAqXG4gICAqIEBzZWUgczNQb2xpY3lCeXBhc3NBUk9Bc1xuICAgKi9cbiAgcmVhZG9ubHkgczNQb2xpY3lCeXBhc3NQcmluY2lwYWxBUk5zPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgd2hlbiB1c2luZyBzM1N0cmljdEJ1Y2tldFBvbGljeSA9IHRydWVcbiAgICpcbiAgICogQVJPQXMgb2YgdGhlIElBTSBSb2xlIHRvIGV4Y2x1ZGUgZnJvbSB0aGUgREVOWSBydWxlcyBvbiB0aGUgUzMgQnVja2V0IFBvbGljeS5cbiAgICogVGhpcyBhbGxvd3Mgc2Vzc2lvbnMgdGhhdCBhc3N1bWUgdGhlIElBTSBSb2xlIHRvIGJlIGV4Y2x1ZGVkIGZyb20gdGhlXG4gICAqIERFTlkgcnVsZXMgb24gdGhlIFMzIEJ1Y2tldCBQb2xpY3kuXG4gICAqXG4gICAqIFR5cGljYWxseSBhbnkgYWRtaW4gcm9sZXMgLyB1c2VycyB0aGF0IG5lZWQgdG8gdmlldyBvciBtYW5hZ2UgdGhlIFMzIEJ1Y2tldFxuICAgKiB3b3VsZCBiZSBhZGRlZCB0byB0aGlzIGxpc3QuXG4gICAqXG4gICAqIFJvbGVzIC8gdXNlcnMgdGhhdCBhcmUgdXNlZCBkaXJlY3RseSwgbm90IGFzc3VtZWQsIGNhbiBiZSBhZGRlZCB0byBgczNQb2xpY3lCeXBhc3NSb2xlTmFtZXNgIGluc3RlYWQuXG4gICAqXG4gICAqIE5vdGU6IFRoaXMgQVJPQSBtdXN0IGJlIHNwZWNpZmllZCB0byBwcmV2ZW50IHRoaXMgcG9saWN5IGZyb20gbG9ja2luZ1xuICAgKiBvdXQgbm9uLXJvb3Qgc2Vzc2lvbnMgdGhhdCBoYXZlIGFzc3VtZWQgdGhlIGFkbWluIHJvbGUuXG4gICAqXG4gICAqIFRoZSBub3RQcmluY2lwYWxzIHdpbGwgb25seSBtYXRjaCB0aGUgcm9sZSBuYW1lIGV4YWN0bHkgYW5kIHdpbGwgbm90IG1hdGNoXG4gICAqIGFueSBzZXNzaW9uIHRoYXQgaGFzIGFzc3VtZWQgdGhlIHJvbGUgc2luY2Ugbm90UHJpbmNpcGFscyBkb2VzIG5vdCBhbGxvd1xuICAgKiB3aWxkY2FyZCBtYXRjaGVzIGFuZCBkb2VzIG5vdCBkbyB3aWxkY2FyZCBtYXRjaGVzIGltcGxpY2l0bHkgZWl0aGVyLlxuICAgKlxuICAgKiBUaGUgQVJPQSBtdXN0IGJlIHVzZWQgYmVjYXVzZSB0aGVyZSBhcmUgb25seSAzIFByaW5jaXBhbCB2YXJpYWJsZXMgYXZhaWxhYmxlOlxuICAgKiAgaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL3JlZmVyZW5jZV9wb2xpY2llc192YXJpYWJsZXMuaHRtbCNwcmluY2lwYWx0YWJsZVxuICAgKiAgYXdzOnVzZXJuYW1lLCBhd3M6dXNlcmlkLCBhd3M6UHJpbmNpcGFsVGFnXG4gICAqXG4gICAqIEZvciBhbiBhc3N1bWVkIHJvbGUsIGF3czp1c2VybmFtZSBpcyBibGFuaywgYXdzOnVzZXJpZCBpczpcbiAgICogIFt1bmlxdWUgaWQgQUtBIEFST0EgZm9yIFJvbGVdOltzZXNzaW9uIG5hbWVdXG4gICAqXG4gICAqIFRhYmxlIG9mIHVuaXF1ZSBJRCBwcmVmaXhlcyBzdWNoIGFzIEFST0E6XG4gICAqICBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vSUFNL2xhdGVzdC9Vc2VyR3VpZGUvcmVmZXJlbmNlX2lkZW50aWZpZXJzLmh0bWwjaWRlbnRpZmllcnMtcHJlZml4ZXNcbiAgICpcbiAgICogVGhlIG5hbWUgb2YgdGhlIHJvbGUgaXMgc2ltcGx5IG5vdCBhdmFpbGFibGUgZm9yIGFuIGFzc3VtZWQgcm9sZSBhbmQsIGlmIGl0IHdhcyxcbiAgICogYSBjb21wbGljYXRlZCBjb21wYXJpc29uIHdvdWxkIGJlIHJlcXVpZXJkIHRvIHByZXZlbnQgZXhjbHVzaW9uXG4gICAqIG9mIGFwcGx5aW5nIHRoZSBEZW55IFJ1bGUgdG8gcm9sZXMgZnJvbSBvdGhlciBhY2NvdW50cy5cbiAgICpcbiAgICogVG8gZ2V0IHRoZSBBUk9BIHdpdGggdGhlIEFXUyBDTEk6XG4gICAqICAgYXdzIGlhbSBnZXQtcm9sZSAtLXJvbGUtbmFtZSBST0xFLU5BTUVcbiAgICogICBhd3MgaWFtIGdldC11c2VyIC0tdXNlci1uYW1lIFVTRVItTkFNRVxuICAgKlxuICAgKiBAZXhhbXBsZSBbICdBUk9BMTIzNDU2Nzg5MDEyMycgXVxuICAgKlxuICAgKiBAc2VlIHMzU3RyaWN0QnVja2V0UG9saWN5XG4gICAqL1xuICByZWFkb25seSBzM1BvbGljeUJ5cGFzc0FST0FzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFBhdGggcHJlZml4IG9uIHRoZSByb290IG9mIHRoZSBkZXBsb3ltZW50XG4gICAqXG4gICAqIEBleGFtcGxlIGRldi9cbiAgICogQGRlZmF1bHQgbm9uZVxuICAgKi9cbiAgcmVhZG9ubHkgcm9vdFBhdGhQcmVmaXg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFJlcXVpcmUgSUFNIGF1dGggb24gQVBJIEdhdGV3YXkgYW5kIExhbWJkYSBGdW5jdGlvbiBVUkxzXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHJlcXVpcmVJQU1BdXRob3JpemF0aW9uPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRXhpc3RpbmcgdGFibGUgZm9yIGFwcHMvdmVyc2lvbnMvcnVsZXNcbiAgICpcbiAgICogQHdhcm5pbmcgLSBJdCBpcyAqc3Ryb25nbHkqIHN1Z2dlc3RlZCB0aGF0IHByb2R1Y3Rpb24gc3RhY2tzIGNyZWF0ZVxuICAgKiB0aGVpciBvd24gRHluYW1vREIgVGFibGUgYW5kIHBhc3MgaXQgaW50byB0aGlzIGNvbnN0cnVjdCwgZm9yIHByb3RlY3Rpb25cbiAgICogYWdhaW5zdCBkYXRhIGxvc3MgZHVlIHRvIGxvZ2ljYWwgSUQgY2hhbmdlcywgdGhlIGFiaWxpdHkgdG8gY29uZmlndXJlXG4gICAqIFByb3Zpc2lvbmVkIGNhcGFjaXR5IHdpdGggQXV0byBTY2FsaW5nLCB0aGUgYWJpbGl0eSB0byBhZGQgYWRkaXRpb25hbCBpbmRpY2VzLCBldGMuXG4gICAqXG4gICAqIFJlcXVpcmVtZW50czpcbiAgICogLSBIYXNoIEtleTogYFBLYFxuICAgKiAtIFNvcnQgS2V5OiBgU0tgXG4gICAqXG4gICAqIEBkZWZhdWx0IGNyZWF0ZWQgYnkgY29uc3RydWN0XG4gICAqL1xuICByZWFkb25seSB0YWJsZT86IGR5bmFtb2RiLklUYWJsZTtcblxuICAvKipcbiAgICogRGVwbG95ZXIgdGltZW91dFxuICAgKlxuICAgKiBGb3IgbGFyZ2VyIGFwcGxpY2F0aW9ucyB0aGlzIG5lZWRzIHRvIGJlIHNldCB1cCB0byAyLTUgbWludXRlcyBmb3IgdGhlIFMzIGNvcHlcbiAgICpcbiAgICogQGRlZmF1bHQgMiBtaW51dGVzXG4gICAqL1xuICByZWFkb25seSBkZXBsb3llclRpbWVvdXQ/OiBEdXJhdGlvbjtcblxuICAvKipcbiAgICogQVJOIG9mIHRoZSBJQU0gUm9sZSBmb3IgdGhlIEVkZ2UgdG8gT3JpZ2luIExhbWJkYSBGdW5jdGlvblxuICAgKi9cbiAgcmVhZG9ubHkgZWRnZVRvT3JpZ2luUm9sZUFSTj86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBNaWNyb0FwcHMgU2VydmljZXNcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJTWljcm9BcHBzU3ZjcyB7XG4gIC8qKlxuICAgKiBEeW5hbW9EQiB0YWJsZSB1c2VkIGJ5IFJvdXRlciwgRGVwbG95ZXIsIGFuZCBSZWxlYXNlIGNvbnNvbGUgYXBwXG4gICAqL1xuICByZWFkb25seSB0YWJsZTogZHluYW1vZGIuSVRhYmxlO1xuXG4gIC8qKlxuICAgKiBMYW1iZGEgZnVuY3Rpb24gZm9yIHRoZSBEZXBsb3llclxuICAgKi9cbiAgcmVhZG9ubHkgZGVwbG95ZXJGdW5jOiBsYW1iZGEuRnVuY3Rpb247XG5cbiAgLyoqXG4gICAqIExhbWJkYSBmdW5jdGlvbiBmb3IgdGhlIFJvdXRlclxuICAgKi9cbiAgcmVhZG9ubHkgcm91dGVyRnVuYz86IGxhbWJkYS5GdW5jdGlvbjtcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgTWljcm9BcHBzIFNlcnZpY2VzIGNvbnN0cnVjdCwgaW5jbHVkaW5nIHRoZSBEZXBsb3llclxuICogYW5kIFJvdXRlciBMYW1iZGEgRnVuY3Rpb25zLCBhbmQgdGhlIER5bmFtb0RCIFRhYmxlIHVzZWQgYnkgYm90aC5cbiAqL1xuZXhwb3J0IGNsYXNzIE1pY3JvQXBwc1N2Y3MgZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJTWljcm9BcHBzU3ZjcyB7XG4gIHByaXZhdGUgX293bmVkVGFibGU/OiBkeW5hbW9kYi5UYWJsZTtcbiAgcHJpdmF0ZSBfdGFibGU6IGR5bmFtb2RiLklUYWJsZTtcbiAgcHVibGljIGdldCB0YWJsZSgpOiBkeW5hbW9kYi5JVGFibGUge1xuICAgIHJldHVybiB0aGlzLl90YWJsZTtcbiAgfVxuXG4gIHByaXZhdGUgX2RlcGxveWVyRnVuYzogbGFtYmRhLkZ1bmN0aW9uO1xuICBwdWJsaWMgZ2V0IGRlcGxveWVyRnVuYygpOiBsYW1iZGEuRnVuY3Rpb24ge1xuICAgIHJldHVybiB0aGlzLl9kZXBsb3llckZ1bmM7XG4gIH1cblxuICBwcml2YXRlIF9yb3V0ZXJGdW5jPzogbGFtYmRhLkZ1bmN0aW9uO1xuICBwdWJsaWMgZ2V0IHJvdXRlckZ1bmMoKTogbGFtYmRhLkZ1bmN0aW9uIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5fcm91dGVyRnVuYztcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzPzogTWljcm9BcHBzU3Zjc1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIGlmIChwcm9wcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb3BzIGNhbm5vdCBiZSB1bmRlZmluZWQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICBidWNrZXRBcHBzLFxuICAgICAgYnVja2V0QXBwc09BSSxcbiAgICAgIGJ1Y2tldEFwcHNTdGFnaW5nLFxuICAgICAgZGVwbG95ZXJUaW1lb3V0ID0gRHVyYXRpb24ubWludXRlcygyKSxcbiAgICAgIHMzUG9saWN5QnlwYXNzQVJPQXMgPSBbXSxcbiAgICAgIHMzUG9saWN5QnlwYXNzUHJpbmNpcGFsQVJOcyA9IFtdLFxuICAgICAgczNTdHJpY3RCdWNrZXRQb2xpY3kgPSBmYWxzZSxcbiAgICAgIGFwcEVudixcbiAgICAgIHJlbW92YWxQb2xpY3ksXG4gICAgICBhc3NldE5hbWVSb290LFxuICAgICAgYXNzZXROYW1lU3VmZml4LFxuICAgICAgcm9vdFBhdGhQcmVmaXggPSAnJyxcbiAgICAgIHJlcXVpcmVJQU1BdXRob3JpemF0aW9uID0gdHJ1ZSxcbiAgICAgIGVkZ2VUb09yaWdpblJvbGVBUk4sXG4gICAgfSA9IHByb3BzO1xuXG4gICAgaWYgKHMzU3RyaWN0QnVja2V0UG9saWN5ID09PSB0cnVlKSB7XG4gICAgICBpZiAoczNQb2xpY3lCeXBhc3NBUk9Bcy5sZW5ndGggPT09IDAgJiYgczNQb2xpY3lCeXBhc3NQcmluY2lwYWxBUk5zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgJ3MzU3RyaWN0QnVja2V0UG9saWN5IGNhbm5vdCBiZSB0cnVlIHdpdGhvdXQgc3BlY2lmeWluZyBhdCBsZWFzdCBvbmUgczNQb2xpY3lCeXBhc3NBUk9BcyBvciBzM1BvbGljeUJ5cGFzc1ByaW5jaXBhbEFSTnMnLFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vXG4gICAgLy8gRHluYW1vREIgVGFibGVcbiAgICAvL1xuICAgIGlmIChwcm9wcy50YWJsZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAvLyBDcmVhdGUgYWJsZSBpZiBub25lIHBhc3NlZFxuICAgICAgdGhpcy5fb3duZWRUYWJsZSA9IG5ldyBkeW5hbW9kYi5UYWJsZSh0aGlzLCAndGFibGUnLCB7XG4gICAgICAgIHRhYmxlTmFtZTogYXNzZXROYW1lUm9vdFxuICAgICAgICAgID8gYCR7YXNzZXROYW1lUm9vdH0ke2Fzc2V0TmFtZVN1ZmZpeH1gXG4gICAgICAgICAgOiBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVELFxuICAgICAgICBiaWxsaW5nTW9kZTogZHluYW1vZGIuQmlsbGluZ01vZGUuUEFZX1BFUl9SRVFVRVNULFxuICAgICAgICBwYXJ0aXRpb25LZXk6IHtcbiAgICAgICAgICBuYW1lOiAnUEsnLFxuICAgICAgICAgIHR5cGU6IGR5bmFtb2RiLkF0dHJpYnV0ZVR5cGUuU1RSSU5HLFxuICAgICAgICB9LFxuICAgICAgICBzb3J0S2V5OiB7XG4gICAgICAgICAgbmFtZTogJ1NLJyxcbiAgICAgICAgICB0eXBlOiBkeW5hbW9kYi5BdHRyaWJ1dGVUeXBlLlNUUklORyxcbiAgICAgICAgfSxcbiAgICAgICAgcmVtb3ZhbFBvbGljeSxcbiAgICAgIH0pO1xuICAgICAgdGhpcy5fdGFibGUgPSB0aGlzLl9vd25lZFRhYmxlO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl90YWJsZSA9IHByb3BzLnRhYmxlO1xuICAgIH1cblxuICAgIC8vXG4gICAgLy8gRGVwbG95ZXIgTGFtYmRhIEZ1bmN0aW9uXG4gICAgLy9cblxuICAgIC8vIENyZWF0ZSBEZXBsb3llciBMYW1iZGEgRnVuY3Rpb25cbiAgICBjb25zdCBpYW1Sb2xlVXBsb2FkTmFtZSA9IGFzc2V0TmFtZVJvb3RcbiAgICAgID8gYCR7YXNzZXROYW1lUm9vdH0tZGVwbG95ZXItdXBsb2FkJHthc3NldE5hbWVTdWZmaXh9YFxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgaWFtUm9sZURlcGxveWVyTmFtZSA9IGFzc2V0TmFtZVJvb3RcbiAgICAgID8gYCR7YXNzZXROYW1lUm9vdH0tZGVwbG95ZXIke2Fzc2V0TmFtZVN1ZmZpeH1gXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBpYW1Sb2xlRGVwbG95ZXIgPSBuZXcgaWFtLlJvbGUodGhpcywgJ2RlcGxveWVyLXJvbGUnLCB7XG4gICAgICBhc3N1bWVkQnk6IG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnbGFtYmRhLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgIHJvbGVOYW1lOiBpYW1Sb2xlRGVwbG95ZXJOYW1lLFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpLFxuICAgICAgXSxcbiAgICB9KTtcbiAgICBjb25zdCBkZXBsb3llckZ1bmNOYW1lID0gYXNzZXROYW1lUm9vdFxuICAgICAgPyBgJHthc3NldE5hbWVSb290fS1kZXBsb3llciR7YXNzZXROYW1lU3VmZml4fWBcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGRlcGxveWVyRnVuY1Byb3BzOiBPbWl0PGxhbWJkYS5GdW5jdGlvblByb3BzLCAnaGFuZGxlcicgfCAnY29kZSc+ID0ge1xuICAgICAgZnVuY3Rpb25OYW1lOiBkZXBsb3llckZ1bmNOYW1lLFxuICAgICAgcm9sZTogaWFtUm9sZURlcGxveWVyLFxuICAgICAgbWVtb3J5U2l6ZTogMTc2OSxcbiAgICAgIGxvZ1JldGVudGlvbjogbG9ncy5SZXRlbnRpb25EYXlzLk9ORV9NT05USCxcbiAgICAgIHJ1bnRpbWU6IGxhbWJkYS5SdW50aW1lLk5PREVKU18yMl9YLFxuICAgICAgdGltZW91dDogZGVwbG95ZXJUaW1lb3V0LFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgTk9ERV9FTlY6IGFwcEVudixcbiAgICAgICAgREFUQUJBU0VfVEFCTEVfTkFNRTogdGhpcy5fdGFibGUudGFibGVOYW1lLFxuICAgICAgICBGSUxFU1RPUkVfU1RBR0lOR19CVUNLRVQ6IGJ1Y2tldEFwcHNTdGFnaW5nLmJ1Y2tldE5hbWUsXG4gICAgICAgIEZJTEVTVE9SRV9ERVNUX0JVQ0tFVDogYnVja2V0QXBwcy5idWNrZXROYW1lLFxuICAgICAgICBBV1NfTk9ERUpTX0NPTk5FQ1RJT05fUkVVU0VfRU5BQkxFRDogJzEnLFxuICAgICAgICBST09UX1BBVEhfUFJFRklYOiByb290UGF0aFByZWZpeCxcbiAgICAgICAgUkVRVUlSRV9JQU1fQVVUSE9SSVpBVElPTjogcmVxdWlyZUlBTUF1dGhvcml6YXRpb24gPyAndHJ1ZScgOiAnZmFsc2UnLFxuICAgICAgICAuLi4oZWRnZVRvT3JpZ2luUm9sZUFSTiA/IHsgRURHRV9UT19PUklHSU5fUk9MRV9BUk46IGVkZ2VUb09yaWdpblJvbGVBUk4uam9pbignLCcpIH0gOiB7fSksXG4gICAgICB9LFxuICAgIH07XG4gICAgaWYgKFxuICAgICAgcHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICd0ZXN0JyAmJlxuICAgICAgZXhpc3RzU3luYyhwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLWRlcGxveWVyJywgJ2Rpc3QnLCAnaW5kZXguanMnKSlcbiAgICApIHtcbiAgICAgIC8vIFRoaXMgaXMgZm9yIGxvY2FsIGRldlxuICAgICAgdGhpcy5fZGVwbG95ZXJGdW5jID0gbmV3IGxhbWJkYS5GdW5jdGlvbih0aGlzLCAnZGVwbG95ZXItZnVuYycsIHtcbiAgICAgICAgY29kZTogbGFtYmRhLkNvZGUuZnJvbUFzc2V0KHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdtaWNyb2FwcHMtZGVwbG95ZXInLCAnZGlzdCcpKSxcbiAgICAgICAgaGFuZGxlcjogJ2luZGV4LmhhbmRsZXInLFxuICAgICAgICAuLi5kZXBsb3llckZ1bmNQcm9wcyxcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoZXhpc3RzU3luYyhwYXRoLmpvaW4oX19kaXJuYW1lLCAnbWljcm9hcHBzLWRlcGxveWVyJywgJ2luZGV4LmpzJykpKSB7XG4gICAgICAvLyBUaGlzIGlzIGZvciBidWlsdCBhcHBzIHBhY2thZ2VkIHdpdGggdGhlIENESyBjb25zdHJ1Y3RcbiAgICAgIHRoaXMuX2RlcGxveWVyRnVuYyA9IG5ldyBsYW1iZGEuRnVuY3Rpb24odGhpcywgJ2RlcGxveWVyLWZ1bmMnLCB7XG4gICAgICAgIGNvZGU6IGxhbWJkYS5Db2RlLmZyb21Bc3NldChwYXRoLmpvaW4oX19kaXJuYW1lLCAnbWljcm9hcHBzLWRlcGxveWVyJykpLFxuICAgICAgICBoYW5kbGVyOiAnaW5kZXguaGFuZGxlcicsXG4gICAgICAgIC4uLmRlcGxveWVyRnVuY1Byb3BzLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX2RlcGxveWVyRnVuYyA9IG5ldyBsYW1iZGFOb2RlanMuTm9kZWpzRnVuY3Rpb24odGhpcywgJ2RlcGxveWVyLWZ1bmMnLCB7XG4gICAgICAgIGVudHJ5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLWRlcGxveWVyJywgJ3NyYycsICdpbmRleC50cycpLFxuICAgICAgICBoYW5kbGVyOiAnaGFuZGxlcicsXG4gICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgbWluaWZ5OiB0cnVlLFxuICAgICAgICAgIHNvdXJjZU1hcDogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgICAgLi4uZGVwbG95ZXJGdW5jUHJvcHMsXG4gICAgICB9KTtcbiAgICB9XG4gICAgaWYgKHJlbW92YWxQb2xpY3kgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhpcy5fZGVwbG95ZXJGdW5jLmFwcGx5UmVtb3ZhbFBvbGljeShyZW1vdmFsUG9saWN5KTtcbiAgICB9XG4gICAgLy8gR2l2ZSB0aGUgRGVwbG95ZXIgYWNjZXNzIHRvIER5bmFtb0RCIHRhYmxlXG4gICAgdGhpcy5fdGFibGUuZ3JhbnRSZWFkV3JpdGVEYXRhKHRoaXMuX2RlcGxveWVyRnVuYyk7XG4gICAgdGhpcy5fdGFibGUuZ3JhbnQodGhpcy5fZGVwbG95ZXJGdW5jLCAnZHluYW1vZGI6RGVzY3JpYmVUYWJsZScpO1xuXG4gICAgLy8gQWRkIFRhZ3MgdG8gRGVwbG95ZXJcbiAgICBUYWdzLm9mKHRoaXMuX2RlcGxveWVyRnVuYykuYWRkKCdtaWNyb2FwcHMtZGVwbG95ZXInLCAndHJ1ZScpO1xuXG4gICAgLy9cbiAgICAvLyBEZXBsb3llciB1cGxvYWQgdGVtcCByb2xlXG4gICAgLy8gRGVwbG95ZXIgYXNzdW1lcyB0aGlzIHJvbGUgd2l0aCBhIGxpbWl0ZWQgcG9saWN5IHRvIGdlbmVyYXRlXG4gICAgLy8gYW4gU1RTIHRlbXAgdG9rZW4gdG8gcmV0dXJuIHRvIHRoZSBgcHdyZHJ2cmAgQ0xJIGZvciB0aGUgdXBsb2FkLlxuICAgIC8vXG4gICAgY29uc3QgaWFtUm9sZVVwbG9hZCA9IG5ldyBpYW0uUm9sZSh0aGlzLCAnZGVwbG95ZXItdXBsb2FkLXJvbGUnLCB7XG4gICAgICByb2xlTmFtZTogaWFtUm9sZVVwbG9hZE5hbWUsXG4gICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICB1cGxvYWRQb2xpY3k6IG5ldyBpYW0uUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgYWN0aW9uczogWydzMzpMaXN0QnVja2V0J10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2J1Y2tldEFwcHNTdGFnaW5nLmJ1Y2tldEFybl0sXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgYWN0aW9uczogWydzMzpQdXRPYmplY3QnLCAnczM6R2V0T2JqZWN0JywgJ3MzOkFib3J0TXVsdGlwYXJ0VXBsb2FkJ10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2Ake2J1Y2tldEFwcHNTdGFnaW5nLmJ1Y2tldEFybn0vKmBdLFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgXSxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgICAgYXNzdW1lZEJ5OiB0aGlzLl9kZXBsb3llckZ1bmMuZ3JhbnRQcmluY2lwYWwsXG4gICAgfSk7XG4gICAgdGhpcy5fZGVwbG95ZXJGdW5jLmFkZEVudmlyb25tZW50KCdVUExPQURfUk9MRV9OQU1FJywgaWFtUm9sZVVwbG9hZC5yb2xlTmFtZSk7XG5cbiAgICAvL1xuICAgIC8vIFVwZGF0ZSBTMyBwZXJtaXNzaW9uc1xuICAgIC8vXG4gICAgLy8gQ3JlYXRlIFByaW5jaXBhbEFSTiBMaXN0XG4gICAgY29uc3QgczNQb2xpY3lCeXBhc3NBcm5QcmluY2lwYWxzOiBpYW0uQXJuUHJpbmNpcGFsW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGFyblByaW5jaXBhbCBvZiBzM1BvbGljeUJ5cGFzc1ByaW5jaXBhbEFSTnMpIHtcbiAgICAgIHMzUG9saWN5QnlwYXNzQXJuUHJpbmNpcGFscy5wdXNoKG5ldyBpYW0uQXJuUHJpbmNpcGFsKGFyblByaW5jaXBhbCkpO1xuICAgIH1cbiAgICAvLyBDcmVhdGUgQVJPQSBMaXN0IHRoYXQgbWF0Y2hlcyBhc3N1bWVkIHNlc3Npb25zXG4gICAgY29uc3QgczNQb2xpY3lCeXBhc3NBUk9BTWF0Y2hlczogc3RyaW5nW10gPSBbXTtcbiAgICBmb3IgKGNvbnN0IGFyb2Egb2YgczNQb2xpY3lCeXBhc3NBUk9Bcykge1xuICAgICAgczNQb2xpY3lCeXBhc3NBUk9BTWF0Y2hlcy5wdXNoKGAke2Fyb2F9OipgKTtcbiAgICB9XG4gICAgLy8gRGVueSBhcHBzIGZyb20gcmVhZGluZzpcbiAgICAvLyAtIElmIHRoZXkgYXJlIG1pc3NpbmcgdGhlIG1pY3JvYXBwLW5hbWUgdGFnXG4gICAgLy8gLSBBbnl0aGluZyBvdXRzaWRlIG9mIHRoZSBmb2xkZXIgdGhhdCBtYXRjaGVzIHRoZWlyIG1pY3JvYXBwLW5hbWUgdGFnXG4gICAgY29uc3QgcG9saWN5RGVueVByZWZpeE91dHNpZGVUYWcgPSBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICBzaWQ6ICdkZW55LXByZWZpeC1vdXRzaWRlLW1pY3JvYXBwLW5hbWUtdGFnJyxcbiAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5ERU5ZLFxuICAgICAgYWN0aW9uczogWydzMzoqJ10sXG4gICAgICBub3RQcmluY2lwYWxzOiBbXG4gICAgICAgIG5ldyBpYW0uQ2Fub25pY2FsVXNlclByaW5jaXBhbChcbiAgICAgICAgICBidWNrZXRBcHBzT0FJLmNsb3VkRnJvbnRPcmlnaW5BY2Nlc3NJZGVudGl0eVMzQ2Fub25pY2FsVXNlcklkLFxuICAgICAgICApLFxuICAgICAgICBuZXcgaWFtLkFjY291bnRSb290UHJpbmNpcGFsKCksXG4gICAgICAgIC4uLnMzUG9saWN5QnlwYXNzQXJuUHJpbmNpcGFscyxcbiAgICAgICAgdGhpcy5fZGVwbG95ZXJGdW5jLmdyYW50UHJpbmNpcGFsLFxuICAgICAgXSxcbiAgICAgIG5vdFJlc291cmNlczogW1xuICAgICAgICBgJHtidWNrZXRBcHBzLmJ1Y2tldEFybn0vXFwke2F3czpQcmluY2lwYWxUYWcvbWljcm9hcHAtbmFtZX0vKmAsXG4gICAgICAgIGJ1Y2tldEFwcHMuYnVja2V0QXJuLFxuICAgICAgXSxcbiAgICAgIGNvbmRpdGlvbnM6IHtcbiAgICAgICAgTnVsbDogeyAnYXdzOlByaW5jaXBhbFRhZy9taWNyb2FwcC1uYW1lJzogJ2ZhbHNlJyB9LFxuICAgICAgICAvLyBTdHJpbmdOb3RMaWtlOiB7J2F3czonfVxuICAgICAgfSxcbiAgICB9KTtcbiAgICBpZiAocmVtb3ZhbFBvbGljeSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBwb2xpY3lEZW55UHJlZml4T3V0c2lkZVRhZy5hZGRDb25kaXRpb24oXG4gICAgICAgIC8vIEFsbG93cyB0aGUgRGVsZXRhYmxlQnVja2V0IExhbWJkYSB0byBkZWxldGUgaXRlbXMgaW4gdGhlIGJ1Y2tldHNcbiAgICAgICAgJ1N0cmluZ05vdExpa2UnLFxuICAgICAgICB7ICdhd3M6UHJpbmNpcGFsVGFnL2FwcGxpY2F0aW9uJzogYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS1jb3JlKmAgfSxcbiAgICAgICk7XG4gICAgfVxuICAgIGNvbnN0IHBvbGljeURlbnlNaXNzaW5nVGFnID0gbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgc2lkOiAnZGVueS1taXNzaW5nLW1pY3JvYXBwLW5hbWUtdGFnJyxcbiAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5ERU5ZLFxuICAgICAgYWN0aW9uczogWydzMzoqJ10sXG4gICAgICBub3RQcmluY2lwYWxzOiBbXG4gICAgICAgIG5ldyBpYW0uQ2Fub25pY2FsVXNlclByaW5jaXBhbChcbiAgICAgICAgICBidWNrZXRBcHBzT0FJLmNsb3VkRnJvbnRPcmlnaW5BY2Nlc3NJZGVudGl0eVMzQ2Fub25pY2FsVXNlcklkLFxuICAgICAgICApLFxuICAgICAgICBuZXcgaWFtLkFjY291bnRSb290UHJpbmNpcGFsKCksXG4gICAgICAgIC8vIEV4Y2x1ZGUgdGhlIERlcGxveWVyIEZ1bmN0aW9uIGRpcmVjdGx5XG4gICAgICAgIHRoaXMuX2RlcGxveWVyRnVuYy5ncmFudFByaW5jaXBhbCxcbi