@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.
282 lines • 51.1 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MicroAppsEdgeToOrigin = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
/* eslint-disable @typescript-eslint/indent */
const crypto = require("crypto");
const fs_1 = require("fs");
const os = require("os");
const path = require("path");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const cf = require("aws-cdk-lib/aws-cloudfront");
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 constructs_1 = require("constructs");
class MicroAppsEdgeToOriginRoleStack extends aws_cdk_lib_1.Stack {
get role() {
return this._role;
}
constructor(scope, id, props) {
super(scope, id, props);
const { assetNameRoot, assetNameSuffix, setupApiGatewayPermissions, allowedFunctionUrlAccounts, } = props;
// Create IAM Role for the Edge Function
this._role = new iam.Role(this, 'edge-role', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
roleName: assetNameRoot
? `${assetNameRoot}-edge-role${assetNameSuffix}`
: aws_cdk_lib_1.PhysicalName.GENERATE_IF_NEEDED,
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
],
inlinePolicies: {
edgeToOriginPolicy: new iam.PolicyDocument({
statements: [
// This can't have a reference to the httpApi because it would mean
// the parent stack (this stack) has to be created before the us-east-1
// child stack for the Edge Lambda Function.
// That's why we use a tag-based policy to allow the Edge Function
// to invoke any API Gateway API that we apply a tag to
// We allow the edge function to sign for all regions since
// we may use custom closest region in the future.
...(setupApiGatewayPermissions
? [
new iam.PolicyStatement({
actions: ['execute-api:Invoke'],
resources: [`arn:aws:execute-api:*:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:*/*/*/*`],
// Unfortunately, API Gateway access cannot be restricted using
// tags on the target resource
// https://docs.aws.amazon.com/IAM/latest/UserGuide/access_tags.html
// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html#networking_svcs
// conditions: {
// // TODO: Set this to a string unique to each stack
// StringEquals: { 'aws:ResourceTag/microapp-managed': 'true' },
// },
}),
]
: []),
//
// Grant permission to invoke tagged Function URLs (in same account)
//
new iam.PolicyStatement({
actions: ['lambda:InvokeFunctionUrl'],
resources: [`arn:aws:lambda:*:${aws_cdk_lib_1.Aws.ACCOUNT_ID}:*`],
conditions: {
StringEquals: { 'aws:ResourceTag/microapp-managed': 'true' },
},
}),
//
// Grant permission to invoke Function URLs in listed accounts
//
...(allowedFunctionUrlAccounts && allowedFunctionUrlAccounts.length > 0
? [
new iam.PolicyStatement({
actions: ['lambda:InvokeFunctionUrl'],
resources: allowedFunctionUrlAccounts.map((accountId) => `arn:aws:lambda:*:${accountId}:*`),
}),
]
: []),
],
}),
},
});
this._role.assumeRolePolicy?.addStatements(new iam.PolicyStatement({
principals: [
new iam.ServicePrincipal('edgelambda.amazonaws.com'),
new iam.ServicePrincipal('lambda.amazonaws.com'),
],
actions: ['sts:AssumeRole'],
effect: iam.Effect.ALLOW,
}));
new aws_cdk_lib_1.CfnOutput(this, 'edge-to-origin-role-arn', {
value: `${this.role.roleArn}`,
exportName: `${this.stackName}-role-arn`,
});
}
}
/**
* Create a new MicroApps Edge to Origin Function w/ `config.yml`
*/
class MicroAppsEdgeToOrigin extends constructs_1.Construct {
/**
* Generate the yaml config for the edge lambda
* @param props
* @returns
*/
static generateEdgeToOriginConfig(props) {
return `originRegion: ${props.originRegion}
${props.signingMode === '' ? '' : `signingMode: ${props.signingMode}`}
addXForwardedHostHeader: ${props.addXForwardedHostHeader}
replaceHostHeader: ${props.replaceHostHeader}
${props.tableName ? `tableName: '${props.tableName}'` : ''}
${props.rootPathPrefix ? `rootPathPrefix: '${props.rootPathPrefix}'` : ''}
${props.locales && props.locales.length > 0
? `locales: [${props.locales.map((locale) => `'${locale}'`).join(', ')}]`
: ''}`;
}
get edgeToOriginFunction() {
return this._edgeToOriginFunction;
}
get edgeToOriginLambdas() {
return this._edgeToOriginLambdas;
}
get edgeToOriginRole() {
return this._edgeToOriginRole;
}
constructor(scope, id, props) {
super(scope, id);
if (props === undefined) {
throw new Error('props must be set');
}
const { addXForwardedHostHeader = true, allowedFunctionUrlAccounts = [], assetNameRoot, assetNameSuffix, originRegion, setupApiGatewayPermissions = false, signingMode = 'sign', removalPolicy, rootPathPrefix, replaceHostHeader = true, tableRulesArn, } = props;
// Create the edge function config file from the construct options
const edgeToOriginConfigYaml = MicroAppsEdgeToOrigin.generateEdgeToOriginConfig({
originRegion: originRegion || aws_cdk_lib_1.Aws.REGION,
addXForwardedHostHeader,
replaceHostHeader,
signingMode: signingMode === 'none' ? '' : signingMode,
rootPathPrefix,
locales: props.allowedLocalePrefixes,
...(tableRulesArn
? {
tableName: tableRulesArn,
}
: {}),
});
const roleStack = new MicroAppsEdgeToOriginRoleStack(this, 'role-stack', {
stackName: `${aws_cdk_lib_1.Stack.of(this).stackName}-edge-role`,
assetNameRoot,
assetNameSuffix,
allowedFunctionUrlAccounts,
setupApiGatewayPermissions,
env: {
region: aws_cdk_lib_1.Stack.of(this).region,
account: aws_cdk_lib_1.Stack.of(this).account,
},
});
aws_cdk_lib_1.Stack.of(this).addDependency(roleStack);
this._edgeToOriginRole = roleStack.role;
new aws_cdk_lib_1.CfnOutput(this, 'role-stack-name', {
value: `${roleStack.stackName}`,
exportName: `${aws_cdk_lib_1.Stack.of(this).stackName}-role-stack`,
});
//
// Create the Edge to Origin Function
//
const edgeToOriginFuncProps = {
functionName: assetNameRoot ? `${assetNameRoot}-edge-to-origin${assetNameSuffix}` : undefined,
role: this._edgeToOriginRole,
memorySize: 1769,
logRetention: logs.RetentionDays.ONE_MONTH,
runtime: lambda.Runtime.NODEJS_18_X,
timeout: aws_cdk_lib_1.Duration.seconds(5),
...(removalPolicy ? { removalPolicy } : {}),
};
const rootDistPath = path.join(__dirname, '..', '..', 'microapps-edge-to-origin', 'dist');
const rootDistExists = (0, fs_1.existsSync)(path.join(rootDistPath, 'index.js'));
const localDistPath = path.join(__dirname, 'microapps-edge-to-origin');
const localDistExists = (0, fs_1.existsSync)(path.join(localDistPath, 'index.js'));
if (process.env.NODE_ENV === 'test' && rootDistExists) {
// This is for tests run under jest - Prefer root dist bundle
// This is also for anytime when the edge function has already been bundled
this._edgeToOriginFunction = this.createEdgeFunction(rootDistPath, edgeToOriginConfigYaml, edgeToOriginFuncProps);
}
else if (localDistExists) {
// Prefer local dist above root dist if both exist (when building for distribution)
this._edgeToOriginFunction = this.createEdgeFunction(localDistPath, edgeToOriginConfigYaml, edgeToOriginFuncProps);
}
else if (rootDistExists) {
// Use local dist if it exists (when deploying from CDK in this repo)
this._edgeToOriginFunction = this.createEdgeFunction(rootDistPath, edgeToOriginConfigYaml, edgeToOriginFuncProps);
}
else {
// This is used when bundling the app and building the CDK module
// for distribution.
(0, fs_1.writeFileSync)(path.join(__dirname, '..', '..', 'microapps-edge-to-origin', 'config.yml'), edgeToOriginConfigYaml);
// Copy the appFrame.html to the place where the bundling will find it
(0, fs_1.copyFileSync)(path.join(__dirname, '..', '..', 'microapps-router', 'appFrame.html'), path.join(__dirname, '..', '..', 'microapps-edge-to-origin', 'appFrame.html'));
// This builds the function for distribution with the CDK Construct
// and will be used during local builds and PR builds of microapps-core
// if the microapps-edge-to-origin function is not already bundled.
// This will fail to deploy in any region other than us-east-1
this._edgeToOriginFunction = new lambdaNodejs.NodejsFunction(this, 'edge-to-apigwy-func', {
entry: path.join(__dirname, '..', '..', 'microapps-edge-to-origin', 'src', 'index.ts'),
handler: 'handler',
bundling: {
minify: true,
sourceMap: true,
commandHooks: {
beforeInstall: () => [],
beforeBundling: () => [],
afterBundling: (_inputDir, outputDir) => {
// 2022-10-02 - Note that this is ignoring the generated config
// file above and including the default template config file
return [
`${os.platform() === 'win32' ? 'copy' : 'cp'} ${path.join(__dirname, '..', '..', '..', 'configs', 'microapps-edge-to-origin', 'config.yml')} ${outputDir}`,
`${os.platform() === 'win32' ? 'copy' : 'cp'} ${path.join(__dirname, '..', '..', 'microapps-router', 'appFrame.html')} ${outputDir}`,
];
},
},
},
...edgeToOriginFuncProps,
});
}
this._edgeToOriginLambdas = [
{
eventType: cf.LambdaEdgeEventType.ORIGIN_REQUEST,
functionVersion: this._edgeToOriginFunction.currentVersion,
includeBody: true,
},
];
// Grant access to the rules table
if (tableRulesArn) {
const tableRules = dynamodb.Table.fromTableName(this, 'tableRules', tableRulesArn);
tableRules.grantReadData(this._edgeToOriginFunction);
}
this._edgeToOriginFunction.stack.stackName;
new aws_cdk_lib_1.CfnOutput(this, 'edge-stack-name', {
value: `${this._edgeToOriginFunction.stack.stackName}`,
exportName: `${aws_cdk_lib_1.Stack.of(this).stackName}-edge-stack`,
});
}
/**
* Hash the stack name to make the EdgeFunction parameter name unique
*
* @param stack
* @returns
*/
hashStackName() {
return crypto.createHash('sha1').update(aws_cdk_lib_1.Stack.of(this).stackName).digest('hex').substring(0, 8);
}
createEdgeFunction(distPath, edgeToOriginConfigYaml, edgeToOriginFuncProps) {
(0, fs_1.writeFileSync)(path.join(distPath, 'config.yml'), edgeToOriginConfigYaml);
// Skip the copy of appFrame.html on deployed modules
if (!__dirname.includes('node_modules')) {
(0, fs_1.copyFileSync)(path.join(__dirname, '..', '..', 'microapps-router', 'appFrame.html'), path.join(distPath, 'appFrame.html'));
}
// The exclude varying per stack name is a kludge to get the asset bundled
// with the stack-specifc config.yml file, otherwise they all get the file
// generated for the first instance of the construct within any stack
// in the app.
const code = lambda.Code.fromAsset(distPath, { exclude: [`**/${aws_cdk_lib_1.Stack.of(this)}`] });
const stackHash = this.hashStackName() ?? '';
// EdgeFunction has a bug where it will generate the same parameter
// name across multiple stacks in the same region if the id param is constant
const edge = new cf.experimental.EdgeFunction(this, `edge-to-apigwy-func-${stackHash}`, {
stackId: `microapps-edge-to-origin-${stackHash}`,
code,
functionName: `microapps-edge-to-origin-${stackHash}`,
handler: 'index.handler',
...edgeToOriginFuncProps,
});
aws_cdk_lib_1.Tags.of(edge).add('Name', aws_cdk_lib_1.Stack.of(this).stackName);
return edge;
}
}
exports.MicroAppsEdgeToOrigin = MicroAppsEdgeToOrigin;
_a = JSII_RTTI_SYMBOL_1;
MicroAppsEdgeToOrigin[_a] = { fqn: "@pwrdrvr/microapps-cdk.MicroAppsEdgeToOrigin", version: "1.0.3" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWljcm9BcHBzRWRnZVRvT3JpZ2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL01pY3JvQXBwc0VkZ2VUb09yaWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLDhDQUE4QztBQUM5QyxpQ0FBaUM7QUFDakMsMkJBQTZEO0FBQzdELHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsNkNBU3FCO0FBQ3JCLGlEQUFpRDtBQUNqRCxxREFBcUQ7QUFDckQsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCw4REFBOEQ7QUFDOUQsNkNBQTZDO0FBQzdDLDJDQUF1QztBQWtLdkMsTUFBTSw4QkFBK0IsU0FBUSxtQkFBSztJQUVoRCxJQUFXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUVELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMkM7UUFDbkYsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFeEIsTUFBTSxFQUNKLGFBQWEsRUFDYixlQUFlLEVBQ2YsMEJBQTBCLEVBQzFCLDBCQUEwQixHQUMzQixHQUFHLEtBQUssQ0FBQztRQUVWLHdDQUF3QztRQUN4QyxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFO1lBQzNDLFNBQVMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQztZQUMzRCxRQUFRLEVBQUUsYUFBYTtnQkFDckIsQ0FBQyxDQUFDLEdBQUcsYUFBYSxhQUFhLGVBQWUsRUFBRTtnQkFDaEQsQ0FBQyxDQUFDLDBCQUFZLENBQUMsa0JBQWtCO1lBQ25DLGVBQWUsRUFBRTtnQkFDZixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLDBDQUEwQyxDQUFDO2FBQ3ZGO1lBQ0QsY0FBYyxFQUFFO2dCQUNkLGtCQUFrQixFQUFFLElB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RSxrQkFBa0IsRUFBRSxlQUFlLENBQUMsRUFDckUsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQ3JDLENBQUM7UUFDSixDQUFDO1FBRUQsMEVBQTBFO1FBQzFFLDBFQUEwRTtRQUMxRSxxRUFBcUU7UUFDckUsY0FBYztRQUNkLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLE1BQU0sbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVwRixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxDQUFDO1FBRTdDLG1FQUFtRTtRQUNuRSw2RUFBNkU7UUFDN0UsTUFBTSxJQUFJLEdBQUcsSUFBSSxFQUFFLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLFNBQVMsRUFBRSxFQUFFO1lBQ3RGLE9BQU8sRUFBRSw0QkFBNEIsU0FBUyxFQUFFO1lBQ2hELElBQUk7WUFDSixZQUFZLEVBQUUsNEJBQTRCLFNBQVMsRUFBRTtZQUNyRCxPQUFPLEVBQUUsZUFBZTtZQUN4QixHQUFHLHFCQUFxQjtTQUN6QixDQUFDLENBQUM7UUFDSCxrQkFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXBELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzs7QUExUEgsc0RBMlBDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L2luZGVudCAqL1xuaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgeyBjb3B5RmlsZVN5bmMsIGV4aXN0c1N5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHtcbiAgQXdzLFxuICBDZm5PdXRwdXQsXG4gIER1cmF0aW9uLFxuICBQaHlzaWNhbE5hbWUsXG4gIFJlbW92YWxQb2xpY3ksXG4gIFN0YWNrLFxuICBTdGFja1Byb3BzLFxuICBUYWdzLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgKiBhcyBjZiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtY2xvdWRmcm9udCc7XG5pbXBvcnQgKiBhcyBkeW5hbW9kYiBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZHluYW1vZGInO1xuaW1wb3J0ICogYXMgaWFtIGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0ICogYXMgbGFtYmRhIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEnO1xuaW1wb3J0ICogYXMgbGFtYmRhTm9kZWpzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sYW1iZGEtbm9kZWpzJztcbmltcG9ydCAqIGFzIGxvZ3MgZnJvbSAnYXdzLWNkay1saWIvYXdzLWxvZ3MnO1xuaW1wb3J0IHsgQ29uc3RydWN0IH0gZnJvbSAnY29uc3RydWN0cyc7XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIE1pY3JvQXBwcyBFZGdlIHRvIE9yaWdpbiBGdW5jdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIElNaWNyb0FwcHNFZGdlVG9PcmlnaW4ge1xuICAvKipcbiAgICogVGhlIGVkZ2UgdG8gb3JpZ2luIGZ1bmN0aW9uIGZvciBBUEkgR2F0ZXdheSBSZXF1ZXN0IE9yaWdpbiBFZGdlIExhbWJkYVxuICAgKlxuICAgKiBUaGUgZ2VuZXJhdGVkIGBjb25maWcueW1sYCBpcyBpbmNsdWRlZCBpbiB0aGUgTGFtYmRhJ3MgY29kZS5cbiAgICovXG4gIHJlYWRvbmx5IGVkZ2VUb09yaWdpbkZ1bmN0aW9uOiBsYW1iZGEuRnVuY3Rpb24gfCBjZi5leHBlcmltZW50YWwuRWRnZUZ1bmN0aW9uO1xuXG4gIC8qKlxuICAgKiBDb25maWd1cmF0aW9uIG9mIHRoZSBlZGdlIHRvIG9yaWdpbiBsYW1iZGEgZnVuY3Rpb25zXG4gICAqL1xuICByZWFkb25seSBlZGdlVG9PcmlnaW5MYW1iZGFzOiBjZi5FZGdlTGFtYmRhW107XG5cbiAgLyoqXG4gICAqIFRoZSBJQU0gUm9sZSBmb3IgdGhlIGVkZ2UgdG8gb3JpZ2luIGZ1bmN0aW9uXG4gICAqL1xuICByZWFkb25seSBlZGdlVG9PcmlnaW5Sb2xlOiBpYW0uUm9sZTtcbn1cblxuLyoqXG4gKiBQcm9wZXJ0aWVzIHRvIGluaXRpYWxpemUgYW4gaW5zdGFuY2Ugb2YgYE1pY3JvQXBwc0VkZ2VUb09yaWdpbmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWljcm9BcHBzRWRnZVRvT3JpZ2luUHJvcHMge1xuICAvKipcbiAgICogUmVtb3ZhbFBvbGljeSBvdmVycmlkZSBmb3IgY2hpbGQgcmVzb3VyY2VzXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcGVyIHJlc291cmNlIGRlZmF1bHRcbiAgICovXG4gIHJlYWRvbmx5IHJlbW92YWxQb2xpY3k/OiBSZW1vdmFsUG9saWN5O1xuXG4gIC8qKlxuICAgKiBPcHRpb25hbCBhc3NldCBuYW1lIHJvb3RcbiAgICpcbiAgICogQGV4YW1wbGUgbWljcm9hcHBzXG4gICAqIEBkZWZhdWx0IC0gcmVzb3VyY2UgbmFtZXMgYXV0byBhc3NpZ25lZFxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXROYW1lUm9vdD86IHN0cmluZztcblxuICAvKipcbiAgICogT3B0aW9uYWwgYXNzZXQgbmFtZSBzdWZmaXhcbiAgICpcbiAgICogQGV4YW1wbGUgLWRldi1wci0xMlxuICAgKiBAZGVmYXVsdCBub25lXG4gICAqL1xuICByZWFkb25seSBhc3NldE5hbWVTdWZmaXg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFBhdGggcHJlZml4IG9uIHRoZSByb290IG9mIHRoZSBBUEkgR2F0ZXdheSBTdGFnZVxuICAgKlxuICAgKiBAZXhhbXBsZSBkZXYvXG4gICAqIEBkZWZhdWx0IG5vbmVcbiAgICovXG4gIHJlYWRvbmx5IHJvb3RQYXRoUHJlZml4Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBMaXN0IG9mIGFsbG93ZWQgbG9jYWxlIHByZWZpeGVzIGZvciBwYWdlc1xuICAgKlxuICAgKiBAZXhhbXBsZTogWydlbicsICdmcicsICdlcyddXG4gICAqIEBkZWZhdWx0IG5vbmVcbiAgICovXG4gIHJlYWRvbmx5IGFsbG93ZWRMb2NhbGVQcmVmaXhlcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBBZGRzIGFuIFgtRm9yd2FyZGVkLUhvc3QtSGVhZGVyIHdoZW4gY2FsbGluZyBBUEkgR2F0ZXdheVxuICAgKlxuICAgKiBDYW4gb25seSBiZSB0cnVzdGVkIGlmIGBzaWduaW5nTW9kZWAgaXMgZW5hYmxlZCwgd2hpY2ggcmVzdHJpY3RzXG4gICAqIGFjY2VzcyB0byBBUEkgR2F0ZXdheSB0byBvbmx5IElBTSBzaWduZWQgcmVxdWVzdHMuXG4gICAqXG4gICAqIE5vdGU6IGlmIHRydWUsIGNyZWF0ZXMgT3JpZ2luUmVxdWVzdCBMYW1iZGEgQCBFZGdlIGZ1bmN0aW9uIGZvciBBUEkgR2F0ZXdheSBPcmlnaW5cbiAgICogQGRlZmF1bHQgdHJ1ZVxuICAgKi9cbiAgcmVhZG9ubHkgYWRkWEZvcndhcmRlZEhvc3RIZWFkZXI/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBSZXBsYWNlcyBIb3N0IGhlYWRlciAod2hpY2ggd2lsbCBiZSB0aGUgRWRnZSBkb21haW4gbmFtZSkgd2l0aCB0aGUgT3JpZ2luIGRvbWFpbiBuYW1lXG4gICAqIHdoZW4gZW5hYmxlZC4gIFRoaXMgaXMgbmVjZXNzYXJ5IHdoZW4gQVBJIEdhdGV3YXkgaGFzIG5vdCBiZWVuIGNvbmZpZ3VyZWRcbiAgICogd2l0aCBhIGN1c3RvbSBkb21haW4gbmFtZSB0aGF0IG1hdGNoZXMgdGhlIGV4YWN0IGRvbWFpbiBuYW1lIHVzZWQgYnkgdGhlIENsb3VkRnJvbnRcbiAgICogRGlzdHJpYnV0aW9uIEFORCB3aGVuIHRoZSBPcmlnaW5SZXF1ZXN0UG9saWN5LkhlYWRlcnNCZWhhdmlvciBpcyBzZXRcbiAgICogdG8gcGFzcyBhbGwgaGVhZGVycyB0byB0aGUgb3JpZ2luLlxuICAgKlxuICAgKiBOb3RlOiBpZiB0cnVlLCBjcmVhdGVzIE9yaWdpblJlcXVlc3QgTGFtYmRhIEAgRWRnZSBmdW5jdGlvbiBmb3IgQVBJIEdhdGV3YXkgT3JpZ2luXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IHJlcGxhY2VIb3N0SGVhZGVyPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmVxdWlyZXMgSUFNIGF1dGggb24gdGhlIEFQSSBHYXRld2F5IG9yaWdpbiBpZiBub3Qgc2V0IHRvICdub25lJy5cbiAgICpcbiAgICogJ3NpZ24nIC0gVXNlcyByZXF1ZXN0IGhlYWRlcnMgZm9yIGF1dGguXG4gICAqICdwcmVzaWduJyAtIFVzZXMgcXVlcnkgc3RyaW5nIGZvciBhdXRoLlxuICAgKlxuICAgKiBJZiBlbmFibGVkLFxuICAgKlxuICAgKiBOb3RlOiBpZiAnc2lnbicgb3IgJ3ByZXNpZ24nLCBjcmVhdGVzIE9yaWdpblJlcXVlc3QgTGFtYmRhIEAgRWRnZSBmdW5jdGlvbiBmb3IgQVBJIEdhdGV3YXkgT3JpZ2luXG4gICAqIEBkZWZhdWx0ICdzaWduJ1xuICAgKi9cbiAgcmVhZG9ubHkgc2lnbmluZ01vZGU/OiAnc2lnbicgfCAncHJlc2lnbicgfCAnbm9uZSc7XG5cbiAgLyoqXG4gICAqIE9yaWdpbiByZWdpb24gdGhhdCBBUEkgR2F0ZXdheSB3aWxsIGJlIGRlcGxveWVkIHRvLCB1c2VkXG4gICAqIGZvciB0aGUgY29uZmlnLnltbCBvbiB0aGUgRWRnZSBmdW5jdGlvbiB0byBzaWduIHJlcXVlc3RzIGZvclxuICAgKiB0aGUgY29ycmVjdCByZWdpb25cbiAgICpcbiAgICogTm90ZSB0aGF0IExhbWJkYSBGdW5jdGlvblVSTHMgZ2V0IHRoZSByZWdpb24gZnJvbSB0aGUgTGFtYmRhIEFSTlxuICAgKiBhbmQgZG8gbm90IG5lZWQgdGhpcyB0byBiZSBjb25maWd1cmVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCB1bmRlZmluZWRcbiAgICovXG4gIHJlYWRvbmx5IG9yaWdpblJlZ2lvbj86IHN0cmluZztcblxuICAvKipcbiAgICogRHluYW1vREIgVGFibGUgTmFtZSBmb3IgYXBwcy92ZXJzaW9ucy9ydWxlcy5cbiAgICpcbiAgICogTXVzdCBiZSBhIGZ1bGwgQVJOIGFzIHRoaXMgY2FuIGJlIGNyb3NzIHJlZ2lvbi5cbiAgICpcbiAgICogSW1wbGllcyB0aGF0IDJuZCBnZW5lcmF0aW9uIHJvdXRpbmcgaXMgZW5hYmxlZC5cbiAgICovXG4gIHJlYWRvbmx5IHRhYmxlUnVsZXNBcm4/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIEVuYWJsZSBpbnZva2luZyBBUEkgR2F0ZXdheSBmcm9tIHRoZSBFZGdlIExhbWJkYVxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgc2V0dXBBcGlHYXRld2F5UGVybWlzc2lvbnM/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBY2NvdW50IElEcyBhbGxvd2VkIGZvciBjcm9zcy1hY2NvdW50IEZ1bmN0aW9uIFVSTCBpbnZvY2F0aW9uc1xuICAgKlxuICAgKiBAZGVmYXVsdCBbXVxuICAgKi9cbiAgcmVhZG9ubHkgYWxsb3dlZEZ1bmN0aW9uVXJsQWNjb3VudHM/OiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHZW5lcmF0ZUVkZ2VUb09yaWdpbkNvbmZpZ09wdGlvbnMge1xuICByZWFkb25seSBvcmlnaW5SZWdpb246IHN0cmluZztcbiAgcmVhZG9ubHkgc2lnbmluZ01vZGU6ICdzaWduJyB8ICdwcmVzaWduJyB8ICcnO1xuICByZWFkb25seSBhZGRYRm9yd2FyZGVkSG9zdEhlYWRlcjogYm9vbGVhbjtcbiAgcmVhZG9ubHkgcmVwbGFjZUhvc3RIZWFkZXI6IGJvb2xlYW47XG4gIHJlYWRvbmx5IHRhYmxlTmFtZT86IHN0cmluZztcbiAgcmVhZG9ubHkgcm9vdFBhdGhQcmVmaXg/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGxvY2FsZXM/OiBzdHJpbmdbXTtcbn1cblxuaW50ZXJmYWNlIElNaWNyb0FwcHNFZGdlVG9PcmlnaW5Sb2xlU3RhY2tQcm9wcyBleHRlbmRzIFN0YWNrUHJvcHMge1xuICBhc3NldE5hbWVSb290Pzogc3RyaW5nO1xuICBhc3NldE5hbWVTdWZmaXg/OiBzdHJpbmc7XG4gIHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQWNjb3VudCBJRHMgYWxsb3dlZCBmb3IgY3Jvc3MtYWNjb3VudCBGdW5jdGlvbiBVUkwgaW52b2NhdGlvbnNcbiAgICpcbiAgICogQGRlZmF1bHQgW11cbiAgICovXG4gIHJlYWRvbmx5IGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzPzogc3RyaW5nW107XG59XG5cbmNsYXNzIE1pY3JvQXBwc0VkZ2VUb09yaWdpblJvbGVTdGFjayBleHRlbmRzIFN0YWNrIHtcbiAgcHJpdmF0ZSBfcm9sZTogaWFtLlJvbGU7XG4gIHB1YmxpYyBnZXQgcm9sZSgpOiBpYW0uUm9sZSB7XG4gICAgcmV0dXJuIHRoaXMuX3JvbGU7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogSU1pY3JvQXBwc0VkZ2VUb09yaWdpblJvbGVTdGFja1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkLCBwcm9wcyk7XG5cbiAgICBjb25zdCB7XG4gICAgICBhc3NldE5hbWVSb290LFxuICAgICAgYXNzZXROYW1lU3VmZml4LFxuICAgICAgc2V0dXBBcGlHYXRld2F5UGVybWlzc2lvbnMsXG4gICAgICBhbGxvd2VkRnVuY3Rpb25VcmxBY2NvdW50cyxcbiAgICB9ID0gcHJvcHM7XG5cbiAgICAvLyBDcmVhdGUgSUFNIFJvbGUgZm9yIHRoZSBFZGdlIEZ1bmN0aW9uXG4gICAgdGhpcy5fcm9sZSA9IG5ldyBpYW0uUm9sZSh0aGlzLCAnZWRnZS1yb2xlJywge1xuICAgICAgYXNzdW1lZEJ5OiBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2xhbWJkYS5hbWF6b25hd3MuY29tJyksXG4gICAgICByb2xlTmFtZTogYXNzZXROYW1lUm9vdFxuICAgICAgICA/IGAke2Fzc2V0TmFtZVJvb3R9LWVkZ2Utcm9sZSR7YXNzZXROYW1lU3VmZml4fWBcbiAgICAgICAgOiBQaHlzaWNhbE5hbWUuR0VORVJBVEVfSUZfTkVFREVELFxuICAgICAgbWFuYWdlZFBvbGljaWVzOiBbXG4gICAgICAgIGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnc2VydmljZS1yb2xlL0FXU0xhbWJkYUJhc2ljRXhlY3V0aW9uUm9sZScpLFxuICAgICAgXSxcbiAgICAgIGlubGluZVBvbGljaWVzOiB7XG4gICAgICAgIGVkZ2VUb09yaWdpblBvbGljeTogbmV3IGlhbS5Qb2xpY3lEb2N1bWVudCh7XG4gICAgICAgICAgc3RhdGVtZW50czogW1xuICAgICAgICAgICAgLy8gVGhpcyBjYW4ndCBoYXZlIGEgcmVmZXJlbmNlIHRvIHRoZSBodHRwQXBpIGJlY2F1c2UgaXQgd291bGQgbWVhblxuICAgICAgICAgICAgLy8gdGhlIHBhcmVudCBzdGFjayAodGhpcyBzdGFjaykgaGFzIHRvIGJlIGNyZWF0ZWQgYmVmb3JlIHRoZSB1cy1lYXN0LTFcbiAgICAgICAgICAgIC8vIGNoaWxkIHN0YWNrIGZvciB0aGUgRWRnZSBMYW1iZGEgRnVuY3Rpb24uXG4gICAgICAgICAgICAvLyBUaGF0J3Mgd2h5IHdlIHVzZSBhIHRhZy1iYXNlZCBwb2xpY3kgdG8gYWxsb3cgdGhlIEVkZ2UgRnVuY3Rpb25cbiAgICAgICAgICAgIC8vIHRvIGludm9rZSBhbnkgQVBJIEdhdGV3YXkgQVBJIHRoYXQgd2UgYXBwbHkgYSB0YWcgdG9cbiAgICAgICAgICAgIC8vIFdlIGFsbG93IHRoZSBlZGdlIGZ1bmN0aW9uIHRvIHNpZ24gZm9yIGFsbCByZWdpb25zIHNpbmNlXG4gICAgICAgICAgICAvLyB3ZSBtYXkgdXNlIGN1c3RvbSBjbG9zZXN0IHJlZ2lvbiBpbiB0aGUgZnV0dXJlLlxuICAgICAgICAgICAgLi4uKHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zXG4gICAgICAgICAgICAgID8gW1xuICAgICAgICAgICAgICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICAgICAgICAgICAgICBhY3Rpb25zOiBbJ2V4ZWN1dGUtYXBpOkludm9rZSddLFxuICAgICAgICAgICAgICAgICAgICByZXNvdXJjZXM6IFtgYXJuOmF3czpleGVjdXRlLWFwaToqOiR7QXdzLkFDQ09VTlRfSUR9OiovKi8qLypgXSxcbiAgICAgICAgICAgICAgICAgICAgLy8gVW5mb3J0dW5hdGVseSwgQVBJIEdhdGV3YXkgYWNjZXNzIGNhbm5vdCBiZSByZXN0cmljdGVkIHVzaW5nXG4gICAgICAgICAgICAgICAgICAgIC8vIHRhZ3Mgb24gdGhlIHRhcmdldCByZXNvdXJjZVxuICAgICAgICAgICAgICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vSUFNL2xhdGVzdC9Vc2VyR3VpZGUvYWNjZXNzX3RhZ3MuaHRtbFxuICAgICAgICAgICAgICAgICAgICAvLyBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vSUFNL2xhdGVzdC9Vc2VyR3VpZGUvcmVmZXJlbmNlX2F3cy1zZXJ2aWNlcy10aGF0LXdvcmstd2l0aC1pYW0uaHRtbCNuZXR3b3JraW5nX3N2Y3NcbiAgICAgICAgICAgICAgICAgICAgLy8gY29uZGl0aW9uczoge1xuICAgICAgICAgICAgICAgICAgICAvLyAgIC8vIFRPRE86IFNldCB0aGlzIHRvIGEgc3RyaW5nIHVuaXF1ZSB0byBlYWNoIHN0YWNrXG4gICAgICAgICAgICAgICAgICAgIC8vICAgU3RyaW5nRXF1YWxzOiB7ICdhd3M6UmVzb3VyY2VUYWcvbWljcm9hcHAtbWFuYWdlZCc6ICd0cnVlJyB9LFxuICAgICAgICAgICAgICAgICAgICAvLyB9LFxuICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICA6IFtdKSxcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBHcmFudCBwZXJtaXNzaW9uIHRvIGludm9rZSB0YWdnZWQgRnVuY3Rpb24gVVJMcyAoaW4gc2FtZSBhY2NvdW50KVxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgYWN0aW9uczogWydsYW1iZGE6SW52b2tlRnVuY3Rpb25VcmwnXSxcbiAgICAgICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6bGFtYmRhOio6JHtBd3MuQUNDT1VOVF9JRH06KmBdLFxuICAgICAgICAgICAgICBjb25kaXRpb25zOiB7XG4gICAgICAgICAgICAgICAgU3RyaW5nRXF1YWxzOiB7ICdhd3M6UmVzb3VyY2VUYWcvbWljcm9hcHAtbWFuYWdlZCc6ICd0cnVlJyB9LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gR3JhbnQgcGVybWlzc2lvbiB0byBpbnZva2UgRnVuY3Rpb24gVVJMcyBpbiBsaXN0ZWQgYWNjb3VudHNcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAuLi4oYWxsb3dlZEZ1bmN0aW9uVXJsQWNjb3VudHMgJiYgYWxsb3dlZEZ1bmN0aW9uVXJsQWNjb3VudHMubGVuZ3RoID4gMFxuICAgICAgICAgICAgICA/IFtcbiAgICAgICAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICAgICAgYWN0aW9uczogWydsYW1iZGE6SW52b2tlRnVuY3Rpb25VcmwnXSxcbiAgICAgICAgICAgICAgICAgICAgcmVzb3VyY2VzOiBhbGxvd2VkRnVuY3Rpb25VcmxBY2NvdW50cy5tYXAoXG4gICAgICAgICAgICAgICAgICAgICAgKGFjY291bnRJZCkgPT4gYGFybjphd3M6bGFtYmRhOio6JHthY2NvdW50SWR9OipgLFxuICAgICAgICAgICAgICAgICAgICApLFxuICAgICAgICAgICAgICAgICAgfSksXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICA6IFtdKSxcbiAgICAgICAgICBdLFxuICAgICAgICB9KSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgdGhpcy5fcm9sZS5hc3N1bWVSb2xlUG9saWN5Py5hZGRTdGF0ZW1lbnRzKFxuICAgICAgbmV3IGlhbS5Qb2xpY3lTdGF0ZW1lbnQoe1xuICAgICAgICBwcmluY2lwYWxzOiBbXG4gICAgICAgICAgbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdlZGdlbGFtYmRhLmFtYXpvbmF3cy5jb20nKSxcbiAgICAgICAgICBuZXcgaWFtLlNlcnZpY2VQcmluY2lwYWwoJ2xhbWJkYS5hbWF6b25hd3MuY29tJyksXG4gICAgICAgIF0sXG4gICAgICAgIGFjdGlvbnM6IFsnc3RzOkFzc3VtZVJvbGUnXSxcbiAgICAgICAgZWZmZWN0OiBpYW0uRWZmZWN0LkFMTE9XLFxuICAgICAgfSksXG4gICAgKTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgJ2VkZ2UtdG8tb3JpZ2luLXJvbGUtYXJuJywge1xuICAgICAgdmFsdWU6IGAke3RoaXMucm9sZS5yb2xlQXJufWAsXG4gICAgICBleHBvcnROYW1lOiBgJHt0aGlzLnN0YWNrTmFtZX0tcm9sZS1hcm5gLFxuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogQ3JlYXRlIGEgbmV3IE1pY3JvQXBwcyBFZGdlIHRvIE9yaWdpbiBGdW5jdGlvbiB3LyBgY29uZmlnLnltbGBcbiAqL1xuZXhwb3J0IGNsYXNzIE1pY3JvQXBwc0VkZ2VUb09yaWdpbiBleHRlbmRzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElNaWNyb0FwcHNFZGdlVG9PcmlnaW4ge1xuICAvKipcbiAgICogR2VuZXJhdGUgdGhlIHlhbWwgY29uZmlnIGZvciB0aGUgZWRnZSBsYW1iZGFcbiAgICogQHBhcmFtIHByb3BzXG4gICAqIEByZXR1cm5zXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGdlbmVyYXRlRWRnZVRvT3JpZ2luQ29uZmlnKHByb3BzOiBHZW5lcmF0ZUVkZ2VUb09yaWdpbkNvbmZpZ09wdGlvbnMpIHtcbiAgICByZXR1cm4gYG9yaWdpblJlZ2lvbjogJHtwcm9wcy5vcmlnaW5SZWdpb259XG4ke3Byb3BzLnNpZ25pbmdNb2RlID09PSAnJyA/ICcnIDogYHNpZ25pbmdNb2RlOiAke3Byb3BzLnNpZ25pbmdNb2RlfWB9XG5hZGRYRm9yd2FyZGVkSG9zdEhlYWRlcjogJHtwcm9wcy5hZGRYRm9yd2FyZGVkSG9zdEhlYWRlcn1cbnJlcGxhY2VIb3N0SGVhZGVyOiAke3Byb3BzLnJlcGxhY2VIb3N0SGVhZGVyfVxuJHtwcm9wcy50YWJsZU5hbWUgPyBgdGFibGVOYW1lOiAnJHtwcm9wcy50YWJsZU5hbWV9J2AgOiAnJ31cbiR7cHJvcHMucm9vdFBhdGhQcmVmaXggPyBgcm9vdFBhdGhQcmVmaXg6ICcke3Byb3BzLnJvb3RQYXRoUHJlZml4fSdgIDogJyd9XG4ke1xuICBwcm9wcy5sb2NhbGVzICYmIHByb3BzLmxvY2FsZXMubGVuZ3RoID4gMFxuICAgID8gYGxvY2FsZXM6IFske3Byb3BzLmxvY2FsZXMubWFwKChsb2NhbGUpID0+IGAnJHtsb2NhbGV9J2ApLmpvaW4oJywgJyl9XWBcbiAgICA6ICcnXG59YDtcbiAgfVxuXG4gIHByaXZhdGUgX2VkZ2VUb09yaWdpbkZ1bmN0aW9uOiBsYW1iZGEuRnVuY3Rpb24gfCBjZi5leHBlcmltZW50YWwuRWRnZUZ1bmN0aW9uO1xuICBwdWJsaWMgZ2V0IGVkZ2VUb09yaWdpbkZ1bmN0aW9uKCk6IGxhbWJkYS5GdW5jdGlvbiB8IGNmLmV4cGVyaW1lbnRhbC5FZGdlRnVuY3Rpb24ge1xuICAgIHJldHVybiB0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbjtcbiAgfVxuXG4gIHByaXZhdGUgX2VkZ2VUb09yaWdpbkxhbWJkYXM6IGNmLkVkZ2VMYW1iZGFbXTtcbiAgcHVibGljIGdldCBlZGdlVG9PcmlnaW5MYW1iZGFzKCk6IGNmLkVkZ2VMYW1iZGFbXSB7XG4gICAgcmV0dXJuIHRoaXMuX2VkZ2VUb09yaWdpbkxhbWJkYXM7XG4gIH1cblxuICBwcml2YXRlIF9lZGdlVG9PcmlnaW5Sb2xlOiBpYW0uUm9sZTtcbiAgcHVibGljIGdldCBlZGdlVG9PcmlnaW5Sb2xlKCk6IGlhbS5Sb2xlIHtcbiAgICByZXR1cm4gdGhpcy5fZWRnZVRvT3JpZ2luUm9sZTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBNaWNyb0FwcHNFZGdlVG9PcmlnaW5Qcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBpZiAocHJvcHMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdwcm9wcyBtdXN0IGJlIHNldCcpO1xuICAgIH1cblxuICAgIGNvbnN0IHtcbiAgICAgIGFkZFhGb3J3YXJkZWRIb3N0SGVhZGVyID0gdHJ1ZSxcbiAgICAgIGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzID0gW10sXG4gICAgICBhc3NldE5hbWVSb290LFxuICAgICAgYXNzZXROYW1lU3VmZml4LFxuICAgICAgb3JpZ2luUmVnaW9uLFxuICAgICAgc2V0dXBBcGlHYXRld2F5UGVybWlzc2lvbnMgPSBmYWxzZSxcbiAgICAgIHNpZ25pbmdNb2RlID0gJ3NpZ24nLFxuICAgICAgcmVtb3ZhbFBvbGljeSxcbiAgICAgIHJvb3RQYXRoUHJlZml4LFxuICAgICAgcmVwbGFjZUhvc3RIZWFkZXIgPSB0cnVlLFxuICAgICAgdGFibGVSdWxlc0FybixcbiAgICB9ID0gcHJvcHM7XG5cbiAgICAvLyBDcmVhdGUgdGhlIGVkZ2UgZnVuY3Rpb24gY29uZmlnIGZpbGUgZnJvbSB0aGUgY29uc3RydWN0IG9wdGlvbnNcbiAgICBjb25zdCBlZGdlVG9PcmlnaW5Db25maWdZYW1sID0gTWljcm9BcHBzRWRnZVRvT3JpZ2luLmdlbmVyYXRlRWRnZVRvT3JpZ2luQ29uZmlnKHtcbiAgICAgIG9yaWdpblJlZ2lvbjogb3JpZ2luUmVnaW9uIHx8IEF3cy5SRUdJT04sXG4gICAgICBhZGRYRm9yd2FyZGVkSG9zdEhlYWRlcixcbiAgICAgIHJlcGxhY2VIb3N0SGVhZGVyLFxuICAgICAgc2lnbmluZ01vZGU6IHNpZ25pbmdNb2RlID09PSAnbm9uZScgPyAnJyA6IHNpZ25pbmdNb2RlLFxuICAgICAgcm9vdFBhdGhQcmVmaXgsXG4gICAgICBsb2NhbGVzOiBwcm9wcy5hbGxvd2VkTG9jYWxlUHJlZml4ZXMsXG4gICAgICAuLi4odGFibGVSdWxlc0FyblxuICAgICAgICA/IHtcbiAgICAgICAgICAgIHRhYmxlTmFtZTogdGFibGVSdWxlc0FybixcbiAgICAgICAgICB9XG4gICAgICAgIDoge30pLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgcm9sZVN0YWNrID0gbmV3IE1pY3JvQXBwc0VkZ2VUb09yaWdpblJvbGVTdGFjayh0aGlzLCAncm9sZS1zdGFjaycsIHtcbiAgICAgIHN0YWNrTmFtZTogYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS1lZGdlLXJvbGVgLFxuICAgICAgYXNzZXROYW1lUm9vdCxcbiAgICAgIGFzc2V0TmFtZVN1ZmZpeCxcbiAgICAgIGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzLFxuICAgICAgc2V0dXBBcGlHYXRld2F5UGVybWlzc2lvbnMsXG4gICAgICBlbnY6IHtcbiAgICAgICAgcmVnaW9uOiBTdGFjay5vZih0aGlzKS5yZWdpb24sXG4gICAgICAgIGFjY291bnQ6IFN0YWNrLm9mKHRoaXMpLmFjY291bnQsXG4gICAgICB9LFxuICAgIH0pO1xuICAgIFN0YWNrLm9mKHRoaXMpLmFkZERlcGVuZGVuY3kocm9sZVN0YWNrKTtcbiAgICB0aGlzLl9lZGdlVG9PcmlnaW5Sb2xlID0gcm9sZVN0YWNrLnJvbGU7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsICdyb2xlLXN0YWNrLW5hbWUnLCB7XG4gICAgICB2YWx1ZTogYCR7cm9sZVN0YWNrLnN0YWNrTmFtZX1gLFxuICAgICAgZXhwb3J0TmFtZTogYCR7U3RhY2sub2YodGhpcykuc3RhY2tOYW1lfS1yb2xlLXN0YWNrYCxcbiAgICB9KTtcblxuICAgIC8vXG4gICAgLy8gQ3JlYXRlIHRoZSBFZGdlIHRvIE9yaWdpbiBGdW5jdGlvblxuICAgIC8vXG4gICAgY29uc3QgZWRnZVRvT3JpZ2luRnVuY1Byb3BzOiBPbWl0PGxhbWJkYS5GdW5jdGlvblByb3BzLCAnaGFuZGxlcicgfCAnY29kZSc+ID0ge1xuICAgICAgZnVuY3Rpb25OYW1lOiBhc3NldE5hbWVSb290ID8gYCR7YXNzZXROYW1lUm9vdH0tZWRnZS10by1vcmlnaW4ke2Fzc2V0TmFtZVN1ZmZpeH1gIDogdW5kZWZpbmVkLFxuICAgICAgcm9sZTogdGhpcy5fZWRnZVRvT3JpZ2luUm9sZSxcbiAgICAgIG1lbW9yeVNpemU6IDE3NjksXG4gICAgICBsb2dSZXRlbnRpb246IGxvZ3MuUmV0ZW50aW9uRGF5cy5PTkVfTU9OVEgsXG4gICAgICBydW50aW1lOiBsYW1iZGEuUnVudGltZS5OT0RFSlNfMThfWCxcbiAgICAgIHRpbWVvdXQ6IER1cmF0aW9uLnNlY29uZHMoNSksXG4gICAgICAuLi4ocmVtb3ZhbFBvbGljeSA/IHsgcmVtb3ZhbFBvbGljeSB9IDoge30pLFxuICAgIH07XG4gICAgY29uc3Qgcm9vdERpc3RQYXRoID0gcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ21pY3JvYXBwcy1lZGdlLXRvLW9yaWdpbicsICdkaXN0Jyk7XG4gICAgY29uc3Qgcm9vdERpc3RFeGlzdHMgPSBleGlzdHNTeW5jKHBhdGguam9pbihyb290RGlzdFBhdGgsICdpbmRleC5qcycpKTtcbiAgICBjb25zdCBsb2NhbERpc3RQYXRoID0gcGF0aC5qb2luKF9fZGlybmFtZSwgJ21pY3JvYXBwcy1lZGdlLXRvLW9yaWdpbicpO1xuICAgIGNvbnN0IGxvY2FsRGlzdEV4aXN0cyA9IGV4aXN0c1N5bmMocGF0aC5qb2luKGxvY2FsRGlzdFBhdGgsICdpbmRleC5qcycpKTtcbiAgICBpZiAocHJvY2Vzcy5lbnYuTk9ERV9FTlYgPT09ICd0ZXN0JyAmJiByb290RGlzdEV4aXN0cykge1xuICAgICAgLy8gVGhpcyBpcyBmb3IgdGVzdHMgcnVuIHVuZGVyIGplc3QgLSBQcmVmZXIgcm9vdCBkaXN0IGJ1bmRsZVxuICAgICAgLy8gVGhpcyBpcyBhbHNvIGZvciBhbnl0aW1lIHdoZW4gdGhlIGVkZ2UgZnVuY3Rpb24gaGFzIGFscmVhZHkgYmVlbiBidW5kbGVkXG4gICAgICB0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbiA9IHRoaXMuY3JlYXRlRWRnZUZ1bmN0aW9uKFxuICAgICAgICByb290RGlzdFBhdGgsXG4gICAgICAgIGVkZ2VUb09yaWdpbkNvbmZpZ1lhbWwsXG4gICAgICAgIGVkZ2VUb09yaWdpbkZ1bmNQcm9wcyxcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChsb2NhbERpc3RFeGlzdHMpIHtcbiAgICAgIC8vIFByZWZlciBsb2NhbCBkaXN0IGFib3ZlIHJvb3QgZGlzdCBpZiBib3RoIGV4aXN0ICh3aGVuIGJ1aWxkaW5nIGZvciBkaXN0cmlidXRpb24pXG4gICAgICB0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbiA9IHRoaXMuY3JlYXRlRWRnZUZ1bmN0aW9uKFxuICAgICAgICBsb2NhbERpc3RQYXRoLFxuICAgICAgICBlZGdlVG9PcmlnaW5Db25maWdZYW1sLFxuICAgICAgICBlZGdlVG9PcmlnaW5GdW5jUHJvcHMsXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAocm9vdERpc3RFeGlzdHMpIHtcbiAgICAgIC8vIFVzZSBsb2NhbCBkaXN0IGlmIGl0IGV4aXN0cyAod2hlbiBkZXBsb3lpbmcgZnJvbSBDREsgaW4gdGhpcyByZXBvKVxuICAgICAgdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gPSB0aGlzLmNyZWF0ZUVkZ2VGdW5jdGlvbihcbiAgICAgICAgcm9vdERpc3RQYXRoLFxuICAgICAgICBlZGdlVG9PcmlnaW5Db25maWdZYW1sLFxuICAgICAgICBlZGdlVG9PcmlnaW5GdW5jUHJvcHMsXG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBUaGlzIGlzIHVzZWQgd2hlbiBidW5kbGluZyB0aGUgYXBwIGFuZCBidWlsZGluZyB0aGUgQ0RLIG1vZHVsZVxuICAgICAgLy8gZm9yIGRpc3RyaWJ1dGlvbi5cbiAgICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4nLCAnY29uZmlnLnltbCcpLFxuICAgICAgICBlZGdlVG9PcmlnaW5Db25maWdZYW1sLFxuICAgICAgKTtcblxuICAgICAgLy8gQ29weSB0aGUgYXBwRnJhbWUuaHRtbCB0byB0aGUgcGxhY2Ugd2hlcmUgdGhlIGJ1bmRsaW5nIHdpbGwgZmluZCBpdFxuICAgICAgY29weUZpbGVTeW5jKFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLXJvdXRlcicsICdhcHBGcmFtZS5odG1sJyksXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4nLCAnYXBwRnJhbWUuaHRtbCcpLFxuICAgICAgKTtcblxuICAgICAgLy8gVGhpcyBidWlsZHMgdGhlIGZ1bmN0aW9uIGZvciBkaXN0cmlidXRpb24gd2l0aCB0aGUgQ0RLIENvbnN0cnVjdFxuICAgICAgLy8gYW5kIHdpbGwgYmUgdXNlZCBkdXJpbmcgbG9jYWwgYnVpbGRzIGFuZCBQUiBidWlsZHMgb2YgbWljcm9hcHBzLWNvcmVcbiAgICAgIC8vIGlmIHRoZSBtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4gZnVuY3Rpb24gaXMgbm90IGFscmVhZHkgYnVuZGxlZC5cbiAgICAgIC8vIFRoaXMgd2lsbCBmYWlsIHRvIGRlcGxveSBpbiBhbnkgcmVnaW9uIG90aGVyIHRoYW4gdXMtZWFzdC0xXG4gICAgICB0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbiA9IG5ldyBsYW1iZGFOb2RlanMuTm9kZWpzRnVuY3Rpb24odGhpcywgJ2VkZ2UtdG8tYXBpZ3d5LWZ1bmMnLCB7XG4gICAgICAgIGVudHJ5OiBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLWVkZ2UtdG8tb3JpZ2luJywgJ3NyYycsICdpbmRleC50cycpLFxuICAgICAgICBoYW5kbGVyOiAnaGFuZGxlcicsXG4gICAgICAgIGJ1bmRsaW5nOiB7XG4gICAgICAgICAgbWluaWZ5OiB0cnVlLFxuICAgICAgICAgIHNvdXJjZU1hcDogdHJ1ZSxcbiAgICAgICAgICBjb21tYW5kSG9va3M6IHtcbiAgICAgICAgICAgIGJlZm9yZUluc3RhbGw6ICgpID0+IFtdLFxuICAgICAgICAgICAgYmVmb3JlQnVuZGxpbmc6ICgpID0+IFtdLFxuICAgICAgICAgICAgYWZ0ZXJCdW5kbGluZzogKF9pbnB1dERpcjogc3RyaW5nLCBvdXRwdXREaXI6IHN0cmluZykgPT4ge1xuICAgICAgICAgICAgICAvLyAyMDIyLTEwLTAyIC0gTm90ZSB0aGF0IHRoaXMgaXMgaWdub3JpbmcgdGhlIGdlbmVyYXRlZCBjb25maWdcbiAgICAgICAgICAgICAgLy8gZmlsZSBhYm92ZSBhbmQgaW5jbHVkaW5nIHRoZSBkZWZhdWx0IHRlbXBsYXRlIGNvbmZpZyBmaWxlXG4gICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgYCR7b3MucGxhdGZvcm0oKSA9PT0gJ3dpbjMyJyA/ICdjb3B5JyA6ICdjcCd9ICR7cGF0aC5qb2luKFxuICAgICAgICAgICAgICAgICAgX19kaXJuYW1lLFxuICAgICAgICAgICAgICAgICAgJy4uJyxcbiAgICAgICAgICAgICAgICAgICcuLicsXG4gICAgICAgICAgICAgICAgICAnLi4nLFxuICAgICAgICAgICAgICAgICAgJ2NvbmZpZ3MnLFxuICAgICAgICAgICAgICAgICAgJ21pY3JvYXBwcy1lZGdlLXRvLW9yaWdpbicsXG4gICAgICAgICAgICAgICAgICAnY29uZmlnLnltbCcsXG4gICAgICAgICAgICAgICAgKX0gJHtvdXRwdXREaXJ9YCxcbiAgICAgICAgICAgICAgICBgJHtvcy5wbGF0Zm9ybSgpID09PSAnd2luMzInID8gJ2NvcHknIDogJ2NwJ30gJHtwYXRoLmpvaW4oXG4gICAgICAgICAgICAgICAgICBfX2Rpcm5hbWUsXG4gICAgICAgICAgICAgICAgICAnLi4nLFxuICAgICAgICAgICAgICAgICAgJy4uJyxcbiAgICAgICAgICAgICAgICAgICdtaWNyb2FwcHMtcm91dGVyJyxcbiAgICAgICAgICAgICAgICAgICdhcHBGcmFtZS5odG1sJyxcbiAgICAgICAgICAgICAgICApfSAke291dHB1dERpcn1gLFxuICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICAuLi5lZGdlVG9PcmlnaW5GdW5jUHJvcHMsXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLl9lZGdlVG9PcmlnaW5MYW1iZGFzID0gW1xuICAgICAge1xuICAgICAgICBldmVudFR5cGU6IGNmLkxhbWJkYUVkZ2VFdmVudFR5cGUuT1JJR0lOX1JFUVVFU1QsXG4gICAgICAgIGZ1bmN0aW9uVmVyc2lvbjogdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24uY3VycmVudFZlcnNpb24sXG4gICAgICAgIGluY2x1ZGVCb2R5OiB0cnVlLFxuICAgICAgfSxcbiAgICBdO1xuXG4gICAgLy8gR3JhbnQgYWNjZXNzIHRvIHRoZSBydWxlcyB0YWJsZVxuICAgIGlmICh0YWJsZVJ1bGVzQXJuKSB7XG4gICAgICBjb25zdCB0YWJsZVJ1bGVzID0gZHluYW1vZGIuVGFibGUuZnJvbVRhYmxlTmFtZSh0aGlzLCAndGFibGVSdWxlcycsIHRhYmxlUnVsZXNBcm4pO1xuICAgICAgdGFibGVSdWxlcy5ncmFudFJlYWREYXRhKHRoaXMuX2VkZ2VUb09yaWdpbkZ1bmN0aW9uKTtcbiAgICB9XG5cbiAgICAodGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gYXMgY2YuZXhwZXJpbWVudGFsLkVkZ2VGdW5jdGlvbikuc3RhY2suc3RhY2tOYW1lO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCAnZWRnZS1zdGFjay1uYW1lJywge1xuICAgICAgdmFsdWU6IGAkeyh0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbiBhcyBjZi5leHBlcmltZW50YWwuRWRnZUZ1bmN0aW9uKS5zdGFjay5zdGFja05hbWV9YCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0tZWRnZS1zdGFja2AsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogSGFzaCB0aGUgc3RhY2sgbmFtZSB0byBtYWtlIHRoZSBFZGdlRnVuY3Rpb24gcGFyYW1ldGVyIG5hbWUgdW5pcXVlXG4gICAqXG4gICAqIEBwYXJhbSBzdGFja1xuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgcHJpdmF0ZSBoYXNoU3RhY2tOYW1lKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGNyeXB0by5jcmVhdGVIYXNoKCdzaGExJykudXBkYXRlKFN0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZSkuZGlnZXN0KCdoZXgnKS5zdWJzdHJpbmcoMCwgOCk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZUVkZ2VGdW5jdGlvbihcbiAgICBkaXN0UGF0aDogc3RyaW5nLFxuICAgIGVkZ2VUb09yaWdpbkNvbmZpZ1lhbWw6IHN0cmluZyxcbiAgICBlZGdlVG9PcmlnaW5GdW5jUHJvcHM6IE9taXQ8bGFtYmRhLkZ1bmN0aW9uUHJvcHMsICdoYW5kbGVyJyB8ICdjb2RlJz4sXG4gICkge1xuICAgIHdyaXRlRmlsZVN5bmMocGF0aC5qb2luKGRpc3RQYXRoLCAnY29uZmlnLnltbCcpLCBlZGdlVG9PcmlnaW5Db25maWdZYW1sKTtcblxuICAgIC8vIFNraXAgdGhlIGNvcHkgb2YgYXBwRnJhbWUuaHRtbCBvbiBkZXBsb3llZCBtb2R1bGVzXG4gICAgaWYgKCFfX2Rpcm5hbWUuaW5jbHVkZXMoJ25vZGVfbW9kdWxlcycpKSB7XG4gICAgICBjb3B5RmlsZVN5bmMoXG4gICAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdtaWNyb2FwcHMtcm91dGVyJywgJ2FwcEZyYW1lLmh0bWwnKSxcbiAgICAgICAgcGF0aC5qb2luKGRpc3RQYXRoLCAnYXBwRnJhbWUuaHRtbCcpLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgZXhjbHVkZSB2YXJ5aW5nIHBlciBzdGFjayBuYW1lIGlzIGEga2x1ZGdlIHRvIGdldCB0aGUgYXNzZXQgYnVuZGxlZFxuICAgIC8vIHdpdGggdGhlIHN0YWNrLXNwZWNpZmMgY29uZmlnLnltbCBmaWxlLCBvdG