UNPKG

@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
"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