UNPKG

@amazon-codecatalyst/blueprints.sam-serverless-application

Version:

This blueprint creates a project that leverages a serverless application model (SAM) to quickly create and deploy an API. You can choose Java, TypeScript, or Python as the programming language

357 lines 55.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Blueprint = void 0; const cp = __importStar(require("child_process")); const fs = __importStar(require("fs")); const path = __importStar(require("path")); const blueprint_component_dev_environments_1 = require("@amazon-codecatalyst/blueprint-component.dev-environments"); const blueprint_component_environments_1 = require("@amazon-codecatalyst/blueprint-component.environments"); const blueprint_component_source_repositories_1 = require("@amazon-codecatalyst/blueprint-component.source-repositories"); const blueprint_component_workflows_1 = require("@amazon-codecatalyst/blueprint-component.workflows"); const blueprints_blueprint_1 = require("@amazon-codecatalyst/blueprints.blueprint"); const projen_1 = require("projen"); const util_1 = require("projen/lib/util"); const defaults_json_1 = __importDefault(require("./defaults.json")); const readmeContents_1 = require("./readmeContents"); const runtimeMappings_1 = require("./runtimeMappings"); /** * This is the actual blueprint class. * 1. This MUST be the only 'class' exported, as 'Blueprint' * 2. This Blueprint should extend another ParentBlueprint */ class Blueprint extends blueprints_blueprint_1.Blueprint { constructor(options_) { super(options_); console.log(defaults_json_1.default); /** * This is a typecheck to ensure that the defaults passed in are of the correct type. * There are some cases where the typecheck will fail, but the defaults will still be valid, such when using enums. * you can override this ex. myEnum: defaults.myEnum as Options['myEnum'], */ const typeCheck = { outdir: this.outdir, ...defaults_json_1.default, runtime: defaults_json_1.default.runtime, }; const options = Object.assign(typeCheck, options_); options.code.sourceRepositoryName = sanitizePath(options.code.sourceRepositoryName); this.options = options; this.repository = new blueprint_component_source_repositories_1.SourceRepository(this, { title: this.options.code.sourceRepositoryName || 'sam-lambda', }); new blueprint_component_source_repositories_1.BlueprintOwnershipFile(this.repository, { resynthesis: { strategies: [ { identifier: 'never_update', strategy: blueprints_blueprint_1.MergeStrategies.neverUpdate, globs: ['*'], }, ], }, }); this.options.lambda = options.lambda; } synth() { var _a, _b, _c, _d, _e, _f, _g; const runtime = this.options.runtime; const runtimeOptions = runtimeMappings_1.runtimeMappings[runtime]; // create an MDE workspace this.createMDEWorkspace({ runtimeOptions }); // create an environment new blueprint_component_environments_1.Environment(this, this.options.environment); // create SAM template and installation scripts this.createSamTemplate({ runtime: runtimeOptions.runtime, codeUri: runtimeOptions.codeUri, handler: runtimeOptions.handler, templateProps: runtimeOptions.templateProps, templateMetadata: runtimeOptions.templateMetadata, }); // create additional files required for this runtime const context = { repositoryRelativePath: this.repository.relativePath, lambdaFunctionName: (_b = (_a = this.options.lambda) === null || _a === void 0 ? void 0 : _a.functionName) !== null && _b !== void 0 ? _b : '.', }; for (const fileTemplate of runtimeOptions.filesToCreate) { new projen_1.SampleFile(this, fileTemplate.resolvePath(context), { contents: fileTemplate.resolveContent(context) }); } // create the build and release workflow const workflowName = 'build-and-release'; this.createWorkflow({ name: 'build-and-release', outputArtifactName: 'build_result', stepsToRunUnitTests: runtimeOptions.stepsToRunUnitTests, autoDiscoveryOverride: runtimeOptions.autoDiscoveryOverride, runtimeOptions, }); // create the cleanup workflow const cleanupWorkflow = new blueprint_component_workflows_1.WorkflowBuilder(this, blueprint_component_workflows_1.emptyWorkflow); cleanupWorkflow.setName(blueprint_component_workflows_1.DEFAULT_DELETE_RESOURCE_WORKFLOW_NAME); cleanupWorkflow.addCfnCleanupAction({ actionName: `delete_${this.options.code.cloudFormationStackName}`, environment: { Name: this.options.environment.name || '<<PUT_YOUR_ENVIRONMENT_NAME_HERE>>', Connections: [ { Name: ((_c = this.options.environment.awsAccountConnection) === null || _c === void 0 ? void 0 : _c.name) || ' ', Role: ((_e = (_d = this.options.environment.awsAccountConnection) === null || _d === void 0 ? void 0 : _d.buildRole) === null || _e === void 0 ? void 0 : _e.name) || ' ', }, ], }, stackName: this.options.code.cloudFormationStackName, region: 'us-west-2', templateBucketName: this.options.cleanupWorkflowTemplateBucketName, }); const additionalComments = [ 'The following workflow is intentionally disabled by the blueprint author to prevent project contributors from accidentally executing it.', 'This workflow will attempt to delete all the deployed resources from the blueprint.', 'The deletion action cannot be undone, please proceed at your own risk.', 'To utilize it, please uncomment all the succeeding lines.', ]; new blueprint_component_workflows_1.Workflow(this, this.repository, cleanupWorkflow.definition, { additionalComments: this.options.uncommentCleanupWorkflow ? undefined : additionalComments, commented: !this.options.uncommentCleanupWorkflow, }); // generate the readme new blueprint_component_source_repositories_1.SourceFile(this.repository, 'README.md', (0, readmeContents_1.generateReadmeContents)({ runtime, runtimeMapping: runtimeOptions, defaultReleaseBranch: 'main', lambdas: [this.options.lambda], environment: this.options.environment, cloudFormationStackName: this.options.code.cloudFormationStackName, workflowName: workflowName, sourceRepositoryName: this.repository.title, })); const toDeletePath = this.populateLambdaSourceCode({ runtime: runtimeOptions.runtime, cacheDir: runtimeOptions.cacheDir, gitSrcPath: runtimeOptions.gitSrcPath, filesToOverride: runtimeOptions.filesToOverride, }); super.synth(); cp.execSync(`rm -rf ${toDeletePath}`); // update permissions const permissionChangeContext = { repositoryRelativePath: path.join(this.outdir, this.repository.relativePath), lambdaFunctionName: (_g = (_f = this.options.lambda) === null || _f === void 0 ? void 0 : _f.functionName) !== null && _g !== void 0 ? _g : '.', }; for (const filePermissionChange of runtimeOptions.filesToChangePermissionsFor) { fs.chmodSync(filePermissionChange.resolvePath(permissionChangeContext), (0, util_1.getFilePermissions)(filePermissionChange.newPermissions)); } } createWorkflow(params) { var _a, _b, _c, _d, _e, _f; const { name } = params; const stripSpaces = (str) => (str || '').replace(/\s/g, ''); const defaultBranch = 'main'; const region = 'us-west-2'; const schemaVersion = '1.0'; const workflowDefinition = { ...(0, blueprint_component_workflows_1.makeEmptyWorkflow)(), SchemaVersion: schemaVersion, Name: name, }; (0, blueprint_component_workflows_1.addGenericBranchTrigger)(workflowDefinition, [defaultBranch]); (0, blueprint_component_workflows_1.addGenericCompute)(workflowDefinition, params.runtimeOptions.computeOptions.Type, params.runtimeOptions.computeOptions.Fleet); const buildActionName = `build_for_${stripSpaces(this.options.environment.name)}`; const samBuildImageOptions = params.runtimeOptions.samBuildImage ? `sam build --template-file template.yaml --use-container --build-image ${params.runtimeOptions.samBuildImage}` : 'sam build --template-file template.yaml'; (0, blueprint_component_workflows_1.addGenericBuildAction)({ blueprint: this, workflow: workflowDefinition, actionName: buildActionName, environment: { Name: this.options.environment.name || '<<PUT_YOUR_ENVIRONMENT_NAME_HERE>>', Connections: [ { Name: ((_a = this.options.environment.awsAccountConnection) === null || _a === void 0 ? void 0 : _a.name) || ' ', Role: ((_c = (_b = this.options.environment.awsAccountConnection) === null || _b === void 0 ? void 0 : _b.buildRole) === null || _c === void 0 ? void 0 : _c.name) || ' ', }, ], }, input: { Sources: ['WorkflowSource'], }, output: { AutoDiscoverReports: { Enabled: true, ReportNamePrefix: 'rpt', }, Artifacts: [ { Name: params.outputArtifactName, Files: ['**/*'], }, ], }, steps: [ ...params.stepsToRunUnitTests, samBuildImageOptions, 'cd .aws-sam/build/', `sam package --output-template-file packaged.yaml --resolve-s3 --template-file template.yaml --region ${region}`, ], }); const deployActionName = `deploy_to_${stripSpaces(this.options.environment.name)}`; (0, blueprint_component_workflows_1.addGenericCloudFormationDeployAction)({ blueprint: this, workflow: workflowDefinition, actionName: deployActionName, inputs: { Artifacts: [params.outputArtifactName], }, configuration: { parameters: { region, 'name': this.options.code.cloudFormationStackName, 'template': '.aws-sam/build/packaged.yaml', 'no-fail-on-empty-changeset': '1', }, }, environment: { Name: this.options.environment.name || ' ', Connections: [ { Name: ((_d = this.options.environment.awsAccountConnection) === null || _d === void 0 ? void 0 : _d.name) || ' ', Role: ((_f = (_e = this.options.environment.awsAccountConnection) === null || _e === void 0 ? void 0 : _e.deployRole) === null || _f === void 0 ? void 0 : _f.name) || ' ', }, ], }, }); new blueprint_component_workflows_1.Workflow(this, this.repository, workflowDefinition); } /** * Populates source code for lambda functions. * Source code is checked out from sam templates */ populateLambdaSourceCode(params) { var _a, _b, _c, _d; const rootSourceDir = '/tmp/sam-lambdas'; if (!fs.existsSync(rootSourceDir)) { fs.mkdirSync(rootSourceDir); } const sourceDir = path.join(rootSourceDir, params.cacheDir); if (!fs.existsSync(sourceDir)) { fs.mkdirSync(sourceDir); } // cp.execFileSync('svn', [ // 'checkout', // `https://github.com/aws/aws-sam-cli-app-templates/trunk/${params.runtime}/${params.gitSrcPath}/{{cookiecutter.project_name}}`, // `${sourceDir}`, // ]); const assetPath = path.join('static-assets', 'sam-templates', params.runtime, params.gitSrcPath, '{{cookiecutter.project_name}}', '*'); //TODO: this is a temporary fix to work around SVN failures. These assets need to be updated. cp.execSync(`cp -R ./${assetPath} ${sourceDir}/`, { cwd: process.cwd(), }); cp.execFileSync('rm', ['-rf', `${sourceDir}/.svn`, `${sourceDir}/.gitignore`, `${sourceDir}/README.md`, `${sourceDir}/template.yaml`]); // override any files that need to be overridden const overrideContext = { repositoryRelativePath: sourceDir, lambdaFunctionName: (_b = (_a = this.options.lambda) === null || _a === void 0 ? void 0 : _a.functionName) !== null && _b !== void 0 ? _b : '.', }; for (const fileTemplate of params.filesToOverride) { (0, util_1.writeFile)(fileTemplate.resolvePath(overrideContext), fileTemplate.resolveContent(overrideContext)); } // copy the lambda to the new path const newLambdaPath = path.join(this.repository.relativePath, (_d = (_c = this.options.lambda) === null || _c === void 0 ? void 0 : _c.functionName) !== null && _d !== void 0 ? _d : ''); new projen_1.SampleDir(this, newLambdaPath, { sourceDir }); return sourceDir; } createSamTemplate(params) { var _a; const header = `Transform: AWS::Serverless-2016-10-31 Description: lambdas Globals: Function: Timeout: 20\n`; let resources = 'Resources:'; let outputs = 'Outputs:'; for (const lambda of [(_a = this.options.lambda) === null || _a === void 0 ? void 0 : _a.functionName]) { resources += ` ${lambda}Function: Type: AWS::Serverless::Function Properties: CodeUri: ${lambda}/${params.codeUri} Runtime: ${params.runtime} Handler: ${params.handler} Description: ${lambda} Events: ${lambda}: Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api Properties: Path: /${lambda} Method: get`; //Append additional template properties resources += params.templateProps; if (params.templateMetadata) { resources += params.templateMetadata; } outputs += ` # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api ${lambda}Api: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://\${ServerlessRestApi}.execute-api.\${AWS::Region}.amazonaws.com/Prod/${lambda}/" ${lambda}Function: Description: "Hello World Lambda Function ARN" Value: !GetAtt ${lambda}Function.Arn ${lambda}FunctionIamRole: Description: "Implicit IAM Role created for Hello World function" Value: !GetAtt ${lambda}FunctionRole.Arn`; } const destinationPath = path.join(this.repository.relativePath, 'template.yaml'); const template = header + resources + '\n' + outputs; new projen_1.SampleFile(this, destinationPath, { contents: template }); } createMDEWorkspace(params) { const devEnvironmentPostStartEvents = params.runtimeOptions.devEnvironmentPostStartEvents; const workspaceDefinition = blueprint_component_dev_environments_1.SampleWorkspaces.default; devEnvironmentPostStartEvents.forEach(postStartEvent => { (0, blueprint_component_dev_environments_1.addPostStartEvent)(workspaceDefinition, { eventName: postStartEvent.eventName, command: postStartEvent.command, workingDirectory: postStartEvent.workingDirectory, component: workspaceDefinition.components[0].name, }); }); new blueprint_component_dev_environments_1.Workspace(this, this.repository, workspaceDefinition); } } exports.Blueprint = Blueprint; /** * removes all '.' '/' and ' ' characters */ function sanitizePath(path_) { return path_.replace(/\.|\/| /g, ''); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmx1ZXByaW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2JsdWVwcmludC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLGtEQUFvQztBQUNwQyx1Q0FBeUI7QUFDekIsMkNBQTZCO0FBQzdCLG9IQUFnSjtBQUNoSiw0R0FBb0k7QUFDcEksMEhBQW9JO0FBQ3BJLHNHQVk0RDtBQUM1RCxvRkFBb0k7QUFDcEksbUNBQStDO0FBQy9DLDBDQUFnRTtBQUNoRSxvRUFBdUM7QUFFdkMscURBQTBEO0FBRTFELHVEQUFvRDtBQXNHcEQ7Ozs7R0FJRztBQUNILE1BQWEsU0FBVSxTQUFRLGdDQUFlO0lBRzVDLFlBQVksUUFBaUI7UUFDM0IsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2hCLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQVEsQ0FBQyxDQUFDO1FBQ3RCOzs7O1dBSUc7UUFDSCxNQUFNLFNBQVMsR0FBWTtZQUN6QixNQUFNLEVBQUUsSUFBSSxDQUFDLE1BQU07WUFDbkIsR0FBRyx1QkFBUTtZQUNYLE9BQU8sRUFBRSx1QkFBUSxDQUFDLE9BQTZCO1NBQ2hELENBQUM7UUFDRixNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDLFNBQVMsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNuRCxPQUFPLENBQUMsSUFBSSxDQUFDLG9CQUFvQixHQUFHLFlBQVksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLG9CQUFvQixDQUFDLENBQUM7UUFDcEYsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7UUFFdkIsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLDBEQUFnQixDQUFDLElBQUksRUFBRTtZQUMzQyxLQUFLLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsb0JBQW9CLElBQUksWUFBWTtTQUM5RCxDQUFDLENBQUM7UUFFSCxJQUFJLGdFQUFzQixDQUFD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QUksZ0RBQVMsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxtQkFBbUIsQ0FBQyxDQUFDO0lBQzVELENBQUM7Q0FDRjtBQTFWRCw4QkEwVkM7QUFFRDs7R0FFRztBQUNILFNBQVMsWUFBWSxDQUFDLEtBQWE7SUFDakMsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQztBQUN2QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3AgZnJvbSAnY2hpbGRfcHJvY2Vzcyc7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgU2FtcGxlV29ya3NwYWNlcywgV29ya3NwYWNlLCBXb3Jrc3BhY2VEZWZpbml0aW9uLCBhZGRQb3N0U3RhcnRFdmVudCB9IGZyb20gJ0BhbWF6b24tY29kZWNhdGFseXN0L2JsdWVwcmludC1jb21wb25lbnQuZGV2LWVudmlyb25tZW50cyc7XG5pbXBvcnQgeyBFbnZpcm9ubWVudCwgRW52aXJvbm1lbnREZWZpbml0aW9uLCBBY2NvdW50Q29ubmVjdGlvbiwgUm9sZSB9IGZyb20gJ0BhbWF6b24tY29kZWNhdGFseXN0L2JsdWVwcmludC1jb21wb25lbnQuZW52aXJvbm1lbnRzJztcbmltcG9ydCB7IFNvdXJjZUZpbGUsIFNvdXJjZVJlcG9zaXRvcnksIEJsdWVwcmludE93bmVyc2hpcEZpbGUgfSBmcm9tICdAYW1hem9uLWNvZGVjYXRhbHlzdC9ibHVlcHJpbnQtY29tcG9uZW50LnNvdXJjZS1yZXBvc2l0b3JpZXMnO1xuaW1wb3J0IHtcbiAgV29ya2Zsb3dEZWZpbml0aW9uLFxuICBXb3JrZmxvdyxcbiAgYWRkR2VuZXJpY0JyYW5jaFRyaWdnZXIsXG4gIGFkZEdlbmVyaWNCdWlsZEFjdGlvbixcbiAgYWRkR2VuZXJpY0NvbXB1dGUsXG4gIGFkZEdlbmVyaWNDbG91ZEZvcm1hdGlvbkRlcGxveUFjdGlvbixcbiAgbWFrZUVtcHR5V29ya2Zsb3csXG4gIEF1dG9EaXNjb3ZlclJlcG9ydERlZmluaXRpb24sXG4gIFdvcmtmbG93QnVpbGRlcixcbiAgZW1wdHlXb3JrZmxvdyxcbiAgREVGQVVMVF9ERUxFVEVfUkVTT1VSQ0VfV09SS0ZMT1dfTkFNRSxcbn0gZnJvbSAnQGFtYXpvbi1jb2RlY2F0YWx5c3QvYmx1ZXByaW50LWNvbXBvbmVudC53b3JrZmxvd3MnO1xuaW1wb3J0IHsgQmx1ZXByaW50IGFzIFBhcmVudEJsdWVwcmludCwgT3B0aW9ucyBhcyBQYXJlbnRPcHRpb25zLCBNZXJnZVN0cmF0ZWdpZXMgfSBmcm9tICdAYW1hem9uLWNvZGVjYXRhbHlzdC9ibHVlcHJpbnRzLmJsdWVwcmludCc7XG5pbXBvcnQgeyBTYW1wbGVEaXIsIFNhbXBsZUZpbGUgfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgZ2V0RmlsZVBlcm1pc3Npb25zLCB3cml0ZUZpbGUgfSBmcm9tICdwcm9qZW4vbGliL3V0aWwnO1xuaW1wb3J0IGRlZmF1bHRzIGZyb20gJy4vZGVmYXVsdHMuanNvbic7XG5pbXBvcnQgeyBGaWxlVGVtcGxhdGUsIEZpbGVUZW1wbGF0ZUNvbnRleHQsIFJ1bnRpbWVNYXBwaW5nIH0gZnJvbSAnLi9tb2RlbHMnO1xuaW1wb3J0IHsgZ2VuZXJhdGVSZWFkbWVDb250ZW50cyB9IGZyb20gJy4vcmVhZG1lQ29udGVudHMnO1xuXG5pbXBvcnQgeyBydW50aW1lTWFwcGluZ3MgfSBmcm9tICcuL3J1bnRpbWVNYXBwaW5ncyc7XG5cbi8qKlxuICogVGhpcyBpcyB0aGUgJ09wdGlvbnMnIGludGVyZmFjZS4gVGhlICdPcHRpb25zJyBpbnRlcmZhY2UgaXMgaW50ZXJwcmV0ZWQgYnkgdGhlIHdpemFyZCB0byBkeW5hbWljYWxseSBnZW5lcmF0ZSBhIHNlbGVjdGlvbiBVSS5cbiAqIDEuIEl0IE1VU1QgYmUgY2FsbGVkICdPcHRpb25zJyBpbiBvcmRlciB0byBiZSBpbnRlcnByZXRlZCBieSB0aGUgd2l6YXJkXG4gKiAyLiBUaGlzIGlzIGhvdyB5b3UgY29udHJvbCB0aGUgZmllbGRzIHRoYXQgc2hvdyB1cCBvbiBhIHdpemFyZCBzZWxlY3Rpb24gcGFuZWwuIEtlZXBpbmcgdGhpcyBzbWFsbCBsZWFkcyB0byBhIGJldHRlciB1c2VyIGV4cGVyaWVuY2UuXG4gKiAzLiBZb3UgY2FuIHVzZSBKU0RPQ3MgYW5kIGFubm90YXRpb25zIHN1Y2ggYXM6ICc/JywgQGFkdmFuY2VkLCBAaGlkZGVuLCBAZGlzcGxheSAtIHRleHRhcmVhLCBldGMuIHRvIGNvbnRyb2wgaG93IHRoZSB3aXphcmQgZGlzcGxheXMgY2VydGFpbiBmaWVsZHMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgT3B0aW9ucyBleHRlbmRzIFBhcmVudE9wdGlvbnMge1xuICAvKipcbiAgICogQGRpc3BsYXlOYW1lIEFXUyBjb25uZWN0aW9uXG4gICAqIEBzaG93TmFtZSBmYWxzZVxuICAgKiBAc2hvd0Vudmlyb25tZW50VHlwZSBmYWxzZVxuICAgKiBAY29sbGFwc2VkIGZhbHNlXG4gICAqL1xuICBlbnZpcm9ubWVudDogRW52aXJvbm1lbnREZWZpbml0aW9uPHtcbiAgICAvKipcbiAgICAgKiBBbiBBV1MgYWNjb3VudCBjb25uZWN0aW9uIGlzIHJlcXVpcmVkIGJ5IHRoZSBwcm9qZWN0IHdvcmtmbG93IHRvIGRlcGxveSB0byBhd3MuXG4gICAgICogQGRpc3BsYXlOYW1lIEFXUyBhY2NvdW50IGNvbm5lY3Rpb25cbiAgICAgKiBAY29sbGFwc2VkIGZhbHNlXG4gICAgICovXG4gICAgYXdzQWNjb3VudENvbm5lY3Rpb246IEFjY291bnRDb25uZWN0aW9uPHtcbiAgICAgIC8qKlxuICAgICAgICogVGhpcyBpcyB0aGUgcm9sZSB0aGF0IHdpbGwgYmUgdXNlZCB0byBkZXBsb3kgdGhlIGFwcGxpY2F0aW9uLiBJdCBzaG91bGQgaGF2ZSBhY2Nlc3MgdG8gZGVwbG95IGFsbCBvZiB5b3VyIHJlc291cmNlcy4gU2VlIHRoZSBSZWFkbWUgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG4gICAgICAgKiBAZGlzcGxheU5hbWUgRGVwbG95IHJvbGVcbiAgICAgICAqIEBpbmxpbmVQb2xpY3kgLi9pbmxpbmUtcG9saWN5LWRlcGxveS5qc29uXG4gICAgICAgKiBAdHJ1c3RQb2xpY3kgLi90cnVzdC1wb2xpY3kuanNvblxuICAgICAgICovXG4gICAgICBkZXBsb3lSb2xlOiBSb2xlPFsnY29kZWNhdGFseXN0KiddPjtcblxuICAgICAgLyoqXG4gICAgICAgKiBUaGlzIGlzIHRoZSByb2xlIHRoYXQgYWxsb3dzIGJ1aWxkIGFjdGlvbnMgdG8gYWNjZXNzIGFuZCB3cml0ZSB0byBBbWF6b24gUzMsIHdoZXJlIHlvdXIgc2VydmVybGVzcyBhcHBsaWNhdGlvbiBwYWNrYWdlIGlzIHN0b3JlZC5cbiAgICAgICAqIEBkaXNwbGF5TmFtZSBCdWlsZCByb2xlXG4gICAgICAgKiBAaW5saW5lUG9saWN5IC4vaW5saW5lLXBvbGljeS1idWlsZC5qc29uXG4gICAgICAgKiBAdHJ1c3RQb2xpY3kgLi90cnVzdC1wb2xpY3kuanNvblxuICAgICAgICovXG4gICAgICBidWlsZFJvbGU6IFJvbGU8Wydjb2RlY2F0YWx5c3QqJ10+O1xuICAgIH0+O1xuICB9PjtcblxuICAvKipcbiAgICogU2VsZWN0IHlvdXIgTGFtYmRhIGRldmVsb3BtZW50IGxhbmd1YWdlXG4gICAqIEBkaXNwbGF5TmFtZSBSdW50aW1lIExhbmd1YWdlXG4gICAqL1xuICBydW50aW1lOiAnTm9kZS5qcyAxNCcgfCAnSmF2YSAxMSBHcmFkbGUnIHwgJ0phdmEgMTEgTWF2ZW4nIHwgJ1B5dGhvbiAzLjknO1xuXG4gIC8qKlxuICAgKiBAZGlzcGxheU5hbWUgQ29kZSBDb25maWd1cmF0aW9uXG4gICAqIEBjb2xsYXBzZWQgdHJ1ZVxuICAgKi9cbiAgY29kZToge1xuICAgIC8qKlxuICAgICAqIEBkaXNwbGF5TmFtZSBDb2RlIFJlcG9zaXRvcnkgbmFtZVxuICAgICAqIEB2YWxpZGF0aW9uUmVnZXggLyg/IS4qXFwuZ2l0JCleW2EtekEtWjAtOV8uLV17MywxMDB9JC9cbiAgICAgKiBAdmFsaWRhdGlvbk1lc3NhZ2UgTXVzdCBjb250YWluIG9ubHkgYWxwaGFudW1lcmljIGNoYXJhY3RlcnMsIHBlcmlvZHMgKC4pLCB1bmRlcnNjb3JlcyAoXyksIGRhc2hlcyAoLSkgYW5kIGJlIGJldHdlZW4gMyBhbmQgMTAwIGNoYXJhY3RlcnMgaW4gbGVuZ3RoLiBDYW5ub3QgZW5kIGluIC5naXQgb3IgY29udGFpbiBzcGFjZXNcbiAgICAgKi9cbiAgICBzb3VyY2VSZXBvc2l0b3J5TmFtZTogc3RyaW5nO1xuXG4gICAgLyoqXG4gICAgICogVGhlIG5hbWUgb2YgdGhlIEFXUyBDbG91ZEZvcm1hdGlvbiBzdGFjayBnZW5lcmF0ZWQgZm9yIHRoZSBibHVlcHJpbnQuIEl0IG11c3QgYmUgdW5pcXVlIGZvciB0aGUgQVdTIGFjY291bnQgaXQncyBiZWluZyBkZXBsb3llZCB0by5cbiAgICAgKiBAZGlzcGxheU5hbWUgQ2xvdWRGb3JtYXRpb24gc3RhY2sgbmFtZVxuICAgICAqIEB2YWxpZGF0aW9uUmVnZXggL15bYS16QS1aXVthLXpBLVowLTktXXsxLDEwMH0kL1xuICAgICAqIEB2YWxpZGF0aW9uTWVzc2FnZSBTdGFjayBuYW1lcyBtdXN0IHN0YXJ0IHdpdGggYSBsZXR0ZXIsIHRoZW4gY29udGFpbiBhbHBoYW51bWVyaWMgY2hhcmFjdGVycyBhbmQgZGFzaGVzKC0pIHVwIHRvIGEgdG90YWwgbGVuZ3RoIG9mIDEyOCBjaGFyYWN0ZXJzXG4gICAgICogQGRlZmF1bHRFbnRyb3B5IDVcbiAgICAgKi9cbiAgICBjbG91ZEZvcm1hdGlvblN0YWNrTmFtZTogc3RyaW5nO1xuICB9O1xuXG4gIC8qKlxuICAgKiBAZGlzcGxheU5hbWUgTGFtYmRhIGZ1bmN0aW9uIG5hbWVcbiAgICogQGNvbGxhcHNlZCB0cnVlXG4gICAqL1xuICBsYW1iZGE6IHtcbiAgICAvKipcbiAgICAgKiBMYW1iZGEgZnVuY3Rpb24gbmFtZSBtdXN0IGJlIHVucWl1ZSB0byB0aGUgQVdTIGFjY291bnQgaXQncyBiZWluZyBkZXBsb3llZCB0by5cbiAgICAgKiBAZGlzcGxheU5hbWUgTGFtYmRhIGZ1bmN0aW9uIG5hbWVcbiAgICAgKiBAZGVmYXVsdEVudHJvcHkgNVxuICAgICAqIEB2YWxpZGF0aW9uUmVnZXggL15bYS16QS1aMC05XXsxLDU2fSQvXG4gICAgICogQHZhbGlkYXRpb25NZXNzYWdlIE11c3QgY29udGFpbiBvbmx5IGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzIGFuZCBiZSB1cCB0byA1NiBjaGFyYWN0ZXJzIGluIGxlbmd0aFxuICAgICAqL1xuICAgIGZ1bmN0aW9uTmFtZTogc3RyaW5nO1xuICB9O1xuXG4gIC8qKlxuICAgKiBUaGlzIGlzIGFuIGludGVudGlvbmFsbHkgaGlkZGVuIGZpZWxkIHRoYXQgZGV0ZXJtaW5lcyBpZiB0aGUgY2xlYW51cCB3b3JrZmxvdyB3aWxsIGJlIGdlbmVyYXRlZCBhcyBjb21tZW50ZWQgb3V0LlxuICAgKiBUaGlzIHdpbGwgYmUgc2V0IHRvIHRydWUgZHVyaW5nIGJsdWVwcmludCBoZWFsdGggYXNzZXNzbWVudCBydW4gZm9yIGNsZWFudXAgd29ya2Zsb3cgdG8gcnVuIGFzIGV4cGVjdGVkLlxuICAgKiBAaGlkZGVuIHRydWVcbiAgICovXG4gIHVuY29tbWVudENsZWFudXBXb3JrZmxvdz86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSB0ZW1wb3JhcnkgUzMgYnVja2V0IHVzZWQgaW4gdGhlIGNsZWFudXAgd29ya2Zsb3cuIFRoaXMgb3B0aW9uIGlzIGhpZGRlbiBhbmQgd2lsbCBiZSBzZXQgYnkgdGhlIHdpemFyZFxuICAgKiB0byBhIGRlZmF1bHQgYnVja2V0IHByZWZpeCBmb2xsb3dlZCBieSB3aXphcmQgZ2VuZXJhdGVkIGVudHJvcHkuIFRoaXMgb3B0aW9uIGFsbG93cyBzdWJzZXF1ZW50IHJlc3ludGhlc2lzIHRvXG4gICAqIGdlbmVyYXRlIHRoZSBjbGVhbnVwIHdvcmtmbG93IHVzaW5nIHRoZSBzYW1lIHJhbmRvbSBidWNrZXQgbmFtZSBhcyB3YXMgZ2VuZXJhdGVkIGJ5IHRoZSBvcmlnaW5hbCBzeW50aGVzaXMuXG4gICAqIEB2YWxpZGF0aW9uUmVnZXggL15bLS5hLXpBLVowLTldezMsNjN9JC9cbiAgICogQHZhbGlkYXRpb25NZXNzYWdlIE11c3QgY29udGFpbiBvbmx5IGFscGhhbnVtZXJpYyBjaGFyYWN0ZXJzLCBwZXJpb2RzICguKSwgZGFzaGVzICgtKSBhbmQgYmUgYmV0d2VlbiAzIGFuZCA2MyBjaGFyYWN0ZXJzIGluIGxlbmd0aC5cbiAgICogQGRlZmF1bHRFbnRyb3B5IDMyXG4gICAqIEBoaWRkZW4gdHJ1ZVxuICAgKi9cbiAgY2xlYW51cFdvcmtmbG93VGVtcGxhdGVCdWNrZXROYW1lPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoaXMgaXMgdGhlIGFjdHVhbCBibHVlcHJpbnQgY2xhc3MuXG4gKiAxLiBUaGlzIE1VU1QgYmUgdGhlIG9ubHkgJ2NsYXNzJyBleHBvcnRlZCwgYXMgJ0JsdWVwcmludCdcbiAqIDIuIFRoaXMgQmx1ZXByaW50IHNob3VsZCBleHRlbmQgYW5vdGhlciBQYXJlbnRCbHVlcHJpbnRcbiAqL1xuZXhwb3J0IGNsYXNzIEJsdWVwcmludCBleHRlbmRzIFBhcmVudEJsdWVwcmludCB7XG4gIHByb3RlY3RlZCBvcHRpb25zOiBPcHRpb25zO1xuICBwcm90ZWN0ZWQgcmVhZG9ubHkgcmVwb3NpdG9yeTogU291cmNlUmVwb3NpdG9yeTtcbiAgY29uc3RydWN0b3Iob3B0aW9uc186IE9wdGlvbnMpIHtcbiAgICBzdXBlcihvcHRpb25zXyk7XG4gICAgY29uc29sZS5sb2coZGVmYXVsdHMpO1xuICAgIC8qKlxuICAgICAqIFRoaXMgaXMgYSB0eXBlY2hlY2sgdG8gZW5zdXJlIHRoYXQgdGhlIGRlZmF1bHRzIHBhc3NlZCBpbiBhcmUgb2YgdGhlIGNvcnJlY3QgdHlwZS5cbiAgICAgKiBUaGVyZSBhcmUgc29tZSBjYXNlcyB3aGVyZSB0aGUgdHlwZWNoZWNrIHdpbGwgZmFpbCwgYnV0IHRoZSBkZWZhdWx0cyB3aWxsIHN0aWxsIGJlIHZhbGlkLCBzdWNoIHdoZW4gdXNpbmcgZW51bXMuXG4gICAgICogeW91IGNhbiBvdmVycmlkZSB0aGlzIGV4LiBteUVudW06IGRlZmF1bHRzLm15RW51bSBhcyBPcHRpb25zWydteUVudW0nXSxcbiAgICAgKi9cbiAgICBjb25zdCB0eXBlQ2hlY2s6IE9wdGlvbnMgPSB7XG4gICAgICBvdXRkaXI6IHRoaXMub3V0ZGlyLFxuICAgICAgLi4uZGVmYXVsdHMsXG4gICAgICBydW50aW1lOiBkZWZhdWx0cy5ydW50aW1lIGFzIE9wdGlvbnNbJ3J1bnRpbWUnXSxcbiAgICB9O1xuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKHR5cGVDaGVjaywgb3B0aW9uc18pO1xuICAgIG9wdGlvbnMuY29kZS5zb3VyY2VSZXBvc2l0b3J5TmFtZSA9IHNhbml0aXplUGF0aChvcHRpb25zLmNvZGUuc291cmNlUmVwb3NpdG9yeU5hbWUpO1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG5cbiAgICB0aGlzLnJlcG9zaXRvcnkgPSBuZXcgU291cmNlUmVwb3NpdG9yeSh0aGlzLCB7XG4gICAgICB0aXRsZTogdGhpcy5vcHRpb25zLmNvZGUuc291cmNlUmVwb3NpdG9yeU5hbWUgfHwgJ3NhbS1sYW1iZGEnLFxuICAgIH0pO1xuXG4gICAgbmV3IEJsdWVwcmludE93bmVyc2hpcEZpbGUodGhpcy5yZXBvc2l0b3J5LCB7XG4gICAgICByZXN5bnRoZXNpczoge1xuICAgICAgICBzdHJhdGVnaWVzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgaWRlbnRpZmllcjogJ25ldmVyX3VwZGF0ZScsXG4gICAgICAgICAgICBzdHJhdGVneTogTWVyZ2VTdHJhdGVnaWVzLm5ldmVyVXBkYXRlLFxuICAgICAgICAgICAgZ2xvYnM6IFsnKiddLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIHRoaXMub3B0aW9ucy5sYW1iZGEgPSBvcHRpb25zLmxhbWJkYTtcbiAgfVxuXG4gIG92ZXJyaWRlIHN5bnRoKCk6IHZvaWQge1xuICAgIGNvbnN0IHJ1bnRpbWUgPSB0aGlzLm9wdGlvbnMucnVudGltZTtcbiAgICBjb25zdCBydW50aW1lT3B0aW9ucyA9IHJ1bnRpbWVNYXBwaW5nc1tydW50aW1lXTtcblxuICAgIC8vIGNyZWF0ZSBhbiBNREUgd29ya3NwYWNlXG4gICAgdGhpcy5jcmVhdGVNREVXb3Jrc3BhY2UoeyBydW50aW1lT3B0aW9ucyB9KTtcblxuICAgIC8vIGNyZWF0ZSBhbiBlbnZpcm9ubWVudFxuICAgIG5ldyBFbnZpcm9ubWVudCh0aGlzLCB0aGlzLm9wdGlvbnMuZW52aXJvbm1lbnQpO1xuXG4gICAgLy8gY3JlYXRlIFNBTSB0ZW1wbGF0ZSBhbmQgaW5zdGFsbGF0aW9uIHNjcmlwdHNcbiAgICB0aGlzLmNyZWF0ZVNhbVRlbXBsYXRlKHtcbiAgICAgIHJ1bnRpbWU6IHJ1bnRpbWVPcHRpb25zLnJ1bnRpbWUsXG4gICAgICBjb2RlVXJpOiBydW50aW1lT3B0aW9ucy5jb2RlVXJpLFxuICAgICAgaGFuZGxlcjogcnVudGltZU9wdGlvbnMuaGFuZGxlcixcbiAgICAgIHRlbXBsYXRlUHJvcHM6IHJ1bnRpbWVPcHRpb25zLnRlbXBsYXRlUHJvcHMsXG4gICAgICB0ZW1wbGF0ZU1ldGFkYXRhOiBydW50aW1lT3B0aW9ucy50ZW1wbGF0ZU1ldGFkYXRhLFxuICAgIH0pO1xuXG4gICAgLy8gY3JlYXRlIGFkZGl0aW9uYWwgZmlsZXMgcmVxdWlyZWQgZm9yIHRoaXMgcnVudGltZVxuICAgIGNvbnN0IGNvbnRleHQ6IEZpbGVUZW1wbGF0ZUNvbnRleHQgPSB7XG4gICAgICByZXBvc2l0b3J5UmVsYXRpdmVQYXRoOiB0aGlzLnJlcG9zaXRvcnkucmVsYXRpdmVQYXRoLFxuICAgICAgbGFtYmRhRnVuY3Rpb25OYW1lOiB0aGlzLm9wdGlvbnMubGFtYmRhPy5mdW5jdGlvbk5hbWUgPz8gJy4nLFxuICAgIH07XG4gICAgZm9yIChjb25zdCBmaWxlVGVtcGxhdGUgb2YgcnVudGltZU9wdGlvbnMuZmlsZXNUb0NyZWF0ZSkge1xuICAgICAgbmV3IFNhbXBsZUZpbGUodGhpcywgZmlsZVRlbXBsYXRlLnJlc29sdmVQYXRoKGNvbnRleHQpLCB7IGNvbnRlbnRzOiBmaWxlVGVtcGxhdGUucmVzb2x2ZUNvbnRlbnQoY29udGV4dCkgfSk7XG4gICAgfVxuXG4gICAgLy8gY3JlYXRlIHRoZSBidWlsZCBhbmQgcmVsZWFzZSB3b3JrZmxvd1xuICAgIGNvbnN0IHdvcmtmbG93TmFtZSA9ICdidWlsZC1hbmQtcmVsZWFzZSc7XG4gICAgdGhpcy5jcmVhdGVXb3JrZmxvdyh7XG4gICAgICBuYW1lOiAnYnVpbGQtYW5kLXJlbGVhc2UnLFxuICAgICAgb3V0cHV0QXJ0aWZhY3ROYW1lOiAnYnVpbGRfcmVzdWx0JyxcbiAgICAgIHN0ZXBzVG9SdW5Vbml0VGVzdHM6IHJ1bnRpbWVPcHRpb25zLnN0ZXBzVG9SdW5Vbml0VGVzdHMsXG4gICAgICBhdXRvRGlzY292ZXJ5T3ZlcnJpZGU6IHJ1bnRpbWVPcHRpb25zLmF1dG9EaXNjb3ZlcnlPdmVycmlkZSxcbiAgICAgIHJ1bnRpbWVPcHRpb25zLFxuICAgIH0pO1xuXG4gICAgLy8gY3JlYXRlIHRoZSBjbGVhbnVwIHdvcmtmbG93XG4gICAgY29uc3QgY2xlYW51cFdvcmtmbG93ID0gbmV3IFdvcmtmbG93QnVpbGRlcih0aGlzLCBlbXB0eVdvcmtmbG93KTtcbiAgICBjbGVhbnVwV29ya2Zsb3cuc2V0TmFtZShERUZBVUxUX0RFTEVURV9SRVNPVVJDRV9XT1JLRkxPV19OQU1FKTtcbiAgICBjbGVhbnVwV29ya2Zsb3cuYWRkQ2ZuQ2xlYW51cEFjdGlvbih7XG4gICAgICBhY3Rpb25OYW1lOiBgZGVsZXRlXyR7dGhpcy5vcHRpb25zLmNvZGUuY2xvdWRGb3JtYXRpb25TdGFja05hbWV9YCxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIE5hbWU6IHRoaXMub3B0aW9ucy5lbnZpcm9ubWVudC5uYW1lIHx8ICc8PFBVVF9ZT1VSX0VOVklST05NRU5UX05BTUVfSEVSRT4+JyxcbiAgICAgICAgQ29ubmVjdGlvbnM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBOYW1lOiB0aGlzLm9wdGlvbnMuZW52aXJvbm1lbnQuYXdzQWNjb3VudENvbm5lY3Rpb24/Lm5hbWUgfHwgJyAnLFxuICAgICAgICAgICAgUm9sZTogdGhpcy5vcHRpb25zLmVudmlyb25tZW50LmF3c0FjY291bnRDb25uZWN0aW9uPy5idWlsZFJvbGU/Lm5hbWUgfHwgJyAnLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICAgc3RhY2tOYW1lOiB0aGlzLm9wdGlvbnMuY29kZS5jbG91ZEZvcm1hdGlvblN0YWNrTmFtZSxcbiAgICAgIHJlZ2lvbjogJ3VzLXdlc3QtMicsXG4gICAgICB0ZW1wbGF0ZUJ1Y2tldE5hbWU6IHRoaXMub3B0aW9ucy5jbGVhbnVwV29ya2Zsb3dUZW1wbGF0ZUJ1Y2tldE5hbWUsXG4gICAgfSk7XG4gICAgY29uc3QgYWRkaXRpb25hbENvbW1lbnRzID0gW1xuICAgICAgJ1RoZSBmb2xsb3dpbmcgd29ya2Zsb3cgaXMgaW50ZW50aW9uYWxseSBkaXNhYmxlZCBieSB0aGUgYmx1ZXByaW50IGF1dGhvciB0byBwcmV2ZW50IHByb2plY3QgY29udHJpYnV0b3JzIGZyb20gYWNjaWRlbnRhbGx5IGV4ZWN1dGluZyBpdC4nLFxuICAgICAgJ1RoaXMgd29ya2Zsb3cgd2lsbCBhdHRlbXB0IHRvIGRlbGV0ZSBhbGwgdGhlIGRlcGxveWVkIHJlc291cmNlcyBmcm9tIHRoZSBibHVlcHJpbnQuJyxcbiAgICAgICdUaGUgZGVsZXRpb24gYWN0aW9uIGNhbm5vdCBiZSB1bmRvbmUsIHBsZWFzZSBwcm9jZWVkIGF0IHlvdXIgb3duIHJpc2suJyxcbiAgICAgICdUbyB1dGlsaXplIGl0LCBwbGVhc2UgdW5jb21tZW50IGFsbCB0aGUgc3VjY2VlZGluZyBsaW5lcy4nLFxuICAgIF07XG4gICAgbmV3IFdvcmtmbG93KHRoaXMsIHRoaXMucmVwb3NpdG9yeSwgY2xlYW51cFdvcmtmbG93LmRlZmluaXRpb24sIHtcbiAgICAgIGFkZGl0aW9uYWxDb21tZW50czogdGhpcy5vcHRpb25zLnVuY29tbWVudENsZWFudXBXb3JrZmxvdyA/IHVuZGVmaW5lZCA6IGFkZGl0aW9uYWxDb21tZW50cyxcbiAgICAgIGNvbW1lbnRlZDogIXRoaXMub3B0aW9ucy51bmNvbW1lbnRDbGVhbnVwV29ya2Zsb3csXG4gICAgfSk7XG5cbiAgICAvLyBnZW5lcmF0ZSB0aGUgcmVhZG1lXG4gICAgbmV3IFNvdXJjZUZpbGUoXG4gICAgICB0aGlzLnJlcG9zaXRvcnksXG4gICAgICAnUkVBRE1FLm1kJyxcbiAgICAgIGdlbmVyYXRlUmVhZG1lQ29udGVudHMoe1xuICAgICAgICBydW50aW1lLFxuICAgICAgICBydW50aW1lTWFwcGluZzogcnVudGltZU9wdGlvbnMsXG4gICAgICAgIGRlZmF1bHRSZWxlYXNlQnJhbmNoOiAnbWFpbicsXG4gICAgICAgIGxhbWJkYXM6IFt0aGlzLm9wdGlvbnMubGFtYmRhXSxcbiAgICAgICAgZW52aXJvbm1lbnQ6IHRoaXMub3B0aW9ucy5lbnZpcm9ubWVudCxcbiAgICAgICAgY2xvdWRGb3JtYXRpb25TdGFja05hbWU6IHRoaXMub3B0aW9ucy5jb2RlLmNsb3VkRm9ybWF0aW9uU3RhY2tOYW1lLFxuICAgICAgICB3b3JrZmxvd05hbWU6IHdvcmtmbG93TmFtZSxcbiAgICAgICAgc291cmNlUmVwb3NpdG9yeU5hbWU6IHRoaXMucmVwb3NpdG9yeS50aXRsZSxcbiAgICAgIH0pLFxuICAgICk7XG5cbiAgICBjb25zdCB0b0RlbGV0ZVBhdGggPSB0aGlzLnBvcHVsYXRlTGFtYmRhU291cmNlQ29kZSh7XG4gICAgICBydW50aW1lOiBydW50aW1lT3B0aW9ucy5ydW50aW1lLFxuICAgICAgY2FjaGVEaXI6IHJ1bnRpbWVPcHRpb25zLmNhY2hlRGlyLFxuICAgICAgZ2l0U3JjUGF0aDogcnVudGltZU9wdGlvbnMuZ2l0U3JjUGF0aCxcbiAgICAgIGZpbGVzVG9PdmVycmlkZTogcnVudGltZU9wdGlvbnMuZmlsZXNUb092ZXJyaWRlLFxuICAgIH0pO1xuXG4gICAgc3VwZXIuc3ludGgoKTtcblxuICAgIGNwLmV4ZWNTeW5jKGBybSAtcmYgJHt0b0RlbGV0ZVBhdGh9YCk7XG5cbiAgICAvLyB1cGRhdGUgcGVybWlzc2lvbnNcbiAgICBjb25zdCBwZXJtaXNzaW9uQ2hhbmdlQ29udGV4dDogRmlsZVRlbXBsYXRlQ29udGV4dCA9IHtcbiAgICAgIHJlcG9zaXRvcnlSZWxhdGl2ZVBhdGg6IHBhdGguam9pbih0aGlzLm91dGRpciwgdGhpcy5yZXBvc2l0b3J5LnJlbGF0aXZlUGF0aCksXG4gICAgICBsYW1iZGFGdW5jdGlvbk5hbWU6IHRoaXMub3B0aW9ucy5sYW1iZGE/LmZ1bmN0aW9uTmFtZSA/PyAnLicsXG4gICAgfTtcbiAgICBmb3IgKGNvbnN0IGZpbGVQZXJtaXNzaW9uQ2hhbmdlIG9mIHJ1bnRpbWVPcHRpb25zLmZpbGVzVG9DaGFuZ2VQZXJtaXNzaW9uc0Zvcikge1xuICAgICAgZnMuY2htb2RTeW5jKGZpbGVQZXJtaXNzaW9uQ2hhbmdlLnJlc29sdmVQYXRoKHBlcm1pc3Npb25DaGFuZ2VDb250ZXh0KSwgZ2V0RmlsZVBlcm1pc3Npb25zKGZpbGVQZXJtaXNzaW9uQ2hhbmdlLm5ld1Blcm1pc3Npb25zKSk7XG4gICAgfVxuICB9XG5cbiAgY3JlYXRlV29ya2Zsb3cocGFyYW1zOiB7XG4gICAgbmFtZTogc3RyaW5nO1xuICAgIG91dHB1dEFydGlmYWN0TmFtZTogc3RyaW5nO1xuICAgIHN0ZXBzVG9SdW5Vbml0VGVzdHM6IEFycmF5PHN0cmluZz47XG4gICAgYXV0b0Rpc2NvdmVyeU92ZXJyaWRlPzogQXV0b0Rpc2NvdmVyUmVwb3J0RGVmaW5pdGlvbjtcbiAgICBydW50aW1lT3B0aW9uczogUnVudGltZU1hcHBpbmc7XG4gIH0pOiB2b2lkIHtcbiAgICBjb25zdCB7IG5hbWUgfSA9IHBhcmFtcztcblxuICAgIGNvbnN0IHN0cmlwU3BhY2VzID0gKHN0cjogc3RyaW5nKSA9PiAoc3RyIHx8ICcnKS5yZXBsYWNlKC9cXHMvZywgJycpO1xuXG4gICAgY29uc3QgZGVmYXVsdEJyYW5jaCA9ICdtYWluJztcbiAgICBjb25zdCByZWdpb24gPSAndXMtd2VzdC0yJztcbiAgICBjb25zdCBzY2hlbWFWZXJzaW9uID0gJzEuMCc7XG5cbiAgICBjb25zdCB3b3JrZmxvd0RlZmluaXRpb246IFdvcmtmbG93RGVmaW5pdGlvbiA9IHtcbiAgICAgIC4uLm1ha2VFbXB0eVdvcmtmbG93KCksXG4gICAgICBTY2hlbWFWZXJzaW9uOiBzY2hlbWFWZXJzaW9uLFxuICAgICAgTmFtZTogbmFtZSxcbiAgICB9O1xuICAgIGFkZEdlbmVyaWNCcmFuY2hUcmlnZ2VyKHdvcmtmbG93RGVmaW5pdGlvbiwgW2RlZmF1bHRCcmFuY2hdKTtcblxuICAgIGFkZEdlbmVyaWNDb21wdXRlKHdvcmtmbG93RGVmaW5pdGlvbiwgcGFyYW1zLnJ1bnRpbWVPcHRpb25zLmNvbXB1dGVPcHRpb25zLlR5cGUsIHBhcmFtcy5ydW50aW1lT3B0aW9ucy5jb21wdXRlT3B0aW9ucy5GbGVldCk7XG5cbiAgICBjb25zdCBidWlsZEFjdGlvbk5hbWUgPSBgYnVpbGRfZm9yXyR7c3RyaXBTcGFjZXModGhpcy5vcHRpb25zLmVudmlyb25tZW50Lm5hbWUpfWA7XG4gICAgY29uc3Qgc2FtQnVpbGRJbWFnZU9wdGlvbnMgPSBwYXJhbXMucnVudGltZU9wdGlvbnMuc2FtQnVpbGRJbWFnZVxuICAgICAgPyBgc2FtIGJ1aWxkIC0tdGVtcGxhdGUtZmlsZSB0ZW1wbGF0ZS55YW1sIC0tdXNlLWNvbnRhaW5lciAtLWJ1aWxkLWltYWdlICR7cGFyYW1zLnJ1bnRpbWVPcHRpb25zLnNhbUJ1aWxkSW1hZ2V9YFxuICAgICAgOiAnc2FtIGJ1aWxkIC0tdGVtcGxhdGUtZmlsZSB0ZW1wbGF0ZS55YW1sJztcbiAgICBhZGRHZW5lcmljQnVpbGRBY3Rpb24oe1xuICAgICAgYmx1ZXByaW50OiB0aGlzLFxuICAgICAgd29ya2Zsb3c6IHdvcmtmbG93RGVmaW5pdGlvbixcbiAgICAgIGFjdGlvbk5hbWU6IGJ1aWxkQWN0aW9uTmFtZSxcbiAgICAgIGVudmlyb25tZW50OiB7XG4gICAgICAgIE5hbWU6IHRoaXMub3B0aW9ucy5lbnZpcm9ubWVudC5uYW1lIHx8ICc8PFBVVF9ZT1VSX0VOVklST05NRU5UX05BTUVfSEVSRT4+JyxcbiAgICAgICAgQ29ubmVjdGlvbnM6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBOYW1lOiB0aGlzLm9wdGlvbnMuZW52aXJvbm1lbnQuYXdzQWNjb3VudENvbm5lY3Rpb24/Lm5hbWUgfHwgJyAnLFxuICAgICAgICAgICAgUm9sZTogdGhpcy5vcHRpb25zLmVudmlyb25tZW50LmF3c0FjY291bnRDb25uZWN0aW9uPy5idWlsZFJvbGU/Lm5hbWUgfHwgJyAnLFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICAgaW5wdXQ6IHtcbiAgICAgICAgU291cmNlczogWydXb3JrZmxvd1NvdXJjZSddLFxuICAgICAgfSxcbiAgICAgIG91dHB1dDoge1xuICAgICAgICBBdXRvRGlzY292ZXJSZXBvcnRzOiB7XG4gICAgICAgICAgRW5hYmxlZDogdHJ1ZSxcbiAgICAgICAgICBSZXBvcnROYW1lUHJlZml4OiAncnB0JyxcbiAgICAgICAgfSxcbiAgICAgICAgQXJ0aWZhY3RzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgTmFtZTogcGFyYW1zLm91dHB1dEFydGlmYWN0TmFtZSxcbiAgICAgICAgICAgIEZpbGVzOiBbJyoqLyonXSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICAgIHN0ZXBzOiBbXG4gICAgICAgIC4uLnBhcmFtcy5zdGVwc1RvUnVuVW5pdFRlc3RzLFxuICAgICAgICBzYW1CdWlsZEltYWdlT3B0aW9ucyxcbiAgICAgICAgJ2NkIC5hd3Mtc2FtL2J1aWxkLycsXG4gICAgICAgIGBzYW0gcGFja2FnZSAtLW91dHB1dC10ZW1wbGF0ZS1maWxlIHBhY2thZ2VkLnlhbWwgLS1yZXNvbHZlLXMzIC0tdGVtcGxhdGUtZmlsZSB0ZW1wbGF0ZS55YW1sIC0tcmVnaW9uICR7cmVnaW9ufWAsXG4gICAgICBdLFxuICAgIH0pO1xuXG4gICAgY29uc3QgZGVwbG95QWN0aW9uTmFtZSA9IGBkZXBsb3lfdG9fJHtzdHJpcFNwYWNlcyh0aGlzLm9wdGlvbnMuZW52aXJvbm1lbnQubmFtZSl9YDtcbiAgICBhZGRHZW5lcmljQ2xvdWRGb3JtYXRpb25EZXBsb3lBY3Rpb24oe1xuICAgICAgYmx1ZXByaW50OiB0aGlzLFxuICAgICAgd29ya2Zsb3c6IHdvcmtmbG93RGVmaW5pdGlvbixcbiAgICAgIGFjdGlvbk5hbWU6IGRlcGxveUFjdGlvbk5hbWUsXG4gICAgICBpbnB1dHM6IHtcbiAgICAgICAgQXJ0aWZhY3RzOiBbcGFyYW1zLm91dHB1dEFydGlmYWN0TmFtZV0sXG4gICAgICB9LFxuICAgICAgY29uZmlndXJhdGlvbjoge1xuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgcmVnaW9uLFxuICAgICAgICAgICduYW1lJzogdGhpcy5vcHRpb25zLmNvZGUuY2xvdWRGb3JtYXRpb25TdGFja05hbWUsXG4gICAgICAgICAgJ3RlbXBsYXRlJzogJy5hd3Mtc2FtL2J1aWxkL3BhY2thZ2VkLnlhbWwnLFxuICAgICAgICAgICduby1mYWlsLW9uLWVtcHR5LWNoYW5nZXNldCc6ICcxJyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBlbnZpcm9ubWVudDoge1xuICAgICAgICBOYW1lOiB0aGlzLm9wdGlvbnMuZW52aXJvbm1lbnQubmFtZSB8fCAnICcsXG4gICAgICAgIENvbm5lY3Rpb25zOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgTmFtZTogdGhpcy5vcHRpb25zLmVudmlyb25tZW50LmF3c0FjY291bnRDb25uZWN0aW9uPy5uYW1lIHx8ICcgJyxcbiAgICAgICAgICAgIFJvbGU6IHRoaXMub3B0aW9ucy5lbnZpcm9ubWVudC5hd3NBY2NvdW50Q29ubmVjdGlvbj8uZGVwbG95Um9sZT8ubmFtZSB8fCAnICcsXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgfSk7XG4gICAgbmV3IFdvcmtmbG93KHRoaXMsIHRoaXMucmVwb3NpdG9yeSwgd29ya2Zsb3dEZWZpbml0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQb3B1bGF0ZXMgc291cmNlIGNvZGUgZm9yIGxhbWJkYSBmdW5jdGlvbnMuXG4gICAqIFNvdXJjZSBjb2RlIGlzIGNoZWNrZWQgb3V0IGZyb20gc2FtIHRlbXBsYXRlc1xuICAgKi9cbiAgcHJvdGVjdGVkIHBvcHVsYXRlTGFtYmRhU291cmNlQ29kZShwYXJhbXM6IHtcbiAgICBydW50aW1lOiBzdHJpbmc7XG4gICAgY2FjaGVEaXI6IHN0cmluZztcbiAgICBnaXRTcmNQYXRoOiBzdHJpbmc7XG4gICAgZmlsZXNUb092ZXJyaWRlOiBBcnJheTxGaWxlVGVtcGxhdGU+O1xuICB9KTogc3RyaW5nIHtcbiAgICBjb25zdCByb290U291cmNlRGlyID0gJy90bXAvc2FtLWxhbWJkYXMnO1xuICAgIGlmICghZnMuZXhpc3RzU3luYyhyb290U291cmNlRGlyKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHJvb3RTb3VyY2VEaXIpO1xuIC