cdk-bootstrapless-synthesizer
Version:
Generate directly usable AWS CloudFormation template with aws-cdk v2.
357 lines • 53.8 kB
JavaScript
"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