UNPKG

cdk-bootstrapless-synthesizer

Version:

Generate directly usable AWS CloudFormation template with aws-cdk v2.

357 lines 53.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __exportStar = (this && this.__exportStar) || function(m, exports) { for (var p in m) if (p !== "default" && !exports.hasOwnProperty(p)) __createBinding(exports, m, p); }; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.BootstraplessStackSynthesizer = exports.ImageAssetTagSuffixType = void 0; const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const fs = require("fs"); const path = require("path"); const aws_cdk_lib_1 = require("aws-cdk-lib"); const cxschema = require("aws-cdk-lib/cloud-assembly-schema"); const cxapi = require("aws-cdk-lib/cx-api"); __exportStar(require("./aspect"), exports); const REGION_PLACEHOLDER = '${AWS::Region}'; const ERR_MSG_CALL_BIND_FIRST = 'You must call bind() first'; var ImageAssetTagSuffixType; (function (ImageAssetTagSuffixType) { ImageAssetTagSuffixType["NONE"] = "NONE"; ImageAssetTagSuffixType["HASH"] = "HASH"; })(ImageAssetTagSuffixType = exports.ImageAssetTagSuffixType || (exports.ImageAssetTagSuffixType = {})); /** * A Bootstrapless stack synthesizer that is designated to generate templates * that can be directly used by Cloudformation */ class BootstraplessStackSynthesizer extends aws_cdk_lib_1.StackSynthesizer { constructor(props = {}) { super(); this.files = {}; this.dockerImages = {}; const { BSS_FILE_ASSET_BUCKET_NAME, BSS_IMAGE_ASSET_REPOSITORY_NAME, BSS_FILE_ASSET_PUBLISHING_ROLE_ARN, BSS_IMAGE_ASSET_PUBLISHING_ROLE_ARN, BSS_FILE_ASSET_PREFIX, BSS_FILE_ASSET_REGION_SET, BSS_TEMPLATE_BUCKET_NAME, BSS_IMAGE_ASSET_TAG_PREFIX, BSS_IMAGE_ASSET_TAG_SUFFIX_TYPE, BSS_IMAGE_ASSET_REGION_SET, BSS_IMAGE_ASSET_ACCOUNT_ID, } = process.env; /* eslint-disable max-len */ this.bucketName = props.fileAssetBucketName ?? BSS_FILE_ASSET_BUCKET_NAME; this.repositoryName = props.imageAssetRepositoryName ?? BSS_IMAGE_ASSET_REPOSITORY_NAME; this.fileAssetPublishingRoleArn = props.fileAssetPublishingRoleArn ?? BSS_FILE_ASSET_PUBLISHING_ROLE_ARN; this.imageAssetPublishingRoleArn = props.imageAssetPublishingRoleArn ?? BSS_IMAGE_ASSET_PUBLISHING_ROLE_ARN; this.fileAssetPrefix = props.fileAssetPrefix ?? BSS_FILE_ASSET_PREFIX; this.fileAssetRegionSet = props.fileAssetRegionSet ?? commaSplit(BSS_FILE_ASSET_REGION_SET); this.templateBucketName = props.templateBucketName ?? BSS_TEMPLATE_BUCKET_NAME; this.imageAssetTagPrefix = (props.imageAssetTagPrefix ?? BSS_IMAGE_ASSET_TAG_PREFIX) ?? ''; this.imageAssetTagSuffixType = validateImageAssetTagSuffixType((props.imageAssetTagSuffixType ?? BSS_IMAGE_ASSET_TAG_SUFFIX_TYPE) ?? ImageAssetTagSuffixType.HASH); this.imageAssetRegionSet = props.imageAssetRegionSet ?? commaSplit(BSS_IMAGE_ASSET_REGION_SET); this.imageAssetAccountId = props.imageAssetAccountId ?? BSS_IMAGE_ASSET_ACCOUNT_ID; /* eslint-enable max-len */ } bind(stack) { if (this._stack !== undefined) { throw new Error('A StackSynthesizer can only be used for one Stack: create a new instance to use with a different Stack'); } this._stack = stack; // Function to replace placeholders in the input string as much as possible // // We replace: // - ${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) => { if (s === undefined) { return undefined; } 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(this.bucketName); this.repositoryName = specialize(this.repositoryName); this.fileAssetPublishingRoleArn = specialize(this.fileAssetPublishingRoleArn); this.imageAssetPublishingRoleArn = specialize(this.imageAssetPublishingRoleArn); this.fileAssetPrefix = specialize(this.fileAssetPrefix ?? ''); /* eslint-enable max-len */ } addFileAsset(asset) { return this._addFileAsset(asset); } _addFileAsset(asset, overrideBucketname) { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); assertNotNull(this.bucketName, 'The bucketName is null'); validateFileAssetSource(asset); const bucketName = overrideBucketname ?? this.bucketName; const objectKey = this.fileAssetPrefix + asset.sourceHash + (asset.packaging === aws_cdk_lib_1.FileAssetPackaging.ZIP_DIRECTORY ? '.zip' : ''); const destinations = {}; if (this.fileAssetRegionSet?.length && bucketName.includes(REGION_PLACEHOLDER)) { for (const region of this.fileAssetRegionSet.map(r => r.trim())) { if (!region) { continue; } destinations[region] = { bucketName: replaceAll(bucketName, REGION_PLACEHOLDER, region), objectKey, region, assumeRoleArn: this.fileAssetPublishingRoleArn, }; } } else { destinations[this.manifestEnvName] = { bucketName, objectKey, region: resolvedOr(this.stack.region, trim(head(this.fileAssetRegionSet))), assumeRoleArn: this.fileAssetPublishingRoleArn, }; } // Add to manifest this.files[asset.sourceHash] = { source: { path: asset.fileName, packaging: asset.packaging, }, destinations, }; const { region, urlSuffix } = stackLocationOrInstrinsics(this.stack); const httpUrl = cfnify(`https://s3.${region}.${urlSuffix}/${bucketName}/${objectKey}`); const s3ObjectUrl = cfnify(`s3://${bucketName}/${objectKey}`); // Return CFN expression return { bucketName: cfnify(bucketName), objectKey, httpUrl, s3ObjectUrl, }; } addDockerImageAsset(asset) { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); assertNotNull(this.repositoryName, 'The repositoryName is null'); validateDockerImageAssetSource(asset); let imageTag = this.imageAssetTagPrefix; if (this.imageAssetTagSuffixType === ImageAssetTagSuffixType.HASH) { imageTag = this.imageAssetTagPrefix + asset.sourceHash; } const destinations = {}; if (this.imageAssetRegionSet?.length) { for (const region of this.imageAssetRegionSet.map(r => r.trim())) { if (!region) { continue; } destinations[region] = { repositoryName: this.repositoryName, imageTag, region, assumeRoleArn: this.fileAssetPublishingRoleArn, }; } } else { destinations[this.manifestEnvName] = { repositoryName: this.repositoryName, imageTag, region: resolvedOr(this.stack.region, undefined), assumeRoleArn: this.imageAssetPublishingRoleArn, }; } // Add to manifest this.dockerImages[asset.sourceHash] = { source: { directory: asset.directoryName, dockerBuildArgs: asset.dockerBuildArgs, dockerBuildTarget: asset.dockerBuildTarget, dockerFile: asset.dockerFile, }, destinations, }; let { account, urlSuffix } = stackLocationOrInstrinsics(this.stack); account = this.imageAssetAccountId ?? account; return { repositoryName: cfnify(this.repositoryName), imageUri: cfnify(`${account}.dkr.ecr.${REGION_PLACEHOLDER}.${urlSuffix}/${this.repositoryName}:${imageTag}`), }; } /** * Dumps current manifest into JSON format */ dumps() { const manifest = { version: cxschema.Manifest.version(), files: this.files, dockerImages: this.dockerImages, }; return JSON.stringify(manifest, undefined, 2); } /** * Synthesize the associated stack to the session */ synthesize(session) { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); 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, { stackTemplateAssetObjectUrl: templateManifestUrl, additionalDependencies: [artifactId], }); } 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(_) { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); const sourceHash = this.stack.templateFile; this._addFileAsset({ fileName: this.stack.templateFile, packaging: aws_cdk_lib_1.FileAssetPackaging.FILE, sourceHash, }, this.templateBucketName); // 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) { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); const artifactId = `${this.stack.artifactId}.assets`; const manifestFile = `${artifactId}.json`; const outPath = path.join(session.assembly.outdir, manifestFile); fs.writeFileSync(outPath, this.dumps()); session.assembly.addArtifact(artifactId, { type: cxschema.ArtifactType.ASSET_MANIFEST, properties: { file: manifestFile, }, }); return artifactId; } get manifestEnvName() { assertNotNull(this.stack, ERR_MSG_CALL_BIND_FIRST); return [ resolvedOr(this.stack.account, 'current_account'), resolvedOr(this.stack.region, 'current_region'), ].join('-'); } } exports.BootstraplessStackSynthesizer = BootstraplessStackSynthesizer; _a = JSII_RTTI_SYMBOL_1; BootstraplessStackSynthesizer[_a] = { fqn: "cdk-bootstrapless-synthesizer.BootstraplessStackSynthesizer", version: "2.3.2" }; /** * Return the given value if resolved or fall back to a default */ function resolvedOr(x, def) { return aws_cdk_lib_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 ? aws_cdk_lib_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}'), }; } // function range(startIncl: number, endExcl: number) { // const ret = new Array<number>(); // for (let i = startIncl; i < endExcl; i++) { // ret.push(i); // } // return ret; // } function assertNotNull(x, msg = 'Null value error') { if (x === null || x === undefined) { throw new Error(msg); } } function commaSplit(v) { if (v) { return v.split(','); } return undefined; } function validateImageAssetTagSuffixType(s) { if (!Object.values(ImageAssetTagSuffixType).includes(s)) { throw new Error(`Invalid ImageAssetTagSuffixType: ${s}, must be in ${Object.values(ImageAssetTagSuffixType)}`); } return s; } function validateFileAssetSource(asset) { if (!!asset.executable === !!asset.fileName) { throw new Error(`Exactly one of 'fileName' or 'executable' is required, got: ${JSON.stringify(asset)}`); } if (!!asset.packaging !== !!asset.fileName) { throw new Error(`'packaging' is expected in combination with 'fileName', got: ${JSON.stringify(asset)}`); } } function validateDockerImageAssetSource(asset) { if (!!asset.executable === !!asset.directoryName) { throw new Error(`Exactly one of 'directoryName' or 'executable' is required, got: ${JSON.stringify(asset)}`); } check('dockerBuildArgs'); check('dockerBuildTarget'); check('dockerFile'); function check(key) { if (asset[key] && !asset.directoryName) { throw new Error(`'${key}' is only allowed in combination with 'directoryName', got: ${JSON.stringify(asset)}`); } } } function head(ss) { if (ss && ss.length > 0) { return ss[0]; } return undefined; } function trim(s) { if (s) { return s.trim(); } return undefined; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7O0FBQUEseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUM3Qiw2Q0FBOEw7QUFDOUwsOERBQThEO0FBQzlELDRDQUE0QztBQUM1QywyQ0FBeUI7QUFHekIsTUFBTSxrQkFBa0IsR0FBRyxnQkFBZ0IsQ0FBQztBQUM1QyxNQUFNLHVCQUF1QixHQUFHLDRCQUE0QixDQUFDO0FBRTdELElBQVksdUJBR1g7QUFIRCxXQUFZLHVCQUF1QjtJQUNqQyx3Q0FBYSxDQUFBO0lBQ2Isd0NBQWEsQ0FBQTtBQUNmLENBQUMsRUFIVyx1QkFBdUIsR0FBdkIsK0JBQXVCLEtBQXZCLCtCQUF1QixRQUdsQztBQW9IRDs7O0dBR0c7QUFDSCxNQUFhLDZCQUE4QixTQUFRLDhCQUFnQjtJQWtCakUsWUFBWSxRQUE0QyxFQUFFO1FBQ3hELEtBQUssRUFBRSxDQUFDO1FBSk8sVUFBSyxHQUFpRCxFQUFFLENBQUM7UUFDekQsaUJBQVksR0FBd0QsRUFBRSxDQUFDO1FBSXRGLE1BQU0sRUFDSiwwQkFBMEIsRUFDMUIsK0JBQStCLEVBRS9CLGtDQUFrQyxFQUNsQyxtQ0FBbUMsRUFFbkMscUJBQXFCLEVBQ3JCLHlCQUF5QixFQUV6Qix3QkFBd0IsRUFDeEIsMEJBQTBCLEVBQzFCLCtCQUErQixFQUMvQiwwQkFBMEIsRUFDMUIsMEJBQTBCLEdBQzNCLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQztRQUNoQiw0QkFBNEI7UUFDNUIsSUFBSSxDQUFDLFVBQVUsR0FBRyxLQUFLLENBQUMsbUJBQW1CLElBQUksMEJBQTBCLENBQUM7UUFDMUUsSUFBSSxDQUFDLGNBQWMsR0FBRyxLQUFLLENBQUMsd0JBQXdCLElBQUksK0JBQStCLENBQUM7UUFDeEYsSUFBSSxDQUFDLDBCQUEwQixHQUFHLEtBQUssQ0FBQywwQkFBMEIsSUFBSSxrQ0FBa0MsQ0FB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XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgRG9ja2VySW1hZ2VBc3NldExvY2F0aW9uLCBEb2NrZXJJbWFnZUFzc2V0U291cmNlLCBGaWxlQXNzZXRMb2NhdGlvbiwgRmlsZUFzc2V0UGFja2FnaW5nLCBGaWxlQXNzZXRTb3VyY2UsIEZuLCBJU3ludGhlc2lzU2Vzc2lvbiwgU3RhY2ssIFN0YWNrU3ludGhlc2l6ZXIsIFRva2VuIH0gZnJvbSAnYXdzLWNkay1saWInO1xuaW1wb3J0ICogYXMgY3hzY2hlbWEgZnJvbSAnYXdzLWNkay1saWIvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ2F3cy1jZGstbGliL2N4LWFwaSc7XG5leHBvcnQgKiBmcm9tICcuL2FzcGVjdCc7XG5cblxuY29uc3QgUkVHSU9OX1BMQUNFSE9MREVSID0gJyR7QVdTOjpSZWdpb259JztcbmNvbnN0IEVSUl9NU0dfQ0FMTF9CSU5EX0ZJUlNUID0gJ1lvdSBtdXN0IGNhbGwgYmluZCgpIGZpcnN0JztcblxuZXhwb3J0IGVudW0gSW1hZ2VBc3NldFRhZ1N1ZmZpeFR5cGUge1xuICBOT05FID0gJ05PTkUnLFxuICBIQVNIID0gJ0hBU0gnLFxufVxuXG4vKipcbiAqIENvbmZpZ3VyYXRpb24gcHJvcGVydGllcyBmb3IgQm9vdHN0cmFwbGVzc1N0YWNrU3ludGhlc2l6ZXJcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCb290c3RyYXBsZXNzU3RhY2tTeW50aGVzaXplclByb3BzIHtcbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIFMzIGJ1Y2tldCB0byBob2xkIGZpbGUgYXNzZXRzXG4gICAqXG4gICAqIFlvdSBtdXN0IHN1cHBseSB0aGlzIGlmIHlvdSBoYXZlIGdpdmVuIGEgbm9uLXN0YW5kYXJkIG5hbWUgdG8gdGhlIHN0YWdpbmcgYnVja2V0LlxuICAgKlxuICAgKiBUaGUgcGxhY2Vob2xkZXJzIGAke0FXUzo6QWNjb3VudElkfWAgYW5kIGAke0FXUzo6UmVnaW9ufWAgd2lsbFxuICAgKiBiZSByZXBsYWNlZCB3aXRoIHRoZSB2YWx1ZXMgb2YgcXVhbGlmaWVyIGFuZCB0aGUgc3RhY2sncyBhY2NvdW50IGFuZCByZWdpb24sXG4gICAqIHJlc3BlY3RpdmVseS5cbiAgICpcbiAgICogQHJlcXVpcmVkIGlmIHlvdSBoYXZlIGZpbGUgYXNzZXRzXG4gICAqIEBkZWZhdWx0IC0gcHJvY2Vzcy5lbnYuQlNTX0ZJTEVfQVNTRVRfQlVDS0VUX05BTUVcbiAgICovXG4gIHJlYWRvbmx5IGZpbGVBc3NldEJ1Y2tldE5hbWU/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIE5hbWUgb2YgdGhlIEVDUiByZXBvc2l0b3J5IHRvIGhvbGQgRG9ja2VyIEltYWdlIGFzc2V0c1xuICAgKlxuICAgKiBZb3UgbXVzdCBzdXBwbHkgdGhpcyBpZiB5b3UgaGF2ZSBnaXZlbiBhIG5vbi1zdGFuZGFyZCBuYW1lIHRvIHRoZSBFQ1IgcmVwb3NpdG9yeS5cbiAgICpcbiAgICogVGhlIHBsYWNlaG9sZGVycyBgJHtBV1M6OkFjY291bnRJZH1gIGFuZCBgJHtBV1M6OlJlZ2lvbn1gIHdpbGxcbiAgICogYmUgcmVwbGFjZWQgd2l0aCB0aGUgdmFsdWVzIG9mIHF1YWxpZmllciBhbmQgdGhlIHN0YWNrJ3MgYWNjb3VudCBhbmQgcmVnaW9uLFxuICAgKiByZXNwZWN0aXZlbHkuXG4gICAqXG4gICAqIEByZXF1aXJlZCBpZiB5b3UgaGF2ZSBkb2NrZXIgaW1hZ2UgYXNzZXRzXG4gICAqIEBkZWZhdWx0IC0gcHJvY2Vzcy5lbnYuQlNTX0lNQUdFX0FTU0VUX1JFUE9TSVRPUllfTkFNRVxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VBc3NldFJlcG9zaXRvcnlOYW1lPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcm9sZSB0byB1c2UgdG8gcHVibGlzaCBmaWxlIGFzc2V0cyB0byB0aGUgUzMgYnVja2V0IGluIHRoaXMgZW52aXJvbm1lbnRcbiAgICpcbiAgICogWW91IG11c3Qgc3VwcGx5IHRoaXMgaWYgeW91IGhhdmUgZ2l2ZW4gYSBub24tc3RhbmRhcmQgbmFtZSB0byB0aGUgcHVibGlzaGluZyByb2xlLlxuICAgKlxuICAgKiBUaGUgcGxhY2Vob2xkZXJzIGAke0FXUzo6QWNjb3VudElkfWAgYW5kIGAke0FXUzo6UmVnaW9ufWAgd2lsbFxuICAgKiBiZSByZXBsYWNlZCB3aXRoIHRoZSB2YWx1ZXMgb2YgcXVhbGlmaWVyIGFuZCB0aGUgc3RhY2sncyBhY2NvdW50IGFuZCByZWdpb24sXG4gICAqIHJlc3BlY3RpdmVseS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBwcm9jZXNzLmVudi5CU1NfRklMRV9BU1NFVF9QVUJMSVNISU5HX1JPTEVfQVJOXG4gICAqL1xuICByZWFkb25seSBmaWxlQXNzZXRQdWJsaXNoaW5nUm9sZUFybj86IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHJvbGUgdG8gdXNlIHRvIHB1Ymxpc2ggaW1hZ2UgYXNzZXRzIHRvIHRoZSBFQ1IgcmVwb3NpdG9yeSBpbiB0aGlzIGVudmlyb25tZW50XG4gICAqXG4gICAqIFlvdSBtdXN0IHN1cHBseSB0aGlzIGlmIHlvdSBoYXZlIGdpdmVuIGEgbm9uLXN0YW5kYXJkIG5hbWUgdG8gdGhlIHB1Ymxpc2hpbmcgcm9sZS5cbiAgICpcbiAgICogVGhlIHBsYWNlaG9sZGVycyBgJHtBV1M6OkFjY291bnRJZH1gIGFuZCBgJHtBV1M6OlJlZ2lvbn1gIHdpbGxcbiAgICogYmUgcmVwbGFjZWQgd2l0aCB0aGUgdmFsdWVzIG9mIHF1YWxpZmllciBhbmQgdGhlIHN0YWNrJ3MgYWNjb3VudCBhbmQgcmVnaW9uLFxuICAgKiByZXNwZWN0aXZlbHkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcHJvY2Vzcy5lbnYuQlNTX0lNQUdFX0FTU0VUX1BVQkxJU0hJTkdfUk9MRV9BUk5cbiAgICovXG4gIHJlYWRvbmx5IGltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybj86IHN0cmluZztcblxuICAvKipcbiAgICogT2JqZWN0IGtleSBwcmVmaXggdG8gdXNlIHdoaWxlIHN0b3JpbmcgUzMgQXNzZXRzXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcHJvY2Vzcy5lbnYuQlNTX0ZJTEVfQVNTRVRfUFJFRklYXG4gICAqL1xuICByZWFkb25seSBmaWxlQXNzZXRQcmVmaXg/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSByZWdpb25zIHNldCBvZiBmaWxlIGFzc2V0cyB0byBiZSBwdWJsaXNoZWQgb25seSB3aGVuIGBmaWxlQXNzZXRCdWNrZXROYW1lYCBjb250YWlucyBgJHtBV1M6OlJlZ2lvbn1gXG4gICAqXG4gICAqIEZvciBleGFtcGxlczpcbiAgICogYFsndXMtZWFzdC0xJywgJ3VzLXdlc3QtMSddYFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHByb2Nlc3MuZW52LkJTU19GSUxFX0FTU0VUX1JFR0lPTl9TRVQgLy8gY29tbWEgZGVsaW1pdGVkIGxpc3RcbiAgICovXG4gIHJlYWRvbmx5IGZpbGVBc3NldFJlZ2lvblNldD86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBPdmVycmlkZSB0aGUgbmFtZSBvZiB0aGUgUzMgYnVja2V0IHRvIGhvbGQgQ2xvdWRmb3JtYXRpb24gdGVtcGxhdGVcbiAgICpcbiAgICogQGRlZmF1bHQgLSBwcm9jZXNzLmVudi5CU1NfVEVNUExBVEVfQlVDS0VUX05BTUVcbiAgICovXG4gIHJlYWRvbmx5IHRlbXBsYXRlQnVja2V0TmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIHRhZyBwcmVmaXggb2YgdGhlIERvY2tlciBJbWFnZSBhc3NldHNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBwcm9jZXNzLmVudi5CU1NfSU1BR0VfQVNTRVRfVEFHX1BSRUZJWFxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VBc3NldFRhZ1ByZWZpeD86IHN0cmluZztcblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIHRhZyBzdWZmaXggb2YgdGhlIERvY2tlciBJbWFnZSBhc3NldHNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBIQVNIIG9yIHByb2Nlc3MuZW52LkJTU19JTUFHRV9BU1NFVF9UQUdfU1VGRklYX1RZUEVcbiAgICovXG4gIHJlYWRvbmx5IGltYWdlQXNzZXRUYWdTdWZmaXhUeXBlPzogSW1hZ2VBc3NldFRhZ1N1ZmZpeFR5cGU7XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSBFQ1IgcmVwb3NpdG9yeSByZWdpb24gb2YgdGhlIERvY2tlciBJbWFnZSBhc3NldHNcbiAgICpcbiAgICogRm9yIGV4YW1wbGVzOlxuICAgKiBgWyd1cy1lYXN0LTEnLCAndXMtd2VzdC0xJ11gXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gcHJvY2Vzcy5lbnYuQlNTX0lNQUdFX0FTU0VUX1JFR0lPTl9TRVQgLy8gY29tbWEgZGVsaW1pdGVkIGxpc3RcbiAgICovXG4gIHJlYWRvbmx5IGltYWdlQXNzZXRSZWdpb25TZXQ/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIEVDUiByZXBvc2l0b3J5IGFjY291bnQgaWQgb2YgdGhlIERvY2tlciBJbWFnZSBhc3NldHNcbiAgICpcbiAgICogQGRlZmF1bHQgLSBwcm9jZXNzLmVudi5CU1NfSU1BR0VfQVNTRVRfQUNDT1VOVF9JRFxuICAgKi9cbiAgcmVhZG9ubHkgaW1hZ2VBc3NldEFjY291bnRJZD86IHN0cmluZztcbn1cblxuLyoqXG4gKiBBIEJvb3RzdHJhcGxlc3Mgc3RhY2sgc3ludGhlc2l6ZXIgdGhhdCBpcyBkZXNpZ25hdGVkIHRvIGdlbmVyYXRlIHRlbXBsYXRlc1xuICogdGhhdCBjYW4gYmUgZGlyZWN0bHkgdXNlZCBieSBDbG91ZGZvcm1hdGlvblxuICovXG5leHBvcnQgY2xhc3MgQm9vdHN0cmFwbGVzc1N0YWNrU3ludGhlc2l6ZXIgZXh0ZW5kcyBTdGFja1N5bnRoZXNpemVyIHtcbiAgcHJpdmF0ZSBfc3RhY2s/OiBTdGFjaztcbiAgcHJpdmF0ZSBidWNrZXROYW1lPzogc3RyaW5nO1xuICBwcml2YXRlIHJlcG9zaXRvcnlOYW1lPzogc3RyaW5nO1xuICBwcml2YXRlIGZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuPzogc3RyaW5nO1xuICBwcml2YXRlIGltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybj86IHN0cmluZztcbiAgcHJpdmF0ZSBmaWxlQXNzZXRQcmVmaXg/OiBzdHJpbmc7XG4gIHByaXZhdGUgZmlsZUFzc2V0UmVnaW9uU2V0Pzogc3RyaW5nW107XG4gIHByaXZhdGUgdGVtcGxhdGVCdWNrZXROYW1lPzogc3RyaW5nO1xuICBwcml2YXRlIGltYWdlQXNzZXRUYWdQcmVmaXg6IHN0cmluZztcbiAgcHJpdmF0ZSBpbWFnZUFzc2V0VGFnU3VmZml4VHlwZTogSW1hZ2VBc3NldFRhZ1N1ZmZpeFR5cGU7XG4gIHByaXZhdGUgaW1hZ2VBc3NldFJlZ2lvblNldD86IHN0cmluZ1tdO1xuICBwcml2YXRlIGltYWdlQXNzZXRBY2NvdW50SWQ/OiBzdHJpbmc7XG5cblxuICBwcml2YXRlIHJlYWRvbmx5IGZpbGVzOiBOb25OdWxsYWJsZTxjeHNjaGVtYS5Bc3NldE1hbmlmZXN0WydmaWxlcyddPiA9IHt9O1xuICBwcml2YXRlIHJlYWRvbmx5IGRvY2tlckltYWdlczogTm9uTnVsbGFibGU8Y3hzY2hlbWEuQXNzZXRNYW5pZmVzdFsnZG9ja2VySW1hZ2VzJ10+ID0ge307XG5cbiAgY29uc3RydWN0b3IocHJvcHM6IEJvb3RzdHJhcGxlc3NTdGFja1N5bnRoZXNpemVyUHJvcHMgPSB7fSkge1xuICAgIHN1cGVyKCk7XG4gICAgY29uc3Qge1xuICAgICAgQlNTX0ZJTEVfQVNTRVRfQlVDS0VUX05BTUUsXG4gICAgICBCU1NfSU1BR0VfQVNTRVRfUkVQT1NJVE9SWV9OQU1FLFxuXG4gICAgICBCU1NfRklMRV9BU1NFVF9QVUJMSVNISU5HX1JPTEVfQVJOLFxuICAgICAgQlNTX0lNQUdFX0FTU0VUX1BVQkxJU0hJTkdfUk9MRV9BUk4sXG5cbiAgICAgIEJTU19GSUxFX0FTU0VUX1BSRUZJWCxcbiAgICAgIEJTU19GSUxFX0FTU0VUX1JFR0lPTl9TRVQsXG5cbiAgICAgIEJTU19URU1QTEFURV9CVUNLRVRfTkFNRSxcbiAgICAgIEJTU19JTUFHRV9BU1NFVF9UQUdfUFJFRklYLFxuICAgICAgQlNTX0lNQUdFX0FTU0VUX1RBR19TVUZGSVhfVFlQRSxcbiAgICAgIEJTU19JTUFHRV9BU1NFVF9SRUdJT05fU0VULFxuICAgICAgQlNTX0lNQUdFX0FTU0VUX0FDQ09VTlRfSUQsXG4gICAgfSA9IHByb2Nlc3MuZW52O1xuICAgIC8qIGVzbGludC1kaXNhYmxlIG1heC1sZW4gKi9cbiAgICB0aGlzLmJ1Y2tldE5hbWUgPSBwcm9wcy5maWxlQXNzZXRCdWNrZXROYW1lID8/IEJTU19GSUxFX0FTU0VUX0JVQ0tFVF9OQU1FO1xuICAgIHRoaXMucmVwb3NpdG9yeU5hbWUgPSBwcm9wcy5pbWFnZUFzc2V0UmVwb3NpdG9yeU5hbWUgPz8gQlNTX0lNQUdFX0FTU0VUX1JFUE9TSVRPUllfTkFNRTtcbiAgICB0aGlzLmZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuID0gcHJvcHMuZmlsZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4gPz8gQlNTX0ZJTEVfQVNTRVRfUFVCTElTSElOR19ST0xFX0FSTjtcbiAgICB0aGlzLmltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybiA9IHByb3BzLmltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybiA/PyBCU1NfSU1BR0VfQVNTRVRfUFVCTElTSElOR19ST0xFX0FSTjtcbiAgICB0aGlzLmZpbGVBc3NldFByZWZpeCA9IHByb3BzLmZpbGVBc3NldFByZWZpeCA/PyBCU1NfRklMRV9BU1NFVF9QUkVGSVg7XG4gICAgdGhpcy5maWxlQXNzZXRSZWdpb25TZXQgPSBwcm9wcy5maWxlQXNzZXRSZWdpb25TZXQgPz8gY29tbWFTcGxpdChCU1NfRklMRV9BU1NFVF9SRUdJT05fU0VUKTtcbiAgICB0aGlzLnRlbXBsYXRlQnVja2V0TmFtZSA9IHByb3BzLnRlbXBsYXRlQnVja2V0TmFtZSA/PyBCU1NfVEVNUExBVEVfQlVDS0VUX05BTUU7XG4gICAgdGhpcy5pbWFnZUFzc2V0VGFnUHJlZml4ID0gKHByb3BzLmltYWdlQXNzZXRUYWdQcmVmaXggPz8gQlNTX0lNQUdFX0FTU0VUX1RBR19QUkVGSVgpID8/ICcnO1xuICAgIHRoaXMuaW1hZ2VBc3NldFRhZ1N1ZmZpeFR5cGUgPSB2YWxpZGF0ZUltYWdlQXNzZXRUYWdTdWZmaXhUeXBlKChwcm9wcy5pbWFnZUFzc2V0VGFnU3VmZml4VHlwZSA/PyBCU1NfSU1BR0VfQVNTRVRfVEFHX1NVRkZJWF9UWVBFKSA/PyBJbWFnZUFzc2V0VGFnU3VmZml4VHlwZS5IQVNIKTtcbiAgICB0aGlzLmltYWdlQXNzZXRSZWdpb25TZXQgPSBwcm9wcy5pbWFnZUFzc2V0UmVnaW9uU2V0ID8/IGNvbW1hU3BsaXQoQlNTX0lNQUdFX0FTU0VUX1JFR0lPTl9TRVQpO1xuICAgIHRoaXMuaW1hZ2VBc3NldEFjY291bnRJZCA9IHByb3BzLmltYWdlQXNzZXRBY2NvdW50SWQgPz8gQlNTX0lNQUdFX0FTU0VUX0FDQ09VTlRfSUQ7XG4gICAgLyogZXNsaW50LWVuYWJsZSBtYXgtbGVuICovXG4gIH1cblxuICBwdWJsaWMgYmluZChzdGFjazogU3RhY2spOiB2b2lkIHtcbiAgICBpZiAodGhpcy5fc3RhY2sgIT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdBIFN0YWNrU3ludGhlc2l6ZXIgY2FuIG9ubHkgYmUgdXNlZCBmb3Igb25lIFN0YWNrOiBjcmVhdGUgYSBuZXcgaW5zdGFuY2UgdG8gdXNlIHdpdGggYSBkaWZmZXJlbnQgU3RhY2snKTtcbiAgICB9XG5cbiAgICB0aGlzLl9zdGFjayA9IHN0YWNrO1xuXG4gICAgLy8gRnVuY3Rpb24gdG8gcmVwbGFjZSBwbGFjZWhvbGRlcnMgaW4gdGhlIGlucHV0IHN0cmluZyBhcyBtdWNoIGFzIHBvc3NpYmxlXG4gICAgLy9cbiAgICAvLyBXZSByZXBsYWNlOlxuICAgIC8vIC0gJHtBV1M6OkFjY291bnRJZH0sICR7QVdTOjpSZWdpb259OiBvbmx5IGlmIHdlIGhhdmUgdGhlIGFjdHVhbCB2YWx1ZXMgYXZhaWxhYmxlXG4gICAgLy8gLSAke0FXUzo6UGFydGl0aW9ufTogbmV2ZXIsIHNpbmNlIHdlIG5ldmVyIGhhdmUgdGhlIGFjdHVhbCBwYXJ0aXRpb24gdmFsdWUuXG4gICAgY29uc3Qgc3BlY2lhbGl6ZSA9IChzOiBzdHJpbmcgfCB1bmRlZmluZWQpID0+IHtcbiAgICAgIGlmIChzID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjeGFwaS5FbnZpcm9ubWVudFBsYWNlaG9sZGVycy5yZXBsYWNlKHMsIHtcbiAgICAgICAgcmVnaW9uOiByZXNvbHZlZE9yKHN0YWNrLnJlZ2lvbiwgY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMuQ1VSUkVOVF9SRUdJT04pLFxuICAgICAgICBhY2NvdW50SWQ6IHJlc29sdmVkT3Ioc3RhY2suYWNjb3VudCwgY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMuQ1VSUkVOVF9BQ0NPVU5UKSxcbiAgICAgICAgcGFydGl0aW9uOiBjeGFwaS5FbnZpcm9ubWVudFBsYWNlaG9sZGVycy5DVVJSRU5UX1BBUlRJVElPTixcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKiBlc2xpbnQtZGlzYWJsZSBtYXgtbGVuICovXG4gICAgdGhpcy5idWNrZXROYW1lID0gc3BlY2lhbGl6ZSh0aGlzLmJ1Y2tldE5hbWUpO1xuICAgIHRoaXMucmVwb3NpdG9yeU5hbWUgPSBzcGVjaWFsaXplKHRoaXMucmVwb3NpdG9yeU5hbWUpO1xuICAgIHRoaXMuZmlsZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4gPSBzcGVjaWFsaXplKHRoaXMuZmlsZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4pO1xuICAgIHRoaXMuaW1hZ2VBc3NldFB1Ymxpc2hpbmdSb2xlQXJuID0gc3BlY2lhbGl6ZSh0aGlzLmltYWdlQXNzZXRQdWJsaXNoaW5nUm9sZUFybik7XG4gICAgdGhpcy5maWxlQXNzZXRQcmVmaXggPSBzcGVjaWFsaXplKHRoaXMuZmlsZUFzc2V0UHJlZml4ID8/ICcnKTtcbiAgICAvKiBlc2xpbnQtZW5hYmxlIG1heC1sZW4gKi9cbiAgfVxuXG4gIHB1YmxpYyBhZGRGaWxlQXNzZXQoYXNzZXQ6IEZpbGVBc3NldFNvdXJjZSk6IEZpbGVBc3NldExvY2F0aW9uIHtcbiAgICByZXR1cm4gdGhpcy5fYWRkRmlsZUFzc2V0KGFzc2V0KTtcbiAgfVxuXG4gIHByaXZhdGUgX2FkZEZpbGVBc3NldChhc3NldDogRmlsZUFzc2V0U291cmNlLCBvdmVycmlkZUJ1Y2tldG5hbWU/OiBzdHJpbmcpOiBGaWxlQXNzZXRMb2NhdGlvbiB7XG4gICAgYXNzZXJ0Tm90TnVsbCh0aGlzLnN0YWNrLCBFUlJfTVNHX0NBTExfQklORF9GSVJTVCk7XG4gICAgYXNzZXJ0Tm90TnVsbCh0aGlzLmJ1Y2tldE5hbWUsICdUaGUgYnVja2V0TmFtZSBpcyBudWxsJyk7XG4gICAgdmFsaWRhdGVGaWxlQXNzZXRTb3VyY2UoYXNzZXQpO1xuXG4gICAgY29uc3QgYnVja2V0TmFtZSA9IG92ZXJyaWRlQnVja2V0bmFtZSA/PyB0aGlzLmJ1Y2tldE5hbWU7XG4gICAgY29uc3Qgb2JqZWN0S2V5ID0gdGhpcy5maWxlQXNzZXRQcmVmaXggKyBhc3NldC5zb3VyY2VIYXNoICsgKGFzc2V0LnBhY2thZ2luZyA9PT0gRmlsZUFzc2V0UGFja2FnaW5nLlpJUF9ESVJFQ1RPUlkgPyAnLnppcCcgOiAnJyk7XG4gICAgY29uc3QgZGVzdGluYXRpb25zOiB7IFtpZDogc3RyaW5nXTogY3hzY2hlbWEuRmlsZURlc3RpbmF0aW9uIH0gPSB7fTtcblxuICAgIGlmICh0aGlzLmZpbGVBc3NldFJlZ2lvblNldD8ubGVuZ3RoICYmIGJ1Y2tldE5hbWUuaW5jbHVkZXMoUkVHSU9OX1BMQUNFSE9MREVSKSkge1xuICAgICAgZm9yIChjb25zdCByZWdpb24gb2YgdGhpcy5maWxlQXNzZXRSZWdpb25TZXQubWFwKHIgPT4gci50cmltKCkpKSB7XG4gICAgICAgIGlmICghcmVnaW9uKSB7IGNvbnRpbnVlOyB9XG4gICAgICAgIGRlc3RpbmF0aW9uc1tyZWdpb25dID0ge1xuICAgICAgICAgIGJ1Y2tldE5hbWU6IHJlcGxhY2VBbGwoYnVja2V0TmFtZSwgUkVHSU9OX1BMQUNFSE9MREVSLCByZWdpb24pLFxuICAgICAgICAgIG9iamVjdEtleSxcbiAgICAgICAgICByZWdpb24sXG4gICAgICAgICAgYXNzdW1lUm9sZUFybjogdGhpcy5maWxlQXNzZXRQdWJsaXNoaW5nUm9sZUFybixcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgZGVzdGluYXRpb25zW3RoaXMubWFuaWZlc3RFbnZOYW1lXSA9IHtcbiAgICAgICAgYnVja2V0TmFtZSxcbiAgICAgICAgb2JqZWN0S2V5LFxuICAgICAgICByZWdpb246IHJlc29sdmVkT3IodGhpcy5zdGFjay5yZWdpb24sIHRyaW0oaGVhZCh0aGlzLmZpbGVBc3NldFJlZ2lvblNldCkpKSxcbiAgICAgICAgYXNzdW1lUm9sZUFybjogdGhpcy5maWxlQXNzZXRQdWJsaXNoaW5nUm9sZUFybixcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQWRkIHRvIG1hbmlmZXN0XG4gICAgdGhpcy5maWxlc1thc3NldC5zb3VyY2VIYXNoXSA9IHtcbiAgICAgIHNvdXJjZToge1xuICAgICAgICBwYXRoOiBhc3NldC5maWxlTmFtZSxcbiAgICAgICAgcGFja2FnaW5nOiBhc3NldC5wYWNrYWdpbmcsXG4gICAgICB9LFxuICAgICAgZGVzdGluYXRpb25zLFxuICAgIH07XG5cbiAgICBjb25zdCB7IHJlZ2lvbiwgdXJsU3VmZml4IH0gPSBzdGFja0xvY2F0aW9uT3JJbnN0cmluc2ljcyh0aGlzLnN0YWNrKTtcbiAgICBjb25zdCBodHRwVXJsID0gY2ZuaWZ5KGBodHRwczovL3MzLiR7cmVnaW9ufS4ke3VybFN1ZmZpeH0vJHtidWNrZXROYW1lfS8ke29iamVjdEtleX1gKTtcbiAgICBjb25zdCBzM09iamVjdFVybCA9IGNmbmlmeShgczM6Ly8ke2J1Y2tldE5hbWV9LyR7b2JqZWN0S2V5fWApO1xuXG4gICAgLy8gUmV0dXJuIENGTiBleHByZXNzaW9uXG4gICAgcmV0dXJuIHtcbiAgICAgIGJ1Y2tldE5hbWU6IGNmbmlmeShidWNrZXROYW1lKSxcbiAgICAgIG9iamVjdEtleSxcbiAgICAgIGh0dHBVcmwsXG4gICAgICBzM09iamVjdFVybCxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGFkZERvY2tlckltYWdlQXNzZXQoYXNzZXQ6IERvY2tlckltYWdlQXNzZXRTb3VyY2UpOiBEb2NrZXJJbWFnZUFzc2V0TG9jYXRpb24ge1xuICAgIGFzc2VydE5vdE51bGwodGhpcy5zdGFjaywgRVJSX01TR19DQUxMX0JJTkRfRklSU1QpO1xuICAgIGFzc2VydE5vdE51bGwodGhpcy5yZXBvc2l0b3J5TmFtZSwgJ1RoZSByZXBvc2l0b3J5TmFtZSBpcyBudWxsJyk7XG4gICAgdmFsaWRhdGVEb2NrZXJJbWFnZUFzc2V0U291cmNlKGFzc2V0KTtcblxuICAgIGxldCBpbWFnZVRhZyA9IHRoaXMuaW1hZ2VBc3NldFRhZ1ByZWZpeDtcbiAgICBpZiAodGhpcy5pbWFnZUFzc2V0VGFnU3VmZml4VHlwZSA9PT0gSW1hZ2VBc3NldFRhZ1N1ZmZpeFR5cGUuSEFTSCkge1xuICAgICAgaW1hZ2VUYWcgPSB0aGlzLmltYWdlQXNzZXRUYWdQcmVmaXggKyBhc3NldC5zb3VyY2VIYXNoO1xuICAgIH1cblxuICAgIGNvbnN0IGRlc3RpbmF0aW9uczogeyBbaWQ6IHN0cmluZ106IGN4c2NoZW1hLkRvY2tlckltYWdlRGVzdGluYXRpb24gfSA9IHt9O1xuXG4gICAgaWYgKHRoaXMuaW1hZ2VBc3NldFJlZ2lvblNldD8ubGVuZ3RoKSB7XG4gICAgICBmb3IgKGNvbnN0IHJlZ2lvbiBvZiB0aGlzLmltYWdlQXNzZXRSZWdpb25TZXQubWFwKHIgPT4gci50cmltKCkpKSB7XG4gICAgICAgIGlmICghcmVnaW9uKSB7IGNvbnRpbnVlOyB9XG4gICAgICAgIGRlc3RpbmF0aW9uc1tyZWdpb25dID0ge1xuICAgICAgICAgIHJlcG9zaXRvcnlOYW1lOiB0aGlzLnJlcG9zaXRvcnlOYW1lLFxuICAgICAgICAgIGltYWdlVGFnLFxuICAgICAgICAgIHJlZ2lvbixcbiAgICAgICAgICBhc3N1bWVSb2xlQXJuOiB0aGlzLmZpbGVBc3NldFB1Ymxpc2hpbmdSb2xlQXJuLFxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBkZXN0aW5hdGlvbnNbdGhpcy5tYW5pZmVzdEVudk5hbWVdID0ge1xuICAgICAgICByZXBvc2l0b3J5TmFtZTogdGhpcy5yZXBvc2l0b3J5TmFtZSxcbiAgICAgICAgaW1hZ2VUYWcsXG4gICAgICAgIHJlZ2lvbjogcmVzb2x2ZWRPcih0aGlzLnN0YWNrLnJlZ2lvbiwgdW5kZWZpbmVkKSxcbiAgICAgICAgYXNzdW1lUm9sZUFybjogdGhpcy5pbWFnZUFzc2V0UHVibGlzaGluZ1JvbGVBcm4sXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8vIEFkZCB0byBtYW5pZmVzdFxuICAgIHRoaXMuZG9ja2VySW1hZ2VzW2Fzc2V0LnNvdXJjZUhhc2hdID0ge1xuICAgICAgc291cmNlOiB7XG4gICAgICAgIGRpcmVjdG9yeTogYXNzZXQuZGlyZWN0b3J5TmFtZSxcbiAgICAgICAgZG9ja2VyQnVpbGRBcmdzOiBhc3NldC5kb2NrZXJCdWlsZEFyZ3MsXG4gICAgICAgIGRvY2tlckJ1aWxkVGFyZ2V0OiBhc3NldC5kb2NrZXJCdWlsZFRhcmdldCxcbiAgICAgICAgZG9ja2VyRmlsZTogYXNzZXQuZG9ja2VyRmlsZSxcbiAgICAgIH0sXG4gICAgICBkZXN0aW5hdGlvbnMsXG4gICAgfTtcblxuICAgIGxldCB7IGFjY291bnQsIHVybFN1ZmZpeCB9ID0gc3RhY2tMb2NhdGlvbk9ySW5zdHJpbnNpY3ModGhpcy5zdGFjayk7XG4gICAgYWNjb3VudCA9IHRoaXMuaW1hZ2VBc3NldEFjY291bnRJZCA/PyBhY2NvdW50O1xuXG4gICAgcmV0dXJuIHtcbiAgICAgIHJlcG9zaXRvcnlOYW1lOiBjZm5pZnkodGhpcy5yZXBvc2l0b3J5TmFtZSksXG4gICAgICBpbWFnZVVyaTogY2ZuaWZ5KGAke2FjY291bnR9LmRrci5lY3IuJHtSRUdJT05fUExBQ0VIT0xERVJ9LiR7dXJsU3VmZml4fS8ke3RoaXMucmVwb3NpdG9yeU5hbWV9OiR7aW1hZ2VUYWd9YCksXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEdW1wcyBjdXJyZW50IG1hbmlmZXN0IGludG8gSlNPTiBmb3JtYXRcbiAgICovXG4gIHB1YmxpYyBkdW1wcygpOiBzdHJpbmcge1xuICAgIGNvbnN0IG1hbmlmZXN0OiBjeHNjaGVtYS5Bc3NldE1hbmlmZXN0ID0ge1xuICAgICAgdmVyc2lvbjogY3hzY2hlbWEuTWFuaWZlc3QudmVyc2lvbigpLFxuICAgICAgZmlsZXM6IHRoaXMuZmlsZXMsXG4gICAgICBkb2NrZXJJbWFnZXM6IHRoaXMuZG9ja2VySW1hZ2VzLFxuICAgIH07XG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG1hbmlmZXN0LCB1bmRlZmluZWQsIDIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN5bnRoZXNpemUgdGhlIGFzc29jaWF0ZWQgc3RhY2sgdG8gdGhlIHNlc3Npb25cbiAgICovXG4gIHB1YmxpYyBzeW50aGVzaXplKHNlc3Npb246IElTeW50aGVzaXNTZXNzaW9uKTogdm9pZCB7XG4gICAgYXNzZXJ0Tm90TnVsbCh0aGlzLnN0YWNrLCBFUlJfTVNHX0NBTExfQklORF9GSVJTVCk7XG5cbiAgICB0aGlzLnN5bnRoZXNpemVTdGFja1RlbXBsYXRlKHRoaXMuc3RhY2ssIHNlc3Npb24pO1xuXG4gICAgLy8gQWRkIHRoZSBzdGFjaydzIHRlbXBsYXRlIHRvIHRoZSBhcnRpZmFjdCBtYW5pZmVzdFxuICAgIGNvbnN0IHRlbXBsYXRlTWFuaWZlc3RVcmwgPSB0aGlzLmFkZFN0YWNrVGVtcGxhdGVUb0Fzc2V0TWFuaWZlc3Qoc2Vzc2lvbik7XG5cbiAgICBjb25zdCBhcnRpZmFjdElkID0gdGhpcy53cml0ZUFzc2V0TWFuaWZlc3Qoc2Vzc2lvbik7XG5cbiAgICB0aGlzLmVtaXRTdGFja0FydGlmYWN0KHRoaXMuc3RhY2ssIHNlc3Npb24sIHtcbiAgICAgIHN0YWNrVGVtcGxhdGVBc3NldE9iamVjdFVybDogdGVtcGxhdGVNYW5pZmVzdFVybCxcbiAgICAgIGFkZGl0aW9uYWxEZXBlbmRlbmNpZXM6IFthcnRpZmFjdElkXSxcbiAgICB9KTtcbiAgfVxuXG4gIHByb3RlY3RlZCBnZXQgc3RhY2soKTogU3RhY2sgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9zdGFjaztcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgdGhlIHN0YWNrJ3MgdGVtcGxhdGUgYXMgb25lIG9mIHRoZSBtYW5pZmVzdCBhc3NldHNcbiAgICpcbiAgICogVGhpcyB3aWxsIG1ha2UgaXQgZ2V0IHVwbG9hZGVkIHRvIFMzIGF1dG9tYXRpY2FsbHkgYnkgUzMtYXNzZXRzLiBSZXR1cm5cbiAgICogdGhlIG1hbmlmZXN0IFVSTC5cbiAgICpcbiAgICogKFdlIGNhbid0IHJldHVybiB0aGUgbG9jYXRpb24gcmV0dXJuZWQgZnJvbSBgYWRkRmlsZUFzc2V0YCwgYXMgdGhhdFxuICAgKiBjb250YWlucyBDbG91ZEZvcm1hdGlvbiBpbnRyaW5zaWNzIHdoaWNoIGNhbid0IGdvIGludG8gdGhlIG1hbmlmZXN0KS5cbiAgICovXG4gIHByaXZhdGUgYWRkU3RhY2tUZW1wbGF0ZVRvQXNzZXRNYW5pZmVzdChfOiBJU3ludGhlc2lzU2Vzc2lvbikge1xuICAgIGFzc2VydE5vdE51bGwodGhpcy5zdGFjaywgRVJSX01TR19DQUxMX0JJTkRfRklSU1QpO1xuXG4gICAgY29uc3Qgc291cmNlSGFzaCA9IHRoaXMuc3RhY2sudGVtcGxhdGVGaWxlO1xuXG4gICAgdGhpcy5fYWRkRmlsZUFzc2V0KHtcbiAgICAgIGZpbGVOYW1lOiB0aGlzLnN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICAgIHBhY2thZ2luZzogRmlsZUFzc2V0UGFja2FnaW5nLkZJTEUsXG4gICAgICBzb3VyY2VIYXNoLFxuICAgIH0sIHRoaXMudGVtcGxhdGVCdWNrZXROYW1lKTtcblxuICAgIC8vIFdlIHNob3VsZCB0ZWNobmljYWxseSByZXR1cm4gYW4gJ2h0dHBzOi8vczMuUkVHSU9OLmFtYXpvbmF3cy5jb21bLmNuXS9uYW1lL2hhc2gnIFVSTCBoZXJlLFxuICAgIC8vIGJlY2F1c2UgdGhhdCBpcyB3aGF0IENsb3VkRm9ybWF0aW9uIGV4cGVjdHMgdG8gc2VlLlxuICAgIC8vXG4gICAgLy8gSG93ZXZlciwgdGhlcmUncyBubyB3YXkgZm9yIHVzIHRvIGFjdHVhbGx5IGtub3cgdGhlIFVybFN1ZmZpeCBhIHByaW9yaSwgc28gd2UgY2FuJ3QgY29uc3RydWN0IGl0IGhlcmUuXG4gICAgLy9cbiAgICAvLyBJbnN0ZWFkLCB3ZSdsbCBoYXZlIGEgcHJvdG9jb2wgd2l0aCB0aGUgQ0xJIHRoYXQgd2UgcHV0IGFuICdzMzovLy4uLi8uLi4nIFVSTCBoZXJlLCBhbmQgdGhlIENMSVxuICAgIC8vIGlzIGdvaW5nIHRvIHJlc29sdmUgaXQgdG8gdGhlIGNvcnJlY3QgJ2h0dHBzOi8vLi4uLycgVVJMIGJlZm9yZSBpdCBnaXZlcyBpdCB0byBDbG91ZEZvcm1hdGlvbi5cbiAgICByZXR1cm4gYHMzOi8vJHt0aGlzLmJ1Y2tldE5hbWV9LyR7c291cmNlSGFzaH1gO1xuICB9XG5cbiAgLyoqXG4gICAqIFdyaXRlIGFuIGFzc2V0IG1hbmlmZXN0IHRvIHRoZSBDbG91ZCBBc3NlbWJseSwgcmV0dXJuIHRoZSBhcnRpZmFjdCBJRHMgd3JpdHRlblxuICAgKi9cbiAgcHJpdmF0ZSB3cml0ZUFzc2V0TWFuaWZlc3Qoc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24pOiBzdHJpbmcge1xuICAgIGFzc2VydE5vdE51bGwodGhpcy5zdGFjaywgRVJSX01TR19DQUxMX0JJTkRfRklSU1QpO1xuXG4gICAgY29uc3QgYXJ0aWZhY3RJZCA9IGAke3RoaXMuc3RhY2suYXJ0aWZhY3RJZH0uYXNzZXRzYDtcbiAgICBjb25zdCBtYW5pZmVzdEZpbGUgPSBgJHthcnRpZmFjdElkfS5qc29uYDtcbiAgICBjb25zdCBvdXRQYXRoID0gcGF0aC5qb2luKHNlc3Npb24uYXNzZW1ibHkub3V0ZGlyLCBtYW5pZmVzdEZpbGUpO1xuXG4gICAgZnMud3JpdGVGaWxlU3luYyhvdXRQYXRoLCB0aGlzLmR1bXBzKCkpO1xuICAgIHNlc3Npb24uYXNzZW1ibHkuYWRkQXJ0aWZhY3QoYXJ0aWZhY3RJZCwge1xuICAgICAgdHlwZTogY3hzY2hlbWEuQXJ0aWZhY3RUeXBlLkFTU0VUX01BTklGRVNULFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBmaWxlOiBtYW5pZmVzdEZpbGUsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIGFydGlmYWN0SWQ7XG4gIH1cblxuICBwcml2YXRlIGdldCBtYW5pZmVzdEVudk5hbWUoKTogc3RyaW5nIHtcbiAgICBhc3NlcnROb3ROdWxsKHRoaXMuc3RhY2ssIEVSUl9NU0dfQ0FMTF9CSU5EX0ZJUlNUKTtcblxuICAgIHJldHVybiBbXG4gICAgICByZXNvbHZlZE9yKHRoaXMuc3RhY2suYWNjb3VudCwgJ2N1cnJlbnRfYWNjb3VudCcpLFxuICAgICAgcmVzb2x2ZWRPcih0aGlzLnN0YWNrLnJlZ2lvbiwgJ2N1cnJlbnRfcmVnaW9uJyksXG4gICAgXS5qb2luKCctJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGdpdmVuIHZhbHVlIGlmIHJlc29sdmVkIG9yIGZhbGwgYmFjayB0byBhIGRlZmF1bHRcbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZWRPcjxBPih4OiBzdHJpbmcsIGRlZjogQSk6IHN0cmluZyB8IEEge1xuICByZXR1cm4gVG9rZW4uaXNVbnJlc29sdmVkKHgpID8gZGVmIDogeDtcbn1cblxuLyoqXG4gKiBBIFwicmVwbGFjZS1hbGxcIiBmdW5jdGlvbiB0aGF0IGRvZXNuJ3QgcmVxdWlyZSB1cyBlc2NhcGluZyBhIGxpdGVyYWwgc3RyaW5nIHRvIGEgcmVnZXhcbiAqL1xuZnVuY3Rpb24gcmVwbGFjZUFsbChzOiBzdHJpbmcsIHNlYXJjaDogc3RyaW5nLCByZXBsYWNlOiBzdHJpbmcpIHtcbiAgcmV0dXJuIHMuc3BsaXQoc2VhcmNoKS5qb2luKHJlcGxhY2UpO1xufVxuXG4vKipcbiAqIElmIHRoZSBzdHJpbmcgc3RpbGwgY29udGFpbnMgcGxhY2Vob2xkZXJzLCB3cmFwIGl0IGluIGEgRm46OlN1YiBzbyB0aGV5IHdpbGwgYmUgc3Vic3RpdHV0ZWQgYXQgQ0ZOIGRlcGxveW1lbnQgdGltZVxuICpcbiAqIChUaGlzIGhhcHBlbnMgdG8gd29yayBiZWNhdXNlIHRoZSBwbGFjZWhvbGRlcnMgd2UgcGlja2VkIG1hcCBkaXJlY3RseSBvbnRvIENGTlxuICogcGxhY2Vob2xkZXJzLiBJZiB0aGV5IGRpZG4ndCB3ZSdkIGhhdmUgdG8gZG8gYSB0cmFuc2Zvcm1hdGlvbiBoZXJlKS5cbiAqL1xuZnVuY3Rpb24gY2ZuaWZ5KHM6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBzLmluZGV4T2YoJyR7JykgPiAtMSA/IEZuLnN1YihzKSA6IHM7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBzdGFjayBsb2NhdGlvbnMgaWYgdGhleSdyZSBjb25jcmV0ZSwgb3IgdGhlIG9yaWdpbmFsIENGTiBpbnRyaXNpY3Mgb3RoZXJ3aXNlXG4gKlxuICogV2UgbmVlZCB0byByZXR1cm4gdGhlc2UgaW5zdGVhZCBvZiB0aGUgdG9rZW5pemVkIHZlcnNpb25zIG9mIHRoZSBz