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