@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
330 lines • 45.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AssetStaging = void 0;
const crypto = require("crypto");
const os = require("os");
const path = require("path");
const cxapi = require("@aws-cdk/cx-api");
const fs = require("fs-extra");
const minimatch = require("minimatch");
const assets_1 = require("./assets");
const fs_1 = require("./fs");
const stack_1 = require("./stack");
const stage_1 = require("./stage");
// v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
// eslint-disable-next-line
const construct_compat_1 = require("./construct-compat");
/**
* Stages a file or directory from a location on the file system into a staging directory.
*
* This is controlled by the context key 'aws:cdk:asset-staging' and enabled
* by the CLI by default in order to ensure that when the CDK app exists, all
* assets are available for deployment. Otherwise, if an app references assets
* in temporary locations, those will not be available when it exists (see
* https://github.com/aws/aws-cdk/issues/1716).
*
* The `stagedPath` property is a stringified token that represents the location
* of the file or directory after staging. It will be resolved only during the
* "prepare" stage and may be either the original path or the staged path
* depending on the context setting.
*
* The file/directory are staged based on their content hash (fingerprint). This
* means that only if content was changed, copy will happen.
*/
class AssetStaging extends construct_compat_1.Construct {
/**
*
*/
constructor(scope, id, props) {
var _a, _b, _c;
super(scope, id);
this.sourcePath = props.sourcePath;
this.fingerprintOptions = props;
const outdir = (_a = stage_1.Stage.of(this)) === null || _a === void 0 ? void 0 : _a.outdir;
if (!outdir) {
throw new Error('unable to determine cloud assembly output directory. Assets must be defined indirectly within a "Stage" or an "App" scope');
}
// Determine the hash type based on the props as props.assetHashType is
// optional from a caller perspective.
const hashType = determineHashType(props.assetHashType, props.assetHash);
// Calculate a cache key from the props. This way we can check if we already
// staged this asset (e.g. the same asset with the same configuration is used
// in multiple stacks). In this case we can completely skip file system and
// bundling operations.
this.cacheKey = calculateCacheKey({
sourcePath: path.resolve(props.sourcePath),
bundling: props.bundling,
assetHashType: hashType,
extraHash: props.extraHash,
exclude: props.exclude,
});
if (props.bundling) {
// Check if we actually have to bundle for this stack
const bundlingStacks = (_b = this.node.tryGetContext(cxapi.BUNDLING_STACKS)) !== null && _b !== void 0 ? _b : ['*'];
const runBundling = !!bundlingStacks.find(pattern => minimatch(stack_1.Stack.of(this).stackName, pattern));
if (runBundling) {
const bundling = props.bundling;
this.assetHash = AssetStaging.getOrCalcAssetHash(this.cacheKey, () => {
// Determine the source hash in advance of bundling if the asset hash type
// is SOURCE so that the bundler can opt to re-use its previous output.
const sourceHash = hashType === assets_1.AssetHashType.SOURCE
? this.calculateHash(hashType, props.assetHash, props.bundling)
: undefined;
this.bundleDir = this.bundle(bundling, outdir, sourceHash);
return sourceHash !== null && sourceHash !== void 0 ? sourceHash : this.calculateHash(hashType, props.assetHash, props.bundling);
});
this.relativePath = renderAssetFilename(this.assetHash);
this.stagedPath = this.relativePath;
}
else { // Bundling is skipped
this.assetHash = AssetStaging.getOrCalcAssetHash(this.cacheKey, () => {
return props.assetHashType === assets_1.AssetHashType.BUNDLE || props.assetHashType === assets_1.AssetHashType.OUTPUT
? this.calculateHash(assets_1.AssetHashType.CUSTOM, this.node.path) // Use node path as dummy hash because we're not bundling
: this.calculateHash(hashType, props.assetHash);
});
this.stagedPath = this.sourcePath;
}
}
else {
this.assetHash = AssetStaging.getOrCalcAssetHash(this.cacheKey, () => this.calculateHash(hashType, props.assetHash));
this.relativePath = renderAssetFilename(this.assetHash, path.extname(this.sourcePath));
this.stagedPath = this.relativePath;
}
const stagingDisabled = this.node.tryGetContext(cxapi.DISABLE_ASSET_STAGING_CONTEXT);
if (stagingDisabled) {
this.relativePath = undefined;
this.stagedPath = (_c = this.bundleDir) !== null && _c !== void 0 ? _c : this.sourcePath;
}
this.sourceHash = this.assetHash;
this.stageAsset(outdir);
}
/**
* Clears the asset hash cache.
*/
static clearAssetHashCache() {
this.assetHashCache = {};
}
/**
* Get asset hash from cache or calculate it in case of cache miss.
*/
static getOrCalcAssetHash(cacheKey, calcFn) {
var _a;
this.assetHashCache[cacheKey] = (_a = this.assetHashCache[cacheKey]) !== null && _a !== void 0 ? _a : calcFn();
return this.assetHashCache[cacheKey];
}
stageAsset(outdir) {
// Staging is disabled
if (!this.relativePath) {
return;
}
const targetPath = path.join(outdir, this.relativePath);
// Staging the bundling asset.
if (this.bundleDir) {
const isAlreadyStaged = fs.existsSync(targetPath);
if (isAlreadyStaged && path.resolve(this.bundleDir) !== path.resolve(targetPath)) {
// When an identical asset is already staged and the bundler used an
// intermediate bundling directory, we remove the extra directory.
fs.removeSync(this.bundleDir);
}
else if (!isAlreadyStaged) {
fs.renameSync(this.bundleDir, targetPath);
}
return;
}
// Already staged
if (fs.existsSync(targetPath)) {
return;
}
// Copy file/directory to staging directory
const stat = fs.statSync(this.sourcePath);
if (stat.isFile()) {
fs.copyFileSync(this.sourcePath, targetPath);
}
else if (stat.isDirectory()) {
fs.mkdirSync(targetPath);
fs_1.FileSystem.copyDirectory(this.sourcePath, targetPath, this.fingerprintOptions);
}
else {
throw new Error(`Unknown file type: ${this.sourcePath}`);
}
}
/**
* Bundles an asset and provides the emitted asset's directory in return.
*
* @param options Bundling options
* @param outdir Parent directory to create the bundle output directory in
* @param sourceHash The asset source hash if known in advance. If this field
* is provided, the bundler may opt to skip bundling, providing any already-
* emitted bundle. If this field is not provided, the bundler uses an
* intermediate directory in outdir.
* @returns The fully resolved bundle output directory.
*/
bundle(options, outdir, sourceHash) {
var _a, _b, _c;
let bundleDir;
if (sourceHash) {
// When an asset hash is known in advance of bundling, the bundler outputs
// directly to the assembly output directory.
bundleDir = path.resolve(path.join(outdir, renderAssetFilename(sourceHash)));
if (fs.existsSync(bundleDir)) {
// Pre-existing bundle directory. The bundle has already been generated
// once before, so we'll give the caller nothing.
return bundleDir;
}
}
else {
// When the asset hash isn't known in advance, bundler outputs to an
// intermediate directory named after the asset's cache key
bundleDir = path.resolve(path.join(outdir, `bundling-temp-${this.cacheKey}`));
}
fs.ensureDirSync(bundleDir);
// Chmod the bundleDir to full access.
fs.chmodSync(bundleDir, 0o777);
let user;
if (options.user) {
user = options.user;
}
else { // Default to current user
const userInfo = os.userInfo();
user = userInfo.uid !== -1 // uid is -1 on Windows
? `${userInfo.uid}:${userInfo.gid}`
: '1000:1000';
}
// Always mount input and output dir
const volumes = [
{
hostPath: this.sourcePath,
containerPath: AssetStaging.BUNDLING_INPUT_DIR,
},
{
hostPath: bundleDir,
containerPath: AssetStaging.BUNDLING_OUTPUT_DIR,
},
...(_a = options.volumes) !== null && _a !== void 0 ? _a : [],
];
let localBundling;
try {
process.stderr.write(`Bundling asset ${this.node.path}...\n`);
localBundling = (_b = options.local) === null || _b === void 0 ? void 0 : _b.tryBundle(bundleDir, options);
if (!localBundling) {
options.image.run({
command: options.command,
user,
volumes,
environment: options.environment,
workingDirectory: (_c = options.workingDirectory) !== null && _c !== void 0 ? _c : AssetStaging.BUNDLING_INPUT_DIR,
});
}
}
catch (err) {
// When bundling fails, keep the bundle output for diagnosability, but
// rename it out of the way so that the next run doesn't assume it has a
// valid bundleDir.
const bundleErrorDir = bundleDir + '-error';
if (fs.existsSync(bundleErrorDir)) {
// Remove the last bundleErrorDir.
fs.removeSync(bundleErrorDir);
}
fs.renameSync(bundleDir, bundleErrorDir);
throw new Error(`Failed to bundle asset ${this.node.path}, bundle output is located at ${bundleErrorDir}: ${err}`);
}
if (fs_1.FileSystem.isEmpty(bundleDir)) {
const outputDir = localBundling ? bundleDir : AssetStaging.BUNDLING_OUTPUT_DIR;
throw new Error(`Bundling did not produce any output. Check that content is written to ${outputDir}.`);
}
return bundleDir;
}
calculateHash(hashType, assetHash, bundling) {
if (hashType === assets_1.AssetHashType.CUSTOM && !assetHash) {
throw new Error('`assetHash` must be specified when `assetHashType` is set to `AssetHashType.CUSTOM`.');
}
// When bundling a CUSTOM or SOURCE asset hash type, we want the hash to include
// the bundling configuration. We handle CUSTOM and bundled SOURCE hash types
// as a special case to preserve existing user asset hashes in all other cases.
if (hashType == assets_1.AssetHashType.CUSTOM || (hashType == assets_1.AssetHashType.SOURCE && bundling)) {
const hash = crypto.createHash('sha256');
// if asset hash is provided by user, use it, otherwise fingerprint the source.
hash.update(assetHash !== null && assetHash !== void 0 ? assetHash : fs_1.FileSystem.fingerprint(this.sourcePath, this.fingerprintOptions));
// If we're bundling an asset, include the bundling configuration in the hash
if (bundling) {
hash.update(JSON.stringify(bundling));
}
return hash.digest('hex');
}
switch (hashType) {
case assets_1.AssetHashType.SOURCE:
return fs_1.FileSystem.fingerprint(this.sourcePath, this.fingerprintOptions);
case assets_1.AssetHashType.BUNDLE:
case assets_1.AssetHashType.OUTPUT:
if (!this.bundleDir) {
throw new Error(`Cannot use \`${hashType}\` hash type when \`bundling\` is not specified.`);
}
return fs_1.FileSystem.fingerprint(this.bundleDir, this.fingerprintOptions);
default:
throw new Error('Unknown asset hash type.');
}
}
}
exports.AssetStaging = AssetStaging;
/**
* (experimental) The directory inside the bundling container into which the asset sources will be mounted.
*
* @experimental
*/
AssetStaging.BUNDLING_INPUT_DIR = '/asset-input';
/**
* (experimental) The directory inside the bundling container into which the bundled output should be written.
*
* @experimental
*/
AssetStaging.BUNDLING_OUTPUT_DIR = '/asset-output';
/**
* Cache of asset hashes based on asset configuration to avoid repeated file
* system and bundling operations.
*/
AssetStaging.assetHashCache = {};
function renderAssetFilename(assetHash, extension = '') {
return `asset.${assetHash}${extension}`;
}
/**
* Determines the hash type from user-given prop values.
*
* @param assetHashType Asset hash type construct prop
* @param assetHash Asset hash given in the construct props
*/
function determineHashType(assetHashType, assetHash) {
if (assetHash) {
if (assetHashType && assetHashType !== assets_1.AssetHashType.CUSTOM) {
throw new Error(`Cannot specify \`${assetHashType}\` for \`assetHashType\` when \`assetHash\` is specified. Use \`CUSTOM\` or leave \`undefined\`.`);
}
return assets_1.AssetHashType.CUSTOM;
}
else if (assetHashType) {
return assetHashType;
}
else {
return assets_1.AssetHashType.SOURCE;
}
}
/**
* Calculates a cache key from the props. Normalize by sorting keys.
*/
function calculateCacheKey(props) {
return crypto.createHash('sha256')
.update(JSON.stringify(sortObject(props)))
.digest('hex');
}
/**
* Recursively sort object keys
*/
function sortObject(object) {
if (typeof object !== 'object' || object instanceof Array) {
return object;
}
const ret = {};
for (const key of Object.keys(object).sort()) {
ret[key] = sortObject(object[key]);
}
return ret;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzZXQtc3RhZ2luZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImFzc2V0LXN0YWdpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IseUNBQXlDO0FBRXpDLCtCQUErQjtBQUMvQix1Q0FBdUM7QUFDdkMscUNBQXVEO0FBRXZELDZCQUFzRDtBQUN0RCxtQ0FBZ0M7QUFDaEMsbUNBQWdDO0FBRWhDLGdIQUFnSDtBQUNoSCwyQkFBMkI7QUFDM0IseURBQWdFOzs7Ozs7Ozs7Ozs7Ozs7Ozs7QUE4QmhFLE1BQWEsWUFBYSxTQUFRLDRCQUFhOzs7O0lBbUU3QyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLEtBQXdCOztRQUNoRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBRWpCLElBQUksQ0FBQyxVQUFVLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQztRQUNuQyxJQUFJLENBQUMsa0JBQWtCLEdBQUcsS0FBSyxDQUFDO1FBRWhDLE1BQU0sTUFBTSxTQUFHLGFBQUssQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLDBDQUFFLE1BQU0sQ0FBQztRQUN0QyxJQUFJLENBQUMsTUFBTSxFQUFFO1lBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQywySEFBMkgsQ0FBQyxDQUFDO1NBQzlJO1FBRUQsdUVBQXVFO1FBQ3ZFLHNDQUFzQztRQUN0QyxNQUFNLFFBQVEsR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsYUFBYSxFQUFFLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUV6RSw0RUFBNEU7UUFDNUUsNkVBQTZFO1FBQzdFLDJFQUEyRTtRQUMzRSx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDLFFBQVEsR0FBRyxpQkFBaUIsQ0FBQztZQUNoQyxVQUFVLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDO1lBQzFDLFFBQVEsRUFBRSxL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QWlCLENBQUMsS0FBd0I7SUFDakQsT0FBTyxNQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQztTQUMvQixNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUN6QyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7QUFDbkIsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxVQUFVLENBQUMsTUFBOEI7SUFDaEQsSUFBSSxPQUFPLE1BQU0sS0FBSyxRQUFRLElBQUksTUFBTSxZQUFZLEtBQUssRUFBRTtRQUN6RCxPQUFPLE1BQU0sQ0FBQztLQUNmO0lBQ0QsTUFBTSxHQUFHLEdBQTJCLEVBQUUsQ0FBQztJQUN2QyxLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUU7UUFDNUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztLQUNwQztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGNyeXB0byBmcm9tICdjcnlwdG8nO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIGN4YXBpIGZyb20gJ0Bhd3MtY2RrL2N4LWFwaSc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCAqIGFzIG1pbmltYXRjaCBmcm9tICdtaW5pbWF0Y2gnO1xuaW1wb3J0IHsgQXNzZXRIYXNoVHlwZSwgQXNzZXRPcHRpb25zIH0gZnJvbSAnLi9hc3NldHMnO1xuaW1wb3J0IHsgQnVuZGxpbmdPcHRpb25zIH0gZnJvbSAnLi9idW5kbGluZyc7XG5pbXBvcnQgeyBGaWxlU3lzdGVtLCBGaW5nZXJwcmludE9wdGlvbnMgfSBmcm9tICcuL2ZzJztcbmltcG9ydCB7IFN0YWNrIH0gZnJvbSAnLi9zdGFjayc7XG5pbXBvcnQgeyBTdGFnZSB9IGZyb20gJy4vc3RhZ2UnO1xuXG4vLyB2MiAtIGtlZXAgdGhpcyBpbXBvcnQgYXMgYSBzZXBhcmF0ZSBzZWN0aW9uIHRvIHJlZHVjZSBtZXJnZSBjb25mbGljdCB3aGVuIGZvcndhcmQgbWVyZ2luZyB3aXRoIHRoZSB2MiBicmFuY2guXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmVcbmltcG9ydCB7IENvbnN0cnVjdCBhcyBDb3JlQ29uc3RydWN0IH0gZnJvbSAnLi9jb25zdHJ1Y3QtY29tcGF0JztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBpbnRlcmZhY2UgQXNzZXRTdGFnaW5nUHJvcHMgZXh0ZW5kcyBGaW5nZXJwcmludE9wdGlvbnMsIEFzc2V0T3B0aW9ucyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBzb3VyY2VQYXRoOiBzdHJpbmc7XG59XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBjbGFzcyBBc3NldFN0YWdpbmcgZXh0ZW5kcyBDb3JlQ29uc3RydWN0IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQlVORExJTkdfSU5QVVRfRElSID0gJy9hc3NldC1pbnB1dCc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQlVORExJTkdfT1VUUFVUX0RJUiA9ICcvYXNzZXQtb3V0cHV0JztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHN0YXRpYyBjbGVhckFzc2V0SGFzaENhY2hlKCkge1xuICAgIHRoaXMuYXNzZXRIYXNoQ2FjaGUgPSB7fTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWNoZSBvZiBhc3NldCBoYXNoZXMgYmFzZWQgb24gYXNzZXQgY29uZmlndXJhdGlvbiB0byBhdm9pZCByZXBlYXRlZCBmaWxlXG4gICAqIHN5c3RlbSBhbmQgYnVuZGxpbmcgb3BlcmF0aW9ucy5cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGFzc2V0SGFzaENhY2hlOiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9ID0ge307XG5cbiAgLyoqXG4gICAqIEdldCBhc3NldCBoYXNoIGZyb20gY2FjaGUgb3IgY2FsY3VsYXRlIGl0IGluIGNhc2Ugb2YgY2FjaGUgbWlzcy5cbiAgICovXG4gIHByaXZhdGUgc3RhdGljIGdldE9yQ2FsY0Fzc2V0SGFzaChjYWNoZUtleTogc3RyaW5nLCBjYWxjRm46ICgpID0+IHN0cmluZykge1xuICAgIHRoaXMuYXNzZXRIYXNoQ2FjaGVbY2FjaGVLZXldID0gdGhpcy5hc3NldEhhc2hDYWNoZVtjYWNoZUtleV0gPz8gY2FsY0ZuKCk7XG4gICAgcmV0dXJuIHRoaXMuYXNzZXRIYXNoQ2FjaGVbY2FjaGVLZXldO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgcmVhZG9ubHkgc3RhZ2VkUGF0aDogc3RyaW5nO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHJlYWRvbmx5IHNvdXJjZVBhdGg6IHN0cmluZztcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyByZWFkb25seSBzb3VyY2VIYXNoOiBzdHJpbmc7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgcmVhZG9ubHkgYXNzZXRIYXNoOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBmaW5nZXJwcmludE9wdGlvbnM6IEZpbmdlcnByaW50T3B0aW9ucztcblxuICBwcml2YXRlIHJlYWRvbmx5IHJlbGF0aXZlUGF0aD86IHN0cmluZztcblxuICBwcml2YXRlIGJ1bmRsZURpcj86IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlS2V5OiBzdHJpbmc7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IEFzc2V0U3RhZ2luZ1Byb3BzKSB7XG4gICAgc3VwZXIoc2NvcGUsIGlkKTtcblxuICAgIHRoaXMuc291cmNlUGF0aCA9IHByb3BzLnNvdXJjZVBhdGg7XG4gICAgdGhpcy5maW5nZXJwcmludE9wdGlvbnMgPSBwcm9wcztcblxuICAgIGNvbnN0IG91dGRpciA9IFN0YWdlLm9mKHRoaXMpPy5vdXRkaXI7XG4gICAgaWYgKCFvdXRkaXIpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcigndW5hYmxlIHRvIGRldGVybWluZSBjbG91ZCBhc3NlbWJseSBvdXRwdXQgZGlyZWN0b3J5LiBBc3NldHMgbXVzdCBiZSBkZWZpbmVkIGluZGlyZWN0bHkgd2l0aGluIGEgXCJTdGFnZVwiIG9yIGFuIFwiQXBwXCIgc2NvcGUnKTtcbiAgICB9XG5cbiAgICAvLyBEZXRlcm1pbmUgdGhlIGhhc2ggdHlwZSBiYXNlZCBvbiB0aGUgcHJvcHMgYXMgcHJvcHMuYXNzZXRIYXNoVHlwZSBpc1xuICAgIC8vIG9wdGlvbmFsIGZyb20gYSBjYWxsZXIgcGVyc3BlY3RpdmUuXG4gICAgY29uc3QgaGFzaFR5cGUgPSBkZXRlcm1pbmVIYXNoVHlwZShwcm9wcy5hc3NldEhhc2hUeXBlLCBwcm9wcy5hc3NldEhhc2gpO1xuXG4gICAgLy8gQ2FsY3VsYXRlIGEgY2FjaGUga2V5IGZyb20gdGhlIHByb3BzLiBUaGlzIHdheSB3ZSBjYW4gY2hlY2sgaWYgd2UgYWxyZWFkeVxuICAgIC8vIHN0YWdlZCB0aGlzIGFzc2V0IChlLmcuIHRoZSBzYW1lIGFzc2V0IHdpdGggdGhlIHNhbWUgY29uZmlndXJhdGlvbiBpcyB1c2VkXG4gICAgLy8gaW4gbXVsdGlwbGUgc3RhY2tzKS4gSW4gdGhpcyBjYXNlIHdlIGNhbiBjb21wbGV0ZWx5IHNraXAgZmlsZSBzeXN0ZW0gYW5kXG4gICAgLy8gYnVuZGxpbmcgb3BlcmF0aW9ucy5cbiAgICB0aGlzLmNhY2hlS2V5ID0gY2FsY3VsYXRlQ2FjaGVLZXkoe1xuICAgICAgc291cmNlUGF0aDogcGF0aC5yZXNvbHZlKHByb3BzLnNvdXJjZVBhdGgpLFxuICAgICAgYnVuZGxpbmc6IHByb3BzLmJ1bmRsaW5nLFxuICAgICAgYXNzZXRIYXNoVHlwZTogaGFzaFR5cGUsXG4gICAgICBleHRyYUhhc2g6IHByb3BzLmV4dHJhSGFzaCxcbiAgICAgIGV4Y2x1ZGU6IHByb3BzLmV4Y2x1ZGUsXG4gICAgfSk7XG5cbiAgICBpZiAocHJvcHMuYnVuZGxpbmcpIHtcbiAgICAgIC8vIENoZWNrIGlmIHdlIGFjdHVhbGx5IGhhdmUgdG8gYnVuZGxlIGZvciB0aGlzIHN0YWNrXG4gICAgICBjb25zdCBidW5kbGluZ1N0YWNrczogc3RyaW5nW10gPSB0aGlzLm5vZGUudHJ5R2V0Q29udGV4dChjeGFwaS5CVU5ETElOR19TVEFDS1MpID8/IFsnKiddO1xuICAgICAgY29uc3QgcnVuQnVuZGxpbmcgPSAhIWJ1bmRsaW5nU3RhY2tzLmZpbmQocGF0dGVybiA9PiBtaW5pbWF0Y2goU3RhY2sub2YodGhpcykuc3RhY2tOYW1lLCBwYXR0ZXJuKSk7XG4gICAgICBpZiAocnVuQnVuZGxpbmcpIHtcbiAgICAgICAgY29uc3QgYnVuZGxpbmcgPSBwcm9wcy5idW5kbGluZztcbiAgICAgICAgdGhpcy5hc3NldEhhc2ggPSBBc3NldFN0YWdpbmcuZ2V0T3JDYWxjQXNzZXRIYXNoKHRoaXMuY2FjaGVLZXksICgpID0+IHtcbiAgICAgICAgICAvLyBEZXRlcm1pbmUgdGhlIHNvdXJjZSBoYXNoIGluIGFkdmFuY2Ugb2YgYnVuZGxpbmcgaWYgdGhlIGFzc2V0IGhhc2ggdHlwZVxuICAgICAgICAgIC8vIGlzIFNPVVJDRSBzbyB0aGF0IHRoZSBidW5kbGVyIGNhbiBvcHQgdG8gcmUtdXNlIGl0cyBwcmV2aW91cyBvdXRwdXQuXG4gICAgICAgICAgY29uc3Qgc291cmNlSGFzaCA9IGhhc2hUeXBlID09PSBBc3NldEhhc2hUeXBlLlNPVVJDRVxuICAgICAgICAgICAgPyB0aGlzLmNhbGN1bGF0ZUhhc2goaGFzaFR5cGUsIHByb3BzLmFzc2V0SGFzaCwgcHJvcHMuYnVuZGxpbmcpXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgICAgICB0aGlzLmJ1bmRsZURpciA9IHRoaXMuYnVuZGxlKGJ1bmRsaW5nLCBvdXRkaXIsIHNvdXJjZUhhc2gpO1xuICAgICAgICAgIHJldHVybiBzb3VyY2VIYXNoID8/IHRoaXMuY2FsY3VsYXRlSGFzaChoYXNoVHlwZSwgcHJvcHMuYXNzZXRIYXNoLCBwcm9wcy5idW5kbGluZyk7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlbGF0aXZlUGF0aCA9IHJlbmRlckFzc2V0RmlsZW5hbWUodGhpcy5hc3NldEhhc2gpO1xuICAgICAgICB0aGlzLnN0YWdlZFBhdGggPSB0aGlzLnJlbGF0aXZlUGF0aDtcbiAgICAgIH0gZWxzZSB7IC8vIEJ1bmRsaW5nIGlzIHNraXBwZWRcbiAgICAgICAgdGhpcy5hc3NldEhhc2ggPSBBc3NldFN0YWdpbmcuZ2V0T3JDYWxjQXNzZXRIYXNoKHRoaXMuY2FjaGVLZXksICgpID0+IHtcbiAgICAgICAgICByZXR1cm4gcHJvcHMuYXNzZXRIYXNoVHlwZSA9PT0gQXNzZXRIYXNoVHlwZS5CVU5ETEUgfHwgcHJvcHMuYXNzZXRIYXNoVHlwZSA9PT0gQXNzZXRIYXNoVHlwZS5PVVRQVVRcbiAgICAgICAgICAgID8gdGhpcy5jYWxjdWxhdGVIYXNoKEFzc2V0SGFzaFR5cGUuQ1VTVE9NLCB0aGlzLm5vZGUucGF0aCkgLy8gVXNlIG5vZGUgcGF0aCBhcyBkdW1teSBoYXNoIGJlY2F1c2Ugd2UncmUgbm90IGJ1bmRsaW5nXG4gICAgICAgICAgICA6IHRoaXMuY2FsY3VsYXRlSGFzaChoYXNoVHlwZSwgcHJvcHMuYXNzZXRIYXNoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuc3RhZ2VkUGF0aCA9IHRoaXMuc291cmNlUGF0aDtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hc3NldEhhc2ggPSBBc3NldFN0YWdpbmcuZ2V0T3JDYWxjQXNzZXRIYXNoKHRoaXMuY2FjaGVLZXksICgpID0+IHRoaXMuY2FsY3VsYXRlSGFzaChoYXNoVHlwZSwgcHJvcHMuYXNzZXRIYXNoKSk7XG4gICAgICB0aGlzLnJlbGF0aXZlUGF0aCA9IHJlbmRlckFzc2V0RmlsZW5hbWUodGhpcy5hc3NldEhhc2gsIHBhdGguZXh0bmFtZSh0aGlzLnNvdXJjZVBhdGgpKTtcbiAgICAgIHRoaXMuc3RhZ2VkUGF0aCA9IHRoaXMucmVsYXRpdmVQYXRoO1xuICAgIH1cblxuICAgIGNvbnN0IHN0YWdpbmdEaXNhYmxlZCA9IHRoaXMubm9kZS50cnlHZXRDb250ZXh0KGN4YXBpLkRJU0FCTEVfQVNTRVRfU1RBR0lOR19DT05URVhUKTtcbiAgICBpZiAoc3RhZ2luZ0Rpc2FibGVkKSB7XG4gICAgICB0aGlzLnJlbGF0aXZlUGF0aCA9IHVuZGVmaW5lZDtcbiAgICAgIHRoaXMuc3RhZ2VkUGF0aCA9IHRoaXMuYnVuZGxlRGlyID8/IHRoaXMuc291cmNlUGF0aDtcbiAgICB9XG5cbiAgICB0aGlzLnNvdXJjZUhhc2ggPSB0aGlzLmFzc2V0SGFzaDtcblxuICAgIHRoaXMuc3RhZ2VBc3NldChvdXRkaXIpO1xuICB9XG5cbiAgcHJpdmF0ZSBzdGFnZUFzc2V0KG91dGRpcjogc3RyaW5nKSB7XG4gICAgLy8gU3RhZ2luZyBpcyBkaXNhYmxlZFxuICAgIGlmICghdGhpcy5yZWxhdGl2ZVBhdGgpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB0YXJnZXRQYXRoID0gcGF0aC5qb2luKG91dGRpciwgdGhpcy5yZWxhdGl2ZVBhdGgpO1xuXG4gICAgLy8gU3RhZ2luZyB0aGUgYnVuZGxpbmcgYXNzZXQuXG4gICAgaWYgKHRoaXMuYnVuZGxlRGlyKSB7XG4gICAgICBjb25zdCBpc0FscmVhZHlTdGFnZWQgPSBmcy5leGlzdHNTeW5jKHRhcmdldFBhdGgpO1xuXG4gICAgICBpZiAoaXNBbHJlYWR5U3RhZ2VkICYmIHBhdGgucmVzb2x2ZSh0aGlzLmJ1bmRsZURpcikgIT09IHBhdGgucmVzb2x2ZSh0YXJnZXRQYXRoKSkge1xuICAgICAgICAvLyBXaGVuIGFuIGlkZW50aWNhbCBhc3NldCBpcyBhbHJlYWR5IHN0YWdlZCBhbmQgdGhlIGJ1bmRsZXIgdXNlZCBhblxuICAgICAgICAvLyBpbnRlcm1lZGlhdGUgYnVuZGxpbmcgZGlyZWN0b3J5LCB3ZSByZW1vdmUgdGhlIGV4dHJhIGRpcmVjdG9yeS5cbiAgICAgICAgZnMucmVtb3ZlU3luYyh0aGlzLmJ1bmRsZURpcik7XG4gICAgICB9IGVsc2UgaWYgKCFpc0FscmVhZHlTdGFnZWQpIHtcbiAgICAgICAgZnMucmVuYW1lU3luYyh0aGlzLmJ1bmRsZURpciwgdGFyZ2V0UGF0aCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBbHJlYWR5IHN0YWdlZFxuICAgIGlmIChmcy5leGlzdHNTeW5jKHRhcmdldFBhdGgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gQ29weSBmaWxlL2RpcmVjdG9yeSB0byBzdGFnaW5nIGRpcmVjdG9yeVxuICAgIGNvbnN0IHN0YXQgPSBmcy5zdGF0U3luYyh0aGlzLnNvdXJjZVBhdGgpO1xuICAgIGlmIChzdGF0LmlzRmlsZSgpKSB7XG4gICAgICBmcy5jb3B5RmlsZVN5bmModGhpcy5zb3VyY2VQYXRoLCB0YXJnZXRQYXRoKTtcbiAgICB9IGVsc2UgaWYgKHN0YXQuaXNEaXJlY3RvcnkoKSkge1xuICAgICAgZnMubWtkaXJTeW5jKHRhcmdldFBhdGgpO1xuICAgICAgRmlsZVN5c3RlbS5jb3B5RGlyZWN0b3J5KHRoaXMuc291cmNlUGF0aCwgdGFyZ2V0UGF0aCwgdGhpcy5maW5nZXJwcmludE9wdGlvbnMpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFVua25vd24gZmlsZSB0eXBlOiAke3RoaXMuc291cmNlUGF0aH1gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQnVuZGxlcyBhbiBhc3NldCBhbmQgcHJvdmlkZXMgdGhlIGVtaXR0ZWQgYXNzZXQncyBkaXJlY3RvcnkgaW4gcmV0dXJuLlxuICAgKlxuICAgKiBAcGFyYW0gb3B0aW9ucyBCdW5kbGluZyBvcHRpb25zXG4gICAqIEBwYXJhbSBvdXRkaXIgUGFyZW50IGRpcmVjdG9yeSB0byBjcmVhdGUgdGhlIGJ1bmRsZSBvdXRwdXQgZGlyZWN0b3J5IGluXG4gICAqIEBwYXJhbSBzb3VyY2VIYXNoIFRoZSBhc3NldCBzb3VyY2UgaGFzaCBpZiBrbm93biBpbiBhZHZhbmNlLiBJZiB0aGlzIGZpZWxkXG4gICAqIGlzIHByb3ZpZGVkLCB0aGUgYnVuZGxlciBtYXkgb3B0IHRvIHNraXAgYnVuZGxpbmcsIHByb3ZpZGluZyBhbnkgYWxyZWFkeS1cbiAgICogZW1pdHRlZCBidW5kbGUuIElmIHRoaXMgZmllbGQgaXMgbm90IHByb3ZpZGVkLCB0aGUgYnVuZGxlciB1c2VzIGFuXG4gICAqIGludGVybWVkaWF0ZSBkaXJlY3RvcnkgaW4gb3V0ZGlyLlxuICAgKiBAcmV0dXJucyBUaGUgZnVsbHkgcmVzb2x2ZWQgYnVuZGxlIG91dHB1dCBkaXJlY3RvcnkuXG4gICAqL1xuICBwcml2YXRlIGJ1bmRsZShvcHRpb25zOiBCdW5kbGluZ09wdGlvbnMsIG91dGRpcjogc3RyaW5nLCBzb3VyY2VIYXNoPzogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBsZXQgYnVuZGxlRGlyOiBzdHJpbmc7XG4gICAgaWYgKHNvdXJjZUhhc2gpIHtcbiAgICAgIC8vIFdoZW4gYW4gYXNzZXQgaGFzaCBpcyBrbm93biBpbiBhZHZhbmNlIG9mIGJ1bmRsaW5nLCB0aGUgYnVuZGxlciBvdXRwdXRzXG4gICAgICAvLyBkaXJlY3RseSB0byB0aGUgYXNzZW1ibHkgb3V0cHV0IGRpcmVjdG9yeS5cbiAgICAgIGJ1bmRsZURpciA9IHBhdGgucmVzb2x2ZShwYXRoLmpvaW4ob3V0ZGlyLCByZW5kZXJBc3NldEZpbGVuYW1lKHNvdXJjZUhhc2gpKSk7XG5cbiAgICAgIGlmIChmcy5leGlzdHNTeW5jKGJ1bmRsZURpcikpIHtcbiAgICAgICAgLy8gUHJlLWV4aXN0aW5nIGJ1bmRsZSBkaXJlY3RvcnkuIFRoZSBidW5kbGUgaGFzIGFscmVhZHkgYmVlbiBnZW5lcmF0ZWRcbiAgICAgICAgLy8gb25jZSBiZWZvcmUsIHNvIHdlJ2xsIGdpdmUgdGhlIGNhbGxlciBub3RoaW5nLlxuICAgICAgICByZXR1cm4gYnVuZGxlRGlyO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICAvLyBXaGVuIHRoZSBhc3NldCBoYXNoIGlzbid0IGtub3duIGluIGFkdmFuY2UsIGJ1bmRsZXIgb3V0cHV0cyB0byBhblxuICAgICAgLy8gaW50ZXJtZWRpYXRlIGRpcmVjdG9yeSBuYW1lZCBhZnRlciB0aGUgYXNzZXQncyBjYWNoZSBrZXlcbiAgICAgIGJ1bmRsZURpciA9IHBhdGgucmVzb2x2ZShwYXRoLmpvaW4ob3V0ZGlyLCBgYnVuZGxpbmctdGVtcC0ke3RoaXMuY2FjaGVLZXl9YCkpO1xuICAgIH1cblxuICAgIGZzLmVuc3VyZURpclN5bmMoYnVuZGxlRGlyKTtcbiAgICAvLyBDaG1vZCB0aGUgYnVuZGxlRGlyIHRvIGZ1bGwgYWNjZXNzLlxuICAgIGZzLmNobW9kU3luYyhidW5kbGVEaXIsIDBvNzc3KTtcblxuICAgIGxldCB1c2VyOiBzdHJpbmc7XG4gICAgaWYgKG9wdGlvbnMudXNlcikge1xuICAgICAgdXNlciA9IG9wdGlvbnMudXNlcjtcbiAgICB9IGVsc2UgeyAvLyBEZWZhdWx0IHRvIGN1cnJlbnQgdXNlclxuICAgICAgY29uc3QgdXNlckluZm8gPSBvcy51c2VySW5mbygpO1xuICAgICAgdXNlciA9IHVzZXJJbmZvLnVpZCAhPT0gLTEgLy8gdWlkIGlzIC0xIG9uIFdpbmRvd3NcbiAgICAgICAgPyBgJHt1c2VySW5mby51aWR9OiR7dXNlckluZm8uZ2lkfWBcbiAgICAgICAgOiAnMTAwMDoxMDAwJztcbiAgICB9XG5cbiAgICAvLyBBbHdheXMgbW91bnQgaW5wdXQgYW5kIG91dHB1dCBkaXJcbiAgICBjb25zdCB2b2x1bWVzID0gW1xuICAgICAge1xuICAgICAgICBob3N0UGF0aDogdGhpcy5zb3VyY2VQYXRoLFxuICAgICAgICBjb250YWluZXJQYXRoOiBBc3NldFN0YWdpbmcuQlVORExJTkdfSU5QVVRfRElSLFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgaG9zdFBhdGg6IGJ1bmRsZURpcixcbiAgICAgICAgY29udGFpbmVyUGF0aDogQXNzZXRTdGFnaW5nLkJVTkRMSU5HX09VVFBVVF9ESVIsXG4gICAgICB9LFxuICAgICAgLi4ub3B0aW9ucy52b2x1bWVzID8/IFtdLFxuICAgIF07XG5cbiAgICBsZXQgbG9jYWxCdW5kbGluZzogYm9vbGVhbiB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgcHJvY2Vzcy5zdGRlcnIud3JpdGUoYEJ1bmRsaW5nIGFzc2V0ICR7dGhpcy5ub2RlLnBhdGh9Li4uXFxuYCk7XG5cbiAgICAgIGxvY2FsQnVuZGxpbmcgPSBvcHRpb25zLmxvY2FsPy50cnlCdW5kbGUoYnVuZGxlRGlyLCBvcHRpb25zKTtcbiAgICAgIGlmICghbG9jYWxCdW5kbGluZykge1xuICAgICAgICBvcHRpb25zLmltYWdlLnJ1bih7XG4gICAgICAgICAgY29tbWFuZDogb3B0aW9ucy5jb21tYW5kLFxuICAgICAgICAgIHVzZXIsXG4gICAgICAgICAgdm9sdW1lcyxcbiAgICAgICAgICBlbnZpcm9ubWVudDogb3B0aW9ucy5lbnZpcm9ubWVudCxcbiAgICAgICAgICB3b3JraW5nRGlyZWN0b3J5OiBvcHRpb25zLndvcmtpbmdEaXJlY3RvcnkgPz8gQXNzZXRTdGFnaW5nLkJVTkRMSU5HX0lOUFVUX0RJUixcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBXaGVuIGJ1bmRsaW5nIGZhaWxzLCBrZWVwIHRoZSBidW5kbGUgb3V0cHV0IGZvciBkaWFnbm9zYWJpbGl0eSwgYnV0XG4gICAgICAvLyByZW5hbWUgaXQgb3V0IG9mIHRoZSB3YXkgc28gdGhhdCB0aGUgbmV4dCBydW4gZG9lc24ndCBhc3N1bWUgaXQgaGFzIGFcbiAgICAgIC8vIHZhbGlkIGJ1bmRsZURpci5cbiAgICAgIGNvbnN0IGJ1bmRsZUVycm9yRGlyID0gYnVuZGxlRGlyICsgJy1lcnJvcic7XG4gICAgICBpZiAoZnMuZXhpc3RzU3luYyhidW5kbGVFcnJvckRpcikpIHtcbiAgICAgICAgLy8gUmVtb3ZlIHRoZSBsYXN0IGJ1bmRsZUVycm9yRGlyLlxuICAgICAgICBmcy5yZW1vdmVTeW5jKGJ1bmRsZUVycm9yRGlyKTtcbiAgICAgIH1cblxuICAgICAgZnMucmVuYW1lU3luYyhidW5kbGVEaXIsIGJ1bmRsZUVycm9yRGlyKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIGJ1bmRsZSBhc3NldCAke3RoaXMubm9kZS5wYXRofSwgYnVuZGxlIG91dHB1dCBpcyBsb2NhdGVkIGF0ICR7YnVuZGxlRXJyb3JEaXJ9OiAke2Vycn1gKTtcbiAgICB9XG5cbiAgICBpZiAoRmlsZVN5c3RlbS5pc0VtcHR5KGJ1bmRsZURpcikpIHtcbiAgICAgIGNvbnN0IG91dHB1dERpciA9IGxvY2FsQnVuZGxpbmcgPyBidW5kbGVEaXIgOiBBc3NldFN0YWdpbmcuQlVORExJTkdfT1VUUFVUX0RJUjtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQnVuZGxpbmcgZGlkIG5vdCBwcm9kdWNlIGFueSBvdXRwdXQuIENoZWNrIHRoYXQgY29udGVudCBpcyB3cml0dGVuIHRvICR7b3V0cHV0RGlyfS5gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYnVuZGxlRGlyO1xuICB9XG5cbiAgcHJpdmF0ZSBjYWxjdWxhdGVIYXNoKGhhc2hUeXBlOiBBc3NldEhhc2hUeXBlLCBhc3NldEhhc2g/OiBzdHJpbmcsIGJ1bmRsaW5nPzogQnVuZGxpbmdPcHRpb25zKTogc3RyaW5nIHtcbiAgICBpZiAoaGFzaFR5cGUgPT09IEFzc2V0SGFzaFR5cGUuQ1VTVE9NICYmICFhc3NldEhhc2gpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignYGFzc2V0SGFzaGAgbXVzdCBiZSBzcGVjaWZpZWQgd2hlbiBgYXNzZXRIYXNoVHlwZWAgaXMgc2V0IHRvIGBBc3NldEhhc2hUeXBlLkNVU1RPTWAuJyk7XG4gICAgfVxuXG4gICAgLy8gV2hlbiBidW5kbGluZyBhIENVU1RPTSBvciBTT1VSQ0UgYXNzZXQgaGFzaCB0eXBlLCB3ZSB3YW50IHRoZSBoYXNoIHRvIGluY2x1ZGVcbiAgICAvLyB0aGUgYnVuZGxpbmcgY29uZmlndXJhdGlvbi4gV2UgaGFuZGxlIENVU1RPTSBhbmQgYnVuZGxlZCBTT1VSQ0UgaGFzaCB0eXBlc1xuICAgIC8vIGFzIGEgc3BlY2lhbCBjYXNlIHRvIHByZXNlcnZlIGV4aXN0aW5nIHVzZXIgYXNzZXQgaGFzaGVzIGluIGFsbCBvdGhlciBjYXNlcy5cbiAgICBpZiAoaGFzaFR5cGUgPT0gQXNzZXRIYXNoVHlwZS5DVVNUT00gfHwgKGhhc2hUeXBlID09IEFzc2V0SGFzaFR5cGUuU09VUkNFICYmIGJ1bmRsaW5nKSkge1xuICAgICAgY29uc3QgaGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyNTYnKTtcblxuICAgICAgLy8gaWYgYXNzZXQgaGFzaCBpcyBwcm92aWRlZCBieSB1c2VyLCB1c2UgaXQsIG90aGVyd2lzZSBmaW5nZXJwcmludCB0aGUgc291cmNlLlxuICAgICAgaGFzaC51cGRhdGUoYXNzZXRIYXNoID8/IEZpbGVTeXN0ZW0uZmluZ2VycHJpbnQodGhpcy5zb3VyY2VQYXRoLCB0aGlzLmZpbmdlcnByaW50T3B0aW9ucykpO1xuXG4gICAgICAvLyBJZiB3ZSdyZSBidW5kbGluZyBhbiBhc3NldCwgaW5jbHVkZSB0aGUgYnVuZGxpbmcgY29uZmlndXJhdGlvbiBpbiB0aGUgaGFzaFxuICAgICAgaWYgKGJ1bmRsaW5nKSB7XG4gICAgICAgIGhhc2gudXBkYXRlKEpTT04uc3RyaW5naWZ5KGJ1bmRsaW5nKSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBoYXNoLmRpZ2VzdCgnaGV4Jyk7XG4gICAgfVxuXG4gICAgc3dpdGNoIChoYXNoVHlwZSkge1xuICAgICAgY2FzZSBBc3NldEhhc2hUeXBlLlNPVVJDRTpcbiAgICAgICAgcmV0dXJuIEZpbGVTeXN0ZW0uZmluZ2VycHJpbnQodGhpcy5zb3VyY2VQYXRoLCB0aGlzLmZpbmdlcnByaW50T3B0aW9ucyk7XG4gICAgICBjYXNlIEFzc2V0SGFzaFR5cGUuQlVORExFOlxuICAgICAgY2FzZSBBc3NldEhhc2hUeXBlLk9VVFBVVDpcbiAgICAgICAgaWYgKCF0aGlzLmJ1bmRsZURpcikge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHVzZSBcXGAke2hhc2hUeXBlfVxcYCBoYXNoIHR5cGUgd2hlbiBcXGBidW5kbGluZ1xcYCBpcyBub3Qgc3BlY2lmaWVkLmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBGaWxlU3lzdGVtLmZpbmdlcnByaW50KHRoaXMuYnVuZGxlRGlyLCB0aGlzLmZpbmdlcnByaW50T3B0aW9ucyk7XG4gICAgICBkZWZhdWx0OlxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1Vua25vd24gYXNzZXQgaGFzaCB0eXBlLicpO1xuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiByZW5kZXJBc3NldEZpbGVuYW1lKGFzc2V0SGFzaDogc3RyaW5nLCBleHRlbnNpb24gPSAnJykge1xuICByZXR1cm4gYGFzc2V0LiR7YXNzZXRIYXNofSR7ZXh0ZW5zaW9ufWA7XG59XG5cbi8qKlxuICogRGV0ZXJtaW5lcyB0aGUgaGFzaCB0eXBlIGZyb20gdXNlci1naXZlbiBwcm9wIHZhbHVlcy5cbiAqXG4gKiBAcGFyYW0gYXNzZXRIYXNoVHlwZSBBc3NldCBoYXNoIHR5cGUgY29uc3RydWN0IHByb3BcbiAqIEBwYXJhbSBhc3NldEhhc2ggQXNzZXQgaGFzaCBnaXZlbiBpbiB0aGUgY29uc3RydWN0IHByb3BzXG4gKi9cbmZ1bmN0aW9uIGRldGVybWluZUhhc2hUeXBlKGFzc2V0SGFzaFR5cGU/OiBBc3NldEhhc2hUeXBlLCBhc3NldEhhc2g/OiBzdHJpbmcpIHtcbiAgaWYgKGFzc2V0SGFzaCkge1xuICAgIGlmIChhc3NldEhhc2hUeXBlICYmIGFzc2V0SGFzaFR5cGUgIT09IEFzc2V0SGFzaFR5cGUuQ1VTVE9NKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBzcGVjaWZ5IFxcYCR7YXNzZXRIYXNoVHlwZX1cXGAgZm9yIFxcYGFzc2V0SGFzaFR5cGVcXGAgd2hlbiBcXGBhc3NldEhhc2hcXGAgaXMgc3BlY2lmaWVkLiBVc2UgXFxgQ1VTVE9NXFxgIG9yIGxlYXZlIFxcYHVuZGVmaW5lZFxcYC5gKTtcbiAgICB9XG4gICAgcmV0dXJuIEFzc2V0SGFzaFR5cGUuQ1VTVE9NO1xuICB9IGVsc2UgaWYgKGFzc2V0SGFzaFR5cGUpIHtcbiAgICByZXR1cm4gYXNzZXRIYXNoVHlwZTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gQXNzZXRIYXNoVHlwZS5TT1VSQ0U7XG4gIH1cbn1cblxuLyoqXG4gKiBDYWxjdWxhdGVzIGEgY2FjaGUga2V5IGZyb20gdGhlIHByb3BzLiBOb3JtYWxpemUgYnkgc29ydGluZyBrZXlzLlxuICovXG5mdW5jdGlvbiBjYWxjdWxhdGVDYWNoZUtleShwcm9wczogQXNzZXRTdGFnaW5nUHJvcHMpOiBzdHJpbmcge1xuICByZXR1cm4gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpXG4gICAgLnVwZGF0ZShKU09OLnN0cmluZ2lmeShzb3J0T2JqZWN0KHByb3BzKSkpXG4gICAgLmRpZ2VzdCgnaGV4Jyk7XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgc29ydCBvYmplY3Qga2V5c1xuICovXG5mdW5jdGlvbiBzb3J0T2JqZWN0KG9iamVjdDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSk6IHsgW2tleTogc3RyaW5nXTogYW55IH0ge1xuICBpZiAodHlwZW9mIG9iamVjdCAhPT0gJ29iamVjdCcgfHwgb2JqZWN0IGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICByZXR1cm4gb2JqZWN0O1xuICB9XG4gIGNvbnN0IHJldDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBmb3IgKGNvbnN0IGtleSBvZiBPYmplY3Qua2V5cyhvYmplY3QpLnNvcnQoKSkge1xuICAgIHJldFtrZXldID0gc29ydE9iamVjdChvYmplY3Rba2V5XSk7XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cbiJdfQ==