UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

330 lines 45.8 kB
"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==