@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 @stylistic/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_22_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.1.2" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTWljcm9BcHBzRWRnZVRvT3JpZ2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL01pY3JvQXBwc0VkZ2VUb09yaWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHNDQUFzQztBQUN0QyxpQ0FBaUM7QUFDakMsMkJBQTZEO0FBQzdELHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsNkNBU3FCO0FBQ3JCLGlEQUFpRDtBQUNqRCxxREFBcUQ7QUFDckQsMkNBQTJDO0FBQzNDLGlEQUFpRDtBQUNqRCw4REFBOEQ7QUFDOUQsNkNBQTZDO0FBQzdDLDJDQUF1QztBQWtLdkMsTUFBTSw4QkFBK0IsU0FBUSxtQkFBSztJQUVoRCxJQUFXLElBQUk7UUFDYixPQUFPLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDcEIsQ0FBQztJQUVELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBMkM7UUFDbkYsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFFeEIsTUFBTSxFQUNKLGFBQWEsRUFDYixlQUFlLEVBQ2YsMEJBQTBCLEVBQzFCLDBCQUEwQixHQUMzQixHQUFHLEtBQUssQ0FBQztRQUVWLHdDQUF3QztRQUN4QyxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsV0FBVyxFQUFFO1lBQzNDLFNBQVMsRUFBRSxJQUFJLEdBQUcsQ0FBQyxnQkFBZ0IsQ0FBQyxzQkFBc0IsQ0FBQztZQUMzRCxRQUFRLEVBQUUsYUFBYTtnQkFDckIsQ0FBQyxDQUFDLEdBQUcsYUFBYSxhQUFhLGVBQWUsRUFBRTtnQkFDaEQsQ0FBQyxDQUFDLDBCQUFZLENBQUMsa0JBQWtCO1lBQ25DLGVBQWUsRUFBRTtnQkFDZixHQUFHLENBQUMsYUFBYSxDQUFDLHdCQUF3QixDQUFDLDBDQUEwQyxDQUFDO2FBQ3ZGO1lBQ0QsY0FBYyxFQUFFO2dCQUNkLGtCQUFrQixFQUFFLElB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RSxrQkFBa0IsRUFBRSxlQUFlLENBQUMsRUFDckUsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQ3JDLENBQUM7UUFDSixDQUFDO1FBRUQsMEVBQTBFO1FBQzFFLDBFQUEwRTtRQUMxRSxxRUFBcUU7UUFDckUsY0FBYztRQUNkLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFDLE1BQU0sbUJBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUVwRixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxDQUFDO1FBRTdDLG1FQUFtRTtRQUNuRSw2RUFBNkU7UUFDN0UsTUFBTSxJQUFJLEdBQUcsSUFBSSxFQUFFLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsdUJBQXVCLFNBQVMsRUFBRSxFQUFFO1lBQ3RGLE9BQU8sRUFBRSw0QkFBNEIsU0FBUyxFQUFFO1lBQ2hELElBQUk7WUFDSixZQUFZLEVBQUUsNEJBQTRCLFNBQVMsRUFBRTtZQUNyRCxPQUFPLEVBQUUsZUFBZTtZQUN4QixHQUFHLHFCQUFxQjtTQUN6QixDQUFDLENBQUM7UUFDSCxrQkFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBRXBELE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQzs7QUExUEgsc0RBMlBDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHN0eWxpc3RpYy9pbmRlbnQgKi9cbmltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0IHsgY29weUZpbGVTeW5jLCBleGlzdHNTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7XG4gIEF3cyxcbiAgQ2ZuT3V0cHV0LFxuICBEdXJhdGlvbixcbiAgUGh5c2ljYWxOYW1lLFxuICBSZW1vdmFsUG9saWN5LFxuICBTdGFjayxcbiAgU3RhY2tQcm9wcyxcbiAgVGFncyxcbn0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgY2YgZnJvbSAnYXdzLWNkay1saWIvYXdzLWNsb3VkZnJvbnQnO1xuaW1wb3J0ICogYXMgZHluYW1vZGIgZnJvbSAnYXdzLWNkay1saWIvYXdzLWR5bmFtb2RiJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtaWFtJztcbmltcG9ydCAqIGFzIGxhbWJkYSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCAqIGFzIGxhbWJkYU5vZGVqcyBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhLW5vZGVqcyc7XG5pbXBvcnQgKiBhcyBsb2dzIGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBNaWNyb0FwcHMgRWRnZSB0byBPcmlnaW4gRnVuY3Rpb25cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJTWljcm9BcHBzRWRnZVRvT3JpZ2luIHtcbiAgLyoqXG4gICAqIFRoZSBlZGdlIHRvIG9yaWdpbiBmdW5jdGlvbiBmb3IgQVBJIEdhdGV3YXkgUmVxdWVzdCBPcmlnaW4gRWRnZSBMYW1iZGFcbiAgICpcbiAgICogVGhlIGdlbmVyYXRlZCBgY29uZmlnLnltbGAgaXMgaW5jbHVkZWQgaW4gdGhlIExhbWJkYSdzIGNvZGUuXG4gICAqL1xuICByZWFkb25seSBlZGdlVG9PcmlnaW5GdW5jdGlvbjogbGFtYmRhLkZ1bmN0aW9uIHwgY2YuZXhwZXJpbWVudGFsLkVkZ2VGdW5jdGlvbjtcblxuICAvKipcbiAgICogQ29uZmlndXJhdGlvbiBvZiB0aGUgZWRnZSB0byBvcmlnaW4gbGFtYmRhIGZ1bmN0aW9uc1xuICAgKi9cbiAgcmVhZG9ubHkgZWRnZVRvT3JpZ2luTGFtYmRhczogY2YuRWRnZUxhbWJkYVtdO1xuXG4gIC8qKlxuICAgKiBUaGUgSUFNIFJvbGUgZm9yIHRoZSBlZGdlIHRvIG9yaWdpbiBmdW5jdGlvblxuICAgKi9cbiAgcmVhZG9ubHkgZWRnZVRvT3JpZ2luUm9sZTogaWFtLlJvbGU7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyB0byBpbml0aWFsaXplIGFuIGluc3RhbmNlIG9mIGBNaWNyb0FwcHNFZGdlVG9PcmlnaW5gLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1pY3JvQXBwc0VkZ2VUb09yaWdpblByb3BzIHtcbiAgLyoqXG4gICAqIFJlbW92YWxQb2xpY3kgb3ZlcnJpZGUgZm9yIGNoaWxkIHJlc291cmNlc1xuICAgKlxuICAgKiBAZGVmYXVsdCAtIHBlciByZXNvdXJjZSBkZWZhdWx0XG4gICAqL1xuICByZWFkb25seSByZW1vdmFsUG9saWN5PzogUmVtb3ZhbFBvbGljeTtcblxuICAvKipcbiAgICogT3B0aW9uYWwgYXNzZXQgbmFtZSByb290XG4gICAqXG4gICAqIEBleGFtcGxlIG1pY3JvYXBwc1xuICAgKiBAZGVmYXVsdCAtIHJlc291cmNlIG5hbWVzIGF1dG8gYXNzaWduZWRcbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0TmFtZVJvb3Q/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE9wdGlvbmFsIGFzc2V0IG5hbWUgc3VmZml4XG4gICAqXG4gICAqIEBleGFtcGxlIC1kZXYtcHItMTJcbiAgICogQGRlZmF1bHQgbm9uZVxuICAgKi9cbiAgcmVhZG9ubHkgYXNzZXROYW1lU3VmZml4Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBQYXRoIHByZWZpeCBvbiB0aGUgcm9vdCBvZiB0aGUgQVBJIEdhdGV3YXkgU3RhZ2VcbiAgICpcbiAgICogQGV4YW1wbGUgZGV2L1xuICAgKiBAZGVmYXVsdCBub25lXG4gICAqL1xuICByZWFkb25seSByb290UGF0aFByZWZpeD86IHN0cmluZztcblxuICAvKipcbiAgICogTGlzdCBvZiBhbGxvd2VkIGxvY2FsZSBwcmVmaXhlcyBmb3IgcGFnZXNcbiAgICpcbiAgICogQGV4YW1wbGU6IFsnZW4nLCAnZnInLCAnZXMnXVxuICAgKiBAZGVmYXVsdCBub25lXG4gICAqL1xuICByZWFkb25seSBhbGxvd2VkTG9jYWxlUHJlZml4ZXM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQWRkcyBhbiBYLUZvcndhcmRlZC1Ib3N0LUhlYWRlciB3aGVuIGNhbGxpbmcgQVBJIEdhdGV3YXlcbiAgICpcbiAgICogQ2FuIG9ubHkgYmUgdHJ1c3RlZCBpZiBgc2lnbmluZ01vZGVgIGlzIGVuYWJsZWQsIHdoaWNoIHJlc3RyaWN0c1xuICAgKiBhY2Nlc3MgdG8gQVBJIEdhdGV3YXkgdG8gb25seSBJQU0gc2lnbmVkIHJlcXVlc3RzLlxuICAgKlxuICAgKiBOb3RlOiBpZiB0cnVlLCBjcmVhdGVzIE9yaWdpblJlcXVlc3QgTGFtYmRhIEAgRWRnZSBmdW5jdGlvbiBmb3IgQVBJIEdhdGV3YXkgT3JpZ2luXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IGFkZFhGb3J3YXJkZWRIb3N0SGVhZGVyPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmVwbGFjZXMgSG9zdCBoZWFkZXIgKHdoaWNoIHdpbGwgYmUgdGhlIEVkZ2UgZG9tYWluIG5hbWUpIHdpdGggdGhlIE9yaWdpbiBkb21haW4gbmFtZVxuICAgKiB3aGVuIGVuYWJsZWQuICBUaGlzIGlzIG5lY2Vzc2FyeSB3aGVuIEFQSSBHYXRld2F5IGhhcyBub3QgYmVlbiBjb25maWd1cmVkXG4gICAqIHdpdGggYSBjdXN0b20gZG9tYWluIG5hbWUgdGhhdCBtYXRjaGVzIHRoZSBleGFjdCBkb21haW4gbmFtZSB1c2VkIGJ5IHRoZSBDbG91ZEZyb250XG4gICAqIERpc3RyaWJ1dGlvbiBBTkQgd2hlbiB0aGUgT3JpZ2luUmVxdWVzdFBvbGljeS5IZWFkZXJzQmVoYXZpb3IgaXMgc2V0XG4gICAqIHRvIHBhc3MgYWxsIGhlYWRlcnMgdG8gdGhlIG9yaWdpbi5cbiAgICpcbiAgICogTm90ZTogaWYgdHJ1ZSwgY3JlYXRlcyBPcmlnaW5SZXF1ZXN0IExhbWJkYSBAIEVkZ2UgZnVuY3Rpb24gZm9yIEFQSSBHYXRld2F5IE9yaWdpblxuICAgKiBAZGVmYXVsdCB0cnVlXG4gICAqL1xuICByZWFkb25seSByZXBsYWNlSG9zdEhlYWRlcj86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFJlcXVpcmVzIElBTSBhdXRoIG9uIHRoZSBBUEkgR2F0ZXdheSBvcmlnaW4gaWYgbm90IHNldCB0byAnbm9uZScuXG4gICAqXG4gICAqICdzaWduJyAtIFVzZXMgcmVxdWVzdCBoZWFkZXJzIGZvciBhdXRoLlxuICAgKiAncHJlc2lnbicgLSBVc2VzIHF1ZXJ5IHN0cmluZyBmb3IgYXV0aC5cbiAgICpcbiAgICogSWYgZW5hYmxlZCxcbiAgICpcbiAgICogTm90ZTogaWYgJ3NpZ24nIG9yICdwcmVzaWduJywgY3JlYXRlcyBPcmlnaW5SZXF1ZXN0IExhbWJkYSBAIEVkZ2UgZnVuY3Rpb24gZm9yIEFQSSBHYXRld2F5IE9yaWdpblxuICAgKiBAZGVmYXVsdCAnc2lnbidcbiAgICovXG4gIHJlYWRvbmx5IHNpZ25pbmdNb2RlPzogJ3NpZ24nIHwgJ3ByZXNpZ24nIHwgJ25vbmUnO1xuXG4gIC8qKlxuICAgKiBPcmlnaW4gcmVnaW9uIHRoYXQgQVBJIEdhdGV3YXkgd2lsbCBiZSBkZXBsb3llZCB0bywgdXNlZFxuICAgKiBmb3IgdGhlIGNvbmZpZy55bWwgb24gdGhlIEVkZ2UgZnVuY3Rpb24gdG8gc2lnbiByZXF1ZXN0cyBmb3JcbiAgICogdGhlIGNvcnJlY3QgcmVnaW9uXG4gICAqXG4gICAqIE5vdGUgdGhhdCBMYW1iZGEgRnVuY3Rpb25VUkxzIGdldCB0aGUgcmVnaW9uIGZyb20gdGhlIExhbWJkYSBBUk5cbiAgICogYW5kIGRvIG5vdCBuZWVkIHRoaXMgdG8gYmUgY29uZmlndXJlZC5cbiAgICpcbiAgICogQGRlZmF1bHQgdW5kZWZpbmVkXG4gICAqL1xuICByZWFkb25seSBvcmlnaW5SZWdpb24/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIER5bmFtb0RCIFRhYmxlIE5hbWUgZm9yIGFwcHMvdmVyc2lvbnMvcnVsZXMuXG4gICAqXG4gICAqIE11c3QgYmUgYSBmdWxsIEFSTiBhcyB0aGlzIGNhbiBiZSBjcm9zcyByZWdpb24uXG4gICAqXG4gICAqIEltcGxpZXMgdGhhdCAybmQgZ2VuZXJhdGlvbiByb3V0aW5nIGlzIGVuYWJsZWQuXG4gICAqL1xuICByZWFkb25seSB0YWJsZVJ1bGVzQXJuPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBFbmFibGUgaW52b2tpbmcgQVBJIEdhdGV3YXkgZnJvbSB0aGUgRWRnZSBMYW1iZGFcbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogQWNjb3VudCBJRHMgYWxsb3dlZCBmb3IgY3Jvc3MtYWNjb3VudCBGdW5jdGlvbiBVUkwgaW52b2NhdGlvbnNcbiAgICpcbiAgICogQGRlZmF1bHQgW11cbiAgICovXG4gIHJlYWRvbmx5IGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzPzogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR2VuZXJhdGVFZGdlVG9PcmlnaW5Db25maWdPcHRpb25zIHtcbiAgcmVhZG9ubHkgb3JpZ2luUmVnaW9uOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHNpZ25pbmdNb2RlOiAnc2lnbicgfCAncHJlc2lnbicgfCAnJztcbiAgcmVhZG9ubHkgYWRkWEZvcndhcmRlZEhvc3RIZWFkZXI6IGJvb2xlYW47XG4gIHJlYWRvbmx5IHJlcGxhY2VIb3N0SGVhZGVyOiBib29sZWFuO1xuICByZWFkb25seSB0YWJsZU5hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJvb3RQYXRoUHJlZml4Pzogc3RyaW5nO1xuICByZWFkb25seSBsb2NhbGVzPzogc3RyaW5nW107XG59XG5cbmludGVyZmFjZSBJTWljcm9BcHBzRWRnZVRvT3JpZ2luUm9sZVN0YWNrUHJvcHMgZXh0ZW5kcyBTdGFja1Byb3BzIHtcbiAgYXNzZXROYW1lUm9vdD86IHN0cmluZztcbiAgYXNzZXROYW1lU3VmZml4Pzogc3RyaW5nO1xuICBzZXR1cEFwaUdhdGV3YXlQZXJtaXNzaW9ucz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIEFjY291bnQgSURzIGFsbG93ZWQgZm9yIGNyb3NzLWFjY291bnQgRnVuY3Rpb24gVVJMIGludm9jYXRpb25zXG4gICAqXG4gICAqIEBkZWZhdWx0IFtdXG4gICAqL1xuICByZWFkb25seSBhbGxvd2VkRnVuY3Rpb25VcmxBY2NvdW50cz86IHN0cmluZ1tdO1xufVxuXG5jbGFzcyBNaWNyb0FwcHNFZGdlVG9PcmlnaW5Sb2xlU3RhY2sgZXh0ZW5kcyBTdGFjayB7XG4gIHByaXZhdGUgX3JvbGU6IGlhbS5Sb2xlO1xuICBwdWJsaWMgZ2V0IHJvbGUoKTogaWFtLlJvbGUge1xuICAgIHJldHVybiB0aGlzLl9yb2xlO1xuICB9XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IElNaWNyb0FwcHNFZGdlVG9PcmlnaW5Sb2xlU3RhY2tQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCwgcHJvcHMpO1xuXG4gICAgY29uc3Qge1xuICAgICAgYXNzZXROYW1lUm9vdCxcbiAgICAgIGFzc2V0TmFtZVN1ZmZpeCxcbiAgICAgIHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zLFxuICAgICAgYWxsb3dlZEZ1bmN0aW9uVXJsQWNjb3VudHMsXG4gICAgfSA9IHByb3BzO1xuXG4gICAgLy8gQ3JlYXRlIElBTSBSb2xlIGZvciB0aGUgRWRnZSBGdW5jdGlvblxuICAgIHRoaXMuX3JvbGUgPSBuZXcgaWFtLlJvbGUodGhpcywgJ2VkZ2Utcm9sZScsIHtcbiAgICAgIGFzc3VtZWRCeTogbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpLFxuICAgICAgcm9sZU5hbWU6IGFzc2V0TmFtZVJvb3RcbiAgICAgICAgPyBgJHthc3NldE5hbWVSb290fS1lZGdlLXJvbGUke2Fzc2V0TmFtZVN1ZmZpeH1gXG4gICAgICAgIDogUGh5c2ljYWxOYW1lLkdFTkVSQVRFX0lGX05FRURFRCxcbiAgICAgIG1hbmFnZWRQb2xpY2llczogW1xuICAgICAgICBpYW0uTWFuYWdlZFBvbGljeS5mcm9tQXdzTWFuYWdlZFBvbGljeU5hbWUoJ3NlcnZpY2Utcm9sZS9BV1NMYW1iZGFCYXNpY0V4ZWN1dGlvblJvbGUnKSxcbiAgICAgIF0sXG4gICAgICBpbmxpbmVQb2xpY2llczoge1xuICAgICAgICBlZGdlVG9PcmlnaW5Qb2xpY3k6IG5ldyBpYW0uUG9saWN5RG9jdW1lbnQoe1xuICAgICAgICAgIHN0YXRlbWVudHM6IFtcbiAgICAgICAgICAgIC8vIFRoaXMgY2FuJ3QgaGF2ZSBhIHJlZmVyZW5jZSB0byB0aGUgaHR0cEFwaSBiZWNhdXNlIGl0IHdvdWxkIG1lYW5cbiAgICAgICAgICAgIC8vIHRoZSBwYXJlbnQgc3RhY2sgKHRoaXMgc3RhY2spIGhhcyB0byBiZSBjcmVhdGVkIGJlZm9yZSB0aGUgdXMtZWFzdC0xXG4gICAgICAgICAgICAvLyBjaGlsZCBzdGFjayBmb3IgdGhlIEVkZ2UgTGFtYmRhIEZ1bmN0aW9uLlxuICAgICAgICAgICAgLy8gVGhhdCdzIHdoeSB3ZSB1c2UgYSB0YWctYmFzZWQgcG9saWN5IHRvIGFsbG93IHRoZSBFZGdlIEZ1bmN0aW9uXG4gICAgICAgICAgICAvLyB0byBpbnZva2UgYW55IEFQSSBHYXRld2F5IEFQSSB0aGF0IHdlIGFwcGx5IGEgdGFnIHRvXG4gICAgICAgICAgICAvLyBXZSBhbGxvdyB0aGUgZWRnZSBmdW5jdGlvbiB0byBzaWduIGZvciBhbGwgcmVnaW9ucyBzaW5jZVxuICAgICAgICAgICAgLy8gd2UgbWF5IHVzZSBjdXN0b20gY2xvc2VzdCByZWdpb24gaW4gdGhlIGZ1dHVyZS5cbiAgICAgICAgICAgIC4uLihzZXR1cEFwaUdhdGV3YXlQZXJtaXNzaW9uc1xuICAgICAgICAgICAgICA/IFtcbiAgICAgICAgICAgICAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgICAgICAgICAgICAgYWN0aW9uczogWydleGVjdXRlLWFwaTpJbnZva2UnXSxcbiAgICAgICAgICAgICAgICAgICAgcmVzb3VyY2VzOiBbYGFybjphd3M6ZXhlY3V0ZS1hcGk6Kjoke0F3cy5BQ0NPVU5UX0lEfToqLyovKi8qYF0sXG4gICAgICAgICAgICAgICAgICAgIC8vIFVuZm9ydHVuYXRlbHksIEFQSSBHYXRld2F5IGFjY2VzcyBjYW5ub3QgYmUgcmVzdHJpY3RlZCB1c2luZ1xuICAgICAgICAgICAgICAgICAgICAvLyB0YWdzIG9uIHRoZSB0YXJnZXQgcmVzb3VyY2VcbiAgICAgICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL2FjY2Vzc190YWdzLmh0bWxcbiAgICAgICAgICAgICAgICAgICAgLy8gaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0lBTS9sYXRlc3QvVXNlckd1aWRlL3JlZmVyZW5jZV9hd3Mtc2VydmljZXMtdGhhdC13b3JrLXdpdGgtaWFtLmh0bWwjbmV0d29ya2luZ19zdmNzXG4gICAgICAgICAgICAgICAgICAgIC8vIGNvbmRpdGlvbnM6IHtcbiAgICAgICAgICAgICAgICAgICAgLy8gICAvLyBUT0RPOiBTZXQgdGhpcyB0byBhIHN0cmluZyB1bmlxdWUgdG8gZWFjaCBzdGFja1xuICAgICAgICAgICAgICAgICAgICAvLyAgIFN0cmluZ0VxdWFsczogeyAnYXdzOlJlc291cmNlVGFnL21pY3JvYXBwLW1hbmFnZWQnOiAndHJ1ZScgfSxcbiAgICAgICAgICAgICAgICAgICAgLy8gfSxcbiAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgOiBbXSksXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gR3JhbnQgcGVybWlzc2lvbiB0byBpbnZva2UgdGFnZ2VkIEZ1bmN0aW9uIFVSTHMgKGluIHNhbWUgYWNjb3VudClcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgIGFjdGlvbnM6IFsnbGFtYmRhOkludm9rZUZ1bmN0aW9uVXJsJ10sXG4gICAgICAgICAgICAgIHJlc291cmNlczogW2Bhcm46YXdzOmxhbWJkYToqOiR7QXdzLkFDQ09VTlRfSUR9OipgXSxcbiAgICAgICAgICAgICAgY29uZGl0aW9uczoge1xuICAgICAgICAgICAgICAgIFN0cmluZ0VxdWFsczogeyAnYXdzOlJlc291cmNlVGFnL21pY3JvYXBwLW1hbmFnZWQnOiAndHJ1ZScgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIEdyYW50IHBlcm1pc3Npb24gdG8gaW52b2tlIEZ1bmN0aW9uIFVSTHMgaW4gbGlzdGVkIGFjY291bnRzXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLi4uKGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzICYmIGFsbG93ZWRGdW5jdGlvblVybEFjY291bnRzLmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgPyBbXG4gICAgICAgICAgICAgICAgICBuZXcgaWFtLlBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbnM6IFsnbGFtYmRhOkludm9rZUZ1bmN0aW9uVXJsJ10sXG4gICAgICAgICAgICAgICAgICAgIHJlc291cmNlczogYWxsb3dlZEZ1bmN0aW9uVXJsQWNjb3VudHMubWFwKFxuICAgICAgICAgICAgICAgICAgICAgIChhY2NvdW50SWQpID0+IGBhcm46YXdzOmxhbWJkYToqOiR7YWNjb3VudElkfToqYCxcbiAgICAgICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICAgIH0pLFxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgICAgOiBbXSksXG4gICAgICAgICAgXSxcbiAgICAgICAgfSksXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHRoaXMuX3JvbGUuYXNzdW1lUm9sZVBvbGljeT8uYWRkU3RhdGVtZW50cyhcbiAgICAgIG5ldyBpYW0uUG9saWN5U3RhdGVtZW50KHtcbiAgICAgICAgcHJpbmNpcGFsczogW1xuICAgICAgICAgIG5ldyBpYW0uU2VydmljZVByaW5jaXBhbCgnZWRnZWxhbWJkYS5hbWF6b25hd3MuY29tJyksXG4gICAgICAgICAgbmV3IGlhbS5TZXJ2aWNlUHJpbmNpcGFsKCdsYW1iZGEuYW1hem9uYXdzLmNvbScpLFxuICAgICAgICBdLFxuICAgICAgICBhY3Rpb25zOiBbJ3N0czpBc3N1bWVSb2xlJ10sXG4gICAgICAgIGVmZmVjdDogaWFtLkVmZmVjdC5BTExPVyxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBuZXcgQ2ZuT3V0cHV0KHRoaXMsICdlZGdlLXRvLW9yaWdpbi1yb2xlLWFybicsIHtcbiAgICAgIHZhbHVlOiBgJHt0aGlzLnJvbGUucm9sZUFybn1gLFxuICAgICAgZXhwb3J0TmFtZTogYCR7dGhpcy5zdGFja05hbWV9LXJvbGUtYXJuYCxcbiAgICB9KTtcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZSBhIG5ldyBNaWNyb0FwcHMgRWRnZSB0byBPcmlnaW4gRnVuY3Rpb24gdy8gYGNvbmZpZy55bWxgXG4gKi9cbmV4cG9ydCBjbGFzcyBNaWNyb0FwcHNFZGdlVG9PcmlnaW4gZXh0ZW5kcyBDb25zdHJ1Y3QgaW1wbGVtZW50cyBJTWljcm9BcHBzRWRnZVRvT3JpZ2luIHtcbiAgLyoqXG4gICAqIEdlbmVyYXRlIHRoZSB5YW1sIGNvbmZpZyBmb3IgdGhlIGVkZ2UgbGFtYmRhXG4gICAqIEBwYXJhbSBwcm9wc1xuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgcHVibGljIHN0YXRpYyBnZW5lcmF0ZUVkZ2VUb09yaWdpbkNvbmZpZyhwcm9wczogR2VuZXJhdGVFZGdlVG9PcmlnaW5Db25maWdPcHRpb25zKSB7XG4gICAgcmV0dXJuIGBvcmlnaW5SZWdpb246ICR7cHJvcHMub3JpZ2luUmVnaW9ufVxuJHtwcm9wcy5zaWduaW5nTW9kZSA9PT0gJycgPyAnJyA6IGBzaWduaW5nTW9kZTogJHtwcm9wcy5zaWduaW5nTW9kZX1gfVxuYWRkWEZvcndhcmRlZEhvc3RIZWFkZXI6ICR7cHJvcHMuYWRkWEZvcndhcmRlZEhvc3RIZWFkZXJ9XG5yZXBsYWNlSG9zdEhlYWRlcjogJHtwcm9wcy5yZXBsYWNlSG9zdEhlYWRlcn1cbiR7cHJvcHMudGFibGVOYW1lID8gYHRhYmxlTmFtZTogJyR7cHJvcHMudGFibGVOYW1lfSdgIDogJyd9XG4ke3Byb3BzLnJvb3RQYXRoUHJlZml4ID8gYHJvb3RQYXRoUHJlZml4OiAnJHtwcm9wcy5yb290UGF0aFByZWZpeH0nYCA6ICcnfVxuJHtcbiAgcHJvcHMubG9jYWxlcyAmJiBwcm9wcy5sb2NhbGVzLmxlbmd0aCA+IDBcbiAgICA/IGBsb2NhbGVzOiBbJHtwcm9wcy5sb2NhbGVzLm1hcCgobG9jYWxlKSA9PiBgJyR7bG9jYWxlfSdgKS5qb2luKCcsICcpfV1gXG4gICAgOiAnJ1xufWA7XG4gIH1cblxuICBwcml2YXRlIF9lZGdlVG9PcmlnaW5GdW5jdGlvbjogbGFtYmRhLkZ1bmN0aW9uIHwgY2YuZXhwZXJpbWVudGFsLkVkZ2VGdW5jdGlvbjtcbiAgcHVibGljIGdldCBlZGdlVG9PcmlnaW5GdW5jdGlvbigpOiBsYW1iZGEuRnVuY3Rpb24gfCBjZi5leHBlcmltZW50YWwuRWRnZUZ1bmN0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb247XG4gIH1cblxuICBwcml2YXRlIF9lZGdlVG9PcmlnaW5MYW1iZGFzOiBjZi5FZGdlTGFtYmRhW107XG4gIHB1YmxpYyBnZXQgZWRnZVRvT3JpZ2luTGFtYmRhcygpOiBjZi5FZGdlTGFtYmRhW10ge1xuICAgIHJldHVybiB0aGlzLl9lZGdlVG9PcmlnaW5MYW1iZGFzO1xuICB9XG5cbiAgcHJpdmF0ZSBfZWRnZVRvT3JpZ2luUm9sZTogaWFtLlJvbGU7XG4gIHB1YmxpYyBnZXQgZWRnZVRvT3JpZ2luUm9sZSgpOiBpYW0uUm9sZSB7XG4gICAgcmV0dXJuIHRoaXMuX2VkZ2VUb09yaWdpblJvbGU7XG4gIH1cblxuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nLCBwcm9wczogTWljcm9BcHBzRWRnZVRvT3JpZ2luUHJvcHMpIHtcbiAgICBzdXBlcihzY29wZSwgaWQpO1xuXG4gICAgaWYgKHByb3BzID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigncHJvcHMgbXVzdCBiZSBzZXQnKTtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICBhZGRYRm9yd2FyZGVkSG9zdEhlYWRlciA9IHRydWUsXG4gICAgICBhbGxvd2VkRnVuY3Rpb25VcmxBY2NvdW50cyA9IFtdLFxuICAgICAgYXNzZXROYW1lUm9vdCxcbiAgICAgIGFzc2V0TmFtZVN1ZmZpeCxcbiAgICAgIG9yaWdpblJlZ2lvbixcbiAgICAgIHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zID0gZmFsc2UsXG4gICAgICBzaWduaW5nTW9kZSA9ICdzaWduJyxcbiAgICAgIHJlbW92YWxQb2xpY3ksXG4gICAgICByb290UGF0aFByZWZpeCxcbiAgICAgIHJlcGxhY2VIb3N0SGVhZGVyID0gdHJ1ZSxcbiAgICAgIHRhYmxlUnVsZXNBcm4sXG4gICAgfSA9IHByb3BzO1xuXG4gICAgLy8gQ3JlYXRlIHRoZSBlZGdlIGZ1bmN0aW9uIGNvbmZpZyBmaWxlIGZyb20gdGhlIGNvbnN0cnVjdCBvcHRpb25zXG4gICAgY29uc3QgZWRnZVRvT3JpZ2luQ29uZmlnWWFtbCA9IE1pY3JvQXBwc0VkZ2VUb09yaWdpbi5nZW5lcmF0ZUVkZ2VUb09yaWdpbkNvbmZpZyh7XG4gICAgICBvcmlnaW5SZWdpb246IG9yaWdpblJlZ2lvbiB8fCBBd3MuUkVHSU9OLFxuICAgICAgYWRkWEZvcndhcmRlZEhvc3RIZWFkZXIsXG4gICAgICByZXBsYWNlSG9zdEhlYWRlcixcbiAgICAgIHNpZ25pbmdNb2RlOiBzaWduaW5nTW9kZSA9PT0gJ25vbmUnID8gJycgOiBzaWduaW5nTW9kZSxcbiAgICAgIHJvb3RQYXRoUHJlZml4LFxuICAgICAgbG9jYWxlczogcHJvcHMuYWxsb3dlZExvY2FsZVByZWZpeGVzLFxuICAgICAgLi4uKHRhYmxlUnVsZXNBcm5cbiAgICAgICAgPyB7XG4gICAgICAgICAgICB0YWJsZU5hbWU6IHRhYmxlUnVsZXNBcm4sXG4gICAgICAgICAgfVxuICAgICAgICA6IHt9KSxcbiAgICB9KTtcblxuICAgIGNvbnN0IHJvbGVTdGFjayA9IG5ldyBNaWNyb0FwcHNFZGdlVG9PcmlnaW5Sb2xlU3RhY2sodGhpcywgJ3JvbGUtc3RhY2snLCB7XG4gICAgICBzdGFja05hbWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0tZWRnZS1yb2xlYCxcbiAgICAgIGFzc2V0TmFtZVJvb3QsXG4gICAgICBhc3NldE5hbWVTdWZmaXgsXG4gICAgICBhbGxvd2VkRnVuY3Rpb25VcmxBY2NvdW50cyxcbiAgICAgIHNldHVwQXBpR2F0ZXdheVBlcm1pc3Npb25zLFxuICAgICAgZW52OiB7XG4gICAgICAgIHJlZ2lvbjogU3RhY2sub2YodGhpcykucmVnaW9uLFxuICAgICAgICBhY2NvdW50OiBTdGFjay5vZih0aGlzKS5hY2NvdW50LFxuICAgICAgfSxcbiAgICB9KTtcbiAgICBTdGFjay5vZih0aGlzKS5hZGREZXBlbmRlbmN5KHJvbGVTdGFjayk7XG4gICAgdGhpcy5fZWRnZVRvT3JpZ2luUm9sZSA9IHJvbGVTdGFjay5yb2xlO1xuXG4gICAgbmV3IENmbk91dHB1dCh0aGlzLCAncm9sZS1zdGFjay1uYW1lJywge1xuICAgICAgdmFsdWU6IGAke3JvbGVTdGFjay5zdGFja05hbWV9YCxcbiAgICAgIGV4cG9ydE5hbWU6IGAke1N0YWNrLm9mKHRoaXMpLnN0YWNrTmFtZX0tcm9sZS1zdGFja2AsXG4gICAgfSk7XG5cbiAgICAvL1xuICAgIC8vIENyZWF0ZSB0aGUgRWRnZSB0byBPcmlnaW4gRnVuY3Rpb25cbiAgICAvL1xuICAgIGNvbnN0IGVkZ2VUb09yaWdpbkZ1bmNQcm9wczogT21pdDxsYW1iZGEuRnVuY3Rpb25Qcm9wcywgJ2hhbmRsZXInIHwgJ2NvZGUnPiA9IHtcbiAgICAgIGZ1bmN0aW9uTmFtZTogYXNzZXROYW1lUm9vdCA/IGAke2Fzc2V0TmFtZVJvb3R9LWVkZ2UtdG8tb3JpZ2luJHthc3NldE5hbWVTdWZmaXh9YCA6IHVuZGVmaW5lZCxcbiAgICAgIHJvbGU6IHRoaXMuX2VkZ2VUb09yaWdpblJvbGUsXG4gICAgICBtZW1vcnlTaXplOiAxNzY5LFxuICAgICAgbG9nUmV0ZW50aW9uOiBsb2dzLlJldGVudGlvbkRheXMuT05FX01PTlRILFxuICAgICAgcnVudGltZTogbGFtYmRhLlJ1bnRpbWUuTk9ERUpTXzIyX1gsXG4gICAgICB0aW1lb3V0OiBEdXJhdGlvbi5zZWNvbmRzKDUpLFxuICAgICAgLi4uKHJlbW92YWxQb2xpY3kgPyB7IHJlbW92YWxQb2xpY3kgfSA6IHt9KSxcbiAgICB9O1xuICAgIGNvbnN0IHJvb3REaXN0UGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICcuLicsICcuLicsICdtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4nLCAnZGlzdCcpO1xuICAgIGNvbnN0IHJvb3REaXN0RXhpc3RzID0gZXhpc3RzU3luYyhwYXRoLmpvaW4ocm9vdERpc3RQYXRoLCAnaW5kZXguanMnKSk7XG4gICAgY29uc3QgbG9jYWxEaXN0UGF0aCA9IHBhdGguam9pbihfX2Rpcm5hbWUsICdtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4nKTtcbiAgICBjb25zdCBsb2NhbERpc3RFeGlzdHMgPSBleGlzdHNTeW5jKHBhdGguam9pbihsb2NhbERpc3RQYXRoLCAnaW5kZXguanMnKSk7XG4gICAgaWYgKHByb2Nlc3MuZW52Lk5PREVfRU5WID09PSAndGVzdCcgJiYgcm9vdERpc3RFeGlzdHMpIHtcbiAgICAgIC8vIFRoaXMgaXMgZm9yIHRlc3RzIHJ1biB1bmRlciBqZXN0IC0gUHJlZmVyIHJvb3QgZGlzdCBidW5kbGVcbiAgICAgIC8vIFRoaXMgaXMgYWxzbyBmb3IgYW55dGltZSB3aGVuIHRoZSBlZGdlIGZ1bmN0aW9uIGhhcyBhbHJlYWR5IGJlZW4gYnVuZGxlZFxuICAgICAgdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gPSB0aGlzLmNyZWF0ZUVkZ2VGdW5jdGlvbihcbiAgICAgICAgcm9vdERpc3RQYXRoLFxuICAgICAgICBlZGdlVG9PcmlnaW5Db25maWdZYW1sLFxuICAgICAgICBlZGdlVG9PcmlnaW5GdW5jUHJvcHMsXG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAobG9jYWxEaXN0RXhpc3RzKSB7XG4gICAgICAvLyBQcmVmZXIgbG9jYWwgZGlzdCBhYm92ZSByb290IGRpc3QgaWYgYm90aCBleGlzdCAod2hlbiBidWlsZGluZyBmb3IgZGlzdHJpYnV0aW9uKVxuICAgICAgdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gPSB0aGlzLmNyZWF0ZUVkZ2VGdW5jdGlvbihcbiAgICAgICAgbG9jYWxEaXN0UGF0aCxcbiAgICAgICAgZWRnZVRvT3JpZ2luQ29uZmlnWWFtbCxcbiAgICAgICAgZWRnZVRvT3JpZ2luRnVuY1Byb3BzLFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKHJvb3REaXN0RXhpc3RzKSB7XG4gICAgICAvLyBVc2UgbG9jYWwgZGlzdCBpZiBpdCBleGlzdHMgKHdoZW4gZGVwbG95aW5nIGZyb20gQ0RLIGluIHRoaXMgcmVwbylcbiAgICAgIHRoaXMuX2VkZ2VUb09yaWdpbkZ1bmN0aW9uID0gdGhpcy5jcmVhdGVFZGdlRnVuY3Rpb24oXG4gICAgICAgIHJvb3REaXN0UGF0aCxcbiAgICAgICAgZWRnZVRvT3JpZ2luQ29uZmlnWWFtbCxcbiAgICAgICAgZWRnZVRvT3JpZ2luRnVuY1Byb3BzLFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gVGhpcyBpcyB1c2VkIHdoZW4gYnVuZGxpbmcgdGhlIGFwcCBhbmQgYnVpbGRpbmcgdGhlIENESyBtb2R1bGVcbiAgICAgIC8vIGZvciBkaXN0cmlidXRpb24uXG4gICAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLWVkZ2UtdG8tb3JpZ2luJywgJ2NvbmZpZy55bWwnKSxcbiAgICAgICAgZWRnZVRvT3JpZ2luQ29uZmlnWWFtbCxcbiAgICAgICk7XG5cbiAgICAgIC8vIENvcHkgdGhlIGFwcEZyYW1lLmh0bWwgdG8gdGhlIHBsYWNlIHdoZXJlIHRoZSBidW5kbGluZyB3aWxsIGZpbmQgaXRcbiAgICAgIGNvcHlGaWxlU3luYyhcbiAgICAgICAgcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ21pY3JvYXBwcy1yb3V0ZXInLCAnYXBwRnJhbWUuaHRtbCcpLFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLWVkZ2UtdG8tb3JpZ2luJywgJ2FwcEZyYW1lLmh0bWwnKSxcbiAgICAgICk7XG5cbiAgICAgIC8vIFRoaXMgYnVpbGRzIHRoZSBmdW5jdGlvbiBmb3IgZGlzdHJpYnV0aW9uIHdpdGggdGhlIENESyBDb25zdHJ1Y3RcbiAgICAgIC8vIGFuZCB3aWxsIGJlIHVzZWQgZHVyaW5nIGxvY2FsIGJ1aWxkcyBhbmQgUFIgYnVpbGRzIG9mIG1pY3JvYXBwcy1jb3JlXG4gICAgICAvLyBpZiB0aGUgbWljcm9hcHBzLWVkZ2UtdG8tb3JpZ2luIGZ1bmN0aW9uIGlzIG5vdCBhbHJlYWR5IGJ1bmRsZWQuXG4gICAgICAvLyBUaGlzIHdpbGwgZmFpbCB0byBkZXBsb3kgaW4gYW55IHJlZ2lvbiBvdGhlciB0aGFuIHVzLWVhc3QtMVxuICAgICAgdGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gPSBuZXcgbGFtYmRhTm9kZWpzLk5vZGVqc0Z1bmN0aW9uKHRoaXMsICdlZGdlLXRvLWFwaWd3eS1mdW5jJywge1xuICAgICAgICBlbnRyeTogcGF0aC5qb2luKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ21pY3JvYXBwcy1lZGdlLXRvLW9yaWdpbicsICdzcmMnLCAnaW5kZXgudHMnKSxcbiAgICAgICAgaGFuZGxlcjogJ2hhbmRsZXInLFxuICAgICAgICBidW5kbGluZzoge1xuICAgICAgICAgIG1pbmlmeTogdHJ1ZSxcbiAgICAgICAgICBzb3VyY2VNYXA6IHRydWUsXG4gICAgICAgICAgY29tbWFuZEhvb2tzOiB7XG4gICAgICAgICAgICBiZWZvcmVJbnN0YWxsOiAoKSA9PiBbXSxcbiAgICAgICAgICAgIGJlZm9yZUJ1bmRsaW5nOiAoKSA9PiBbXSxcbiAgICAgICAgICAgIGFmdGVyQnVuZGxpbmc6IChfaW5wdXREaXI6IHN0cmluZywgb3V0cHV0RGlyOiBzdHJpbmcpID0+IHtcbiAgICAgICAgICAgICAgLy8gMjAyMi0xMC0wMiAtIE5vdGUgdGhhdCB0aGlzIGlzIGlnbm9yaW5nIHRoZSBnZW5lcmF0ZWQgY29uZmlnXG4gICAgICAgICAgICAgIC8vIGZpbGUgYWJvdmUgYW5kIGluY2x1ZGluZyB0aGUgZGVmYXVsdCB0ZW1wbGF0ZSBjb25maWcgZmlsZVxuICAgICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgIGAke29zLnBsYXRmb3JtKCkgPT09ICd3aW4zMicgPyAnY29weScgOiAnY3AnfSAke3BhdGguam9pbihcbiAgICAgICAgICAgICAgICAgIF9fZGlybmFtZSxcbiAgICAgICAgICAgICAgICAgICcuLicsXG4gICAgICAgICAgICAgICAgICAnLi4nLFxuICAgICAgICAgICAgICAgICAgJy4uJyxcbiAgICAgICAgICAgICAgICAgICdjb25maWdzJyxcbiAgICAgICAgICAgICAgICAgICdtaWNyb2FwcHMtZWRnZS10by1vcmlnaW4nLFxuICAgICAgICAgICAgICAgICAgJ2NvbmZpZy55bWwnLFxuICAgICAgICAgICAgICAgICl9ICR7b3V0cHV0RGlyfWAsXG4gICAgICAgICAgICAgICAgYCR7b3MucGxhdGZvcm0oKSA9PT0gJ3dpbjMyJyA/ICdjb3B5JyA6ICdjcCd9ICR7cGF0aC5qb2luKFxuICAgICAgICAgICAgICAgICAgX19kaXJuYW1lLFxuICAgICAgICAgICAgICAgICAgJy4uJyxcbiAgICAgICAgICAgICAgICAgICcuLicsXG4gICAgICAgICAgICAgICAgICAnbWljcm9hcHBzLXJvdXRlcicsXG4gICAgICAgICAgICAgICAgICAnYXBwRnJhbWUuaHRtbCcsXG4gICAgICAgICAgICAgICAgKX0gJHtvdXRwdXREaXJ9YCxcbiAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgICAgLi4uZWRnZVRvT3JpZ2luRnVuY1Byb3BzLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5fZWRnZVRvT3JpZ2luTGFtYmRhcyA9IFtcbiAgICAgIHtcbiAgICAgICAgZXZlbnRUeXBlOiBjZi5MYW1iZGFFZGdlRXZlbnRUeXBlLk9SSUdJTl9SRVFVRVNULFxuICAgICAgICBmdW5jdGlvblZlcnNpb246IHRoaXMuX2VkZ2VUb09yaWdpbkZ1bmN0aW9uLmN1cnJlbnRWZXJzaW9uLFxuICAgICAgICBpbmNsdWRlQm9keTogdHJ1ZSxcbiAgICAgIH0sXG4gICAgXTtcblxuICAgIC8vIEdyYW50IGFjY2VzcyB0byB0aGUgcnVsZXMgdGFibGVcbiAgICBpZiAodGFibGVSdWxlc0Fybikge1xuICAgICAgY29uc3QgdGFibGVSdWxlcyA9IGR5bmFtb2RiLlRhYmxlLmZyb21UYWJsZU5hbWUodGhpcywgJ3RhYmxlUnVsZXMnLCB0YWJsZVJ1bGVzQXJuKTtcbiAgICAgIHRhYmxlUnVsZXMuZ3JhbnRSZWFkRGF0YSh0aGlzLl9lZGdlVG9PcmlnaW5GdW5jdGlvbik7XG4gICAgfVxuXG4gICAgKHRoaXMuX2VkZ2VUb09yaWdpbkZ1bmN0aW9uIGFzIGNmLmV4cGVyaW1lbnRhbC5FZGdlRnVuY3Rpb24pLnN0YWNrLnN0YWNrTmFtZTtcblxuICAgIG5ldyBDZm5PdXRwdXQodGhpcywgJ2VkZ2Utc3RhY2stbmFtZScsIHtcbiAgICAgIHZhbHVlOiBgJHsodGhpcy5fZWRnZVRvT3JpZ2luRnVuY3Rpb24gYXMgY2YuZXhwZXJpbWVudGFsLkVkZ2VGdW5jdGlvbikuc3RhY2suc3RhY2tOYW1lfWAsXG4gICAgICBleHBvcnROYW1lOiBgJHtTdGFjay5vZih0aGlzKS5zdGFja05hbWV9LWVkZ2Utc3RhY2tgLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEhhc2ggdGhlIHN0YWNrIG5hbWUgdG8gbWFrZSB0aGUgRWRnZUZ1bmN0aW9uIHBhcmFtZXRlciBuYW1lIHVuaXF1ZVxuICAgKlxuICAgKiBAcGFyYW0gc3RhY2tcbiAgICogQHJldHVybnNcbiAgICovXG4gIHByaXZhdGUgaGFzaFN0YWNrTmFtZSgpOiBzdHJpbmcge1xuICAgIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMScpLnVwZGF0ZShTdGFjay5vZih0aGlzKS5zdGFja05hbWUpLmRpZ2VzdCgnaGV4Jykuc3Vic3RyaW5nKDAsIDgpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVFZGdlRnVuY3Rpb24oXG4gICAgZGlzdFBhdGg6IHN0cmluZyxcbiAgICBlZGdlVG9PcmlnaW5Db25maWdZYW1sOiBzdHJpbmcsXG4gICAgZWRnZVRvT3JpZ2luRnVuY1Byb3BzOiBPbWl0PGxhbWJkYS5GdW5jdGlvblByb3BzLCAnaGFuZGxlcicgfCAnY29kZSc+LFxuICApIHtcbiAgICB3cml0ZUZpbGVTeW5jKHBhdGguam9pbihkaXN0UGF0aCwgJ2NvbmZpZy55bWwnKSwgZWRnZVRvT3JpZ2luQ29uZmlnWWFtbCk7XG5cbiAgICAvLyBTa2lwIHRoZSBjb3B5IG9mIGFwcEZyYW1lLmh0bWwgb24gZGVwbG95ZWQgbW9kdWxlc1xuICAgIGlmICghX19kaXJuYW1lLmluY2x1ZGVzKCdub2RlX21vZHVsZXMnKSkge1xuICAgICAgY29weUZpbGVTeW5jKFxuICAgICAgICBwYXRoLmpvaW4oX19kaXJuYW1lLCAnLi4nLCAnLi4nLCAnbWljcm9hcHBzLXJvdXRlcicsICdhcHBGcmFtZS5odG1sJyksXG4gICAgICAgIHBhdGguam9pbihkaXN0UGF0aCwgJ2FwcEZyYW1lLmh0bWwnKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gVGhlIGV4Y2x1ZGUgdmFyeWluZyBwZXIgc3RhY2sgbmFtZSBpcyBhIGtsdWRnZSB0byBnZXQgdGhlIGFzc2V0IGJ1bmRsZWRcbiAgICAvLyB3aXRoIHRoZSBzdGFjay1zcGVjaWZjIGNvbmZpZy55bWwgZmlsZSwgb3RoZXJ3aXNlIHRoZXkgYW