@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
364 lines • 54.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DefaultStackSynthesizer = exports.BOOTSTRAP_QUALIFIER_CONTEXT = void 0;
const fs = require("fs");
const path = require("path");
const cxschema = require("@aws-cdk/cloud-assembly-schema");
const cxapi = require("@aws-cdk/cx-api");
const assets_1 = require("../assets");
const cfn_fn_1 = require("../cfn-fn");
const cfn_parameter_1 = require("../cfn-parameter");
const cfn_rule_1 = require("../cfn-rule");
const token_1 = require("../token");
const _shared_1 = require("./_shared");
const stack_synthesizer_1 = require("./stack-synthesizer");
exports.BOOTSTRAP_QUALIFIER_CONTEXT = '@aws-cdk/core:bootstrapQualifier';
/* eslint-disable max-len */
/**
* The minimum bootstrap stack version required by this app.
*/
const MIN_BOOTSTRAP_STACK_VERSION = 4;
/**
* Uses conventionally named roles and reify asset storage locations.
*
* This synthesizer is the only StackSynthesizer that generates
* an asset manifest, and is required to deploy CDK applications using the
* `@aws-cdk/app-delivery` CI/CD library.
*
* Requires the environment to have been bootstrapped with Bootstrap Stack V2.
*/
class DefaultStackSynthesizer extends stack_synthesizer_1.StackSynthesizer {
/**
*
*/
constructor(props = {}) {
super();
this.props = props;
this.files = {};
this.dockerImages = {};
}
/**
* Bind to the stack this environment is going to be used on.
*
* Must be called before any of the other methods are called.
*/
bind(stack) {
var _a, _b, _c, _d, _e, _f, _g, _h;
this._stack = stack;
const qualifier = (_b = (_a = this.props.qualifier) !== null && _a !== void 0 ? _a : stack.node.tryGetContext(exports.BOOTSTRAP_QUALIFIER_CONTEXT)) !== null && _b !== void 0 ? _b : DefaultStackSynthesizer.DEFAULT_QUALIFIER;
this.qualifier = qualifier;
// Function to replace placeholders in the input string as much as possible
//
// We replace:
// - ${Qualifier}: always
// - ${AWS::AccountId}, ${AWS::Region}: only if we have the actual values available
// - ${AWS::Partition}: never, since we never have the actual partition value.
const specialize = (s) => {
s = replaceAll(s, '${Qualifier}', qualifier);
return cxapi.EnvironmentPlaceholders.replace(s, {
region: resolvedOr(stack.region, cxapi.EnvironmentPlaceholders.CURRENT_REGION),
accountId: resolvedOr(stack.account, cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT),
partition: cxapi.EnvironmentPlaceholders.CURRENT_PARTITION,
});
};
/* eslint-disable max-len */
this.bucketName = specialize((_c = this.props.fileAssetsBucketName) !== null && _c !== void 0 ? _c : DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME);
this.repositoryName = specialize((_d = this.props.imageAssetsRepositoryName) !== null && _d !== void 0 ? _d : DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME);
this._deployRoleArn = specialize((_e = this.props.deployRoleArn) !== null && _e !== void 0 ? _e : DefaultStackSynthesizer.DEFAULT_DEPLOY_ROLE_ARN);
this._cloudFormationExecutionRoleArn = specialize((_f = this.props.cloudFormationExecutionRole) !== null && _f !== void 0 ? _f : DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN);
this.fileAssetPublishingRoleArn = specialize((_g = this.props.fileAssetPublishingRoleArn) !== null && _g !== void 0 ? _g : DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PUBLISHING_ROLE_ARN);
this.imageAssetPublishingRoleArn = specialize((_h = this.props.imageAssetPublishingRoleArn) !== null && _h !== void 0 ? _h : DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN);
/* eslint-enable max-len */
}
/**
* Register a File Asset.
*
* Returns the parameters that can be used to refer to the asset inside the template.
*/
addFileAsset(asset) {
_shared_1.assertBound(this.stack);
_shared_1.assertBound(this.bucketName);
const objectKey = asset.sourceHash + (asset.packaging === assets_1.FileAssetPackaging.ZIP_DIRECTORY ? '.zip' : '');
// Add to manifest
this.files[asset.sourceHash] = {
source: {
path: asset.fileName,
packaging: asset.packaging,
},
destinations: {
[this.manifestEnvName]: {
bucketName: this.bucketName,
objectKey,
region: resolvedOr(this.stack.region, undefined),
assumeRoleArn: this.fileAssetPublishingRoleArn,
assumeRoleExternalId: this.props.fileAssetPublishingExternalId,
},
},
};
const { region, urlSuffix } = stackLocationOrInstrinsics(this.stack);
const httpUrl = cfnify(`https://s3.${region}.${urlSuffix}/${this.bucketName}/${objectKey}`);
const s3ObjectUrl = cfnify(`s3://${this.bucketName}/${objectKey}`);
// Return CFN expression
return {
bucketName: cfnify(this.bucketName),
objectKey,
httpUrl,
s3ObjectUrl,
s3Url: httpUrl,
};
}
/**
* Register a Docker Image Asset.
*
* Returns the parameters that can be used to refer to the asset inside the template.
*/
addDockerImageAsset(asset) {
_shared_1.assertBound(this.stack);
_shared_1.assertBound(this.repositoryName);
const imageTag = asset.sourceHash;
// Add to manifest
this.dockerImages[asset.sourceHash] = {
source: {
directory: asset.directoryName,
dockerBuildArgs: asset.dockerBuildArgs,
dockerBuildTarget: asset.dockerBuildTarget,
dockerFile: asset.dockerFile,
},
destinations: {
[this.manifestEnvName]: {
repositoryName: this.repositoryName,
imageTag,
region: resolvedOr(this.stack.region, undefined),
assumeRoleArn: this.imageAssetPublishingRoleArn,
assumeRoleExternalId: this.props.imageAssetPublishingExternalId,
},
},
};
const { account, region, urlSuffix } = stackLocationOrInstrinsics(this.stack);
// Return CFN expression
return {
repositoryName: cfnify(this.repositoryName),
imageUri: cfnify(`${account}.dkr.ecr.${region}.${urlSuffix}/${this.repositoryName}:${imageTag}`),
};
}
/**
* Synthesize the associated stack to the session.
*/
synthesize(session) {
var _a;
_shared_1.assertBound(this.stack);
_shared_1.assertBound(this.qualifier);
// Must be done here -- if it's done in bind() (called in the Stack's constructor)
// then it will become impossible to set context after that.
//
// If it's done AFTER _synthesizeTemplate(), then the template won't contain the
// right constructs.
if ((_a = this.props.generateBootstrapVersionRule) !== null && _a !== void 0 ? _a : true) {
addBootstrapVersionRule(this.stack, MIN_BOOTSTRAP_STACK_VERSION, this.qualifier);
}
this.synthesizeStackTemplate(this.stack, session);
// Add the stack's template to the artifact manifest
const templateManifestUrl = this.addStackTemplateToAssetManifest(session);
const artifactId = this.writeAssetManifest(session);
this.emitStackArtifact(this.stack, session, {
assumeRoleArn: this._deployRoleArn,
cloudFormationExecutionRoleArn: this._cloudFormationExecutionRoleArn,
stackTemplateAssetObjectUrl: templateManifestUrl,
requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION,
additionalDependencies: [artifactId],
});
}
/**
* Returns the ARN of the deploy Role.
*/
get deployRoleArn() {
if (!this._deployRoleArn) {
throw new Error('deployRoleArn getter can only be called after the synthesizer has been bound to a Stack');
}
return this._deployRoleArn;
}
/**
* Returns the ARN of the CFN execution Role.
*/
get cloudFormationExecutionRoleArn() {
if (!this._cloudFormationExecutionRoleArn) {
throw new Error('cloudFormationExecutionRoleArn getter can only be called after the synthesizer has been bound to a Stack');
}
return this._cloudFormationExecutionRoleArn;
}
/**
*
*/
get stack() {
return this._stack;
}
/**
* Add the stack's template as one of the manifest assets
*
* This will make it get uploaded to S3 automatically by S3-assets. Return
* the manifest URL.
*
* (We can't return the location returned from `addFileAsset`, as that
* contains CloudFormation intrinsics which can't go into the manifest).
*/
addStackTemplateToAssetManifest(session) {
_shared_1.assertBound(this.stack);
const templatePath = path.join(session.assembly.outdir, this.stack.templateFile);
const template = fs.readFileSync(templatePath, { encoding: 'utf-8' });
const sourceHash = _shared_1.contentHash(template);
this.addFileAsset({
fileName: this.stack.templateFile,
packaging: assets_1.FileAssetPackaging.FILE,
sourceHash,
});
// We should technically return an 'https://s3.REGION.amazonaws.com[.cn]/name/hash' URL here,
// because that is what CloudFormation expects to see.
//
// However, there's no way for us to actually know the UrlSuffix a priori, so we can't construct it here.
//
// Instead, we'll have a protocol with the CLI that we put an 's3://.../...' URL here, and the CLI
// is going to resolve it to the correct 'https://.../' URL before it gives it to CloudFormation.
return `s3://${this.bucketName}/${sourceHash}`;
}
/**
* Write an asset manifest to the Cloud Assembly, return the artifact IDs written
*/
writeAssetManifest(session) {
_shared_1.assertBound(this.stack);
const artifactId = `${this.stack.artifactId}.assets`;
const manifestFile = `${artifactId}.json`;
const outPath = path.join(session.assembly.outdir, manifestFile);
const manifest = {
version: cxschema.Manifest.version(),
files: this.files,
dockerImages: this.dockerImages,
};
fs.writeFileSync(outPath, JSON.stringify(manifest, undefined, 2));
session.assembly.addArtifact(artifactId, {
type: cxschema.ArtifactType.ASSET_MANIFEST,
properties: {
file: manifestFile,
requiresBootstrapStackVersion: MIN_BOOTSTRAP_STACK_VERSION,
},
});
return artifactId;
}
get manifestEnvName() {
_shared_1.assertBound(this.stack);
return [
resolvedOr(this.stack.account, 'current_account'),
resolvedOr(this.stack.region, 'current_region'),
].join('-');
}
}
exports.DefaultStackSynthesizer = DefaultStackSynthesizer;
/**
* Default ARN qualifier.
*/
DefaultStackSynthesizer.DEFAULT_QUALIFIER = 'hnb659fds';
/**
* Default CloudFormation role ARN.
*/
DefaultStackSynthesizer.DEFAULT_CLOUDFORMATION_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-cfn-exec-role-${AWS::AccountId}-${AWS::Region}';
/**
* Default deploy role ARN.
*/
DefaultStackSynthesizer.DEFAULT_DEPLOY_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-deploy-role-${AWS::AccountId}-${AWS::Region}';
/**
* Default asset publishing role ARN for file (S3) assets.
*/
DefaultStackSynthesizer.DEFAULT_FILE_ASSET_PUBLISHING_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-file-publishing-role-${AWS::AccountId}-${AWS::Region}';
/**
* Default asset publishing role ARN for image (ECR) assets.
*/
DefaultStackSynthesizer.DEFAULT_IMAGE_ASSET_PUBLISHING_ROLE_ARN = 'arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-${Qualifier}-image-publishing-role-${AWS::AccountId}-${AWS::Region}';
/**
* Default image assets repository name.
*/
DefaultStackSynthesizer.DEFAULT_IMAGE_ASSETS_REPOSITORY_NAME = 'cdk-${Qualifier}-container-assets-${AWS::AccountId}-${AWS::Region}';
/**
* Default file assets bucket name.
*/
DefaultStackSynthesizer.DEFAULT_FILE_ASSETS_BUCKET_NAME = 'cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}';
/**
* Name of the CloudFormation Export with the asset key name.
*/
DefaultStackSynthesizer.DEFAULT_FILE_ASSET_KEY_ARN_EXPORT_NAME = 'CdkBootstrap-${Qualifier}-FileAssetKeyArn';
/**
* Return the given value if resolved or fall back to a default
*/
function resolvedOr(x, def) {
return token_1.Token.isUnresolved(x) ? def : x;
}
/**
* A "replace-all" function that doesn't require us escaping a literal string to a regex
*/
function replaceAll(s, search, replace) {
return s.split(search).join(replace);
}
/**
* If the string still contains placeholders, wrap it in a Fn::Sub so they will be substituted at CFN deployment time
*
* (This happens to work because the placeholders we picked map directly onto CFN
* placeholders. If they didn't we'd have to do a transformation here).
*/
function cfnify(s) {
return s.indexOf('${') > -1 ? cfn_fn_1.Fn.sub(s) : s;
}
/**
* Return the stack locations if they're concrete, or the original CFN intrisics otherwise
*
* We need to return these instead of the tokenized versions of the strings,
* since we must accept those same ${AWS::AccountId}/${AWS::Region} placeholders
* in bucket names and role names (in order to allow environment-agnostic stacks).
*
* We'll wrap a single {Fn::Sub} around the final string in order to replace everything,
* but we can't have the token system render part of the string to {Fn::Join} because
* the CFN specification doesn't allow the {Fn::Sub} template string to be an arbitrary
* expression--it must be a string literal.
*/
function stackLocationOrInstrinsics(stack) {
return {
account: resolvedOr(stack.account, '${AWS::AccountId}'),
region: resolvedOr(stack.region, '${AWS::Region}'),
urlSuffix: resolvedOr(stack.urlSuffix, '${AWS::URLSuffix}'),
};
}
/**
* Add a CfnRule to the Stack which checks the current version of the bootstrap stack this template is targeting
*
* The CLI normally checks this, but in a pipeline the CLI is not involved
* so we encode this rule into the template in a way that CloudFormation will check it.
*/
function addBootstrapVersionRule(stack, requiredVersion, qualifier) {
// Because of https://github.com/aws/aws-cdk/blob/master/packages/@aws-cdk/assert/lib/synth-utils.ts#L74
// synthesize() may be called more than once on a stack in unit tests, and the below would break
// if we execute it a second time. Guard against the constructs already existing.
if (stack.node.tryFindChild('BootstrapVersion')) {
return;
}
const param = new cfn_parameter_1.CfnParameter(stack, 'BootstrapVersion', {
type: 'AWS::SSM::Parameter::Value<String>',
description: 'Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store.',
default: `/cdk-bootstrap/${qualifier}/version`,
});
// There is no >= check in CloudFormation, so we have to check the number
// is NOT in [1, 2, 3, ... <required> - 1]
const oldVersions = range(1, requiredVersion).map(n => `${n}`);
new cfn_rule_1.CfnRule(stack, 'CheckBootstrapVersion', {
assertions: [
{
assert: cfn_fn_1.Fn.conditionNot(cfn_fn_1.Fn.conditionContains(oldVersions, param.valueAsString)),
assertDescription: `CDK bootstrap stack version ${requiredVersion} required. Please run 'cdk bootstrap' with a recent version of the CDK CLI.`,
},
],
});
}
function range(startIncl, endExcl) {
const ret = new Array();
for (let i = startIncl; i < endExcl; i++) {
ret.push(i);
}
return ret;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1zeW50aGVzaXplci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRlZmF1bHQtc3ludGhlc2l6ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3QiwyREFBMkQ7QUFDM0QseUNBQXlDO0FBQ3pDLHNDQUFxSTtBQUNySSxzQ0FBK0I7QUFDL0Isb0RBQWdEO0FBQ2hELDBDQUFzQztBQUd0QyxvQ0FBaUM7QUFDakMsdUNBQXFEO0FBQ3JELDJEQUF1RDtBQUUxQyxRQUFBLDJCQUEyQixHQUFHLGtDQUFrQyxDQUFDO0FBRTlFLDRCQUE0QjtBQUU1Qjs7R0FFRztBQUNILE1BQU0sMkJBQTJCLEdBQUcsQ0FBQyxDQUFDOzs7Ozs7Ozs7O0FBOEl0QyxNQUFhLHVCQUF3QixTQUFRLG9DQUFnQjs7OztJQXFEM0QsWUFBNkIsUUFBc0MsRUFBRTtRQUNuRSxLQUFLLEVBQUUsQ0FBQztRQURtQixVQUFLLEdBQUwsS0FBSyxDQUFtQztRQUhwRCxVQUFLLEdBQWlELEVBQUUsQ0FBQztRQUN6RCxpQkFBWSxHQUF3RCxFQUFFLENBQUM7SUFJeEYsQ0FBQzs7Ozs7O0lBRU0sSUFBSSxDQUFDLEtBQVk7O1FBQ3RCLElBQUksQ0FBQyxNQUFNLEdBQUcsS0FBSyxDQUFDO1FBRXBCLE1BQU0sU0FBUyxlQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsU0FBUyxtQ0FBSSxLQUFLLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxtQ0FBMkIsQ0FBQyxtQ0FBSSx1QkFBdUIsQ0FBQyxpQkFBaUIsQ0FBQztRQUM3SSxJQUFJLENBQUMsU0FBUyxHQUFHLFNBQVMsQ0FBQztRQUUzQiwyRUFBMkU7UUFDM0UsRUFBRTtRQUNGLGNBQWM7UUFDZCx5QkFBeUI7UUFDekIsbUZBQW1GO1FBQ25GLDhFQUE4RTtRQUM5RSxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQVMsRUFBRSxFQUFFO1lBQy9CLENBQUMsR0FBRyxVQUFVLENBQUMs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LFNBQVMsS0FBSyxDQUFDLFNBQWlCLEVBQUUsT0FBZTtJQUMvQyxNQUFNLEdBQUcsR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBQ2hDLEtBQUssSUFBSSxDQUFDLEdBQUcsU0FBUyxFQUFFLENBQUMsR0FBRyxPQUFPLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDeEMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUNiO0lBQ0QsT0FBTyxHQUFHLENBQUM7QUFDYixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIGN4c2NoZW1hIGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgRG9ja2VySW1hZ2VBc3NldExvY2F0aW9uLCBEb2NrZXJJbWFnZUFzc2V0U291cmNlLCBGaWxlQXNzZXRMb2NhdGlvbiwgRmlsZUFzc2V0UGFja2FnaW5nLCBGaWxlQXNzZXRTb3VyY2UgfSBmcm9tICcuLi9hc3NldHMnO1xuaW1wb3J0IHsgRm4gfSBmcm9tICcuLi9jZm4tZm4nO1xuaW1wb3J0IHsgQ2ZuUGFyYW1ldGVyIH0gZnJvbSAnLi4vY2ZuLXBhcmFtZXRlcic7XG5pbXBvcnQgeyBDZm5SdWxlIH0gZnJvbSAnLi4vY2ZuLXJ1bGUnO1xuaW1wb3J0IHsgSVN5bnRoZXNpc1Nlc3Npb24gfSBmcm9tICcuLi9jb25zdHJ1Y3QtY29tcGF0JztcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnLi4vc3RhY2snO1xuaW1wb3J0IHsgVG9rZW4gfSBmcm9tICcuLi90b2tlbic7XG5pbXBvcnQgeyBhc3NlcnRCb3VuZCwgY29udGVudEhhc2ggfSBmcm9tICcuL19zaGFyZWQnO1xuaW1wb3J0IHsgU3RhY2tTeW50aGVzaXplciB9IGZyb20gJy4vc3RhY2stc3ludGhlc2l6ZXInO1xuXG5leHBvcnQgY29uc3QgQk9PVFNUUkFQX1FVQUxJRklFUl9DT05URVhUID0gJ0Bhd3MtY2RrL2NvcmU6Ym9vdHN0cmFwUXVhbGlmaWVyJztcblxuLyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuXG4vKipcbiAqIFRoZSBtaW5pbXVtIGJvb3RzdHJhcCBzdGFjayB2ZXJzaW9uIHJlcXVpcmVkIGJ5IHRoaXMgYXBwLlxuICovXG5jb25zdCBNSU5fQk9PVFNUUkFQX1NUQUNLX1ZFUlNJT04gPSA0O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBpbnRlcmZhY2UgRGVmYXVsdFN0YWNrU3ludGhlc2l6ZXJQcm9wcyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGZpbGVBc3NldHNCdWNrZXROYW1lPzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGltYWdlQXNzZXRzUmVwb3NpdG9yeU5hbWU/OiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgZmlsZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4/OiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGZpbGVBc3NldFB1Ymxpc2hpbmdFeHRlcm5hbElkPzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBpbWFnZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4/OiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBpbWFnZUFzc2V0UHVibGlzaGluZ0V4dGVybmFsSWQ/OiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgZGVwbG95Um9sZUFybj86IHN0cmluZztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Sb2xlPzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBmaWxlQXNzZXRLZXlBcm5FeHBvcnROYW1lPzogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IHF1YWxpZmllcj86IHN0cmluZztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHJlYWRvbmx5IGdlbmVyYXRlQm9vdHN0cmFwVmVyc2lvblJ1bGU/OiBib29sZWFuO1xufVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBjbGFzcyBEZWZhdWx0U3RhY2tTeW50aGVzaXplciBleHRlbmRzIFN0YWNrU3ludGhlc2l6ZXIge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX1FVQUxJRklFUiA9ICdobmI2NTlmZHMnO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9DTE9VREZPUk1BVElPTl9ST0xFX0FSTiA9ICdhcm46JHtBV1M6OlBhcnRpdGlvbn06aWFtOjoke0FXUzo6QWNjb3VudElkfTpyb2xlL2Nkay0ke1F1YWxpZmllcn0tY2ZuLWV4ZWMtcm9sZS0ke0FXUzo6QWNjb3VudElkfS0ke0FXUzo6UmVnaW9ufSc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9ERVBMT1lfUk9MRV9BUk4gPSAnYXJuOiR7QVdTOjpQYXJ0aXRpb259OmlhbTo6JHtBV1M6OkFjY291bnRJZH06cm9sZS9jZGstJHtRdWFsaWZpZXJ9LWRlcGxveS1yb2xlLSR7QVdTOjpBY2NvdW50SWR9LSR7QVdTOjpSZWdpb259JztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9GSUxFX0FTU0VUX1BVQkxJU0hJTkdfUk9MRV9BUk4gPSAnYXJuOiR7QVdTOjpQYXJ0aXRpb259OmlhbTo6JHtBV1M6OkFjY291bnRJZH06cm9sZS9jZGstJHtRdWFsaWZpZXJ9LWZpbGUtcHVibGlzaGluZy1yb2xlLSR7QVdTOjpBY2NvdW50SWR9LSR7QVdTOjpSZWdpb259JztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX0lNQUdFX0FTU0VUX1BVQkxJU0hJTkdfUk9MRV9BUk4gPSAnYXJuOiR7QVdTOjpQYXJ0aXRpb259OmlhbTo6JHtBV1M6OkFjY291bnRJZH06cm9sZS9jZGstJHtRdWFsaWZpZXJ9LWltYWdlLXB1Ymxpc2hpbmctcm9sZS0ke0FXUzo6QWNjb3VudElkfS0ke0FXUzo6UmVnaW9ufSc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9JTUFHRV9BU1NFVFNfUkVQT1NJVE9SWV9OQU1FID0gJ2Nkay0ke1F1YWxpZmllcn0tY29udGFpbmVyLWFzc2V0cy0ke0FXUzo6QWNjb3VudElkfS0ke0FXUzo6UmVnaW9ufSc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfRklMRV9BU1NFVFNfQlVDS0VUX05BTUUgPSAnY2RrLSR7UXVhbGlmaWVyfS1hc3NldHMtJHtBV1M6OkFjY291bnRJZH0tJHtBV1M6OlJlZ2lvbn0nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IERFRkFVTFRfRklMRV9BU1NFVF9LRVlfQVJOX0VYUE9SVF9OQU1FID0gJ0Nka0Jvb3RzdHJhcC0ke1F1YWxpZmllcn0tRmlsZUFzc2V0S2V5QXJuJztcblxuICBwcml2YXRlIF9zdGFjaz86IFN0YWNrO1xuICBwcml2YXRlIGJ1Y2tldE5hbWU/OiBzdHJpbmc7XG4gIHByaXZhdGUgcmVwb3NpdG9yeU5hbWU/OiBzdHJpbmc7XG4gIHByaXZhdGUgX2RlcGxveVJvbGVBcm4/OiBzdHJpbmc7XG4gIHByaXZhdGUgX2Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUm9sZUFybj86IHN0cmluZztcbiAgcHJpdmF0ZSBmaWxlQXNzZXRQdWJsaXNoaW5nUm9sZUFybj86IHN0cmluZztcbiAgcHJpdmF0ZSBpbWFnZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4/OiBzdHJpbmc7XG4gIHByaXZhdGUgcXVhbGlmaWVyPzogc3RyaW5nO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgZmlsZXM6IE5vbk51bGxhYmxlPGN4c2NoZW1hLkFzc2V0TWFuaWZlc3RbJ2ZpbGVzJ10+ID0ge307XG4gIHByaXZhdGUgcmVhZG9ubHkgZG9ja2VySW1hZ2VzOiBOb25OdWxsYWJsZTxjeHNjaGVtYS5Bc3NldE1hbmlmZXN0Wydkb2NrZXJJbWFnZXMnXT4gPSB7fTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHByb3BzOiBEZWZhdWx0U3RhY2tTeW50aGVzaXplclByb3BzID0ge30pIHtcbiAgICBzdXBlcigpO1xuICB9XG5cbiAgcHVibGljIGJpbmQoc3RhY2s6IFN0YWNrKTogdm9pZCB7XG4gICAgdGhpcy5fc3RhY2sgPSBzdGFjaztcblxuICAgIGNvbnN0IHF1YWxpZmllciA9IHRoaXMucHJvcHMucXVhbGlmaWVyID8/IHN0YWNrLm5vZGUudHJ5R2V0Q29udGV4dChCT09UU1RSQVBfUVVBTElGSUVSX0NPTlRFWFQpID8/IERlZmF1bHRTdGFja1N5bnRoZXNpemVyLkRFRkFVTFRfUVVBTElGSUVSO1xuICAgIHRoaXMucXVhbGlmaWVyID0gcXVhbGlmaWVyO1xuXG4gICAgLy8gRnVuY3Rpb24gdG8gcmVwbGFjZSBwbGFjZWhvbGRlcnMgaW4gdGhlIGlucHV0IHN0cmluZyBhcyBtdWNoIGFzIHBvc3NpYmxlXG4gICAgLy9cbiAgICAvLyBXZSByZXBsYWNlOlxuICAgIC8vIC0gJHtRdWFsaWZpZXJ9OiBhbHdheXNcbiAgICAvLyAtICR7QVdTOjpBY2NvdW50SWR9LCAke0FXUzo6UmVnaW9ufTogb25seSBpZiB3ZSBoYXZlIHRoZSBhY3R1YWwgdmFsdWVzIGF2YWlsYWJsZVxuICAgIC8vIC0gJHtBV1M6OlBhcnRpdGlvbn06IG5ldmVyLCBzaW5jZSB3ZSBuZXZlciBoYXZlIHRoZSBhY3R1YWwgcGFydGl0aW9uIHZhbHVlLlxuICAgIGNvbnN0IHNwZWNpYWxpemUgPSAoczogc3RyaW5nKSA9PiB7XG4gICAgICBzID0gcmVwbGFjZUFsbChzLCAnJHtRdWFsaWZpZXJ9JywgcXVhbGlmaWVyKTtcbiAgICAgIHJldHVybiBjeGFwaS5FbnZpcm9ubWVudFBsYWNlaG9sZGVycy5yZXBsYWNlKHMsIHtcbiAgICAgICAgcmVnaW9uOiByZXNvbHZlZE9yKHN0YWNrLnJlZ2lvbiwgY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMuQ1VSUkVOVF9SRUdJT04pLFxuICAgICAgICBhY2NvdW50SWQ6IHJlc29sdmVkT3Ioc3RhY2suYWNjb3VudCwgY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMuQ1VSUkVOVF9BQ0NPVU5UKSxcbiAgICAgICAgcGFydGl0aW9uOiBjeGFwaS5FbnZpcm9ubWVudFBsYWNlaG9sZGVycy5DVVJSRU5UX1BBUlRJVElPTixcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKiBlc2xpbnQtZGlzYWJsZSBtYXgtbGVuICovXG4gICAgdGhpcy5idWNrZXROYW1lID0gc3BlY2lhbGl6ZSh0aGlzLnByb3BzLmZpbGVBc3NldHNCdWNrZXROYW1lID8/IERlZmF1bHRTdGFja1N5bnRoZXNpemVyLkRFRkFVTFRfRklMRV9BU1NFVFNfQlVDS0VUX05BTUUpO1xuICAgIHRoaXMucmVwb3NpdG9yeU5hbWUgPSBzcGVjaWFsaXplKHRoaXMucHJvcHMuaW1hZ2VBc3NldHNSZXBvc2l0b3J5TmFtZSA/PyBEZWZhdWx0U3RhY2tTeW50aGVzaXplci5ERUZBVUxUX0lNQUdFX0FTU0VUU19SRVBPU0lUT1JZX05BTUUpO1xuICAgIHRoaXMuX2RlcGxveVJvbGVBcm4gPSBzcGVjaWFsaXplKHRoaXMucHJvcHMuZGVwbG95Um9sZUFybiA/PyBEZWZhdWx0U3RhY2tTeW50aGVzaXplci5ERUZBVUxUX0RFUExPWV9ST0xFX0FSTik7XG4gICAgdGhpcy5fY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Sb2xlQXJuID0gc3BlY2lhbGl6ZSh0aGlzLnByb3BzLmNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUm9sZSA/PyBEZWZhdWx0U3RhY2tTeW50aGVzaXplci5ERUZBVUxUX0NMT1VERk9STUFUSU9OX1JPTEVfQVJOKTtcbiAgICB0aGlzLmZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuID0gc3BlY2lhbGl6ZSh0aGlzLnByb3BzLmZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuID8/IERlZmF1bHRTdGFja1N5bnRoZXNpemVyLkRFRkFVTFRfRklMRV9BU1NFVF9QVUJMSVNISU5HX1JPTEVfQVJOKTtcbiAgICB0aGlzLmltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybiA9IHNwZWNpYWxpemUodGhpcy5wcm9wcy5pbWFnZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4gPz8gRGVmYXVsdFN0YWNrU3ludGhlc2l6ZXIuREVGQVVMVF9JTUFHRV9BU1NFVF9QVUJMSVNISU5HX1JPTEVfQVJOKTtcbiAgICAvKiBlc2xpbnQtZW5hYmxlIG1heC1sZW4gKi9cbiAgfVxuXG4gIHB1YmxpYyBhZGRGaWxlQXNzZXQoYXNzZXQ6IEZpbGVBc3NldFNvdXJjZSk6IEZpbGVBc3NldExvY2F0aW9uIHtcbiAgICBhc3NlcnRCb3VuZCh0aGlzLnN0YWNrKTtcbiAgICBhc3NlcnRCb3VuZCh0aGlzLmJ1Y2tldE5hbWUpO1xuXG4gICAgY29uc3Qgb2JqZWN0S2V5ID0gYXNzZXQuc291cmNlSGFzaCArIChhc3NldC5wYWNrYWdpbmcgPT09IEZpbGVBc3NldFBhY2thZ2luZy5aSVBfRElSRUNUT1JZID8gJy56aXAnIDogJycpO1xuXG4gICAgLy8gQWRkIHRvIG1hbmlmZXN0XG4gICAgdGhpcy5maWxlc1thc3NldC5zb3VyY2VIYXNoXSA9IHtcbiAgICAgIHNvdXJjZToge1xuICAgICAgICBwYXRoOiBhc3NldC5maWxlTmFtZSxcbiAgICAgICAgcGFja2FnaW5nOiBhc3NldC5wYWNrYWdpbmcsXG4gICAgICB9LFxuICAgICAgZGVzdGluYXRpb25zOiB7XG4gICAgICAgIFt0aGlzLm1hbmlmZXN0RW52TmFtZV06IHtcbiAgICAgICAgICBidWNrZXROYW1lOiB0aGlzLmJ1Y2tldE5hbWUsXG4gICAgICAgICAgb2JqZWN0S2V5LFxuICAgICAgICAgIHJlZ2lvbjogcmVzb2x2ZWRPcih0aGlzLnN0YWNrLnJlZ2lvbiwgdW5kZWZpbmVkKSxcbiAgICAgICAgICBhc3N1bWVSb2xlQXJuOiB0aGlzLmZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuLFxuICAgICAgICAgIGFzc3VtZVJvbGVFeHRlcm5hbElkOiB0aGlzLnByb3BzLmZpbGVBc3NldFB1Ymxpc2hpbmdFeHRlcm5hbElkLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgY29uc3QgeyByZWdpb24sIHVybFN1ZmZpeCB9ID0gc3RhY2tMb2NhdGlvbk9ySW5zdHJpbnNpY3ModGhpcy5zdGFjayk7XG4gICAgY29uc3QgaHR0cFVybCA9IGNmbmlmeShgaHR0cHM6Ly9zMy4ke3JlZ2lvbn0uJHt1cmxTdWZmaXh9LyR7dGhpcy5idWNrZXROYW1lfS8ke29iamVjdEtleX1gKTtcbiAgICBjb25zdCBzM09iamVjdFVybCA9IGNmbmlmeShgczM6Ly8ke3RoaXMuYnVja2V0TmFtZX0vJHtvYmplY3RLZXl9YCk7XG5cbiAgICAvLyBSZXR1cm4gQ0ZOIGV4cHJlc3Npb25cbiAgICByZXR1cm4ge1xuICAgICAgYnVja2V0TmFtZTogY2ZuaWZ5KHRoaXMuYnVja2V0TmFtZSksXG4gICAgICBvYmplY3RLZXksXG4gICAgICBodHRwVXJsLFxuICAgICAgczNPYmplY3RVcmwsXG4gICAgICBzM1VybDogaHR0cFVybCxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGFkZERvY2tlckltYWdlQXNzZXQoYXNzZXQ6IERvY2tlckltYWdlQXNzZXRTb3VyY2UpOiBEb2NrZXJJbWFnZUFzc2V0TG9jYXRpb24ge1xuICAgIGFzc2VydEJvdW5kKHRoaXMuc3RhY2spO1xuICAgIGFzc2VydEJvdW5kKHRoaXMucmVwb3NpdG9yeU5hbWUpO1xuXG4gICAgY29uc3QgaW1hZ2VUYWcgPSBhc3NldC5zb3VyY2VIYXNoO1xuXG4gICAgLy8gQWRkIHRvIG1hbmlmZXN0XG4gICAgdGhpcy5kb2NrZXJJbWFnZXNbYXNzZXQuc291cmNlSGFzaF0gPSB7XG4gICAgICBzb3VyY2U6IHtcbiAgICAgICAgZGlyZWN0b3J5OiBhc3NldC5kaXJlY3RvcnlOYW1lLFxuICAgICAgICBkb2NrZXJCdWlsZEFyZ3M6IGFzc2V0LmRvY2tlckJ1aWxkQXJncyxcbiAgICAgICAgZG9ja2VyQnVpbGRUYXJnZXQ6IGFzc2V0LmRvY2tlckJ1aWxkVGFyZ2V0LFxuICAgICAgICBkb2NrZXJGaWxlOiBhc3NldC5kb2NrZXJGaWxlLFxuICAgICAgfSxcbiAgICAgIGRlc3RpbmF0aW9uczoge1xuICAgICAgICBbdGhpcy5tYW5pZmVzdEVudk5hbWVdOiB7XG4gICAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHRoaXMucmVwb3NpdG9yeU5hbWUsXG4gICAgICAgICAgaW1hZ2VUYWcsXG4gICAgICAgICAgcmVnaW9uOiByZXNvbHZlZE9yKHRoaXMuc3RhY2sucmVnaW9uLCB1bmRlZmluZWQpLFxuICAgICAgICAgIGFzc3VtZVJvbGVBcm46IHRoaXMuaW1hZ2VBc3NldFB1Ymxpc2hpbmdSb2xlQXJuLFxuICAgICAgICAgIGFzc3VtZVJvbGVFeHRlcm5hbElkOiB0aGlzLnByb3BzLmltYWdlQXNzZXRQdWJsaXNoaW5nRXh0ZXJuYWxJZCxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIGNvbnN0IHsgYWNjb3VudCwgcmVnaW9uLCB1cmxTdWZmaXggfSA9IHN0YWNrTG9jYXRpb25Pckluc3RyaW5zaWNzKHRoaXMuc3RhY2spO1xuXG4gICAgLy8gUmV0dXJuIENGTiBleHByZXNzaW9uXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcG9zaXRvcnlOYW1lOiBjZm5pZnkodGhpcy5yZXBvc2l0b3J5TmFtZSksXG4gICAgICBpbWFnZVVyaTogY2ZuaWZ5KGAke2FjY291bnR9LmRrci5lY3IuJHtyZWdpb259LiR7dXJsU3VmZml4fS8ke3RoaXMucmVwb3NpdG9yeU5hbWV9OiR7aW1hZ2VUYWd9YCksXG4gICAgfTtcbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN5bnRoZXNpemUoc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24pOiB2b2lkIHtcbiAgICBhc3NlcnRCb3VuZCh0aGlzLnN0YWNrKTtcbiAgICBhc3NlcnRCb3VuZCh0aGlzLnF1YWxpZmllcik7XG5cbiAgICAvLyBNdXN0IGJlIGRvbmUgaGVyZSAtLSBpZiBpdCdzIGRvbmUgaW4gYmluZCgpIChjYWxsZWQgaW4gdGhlIFN0YWNrJ3MgY29uc3RydWN0b3IpXG4gICAgLy8gdGhlbiBpdCB3aWxsIGJlY29tZSBpbXBvc3NpYmxlIHRvIHNldCBjb250ZXh0IGFmdGVyIHRoYXQuXG4gICAgLy9cbiAgICAvLyBJZiBpdCdzIGRvbmUgQUZURVIgX3N5bnRoZXNpemVUZW1wbGF0ZSgpLCB0aGVuIHRoZSB0ZW1wbGF0ZSB3b24ndCBjb250YWluIHRoZVxuICAgIC8vIHJpZ2h0IGNvbnN0cnVjdHMuXG4gICAgaWYgKHRoaXMucHJvcHMuZ2VuZXJhdGVCb290c3RyYXBWZXJzaW9uUnVsZSA/PyB0cnVlKSB7XG4gICAgICBhZGRCb290c3RyYXBWZXJzaW9uUnVsZSh0aGlzLnN0YWNrLCBNSU5fQk9PVFNUUkFQX1NUQUNLX1ZFUlNJT04sIHRoaXMucXVhbGlmaWVyKTtcbiAgICB9XG5cbiAgICB0aGlzLnN5bnRoZXNpemVTdGFja1RlbXBsYXRlKHRoaXMuc3RhY2ssIHNlc3Npb24pO1xuXG4gICAgLy8gQWRkIHRoZSBzdGFjaydzIHRlbXBsYXRlIHRvIHRoZSBhcnRpZmFjdCBtYW5pZmVzdFxuICAgIGNvbnN0IHRlbXBsYXRlTWFuaWZlc3RVcmwgPSB0aGlzLmFkZFN0YWNrVGVtcGxhdGVUb0Fzc2V0TWFuaWZlc3Qoc2Vzc2lvbik7XG5cbiAgICBjb25zdCBhcnRpZmFjdElkID0gdGhpcy53cml0ZUFzc2V0TWFuaWZlc3Qoc2Vzc2lvbik7XG5cbiAgICB0aGlzLmVtaXRTdGFja0FydGlmYWN0KHRoaXMuc3RhY2ssIHNlc3Npb24sIHtcbiAgICAgIGFzc3VtZVJvbGVBcm46IHRoaXMuX2RlcGxveVJvbGVBcm4sXG4gICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblJvbGVBcm46IHRoaXMuX2Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUm9sZUFybixcbiAgICAgIHN0YWNrVGVtcGxhdGVBc3NldE9iamVjdFVybDogdGVtcGxhdGVNYW5pZmVzdFVybCxcbiAgICAgIHJlcXVpcmVzQm9vdHN0cmFwU3RhY2tWZXJzaW9uOiBNSU5fQk9PVFNUUkFQX1NUQUNLX1ZFUlNJT04sXG4gICAgICBhZGRpdGlvbmFsRGVwZW5kZW5jaWVzOiBbYXJ0aWZhY3RJZF0sXG4gICAgfSk7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgZ2V0IGRlcGxveVJvbGVBcm4oKTogc3RyaW5nIHtcbiAgICBpZiAoIXRoaXMuX2RlcGxveVJvbGVBcm4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignZGVwbG95Um9sZUFybiBnZXR0ZXIgY2FuIG9ubHkgYmUgY2FsbGVkIGFmdGVyIHRoZSBzeW50aGVzaXplciBoYXMgYmVlbiBib3VuZCB0byBhIFN0YWNrJyk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLl9kZXBsb3lSb2xlQXJuO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBnZXQgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Sb2xlQXJuKCk6IHN0cmluZyB7XG4gICAgaWYgKCF0aGlzLl9jbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblJvbGVBcm4pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Sb2xlQXJuIGdldHRlciBjYW4gb25seSBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHN5bnRoZXNpemVyIGhhcyBiZWVuIGJvdW5kIHRvIGEgU3RhY2snKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUm9sZUFybjtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgc3RhY2soKTogU3RhY2sgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9zdGFjaztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgdGhlIHN0YWNrJ3MgdGVtcGxhdGUgYXMgb25lIG9mIHRoZSBtYW5pZmVzdCBhc3NldHNcbiAgICpcbiAgICogVGhpcyB3aWxsIG1ha2UgaXQgZ2V0IHVwbG9hZGVkIHRvIFMzIGF1dG9tYXRpY2FsbHkgYnkgUzMtYXNzZXRzLiBSZXR1cm5cbiAgICogdGhlIG1hbmlmZXN0IFVSTC5cbiAgICpcbiAgICogKFdlIGNhbid0IHJldHVybiB0aGUgbG9jYXRpb24gcmV0dXJuZWQgZnJvbSBgYWRkRmlsZUFzc2V0YCwgYXMgdGhhdFxuICAgKiBjb250YWlucyBDbG91ZEZvcm1hdGlvbiBpbnRyaW5zaWNzIHdoaWNoIGNhbid0IGdvIGludG8gdGhlIG1hbmlmZXN0KS5cbiAgICovXG4gIHByaXZhdGUgYWRkU3RhY2tUZW1wbGF0ZVRvQXNzZXRNYW5pZmVzdChzZXNzaW9uOiBJU3ludGhlc2lzU2Vzc2lvbikge1xuICAgIGFzc2VydEJvdW5kKHRoaXMuc3RhY2spO1xuXG4gICAgY29uc3QgdGVtcGxhdGVQYXRoID0gcGF0aC5qb2luKHNlc3Npb24uYXNzZW1ibHkub3V0ZGlyLCB0aGlzLnN0YWNrLnRlbXBsYXRlRmlsZSk7XG4gICAgY29uc3QgdGVtcGxhdGUgPSBmcy5yZWFkRmlsZVN5bmModGVtcGxhdGVQYXRoLCB7IGVuY29kaW5nOiAndXRmLTgnIH0pO1xuXG4gICAgY29uc3Qgc291cmNlSGFzaCA9IGNvbnRlbnRIYXNoKHRlbXBsYXRlKTtcblxuICAgIHRoaXMuYWRkRmlsZUFzc2V0KHtcbiAgICAgIGZpbGVOYW1lOiB0aGlzLnN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICAgIHBhY2thZ2luZzogRmlsZUFzc2V0UGFja2FnaW5nLkZJTEUsXG4gICAgICBzb3VyY2VIYXNoLFxuICAgIH0pO1xuXG4gICAgLy8gV2Ugc2hvdWxkIHRlY2huaWNhbGx5IHJldHVybiBhbiAnaHR0cHM6Ly9zMy5SRUdJT04uYW1hem9uYXdzLmNvbVsuY25dL25hbWUvaGFzaCcgVVJMIGhlcmUsXG4gICAgLy8gYmVjYXVzZSB0aGF0IGlzIHdoYXQgQ2xvdWRGb3JtYXRpb24gZXhwZWN0cyB0byBzZWUuXG4gICAgLy9cbiAgICAvLyBIb3dldmVyLCB0aGVyZSdzIG5vIHdheSBmb3IgdXMgdG8gYWN0dWFsbHkga25vdyB0aGUgVXJsU3VmZml4IGEgcHJpb3JpLCBzbyB3ZSBjYW4ndCBjb25zdHJ1Y3QgaXQgaGVyZS5cbiAgICAvL1xuICAgIC8vIEluc3RlYWQsIHdlJ2xsIGhhdmUgYSBwcm90b2NvbCB3aXRoIHRoZSBDTEkgdGhhdCB3ZSBwdXQgYW4gJ3MzOi8vLi4uLy4uLicgVVJMIGhlcmUsIGFuZCB0aGUgQ0xJXG4gICAgLy8gaXMgZ29pbmcgdG8gcmVzb2x2ZSBpdCB0byB0aGUgY29ycmVjdCAnaHR0cHM6Ly8uLi4vJyBVUkwgYmVmb3JlIGl0IGdpdmVzIGl0IHRvIENsb3VkRm9ybWF0aW9uLlxuICAgIHJldHVybiBgczM6Ly8ke3RoaXMuYnVja2V0TmFtZX0vJHtzb3VyY2VIYXNofWA7XG4gIH1cblxuICAvKipcbiAgICogV3JpdGUgYW4gYXNzZXQgbWFuaWZlc3QgdG8gdGhlIENsb3VkIEFzc2VtYmx5LCByZXR1cm4gdGhlIGFydGlmYWN0IElEcyB3cml0dGVuXG4gICAqL1xuICBwcml2YXRlIHdyaXRlQXNzZXRNYW5pZmVzdChzZXNzaW9uOiBJU3ludGhlc2lzU2Vzc2lvbik6IHN0cmluZyB7XG4gICAgYXNzZXJ0Qm91bmQodGhpcy5zdGFjayk7XG5cbiAgICBjb25zdCBhcnRpZmFjdElkID0gYCR7dGhpcy5zdGFjay5hcnRpZmFjdElkfS5hc3NldHNgO1xuICAgIGNvbnN0IG1hbmlmZXN0RmlsZSA9IGAke2FydGlmYWN0SWR9Lmpzb25gO1xuICAgIGNvbnN0IG91dFBhdGggPSBwYXRoLmpvaW4oc2Vzc2lvbi5hc3NlbWJseS5vdXRkaXIsIG1hbmlmZXN0RmlsZSk7XG5cbiAgICBjb25zdCBtYW5pZmVzdDogY3hzY2hlbWEuQXNzZXRNYW5pZmVzdCA9IHtcbiAgICAgIHZlcnNpb246IGN4c2NoZW1hLk1hbmlmZXN0LnZlcnNpb24oKSxcbiAgICAgIGZpbGVzOiB0aGlzLmZpbGVzLFxuICAgICAgZG9ja2VySW1hZ2VzOiB0aGlzLmRvY2tlckltYWdlcyxcbiAgICB9O1xuXG4gICAgZnMud3JpdGVGaWxlU3luYyhvdXRQYXRoLCBKU09OLnN0cmluZ2lmeShtYW5pZmVzdCwgdW5kZWZpbmVkLCAyKSk7XG4gICAgc2Vzc2lvbi5hc3NlbWJseS5hZGRBcnRpZmFjdChhcnRpZmFjdElkLCB7XG4gICAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVNTRVRfTUFOSUZFU1QsXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGZpbGU6IG1hbmlmZXN0RmlsZSxcbiAgICAgICAgcmVxdWlyZXNCb290c3RyYXBTdGFja1ZlcnNpb246IE1JTl9CT09UU1RSQVBfU1RBQ0tfVkVSU0lPTixcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICByZXR1cm4gYXJ0aWZhY3RJZDtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0IG1hbmlmZXN0RW52TmFtZSgpOiBzdHJpbmcge1xuICAgIGFzc2VydEJvdW5kKHRoaXMuc3RhY2spO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgIHJlc29sdmVkT3IodGhpcy5zdGFjay5hY2NvdW50LCAnY3VycmVudF9hY2NvdW50JyksXG4gICAgICByZXN