UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

364 lines 54.7 kB
"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