UNPKG

aws-cdk-lib

Version:

Version 2 of the AWS Cloud Development Kit library

375 lines 51.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CloudAssemblyBuilder = exports.CloudAssembly = void 0; const fs = require("fs"); const os = require("os"); const path = require("path"); const cxschema = require("@aws-cdk/cloud-assembly-schema/lib"); const cloudformation_artifact_1 = require("./artifacts/cloudformation-artifact"); const nested_cloud_assembly_artifact_1 = require("./artifacts/nested-cloud-assembly-artifact"); const tree_cloud_artifact_1 = require("./artifacts/tree-cloud-artifact"); const cloud_artifact_1 = require("./cloud-artifact"); const error_1 = require("./private/error"); const toposort_1 = require("./private/toposort"); const CLOUD_ASSEMBLY_SYMBOL = Symbol.for('@aws-cdk/cx-api.CloudAssembly'); /** * The name of the root manifest file of the assembly. */ const MANIFEST_FILE = 'manifest.json'; /** * Represents a deployable cloud application. */ class CloudAssembly { /** * Return whether the given object is a CloudAssembly. * * We do attribute detection since we can't reliably use 'instanceof'. */ static isCloudAssembly(x) { return x !== null && typeof (x) === 'object' && CLOUD_ASSEMBLY_SYMBOL in x; } /** * Cleans up any temporary assembly directories that got created in this process * * If a Cloud Assembly is emitted to a temporary directory, its directory gets * added to a list. This function iterates over that list and deletes each * directory in it, to free up disk space. * * This function will normally be called automatically during Node process * exit and so you don't need to call this. However, some test environments do * not properly trigger Node's `exit` event. Notably: Jest does not trigger * the `exit` event (<https://github.com/jestjs/jest/issues/10927>). * * ## Cleaning up temporary directories in jest * * For Jest, you have to make sure this function is called at the end of the * test suite instead: * * ```js * import { CloudAssembly } from 'aws-cdk-lib/cx-api'; * * afterAll(CloudAssembly.cleanupTemporaryDirectories); * ``` * * Alternatively, you can use the `setupFilesAfterEnv` feature and use a * provided helper script to automatically inject the above into every * test file, so you don't have to do it by hand. * * ``` * $ npx jest --setupFilesAfterEnv aws-cdk-lib/testhelpers/jest-autoclean * ``` * * Or put the following into `jest.config.js`: * * ```js * module.exports = { * // ... * setupFilesAfterEnv: ['aws-cdk-lib/testhelpers/jest-cleanup'], * }; * ``` */ static cleanupTemporaryDirectories() { for (const dir of TEMPORARY_ASSEMBLY_DIRS) { fs.rmSync(dir, { recursive: true, force: true }); } TEMPORARY_ASSEMBLY_DIRS.splice(0, TEMPORARY_ASSEMBLY_DIRS.length); } /** * Reads a cloud assembly from the specified directory. * @param directory - The root directory of the assembly. */ constructor(directory, loadOptions) { this.directory = directory; this.loadOptions = loadOptions; this.manifest = cxschema.Manifest.loadAssemblyManifest(path.join(directory, MANIFEST_FILE), this.loadOptions); this.version = this.manifest.version; this.artifacts = this.renderArtifacts(this.loadOptions?.topoSort ?? true); this.runtime = this.manifest.runtime || { libraries: {} }; Object.defineProperty(this, CLOUD_ASSEMBLY_SYMBOL, { value: true }); // force validation of deps by accessing 'depends' on all artifacts this.validateDeps(); } /** * Attempts to find an artifact with a specific identity. * @returns A `CloudArtifact` object or `undefined` if the artifact does not exist in this assembly. * @param id - The artifact ID */ tryGetArtifact(id) { return this.artifacts.find(a => a.id === id); } /** * Returns a CloudFormation stack artifact from this assembly. * * Will only search the current assembly. * * @param stackName - the name of the CloudFormation stack. * @throws if there is no stack artifact by that name * @throws if there is more than one stack with the same stack name. You can * use `getStackArtifact(stack.artifactId)` instead. * @returns a `CloudFormationStackArtifact` object. */ getStackByName(stackName) { const artifacts = this.artifacts.filter(a => a instanceof cloudformation_artifact_1.CloudFormationStackArtifact && a.stackName === stackName); if (!artifacts || artifacts.length === 0) { throw new error_1.CloudAssemblyError(`Unable to find stack with stack name "${stackName}"`); } if (artifacts.length > 1) { throw new error_1.CloudAssemblyError(`There are multiple stacks with the stack name "${stackName}" (${artifacts.map(a => a.id).join(',')}). Use "getStackArtifact(id)" instead`); } return artifacts[0]; } /** * Returns a CloudFormation stack artifact by name from this assembly. * @deprecated renamed to `getStackByName` (or `getStackArtifact(id)`) */ getStack(stackName) { return this.getStackByName(stackName); } /** * Returns a CloudFormation stack artifact from this assembly. * * @param artifactId - the artifact id of the stack (can be obtained through `stack.artifactId`). * @throws if there is no stack artifact with that id * @returns a `CloudFormationStackArtifact` object. */ getStackArtifact(artifactId) { const artifact = this.tryGetArtifactRecursively(artifactId); if (!artifact) { throw new error_1.CloudAssemblyError(`Unable to find artifact with id "${artifactId}"`); } if (!(artifact instanceof cloudformation_artifact_1.CloudFormationStackArtifact)) { throw new error_1.CloudAssemblyError(`Artifact ${artifactId} is not a CloudFormation stack`); } return artifact; } tryGetArtifactRecursively(artifactId) { return this.stacksRecursively.find(a => a.id === artifactId); } /** * Returns all the stacks, including the ones in nested assemblies */ get stacksRecursively() { function search(stackArtifacts, assemblies) { if (assemblies.length === 0) { return stackArtifacts; } const [head, ...tail] = assemblies; const nestedAssemblies = head.nestedAssemblies.map(asm => asm.nestedAssembly); return search(stackArtifacts.concat(head.stacks), tail.concat(nestedAssemblies)); } return search([], [this]); } /** * Returns a nested assembly artifact. * * @param artifactId - The artifact ID of the nested assembly */ getNestedAssemblyArtifact(artifactId) { const artifact = this.tryGetArtifact(artifactId); if (!artifact) { throw new error_1.CloudAssemblyError(`Unable to find artifact with id "${artifactId}"`); } if (!(artifact instanceof nested_cloud_assembly_artifact_1.NestedCloudAssemblyArtifact)) { throw new error_1.CloudAssemblyError(`Found artifact '${artifactId}' but it's not a nested cloud assembly`); } return artifact; } /** * Returns a nested assembly. * * @param artifactId - The artifact ID of the nested assembly */ getNestedAssembly(artifactId) { return this.getNestedAssemblyArtifact(artifactId).nestedAssembly; } /** * Returns the tree metadata artifact from this assembly. * @throws if there is no metadata artifact by that name * @returns a `TreeCloudArtifact` object if there is one defined in the manifest, `undefined` otherwise. */ tree() { const trees = this.artifacts.filter(a => a.manifest.type === cxschema.ArtifactType.CDK_TREE); if (trees.length === 0) { return undefined; } else if (trees.length > 1) { throw new error_1.CloudAssemblyError(`Multiple artifacts of type ${cxschema.ArtifactType.CDK_TREE} found in manifest`); } const tree = trees[0]; if (!(tree instanceof tree_cloud_artifact_1.TreeCloudArtifact)) { throw new error_1.CloudAssemblyError('"Tree" artifact is not of expected type'); } return tree; } /** * @returns all the CloudFormation stack artifacts that are included in this assembly. */ get stacks() { return this.artifacts.filter(isCloudFormationStackArtifact); function isCloudFormationStackArtifact(x) { return x instanceof cloudformation_artifact_1.CloudFormationStackArtifact; } } /** * The nested assembly artifacts in this assembly */ get nestedAssemblies() { return this.artifacts.filter(isNestedCloudAssemblyArtifact); function isNestedCloudAssemblyArtifact(x) { return x instanceof nested_cloud_assembly_artifact_1.NestedCloudAssemblyArtifact; } } validateDeps() { for (const artifact of this.artifacts) { ignore(artifact.dependencies); } } renderArtifacts(topoSort) { const result = new Array(); for (const [name, artifact] of Object.entries(this.manifest.artifacts || {})) { const cloudartifact = cloud_artifact_1.CloudArtifact.fromManifest(this, name, artifact); if (cloudartifact) { result.push(cloudartifact); } } return topoSort ? (0, toposort_1.topologicalSort)(result, x => x.id, x => x._dependencyIDs) : result; } } exports.CloudAssembly = CloudAssembly; /** * Can be used to build a cloud assembly. */ class CloudAssemblyBuilder { /** * Initializes a cloud assembly builder. * @param outdir - The output directory, uses temporary directory if undefined */ constructor(outdir, props = {}) { this.artifacts = {}; this.missing = new Array(); this.outdir = determineOutputDirectory(outdir); this.assetOutdir = props.assetOutdir ?? this.outdir; this.parentBuilder = props.parentBuilder; // we leverage the fact that outdir is long-lived to avoid staging assets into it // that were already staged (copying can be expensive). this is achieved by the fact // that assets use a source hash as their name. other artifacts, and the manifest itself, // will overwrite existing files as needed. ensureDirSync(this.outdir); } /** * Adds an artifact into the cloud assembly. * @param id - The ID of the artifact. * @param manifest - The artifact manifest */ addArtifact(id, manifest) { this.artifacts[id] = filterUndefined(manifest); } /** * Reports that some context is missing in order for this cloud assembly to be fully synthesized. * @param missing - Missing context information. */ addMissing(missing) { if (this.missing.every(m => m.key !== missing.key)) { this.missing.push(missing); } // Also report in parent this.parentBuilder?.addMissing(missing); } /** * Finalizes the cloud assembly into the output directory returns a * `CloudAssembly` object that can be used to inspect the assembly. */ buildAssembly(options = {}) { // explicitly initializing this type will help us detect // breaking changes. (For example adding a required property will break compilation). let manifest = { version: cxschema.Manifest.version(), artifacts: this.artifacts, runtime: options.runtimeInfo, missing: this.missing.length > 0 ? this.missing : undefined, }; // now we can filter manifest = filterUndefined(manifest); const manifestFilePath = path.join(this.outdir, MANIFEST_FILE); cxschema.Manifest.saveAssemblyManifest(manifest, manifestFilePath); // "backwards compatibility": in order for the old CLI to tell the user they // need a new version, we'll emit the legacy manifest with only "version". // this will result in an error "CDK Toolkit >= CLOUD_ASSEMBLY_VERSION is required in order to interact with this program." fs.writeFileSync(path.join(this.outdir, 'cdk.out'), JSON.stringify({ version: manifest.version })); return new CloudAssembly(this.outdir); } /** * Creates a nested cloud assembly */ createNestedAssembly(artifactId, displayName) { const directoryName = artifactId; const innerAsmDir = path.join(this.outdir, directoryName); this.addArtifact(artifactId, { type: cxschema.ArtifactType.NESTED_CLOUD_ASSEMBLY, properties: { directoryName, displayName, }, }); return new CloudAssemblyBuilder(innerAsmDir, { // Reuse the same asset output directory as the current Casm builder assetOutdir: this.assetOutdir, parentBuilder: this, }); } /** * Delete the cloud assembly directory */ delete() { fs.rmSync(this.outdir, { recursive: true, force: true }); } } exports.CloudAssemblyBuilder = CloudAssemblyBuilder; /** * Returns a copy of `obj` without undefined values in maps or arrays. */ function filterUndefined(obj) { if (Array.isArray(obj)) { return obj.filter(x => x !== undefined).map(x => filterUndefined(x)); } if (typeof (obj) === 'object') { const ret = {}; for (const [key, value] of Object.entries(obj)) { if (value === undefined) { continue; } ret[key] = filterUndefined(value); } return ret; } return obj; } function ignore(_x) { return; } /** * Turn the given optional output directory into a fixed output directory */ function determineOutputDirectory(outdir) { if (outdir) { return outdir; } // Make a temporary directory; clean it up automatically if this is done for testing. const tmpDir = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'cdk.out')); TEMPORARY_ASSEMBLY_DIRS.push(tmpDir); return outdir ?? tmpDir; } function ensureDirSync(dir) { if (fs.existsSync(dir)) { if (!fs.statSync(dir).isDirectory()) { throw new error_1.CloudAssemblyError(`${dir} must be a directory`); } } else { fs.mkdirSync(dir, { recursive: true }); } } // On process exit, delete all temporary assembly directories const TEMPORARY_ASSEMBLY_DIRS = []; process.on('exit', () => CloudAssembly.cleanupTemporaryDirectories()); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWQtYXNzZW1ibHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbG91ZC1hc3NlbWJseS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx5QkFBeUI7QUFDekIseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUU3QiwrREFBK0Q7QUFDL0QsaUZBQWtGO0FBQ2xGLCtGQUF5RjtBQUN6Rix5RUFBb0U7QUFDcEUscURBQWlEO0FBQ2pELDJDQUFxRDtBQUNyRCxpREFBcUQ7QUFFckQsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLCtCQUErQixDQUFDLENBQUM7QUFFMUU7O0dBRUc7QUFDSCxNQUFNLGFBQWEsR0FBRyxlQUFlLENBQUM7QUFFdEM7O0dBRUc7QUFDSCxNQUFhLGFBQWE7SUFDeEI7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBTTtRQUNsQyxPQUFPLENBQUMsS0FBSyxJQUFJLElBQUksT0FBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsSUFBSSxxQkFBcUIsSUFBSSxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0F1Q0c7SUFDSSxNQUFNLENBQUMsMkJBQTJCO1FBQ3ZDLEtBQUssTUFBTSxHQUFHLElBQUksdUJBQXVCLEVBQUUsQ0FBQztZQUMxQyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUNELHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsdUJBQXVCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQWdDRDs7O09BR0c7SUFDSCxZQUFZLFNBQWlCLEVBQUUsV0FBMEM7UUFDdkUsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFDM0IsSUFBSSxDQUFDLFdB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QU0sRUFBRSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQztJQUNsRix1QkFBdUIsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDckMsT0FBTyxNQUFNLElBQUksTUFBTSxDQUFDO0FBQzFCLENBQUM7QUFFRCxTQUFTLGFBQWEsQ0FBQyxHQUFXO0lBQ2hDLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUM7WUFDcEMsTUFBTSxJQUFJLDBCQUFrQixDQUFDLEdBQUcsR0FBRyxzQkFBc0IsQ0FBQyxDQUFDO1FBQzdELENBQUM7SUFDSCxDQUFDO1NBQU0sQ0FBQztRQUNOLEVBQUUsQ0FBQyxTQUFTLENBQUMsR0FBRyxFQUFFLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDekMsQ0FBQztBQUNILENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsTUFBTSx1QkFBdUIsR0FBYSxFQUFFLENBQUM7QUFDN0MsT0FBTyxDQUFDLEVBQUUsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLENBQUMsYUFBYSxDQUFDLDJCQUEyQixFQUFFLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIG9zIGZyb20gJ29zJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgdHlwZSB7IElDbG91ZEFzc2VtYmx5IH0gZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCAqIGFzIGN4c2NoZW1hIGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYS9saWInO1xuaW1wb3J0IHsgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IH0gZnJvbSAnLi9hcnRpZmFjdHMvY2xvdWRmb3JtYXRpb24tYXJ0aWZhY3QnO1xuaW1wb3J0IHsgTmVzdGVkQ2xvdWRBc3NlbWJseUFydGlmYWN0IH0gZnJvbSAnLi9hcnRpZmFjdHMvbmVzdGVkLWNsb3VkLWFzc2VtYmx5LWFydGlmYWN0JztcbmltcG9ydCB7IFRyZWVDbG91ZEFydGlmYWN0IH0gZnJvbSAnLi9hcnRpZmFjdHMvdHJlZS1jbG91ZC1hcnRpZmFjdCc7XG5pbXBvcnQgeyBDbG91ZEFydGlmYWN0IH0gZnJvbSAnLi9jbG91ZC1hcnRpZmFjdCc7XG5pbXBvcnQgeyBDbG91ZEFzc2VtYmx5RXJyb3IgfSBmcm9tICcuL3ByaXZhdGUvZXJyb3InO1xuaW1wb3J0IHsgdG9wb2xvZ2ljYWxTb3J0IH0gZnJvbSAnLi9wcml2YXRlL3RvcG9zb3J0JztcblxuY29uc3QgQ0xPVURfQVNTRU1CTFlfU1lNQk9MID0gU3ltYm9sLmZvcignQGF3cy1jZGsvY3gtYXBpLkNsb3VkQXNzZW1ibHknKTtcblxuLyoqXG4gKiBUaGUgbmFtZSBvZiB0aGUgcm9vdCBtYW5pZmVzdCBmaWxlIG9mIHRoZSBhc3NlbWJseS5cbiAqL1xuY29uc3QgTUFOSUZFU1RfRklMRSA9ICdtYW5pZmVzdC5qc29uJztcblxuLyoqXG4gKiBSZXByZXNlbnRzIGEgZGVwbG95YWJsZSBjbG91ZCBhcHBsaWNhdGlvbi5cbiAqL1xuZXhwb3J0IGNsYXNzIENsb3VkQXNzZW1ibHkgaW1wbGVtZW50cyBJQ2xvdWRBc3NlbWJseSB7XG4gIC8qKlxuICAgKiBSZXR1cm4gd2hldGhlciB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGEgQ2xvdWRBc3NlbWJseS5cbiAgICpcbiAgICogV2UgZG8gYXR0cmlidXRlIGRldGVjdGlvbiBzaW5jZSB3ZSBjYW4ndCByZWxpYWJseSB1c2UgJ2luc3RhbmNlb2YnLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBpc0Nsb3VkQXNzZW1ibHkoeDogYW55KTogeCBpcyBDbG91ZEFzc2VtYmx5IHtcbiAgICByZXR1cm4geCAhPT0gbnVsbCAmJiB0eXBlb2YoeCkgPT09ICdvYmplY3QnICYmIENMT1VEX0FTU0VNQkxZX1NZTUJPTCBpbiB4O1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFucyB1cCBhbnkgdGVtcG9yYXJ5IGFzc2VtYmx5IGRpcmVjdG9yaWVzIHRoYXQgZ290IGNyZWF0ZWQgaW4gdGhpcyBwcm9jZXNzXG4gICAqXG4gICAqIElmIGEgQ2xvdWQgQXNzZW1ibHkgaXMgZW1pdHRlZCB0byBhIHRlbXBvcmFyeSBkaXJlY3RvcnksIGl0cyBkaXJlY3RvcnkgZ2V0c1xuICAgKiBhZGRlZCB0byBhIGxpc3QuIFRoaXMgZnVuY3Rpb24gaXRlcmF0ZXMgb3ZlciB0aGF0IGxpc3QgYW5kIGRlbGV0ZXMgZWFjaFxuICAgKiBkaXJlY3RvcnkgaW4gaXQsIHRvIGZyZWUgdXAgZGlzayBzcGFjZS5cbiAgICpcbiAgICogVGhpcyBmdW5jdGlvbiB3aWxsIG5vcm1hbGx5IGJlIGNhbGxlZCBhdXRvbWF0aWNhbGx5IGR1cmluZyBOb2RlIHByb2Nlc3NcbiAgICogZXhpdCBhbmQgc28geW91IGRvbid0IG5lZWQgdG8gY2FsbCB0aGlzLiBIb3dldmVyLCBzb21lIHRlc3QgZW52aXJvbm1lbnRzIGRvXG4gICAqIG5vdCBwcm9wZXJseSB0cmlnZ2VyIE5vZGUncyBgZXhpdGAgZXZlbnQuIE5vdGFibHk6IEplc3QgZG9lcyBub3QgdHJpZ2dlclxuICAgKiB0aGUgYGV4aXRgIGV2ZW50ICg8aHR0cHM6Ly9naXRodWIuY29tL2plc3Rqcy9qZXN0L2lzc3Vlcy8xMDkyNz4pLlxuICAgKlxuICAgKiAjIyBDbGVhbmluZyB1cCB0ZW1wb3JhcnkgZGlyZWN0b3JpZXMgaW4gamVzdFxuICAgKlxuICAgKiBGb3IgSmVzdCwgeW91IGhhdmUgdG8gbWFrZSBzdXJlIHRoaXMgZnVuY3Rpb24gaXMgY2FsbGVkIGF0IHRoZSBlbmQgb2YgdGhlXG4gICAqIHRlc3Qgc3VpdGUgaW5zdGVhZDpcbiAgICpcbiAgICogYGBganNcbiAgICogaW1wb3J0IHsgQ2xvdWRBc3NlbWJseSB9IGZyb20gJ2F3cy1jZGstbGliL2N4LWFwaSc7XG4gICAqXG4gICAqIGFmdGVyQWxsKENsb3VkQXNzZW1ibHkuY2xlYW51cFRlbXBvcmFyeURpcmVjdG9yaWVzKTtcbiAgICogYGBgXG4gICAqXG4gICAqIEFsdGVybmF0aXZlbHksIHlvdSBjYW4gdXNlIHRoZSBgc2V0dXBGaWxlc0FmdGVyRW52YCBmZWF0dXJlIGFuZCB1c2UgYVxuICAgKiBwcm92aWRlZCBoZWxwZXIgc2NyaXB0IHRvIGF1dG9tYXRpY2FsbHkgaW5qZWN0IHRoZSBhYm92ZSBpbnRvIGV2ZXJ5XG4gICAqIHRlc3QgZmlsZSwgc28geW91IGRvbid0IGhhdmUgdG8gZG8gaXQgYnkgaGFuZC5cbiAgICpcbiAgICogYGBgXG4gICAqICQgbnB4IGplc3QgLS1zZXR1cEZpbGVzQWZ0ZXJFbnYgYXdzLWNkay1saWIvdGVzdGhlbHBlcnMvamVzdC1hdXRvY2xlYW5cbiAgICogYGBgXG4gICAqXG4gICAqIE9yIHB1dCB0aGUgZm9sbG93aW5nIGludG8gYGplc3QuY29uZmlnLmpzYDpcbiAgICpcbiAgICogYGBganNcbiAgICogbW9kdWxlLmV4cG9ydHMgPSB7XG4gICAqICAgLy8gLi4uXG4gICAqICAgc2V0dXBGaWxlc0FmdGVyRW52OiBbJ2F3cy1jZGstbGliL3Rlc3RoZWxwZXJzL2plc3QtY2xlYW51cCddLFxuICAgKiB9O1xuICAgKiBgYGBcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgY2xlYW51cFRlbXBvcmFyeURpcmVjdG9yaWVzKCkge1xuICAgIGZvciAoY29uc3QgZGlyIG9mIFRFTVBPUkFSWV9BU1NFTUJMWV9ESVJTKSB7XG4gICAgICBmcy5ybVN5bmMoZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gICAgfVxuICAgIFRFTVBPUkFSWV9BU1NFTUJMWV9ESVJTLnNwbGljZSgwLCBURU1QT1JBUllfQVNTRU1CTFlfRElSUy5sZW5ndGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSByb290IGRpcmVjdG9yeSBvZiB0aGUgY2xvdWQgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgZGlyZWN0b3J5OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBzY2hlbWEgdmVyc2lvbiBvZiB0aGUgYXNzZW1ibHkgbWFuaWZlc3QuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgdmVyc2lvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBbGwgYXJ0aWZhY3RzIGluY2x1ZGVkIGluIHRoaXMgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXJ0aWZhY3RzOiBDbG91ZEFydGlmYWN0W107XG5cbiAgLyoqXG4gICAqIFJ1bnRpbWUgaW5mb3JtYXRpb24gc3VjaCBhcyBtb2R1bGUgdmVyc2lvbnMgdXNlZCB0byBzeW50aGVzaXplIHRoaXMgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcnVudGltZTogY3hzY2hlbWEuUnVudGltZUluZm87XG5cbiAgLyoqXG4gICAqIFRoZSByYXcgYXNzZW1ibHkgbWFuaWZlc3QuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgbWFuaWZlc3Q6IGN4c2NoZW1hLkFzc2VtYmx5TWFuaWZlc3Q7XG5cbiAgLyoqXG4gICAqIFRoZSBsb2FkIG9wdGlvbnMgdXNlZCB0byBjcmVhdGUgdGhpcyBhc3NlbWJseSwgcHJvcGFnYXRlZCB0byBuZXN0ZWQgYXNzZW1ibGllcy5cbiAgICovXG4gIHByaXZhdGUgcmVhZG9ubHkgbG9hZE9wdGlvbnM/OiBjeHNjaGVtYS5Mb2FkTWFuaWZlc3RPcHRpb25zO1xuXG4gIC8qKlxuICAgKiBSZWFkcyBhIGNsb3VkIGFzc2VtYmx5IGZyb20gdGhlIHNwZWNpZmllZCBkaXJlY3RvcnkuXG4gICAqIEBwYXJhbSBkaXJlY3RvcnkgLSBUaGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhlIGFzc2VtYmx5LlxuICAgKi9cbiAgY29uc3RydWN0b3IoZGlyZWN0b3J5OiBzdHJpbmcsIGxvYWRPcHRpb25zPzogY3hzY2hlbWEuTG9hZE1hbmlmZXN0T3B0aW9ucykge1xuICAgIHRoaXMuZGlyZWN0b3J5ID0gZGlyZWN0b3J5O1xuICAgIHRoaXMubG9hZE9wdGlvbnMgPSBsb2FkT3B0aW9ucztcblxuICAgIHRoaXMubWFuaWZlc3QgPSBjeHNjaGVtYS5NYW5pZmVzdC5sb2FkQXNzZW1ibHlNYW5pZmVzdChwYXRoLmpvaW4oZGlyZWN0b3J5LCBNQU5JRkVTVF9GSUxFKSwgdGhpcy5sb2FkT3B0aW9ucyk7XG4gICAgdGhpcy52ZXJzaW9uID0gdGhpcy5tYW5pZmVzdC52ZXJzaW9uO1xuICAgIHRoaXMuYXJ0aWZhY3RzID0gdGhpcy5yZW5kZXJBcnRpZmFjdHModGhpcy5sb2FkT3B0aW9ucz8udG9wb1NvcnQgPz8gdHJ1ZSk7XG4gICAgdGhpcy5ydW50aW1lID0gdGhpcy5tYW5pZmVzdC5ydW50aW1lIHx8IHsgbGlicmFyaWVzOiB7IH0gfTtcblxuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0aGlzLCBDTE9VRF9BU1NFTUJMWV9TWU1CT0wsIHsgdmFsdWU6IHRydWUgfSk7XG5cbiAgICAvLyBmb3JjZSB2YWxpZGF0aW9uIG9mIGRlcHMgYnkgYWNjZXNzaW5nICdkZXBlbmRzJyBvbiBhbGwgYXJ0aWZhY3RzXG4gICAgdGhpcy52YWxpZGF0ZURlcHMoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBdHRlbXB0cyB0byBmaW5kIGFuIGFydGlmYWN0IHdpdGggYSBzcGVjaWZpYyBpZGVudGl0eS5cbiAgICogQHJldHVybnMgQSBgQ2xvdWRBcnRpZmFjdGAgb2JqZWN0IG9yIGB1bmRlZmluZWRgIGlmIHRoZSBhcnRpZmFjdCBkb2VzIG5vdCBleGlzdCBpbiB0aGlzIGFzc2VtYmx5LlxuICAgKiBAcGFyYW0gaWQgLSBUaGUgYXJ0aWZhY3QgSURcbiAgICovXG4gIHB1YmxpYyB0cnlHZXRBcnRpZmFjdChpZDogc3RyaW5nKTogQ2xvdWRBcnRpZmFjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuYXJ0aWZhY3RzLmZpbmQoYSA9PiBhLmlkID09PSBpZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICpcbiAgICogV2lsbCBvbmx5IHNlYXJjaCB0aGUgY3VycmVudCBhc3NlbWJseS5cbiAgICpcbiAgICogQHBhcmFtIHN0YWNrTmFtZSAtIHRoZSBuYW1lIG9mIHRoZSBDbG91ZEZvcm1hdGlvbiBzdGFjay5cbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBubyBzdGFjayBhcnRpZmFjdCBieSB0aGF0IG5hbWVcbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIHN0YWNrIHdpdGggdGhlIHNhbWUgc3RhY2sgbmFtZS4gWW91IGNhblxuICAgKiB1c2UgYGdldFN0YWNrQXJ0aWZhY3Qoc3RhY2suYXJ0aWZhY3RJZClgIGluc3RlYWQuXG4gICAqIEByZXR1cm5zIGEgYENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdGAgb2JqZWN0LlxuICAgKi9cbiAgcHVibGljIGdldFN0YWNrQnlOYW1lKHN0YWNrTmFtZTogc3RyaW5nKTogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IHtcbiAgICBjb25zdCBhcnRpZmFjdHMgPSB0aGlzLmFydGlmYWN0cy5maWx0ZXIoYSA9PiBhIGluc3RhbmNlb2YgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0ICYmIGEuc3RhY2tOYW1lID09PSBzdGFja05hbWUpO1xuICAgIGlmICghYXJ0aWZhY3RzIHx8IGFydGlmYWN0cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHRocm93IG5ldyBDbG91ZEFzc2VtYmx5RXJyb3IoYFVuYWJsZSB0byBmaW5kIHN0YWNrIHdpdGggc3RhY2sgbmFtZSBcIiR7c3RhY2tOYW1lfVwiYCk7XG4gICAgfVxuXG4gICAgaWYgKGFydGlmYWN0cy5sZW5ndGggPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBUaGVyZSBhcmUgbXVsdGlwbGUgc3RhY2tzIHdpdGggdGhlIHN0YWNrIG5hbWUgXCIke3N0YWNrTmFtZX1cIiAoJHthcnRpZmFjdHMubWFwKGEgPT4gYS5pZCkuam9pbignLCcpfSkuIFVzZSBcImdldFN0YWNrQXJ0aWZhY3QoaWQpXCIgaW5zdGVhZGApO1xuICAgIH1cblxuICAgIHJldHVybiBhcnRpZmFjdHNbMF0gYXMgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBDbG91ZEZvcm1hdGlvbiBzdGFjayBhcnRpZmFjdCBieSBuYW1lIGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICogQGRlcHJlY2F0ZWQgcmVuYW1lZCB0byBgZ2V0U3RhY2tCeU5hbWVgIChvciBgZ2V0U3RhY2tBcnRpZmFjdChpZClgKVxuICAgKi9cbiAgcHVibGljIGdldFN0YWNrKHN0YWNrTmFtZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0U3RhY2tCeU5hbWUoc3RhY2tOYW1lKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgQ2xvdWRGb3JtYXRpb24gc3RhY2sgYXJ0aWZhY3QgZnJvbSB0aGlzIGFzc2VtYmx5LlxuICAgKlxuICAgKiBAcGFyYW0gYXJ0aWZhY3RJZCAtIHRoZSBhcnRpZmFjdCBpZCBvZiB0aGUgc3RhY2sgKGNhbiBiZSBvYnRhaW5lZCB0aHJvdWdoIGBzdGFjay5hcnRpZmFjdElkYCkuXG4gICAqIEB0aHJvd3MgaWYgdGhlcmUgaXMgbm8gc3RhY2sgYXJ0aWZhY3Qgd2l0aCB0aGF0IGlkXG4gICAqIEByZXR1cm5zIGEgYENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdGAgb2JqZWN0LlxuICAgKi9cbiAgcHVibGljIGdldFN0YWNrQXJ0aWZhY3QoYXJ0aWZhY3RJZDogc3RyaW5nKTogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IHtcbiAgICBjb25zdCBhcnRpZmFjdCA9IHRoaXMudHJ5R2V0QXJ0aWZhY3RSZWN1cnNpdmVseShhcnRpZmFjdElkKTtcblxuICAgIGlmICghYXJ0aWZhY3QpIHtcbiAgICAgIHRocm93IG5ldyBDbG91ZEFzc2VtYmx5RXJyb3IoYFVuYWJsZSB0byBmaW5kIGFydGlmYWN0IHdpdGggaWQgXCIke2FydGlmYWN0SWR9XCJgKTtcbiAgICB9XG5cbiAgICBpZiAoIShhcnRpZmFjdCBpbnN0YW5jZW9mIENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCkpIHtcbiAgICAgIHRocm93IG5ldyBDbG91ZEFzc2VtYmx5RXJyb3IoYEFydGlmYWN0ICR7YXJ0aWZhY3RJZH0gaXMgbm90IGEgQ2xvdWRGb3JtYXRpb24gc3RhY2tgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJ0aWZhY3Q7XG4gIH1cblxuICBwcml2YXRlIHRyeUdldEFydGlmYWN0UmVjdXJzaXZlbHkoYXJ0aWZhY3RJZDogc3RyaW5nKTogQ2xvdWRBcnRpZmFjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc3RhY2tzUmVjdXJzaXZlbHkuZmluZChhID0+IGEuaWQgPT09IGFydGlmYWN0SWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYWxsIHRoZSBzdGFja3MsIGluY2x1ZGluZyB0aGUgb25lcyBpbiBuZXN0ZWQgYXNzZW1ibGllc1xuICAgKi9cbiAgcHVibGljIGdldCBzdGFja3NSZWN1cnNpdmVseSgpOiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RbXSB7XG4gICAgZnVuY3Rpb24gc2VhcmNoKHN0YWNrQXJ0aWZhY3RzOiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RbXSwgYXNzZW1ibGllczogQ2xvdWRBc3NlbWJseVtdKTogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0W10ge1xuICAgICAgaWYgKGFzc2VtYmxpZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHJldHVybiBzdGFja0FydGlmYWN0cztcbiAgICAgIH1cblxuICAgICAgY29uc3QgW2hlYWQsIC4uLnRhaWxdID0gYXNzZW1ibGllcztcbiAgICAgIGNvbnN0IG5lc3RlZEFzc2VtYmxpZXMgPSBoZWFkLm5lc3RlZEFzc2VtYmxpZXMubWFwKGFzbSA9PiBhc20ubmVzdGVkQXNzZW1ibHkpO1xuICAgICAgcmV0dXJuIHNlYXJjaChzdGFja0FydGlmYWN0cy5jb25jYXQoaGVhZC5zdGFja3MpLCB0YWlsLmNvbmNhdChuZXN0ZWRBc3NlbWJsaWVzKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHNlYXJjaChbXSwgW3RoaXNdKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbmVzdGVkIGFzc2VtYmx5IGFydGlmYWN0LlxuICAgKlxuICAgKiBAcGFyYW0gYXJ0aWZhY3RJZCAtIFRoZSBhcnRpZmFjdCBJRCBvZiB0aGUgbmVzdGVkIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0TmVzdGVkQXNzZW1ibHlBcnRpZmFjdChhcnRpZmFjdElkOiBzdHJpbmcpOiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Qge1xuICAgIGNvbnN0IGFydGlmYWN0ID0gdGhpcy50cnlHZXRBcnRpZmFjdChhcnRpZmFjdElkKTtcbiAgICBpZiAoIWFydGlmYWN0KSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBVbmFibGUgdG8gZmluZCBhcnRpZmFjdCB3aXRoIGlkIFwiJHthcnRpZmFjdElkfVwiYCk7XG4gICAgfVxuXG4gICAgaWYgKCEoYXJ0aWZhY3QgaW5zdGFuY2VvZiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QpKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBGb3VuZCBhcnRpZmFjdCAnJHthcnRpZmFjdElkfScgYnV0IGl0J3Mgbm90IGEgbmVzdGVkIGNsb3VkIGFzc2VtYmx5YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFydGlmYWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBuZXN0ZWQgYXNzZW1ibHkuXG4gICAqXG4gICAqIEBwYXJhbSBhcnRpZmFjdElkIC0gVGhlIGFydGlmYWN0IElEIG9mIHRoZSBuZXN0ZWQgYXNzZW1ibHlcbiAgICovXG4gIHB1YmxpYyBnZXROZXN0ZWRBc3NlbWJseShhcnRpZmFjdElkOiBzdHJpbmcpOiBDbG91ZEFzc2VtYmx5IHtcbiAgICByZXR1cm4gdGhpcy5nZXROZXN0ZWRBc3NlbWJseUFydGlmYWN0KGFydGlmYWN0SWQpLm5lc3RlZEFzc2VtYmx5O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHRyZWUgbWV0YWRhdGEgYXJ0aWZhY3QgZnJvbSB0aGlzIGFzc2VtYmx5LlxuICAgKiBAdGhyb3dzIGlmIHRoZXJlIGlzIG5vIG1ldGFkYXRhIGFydGlmYWN0IGJ5IHRoYXQgbmFtZVxuICAgKiBAcmV0dXJucyBhIGBUcmVlQ2xvdWRBcnRpZmFjdGAgb2JqZWN0IGlmIHRoZXJlIGlzIG9uZSBkZWZpbmVkIGluIHRoZSBtYW5pZmVzdCwgYHVuZGVmaW5lZGAgb3RoZXJ3aXNlLlxuICAgKi9cbiAgcHVibGljIHRyZWUoKTogVHJlZUNsb3VkQXJ0aWZhY3QgfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHRyZWVzID0gdGhpcy5hcnRpZmFjdHMuZmlsdGVyKGEgPT4gYS5tYW5pZmVzdC50eXBlID09PSBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQ0RLX1RSRUUpO1xuICAgIGlmICh0cmVlcy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSBlbHNlIGlmICh0cmVlcy5sZW5ndGggPiAxKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBNdWx0aXBsZSBhcnRpZmFjdHMgb2YgdHlwZSAke2N4c2NoZW1hLkFydGlmYWN0VHlwZS5DREtfVFJFRX0gZm91bmQgaW4gbWFuaWZlc3RgKTtcbiAgICB9XG4gICAgY29uc3QgdHJlZSA9IHRyZWVzWzBdO1xuXG4gICAgaWYgKCEodHJlZSBpbnN0YW5jZW9mIFRyZWVDbG91ZEFydGlmYWN0KSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcignXCJUcmVlXCIgYXJ0aWZhY3QgaXMgbm90IG9mIGV4cGVjdGVkIHR5cGUnKTtcbiAgICB9XG5cbiAgICByZXR1cm4gdHJlZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJucyBhbGwgdGhlIENsb3VkRm9ybWF0aW9uIHN0YWNrIGFydGlmYWN0cyB0aGF0IGFyZSBpbmNsdWRlZCBpbiB0aGlzIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIGdldCBzdGFja3MoKTogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0W10ge1xuICAgIHJldHVybiB0aGlzLmFydGlmYWN0cy5maWx0ZXIoaXNDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QpO1xuXG4gICAgZnVuY3Rpb24gaXNDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QoeDogYW55KTogeCBpcyBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3Qge1xuICAgICAgcmV0dXJuIHggaW5zdGFuY2VvZiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3Q7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBuZXN0ZWQgYXNzZW1ibHkgYXJ0aWZhY3RzIGluIHRoaXMgYXNzZW1ibHlcbiAgICovXG4gIHB1YmxpYyBnZXQgbmVzdGVkQXNzZW1ibGllcygpOiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3RbXSB7XG4gICAgcmV0dXJuIHRoaXMuYXJ0aWZhY3RzLmZpbHRlcihpc05lc3RlZENsb3VkQXNzZW1ibHlBcnRpZmFjdCk7XG5cbiAgICBmdW5jdGlvbiBpc05lc3RlZENsb3VkQXNzZW1ibHlBcnRpZmFjdCh4OiBhbnkpOiB4IGlzIE5lc3RlZENsb3VkQXNzZW1ibHlBcnRpZmFjdCB7XG4gICAgICByZXR1cm4geCBpbnN0YW5jZW9mIE5lc3RlZENsb3VkQXNzZW1ibHlBcnRpZmFjdDtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHZhbGlkYXRlRGVwcygpIHtcbiAgICBmb3IgKGNvbnN0IGFydGlmYWN0IG9mIHRoaXMuYXJ0aWZhY3RzKSB7XG4gICAgICBpZ25vcmUoYXJ0aWZhY3QuZGVwZW5kZW5jaWVzKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHJlbmRlckFydGlmYWN0cyh0b3BvU29ydDogYm9vbGVhbikge1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheTxDbG91ZEFydGlmYWN0PigpO1xuICAgIGZvciAoY29uc3QgW25hbWUsIGFydGlmYWN0XSBvZiBPYmplY3QuZW50cmllcyh0aGlzLm1hbmlmZXN0LmFydGlmYWN0cyB8fCB7IH0pKSB7XG4gICAgICBjb25zdCBjbG91ZGFydGlmYWN0ID0gQ2xvdWRBcnRpZmFjdC5mcm9tTWFuaWZlc3QodGhpcywgbmFtZSwgYXJ0aWZhY3QpO1xuICAgICAgaWYgKGNsb3VkYXJ0aWZhY3QpIHtcbiAgICAgICAgcmVzdWx0LnB1c2goY2xvdWRhcnRpZmFjdCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHRvcG9Tb3J0ID8gdG9wb2xvZ2ljYWxTb3J0KHJlc3VsdCwgeCA9PiB4LmlkLCB4ID0+IHguX2RlcGVuZGVuY3lJRHMpIDogcmVzdWx0O1xuICB9XG59XG5cbi8qKlxuICogQ29uc3RydWN0aW9uIHByb3BlcnRpZXMgZm9yIENsb3VkQXNzZW1ibHlCdWlsZGVyXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xvdWRBc3NlbWJseUJ1aWxkZXJQcm9wcyB7XG4gIC8qKlxuICAgKiBVc2UgdGhlIGdpdmVuIGFzc2V0IG91dHB1dCBkaXJlY3RvcnlcbiAgICpcbiAgICogQGRlZmF1bHQgLSBTYW1lIGFzIHRoZSBtYW5pZmVzdCBvdXRkaXJcbiAgICovXG4gIHJlYWRvbmx5IGFzc2V0T3V0ZGlyPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBJZiB0aGlzIGJ1aWxkZXIgaXMgZm9yIGEgbmVzdGVkIGFzc2VtYmx5LCB0aGUgcGFyZW50IGFzc2VtYmx5IGJ1aWxkZXJcbiAgICpcbiAgICogQGRlZmF1bHQgLSBUaGlzIGlzIGEgcm9vdCBhc3NlbWJseVxuICAgKi9cbiAgcmVhZG9ubHkgcGFyZW50QnVpbGRlcj86IENsb3VkQXNzZW1ibHlCdWlsZGVyO1xufVxuXG4vKipcbiAqIENhbiBiZSB1c2VkIHRvIGJ1aWxkIGEgY2xvdWQgYXNzZW1ibHkuXG4gKi9cbmV4cG9ydCBjbGFzcyBDbG91ZEFzc2VtYmx5QnVpbGRlciB7XG4gIC8qKlxuICAgKiBUaGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhlIHJlc3VsdGluZyBjbG91ZCBhc3NlbWJseS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBvdXRkaXI6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRpcmVjdG9yeSB3aGVyZSBhc3NldHMgb2YgdGhpcyBDbG91ZCBBc3NlbWJseSBzaG91bGQgYmUgc3RvcmVkXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgYXNzZXRPdXRkaXI6IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IGFydGlmYWN0czogeyBbaWQ6IHN0cmluZ106IGN4c2NoZW1hLkFydGlmYWN0TWFuaWZlc3QgfSA9IHsgfTtcbiAgcHJpdmF0ZSByZWFkb25seSBtaXNzaW5nID0gbmV3IEFycmF5PGN4c2NoZW1hLk1pc3NpbmdDb250ZXh0PigpO1xuICBwcml2YXRlIHJlYWRvbmx5IHBhcmVudEJ1aWxkZXI/OiBDbG91ZEFzc2VtYmx5QnVpbGRlcjtcblxuICAvKipcbiAgICogSW5pdGlhbGl6ZXMgYSBjbG91ZCBhc3NlbWJseSBidWlsZGVyLlxuICAgKiBAcGFyYW0gb3V0ZGlyIC0gVGhlIG91dHB1dCBkaXJlY3RvcnksIHVzZXMgdGVtcG9yYXJ5IGRpcmVjdG9yeSBpZiB1bmRlZmluZWRcbiAgICovXG4gIGNvbnN0cnVjdG9yKG91dGRpcj86IHN0cmluZywgcHJvcHM6IENsb3VkQXNzZW1ibHlCdWlsZGVyUHJvcHMgPSB7fSkge1xuICAgIHRoaXMub3V0ZGlyID0gZGV0ZXJtaW5lT3V0cHV0RGlyZWN0b3J5KG91dGRpcik7XG4gICAgdGhpcy5hc3NldE91dGRpciA9IHByb3BzLmFzc2V0T3V0ZGlyID8/IHRoaXMub3V0ZGlyO1xuICAgIHRoaXMucGFyZW50QnVpbGRlciA9IHByb3BzLnBhcmVudEJ1aWxkZXI7XG5cbiAgICAvLyB3ZSBsZXZlcmFnZSB0aGUgZmFjdCB0aGF0IG91dGRpciBpcyBsb25nLWxpdmVkIHRvIGF2b2lkIHN0YWdpbmcgYXNzZXRzIGludG8gaXRcbiAgICAvLyB0aGF0IHdlcmUgYWxyZWFkeSBzdGFnZWQgKGNvcHlpbmcgY2FuIGJlIGV4cGVuc2l2ZSkuIHRoaXMgaXMgYWNoaWV2ZWQgYnkgdGhlIGZhY3RcbiAgICAvLyB0aGF0IGFzc2V0cyB1c2UgYSBzb3VyY2UgaGFzaCBhcyB0aGVpciBuYW1lLiBvdGhlciBhcnRpZmFjdHMsIGFuZCB0aGUgbWFuaWZlc3QgaXRzZWxmLFxuICAgIC8vIHdpbGwgb3ZlcndyaXRlIGV4aXN0aW5nIGZpbGVzIGFzIG5lZWRlZC5cbiAgICBlbnN1cmVEaXJTeW5jKHRoaXMub3V0ZGlyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIGFydGlmYWN0IGludG8gdGhlIGNsb3VkIGFzc2VtYmx5LlxuICAgKiBAcGFyYW0gaWQgLSBUaGUgSUQgb2YgdGhlIGFydGlmYWN0LlxuICAgKiBAcGFyYW0gbWFuaWZlc3QgLSBUaGUgYXJ0aWZhY3QgbWFuaWZlc3RcbiAgICovXG4gIHB1YmxpYyBhZGRBcnRpZmFjdChpZDogc3RyaW5nLCBtYW5pZmVzdDogY3hzY2hlbWEuQXJ0aWZhY3RNYW5pZmVzdCkge1xuICAgIHRoaXMuYXJ0aWZhY3RzW2lkXSA9IGZpbHRlclVuZGVmaW5lZChtYW5pZmVzdCk7XG4gIH1cblxuICAvKipcbiAgICogUmVwb3J0cyB0aGF0IHNvbWUgY29udGV4dCBpcyBtaXNzaW5nIGluIG9yZGVyIGZvciB0aGlzIGNsb3VkIGFzc2VtYmx5IHRvIGJlIGZ1bGx5IHN5bnRoZXNpemVkLlxuICAgKiBAcGFyYW0gbWlzc2luZyAtIE1pc3NpbmcgY29udGV4dCBpbmZvcm1hdGlvbi5cbiAgICovXG4gIHB1YmxpYyBhZGRNaXNzaW5nKG1pc3Npbmc6IGN4c2NoZW1hLk1pc3NpbmdDb250ZXh0KSB7XG4gICAgaWYgKHRoaXMubWlzc2luZy5ldmVyeShtID0+IG0ua2V5ICE9PSBtaXNzaW5nLmtleSkpIHtcbiAgICAgIHRoaXMubWlzc2luZy5wdXNoKG1pc3NpbmcpO1xuICAgIH1cbiAgICAvLyBBbHNvIHJlcG9ydCBpbiBwYXJlbnRcbiAgICB0aGlzLnBhcmVudEJ1aWxkZXI/LmFkZE1pc3NpbmcobWlzc2luZyk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemVzIHRoZSBjbG91ZCBhc3NlbWJseSBpbnRvIHRoZSBvdXRwdXQgZGlyZWN0b3J5IHJldHVybnMgYVxuICAgKiBgQ2xvdWRBc3NlbWJseWAgb2JqZWN0IHRoYXQgY2FuIGJlIHVzZWQgdG8gaW5zcGVjdCB0aGUgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgYnVpbGRBc3NlbWJseShvcHRpb25zOiBBc3NlbWJseUJ1aWxkT3B0aW9ucyA9IHsgfSk6IENsb3VkQXNzZW1ibHkge1xuICAgIC8vIGV4cGxpY2l0bHkgaW5pdGlhbGl6aW5nIHRoaXMgdHlwZSB3aWxsIGhlbHAgdXMgZGV0ZWN0XG4gICAgLy8gYnJlYWtpbmcgY2hhbmdlcy4gKEZvciBleGFtcGxlIGFkZGluZyBhIHJlcXVpcmVkIHByb3BlcnR5IHdpbGwgYnJlYWsgY29tcGlsYXRpb24pLlxuICAgIGxldCBtYW5pZmVzdDogY3hzY2hlbWEuQXNzZW1ibHlNYW5pZmVzdCA9IHtcbiAgICAgIHZlcnNpb246IGN4c2NoZW1hLk1hbmlmZXN0LnZlcnNpb24oKSxcbiAgICAgIGFydGlmYWN0czogdGhpcy5hcnRpZmFjdHMsXG4gICAgICBydW50aW1lOiBvcHRpb25zLnJ1bnRpbWVJbmZvLFxuICAgICAgbWlzc2luZzogdGhpcy5taXNzaW5nLmxlbmd0aCA+IDAgPyB0aGlzLm1pc3NpbmcgOiB1bmRlZmluZWQsXG4gICAgfTtcblxuICAgIC8vIG5vdyB3ZSBjYW4gZmlsdGVyXG4gICAgbWFuaWZlc3QgPSBmaWx0ZXJVbmRlZmluZWQobWFuaWZlc3QpO1xuXG4gICAgY29uc3QgbWFuaWZlc3RGaWxlUGF0aCA9IHBhdGguam9pbih0aGlzLm91dGRpciwgTUFOSUZFU1RfRklMRSk7XG4gICAgY3hzY2hlbWEuTWFuaWZlc3Quc2F2ZUFzc2VtYmx5TWFuaWZlc3QobWFuaWZlc3QsIG1hbmlmZXN0RmlsZVBhdGgpO1xuXG4gICAgLy8gXCJiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVwiOiBpbiBvcmRlciBmb3IgdGhlIG9sZCBDTEkgdG8gdGVsbCB0aGUgdXNlciB0aGV5XG4gICAgLy8gbmVlZCBhIG5ldyB2ZXJzaW9uLCB3ZSdsbCBlbWl0IHRoZSBsZWdhY3kgbWFuaWZlc3Qgd2l0aCBvbmx5IFwidmVyc2lvblwiLlxuICAgIC8vIHRoaXMgd2lsbCByZXN1bHQgaW4gYW4gZXJyb3IgXCJDREsgVG9vbGtpdCA+PSBDTE9VRF9BU1NFTUJMWV9WRVJTSU9OIGlzIHJlcXVpcmVkIGluIG9yZGVyIHRvIGludGVyYWN0IHdpdGggdGhpcyBwcm9ncmFtLlwiXG4gICAgZnMud3JpdGVGaWxlU3luYyhwYXRoLmpvaW4odGhpcy5vdXRkaXIsICdjZGsub3V0JyksIEpTT04uc3RyaW5naWZ5KHsgdmVyc2lvbjogbWFuaWZlc3QudmVyc2lvbiB9KSk7XG5cbiAgICByZXR1cm4gbmV3IENsb3VkQXNzZW1ibHkodGhpcy5vdXRkaXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXN0ZWQgY2xvdWQgYXNzZW1ibHlcbiAgICovXG4gIHB1YmxpYyBjcmVhdGVOZXN0ZWRBc3NlbWJseShhcnRpZmFjdElkOiBzdHJpbmcsIGRpc3BsYXlOYW1lOiBzdHJpbmcpIHtcbiAgICBjb25zdCBkaXJlY3RvcnlOYW1lID0gYXJ0aWZhY3RJZDtcbiAgICBjb25zdCBpbm5lckFzbURpciA9IHBhdGguam9pbih0aGlzLm91dGRpciwgZGlyZWN0b3J5TmFtZSk7XG5cbiAgICB0aGlzLmFkZEFydGlmYWN0KGFydGlmYWN0SWQsIHtcbiAgICAgIHR5cGU6IGN4c2NoZW1hLkFydGlmYWN0VHlwZS5ORVNURURfQ0xPVURfQVNTRU1CTFksXG4gICAgICBwcm9wZXJ0aWVzOiB7XG4gICAgICAgIGRpcmVjdG9yeU5hbWUsXG4gICAgICAgIGRpc3BsYXlOYW1lLFxuICAgICAgfSBhcyBjeHNjaGVtYS5OZXN0ZWRDbG91ZEFzc2VtYmx5UHJvcGVydGllcyxcbiAgICB9KTtcblxuICAgIHJldHVybiBuZXcgQ2xvdWRBc3NlbWJseUJ1aWxkZXIoaW5uZXJBc21EaXIsIHtcbiAgICAgIC8vIFJldXNlIHRoZSBzYW1lIGFzc2V0IG91dHB1dCBkaXJlY3RvcnkgYXMgdGhlIGN1cnJlbnQgQ2FzbSBidWlsZGVyXG4gICAgICBhc3NldE91dGRpcjogdGhpcy5hc3NldE91dGRpcixcbiAgICAgIHBhcmVudEJ1aWxkZXI6IHRoaXMsXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlIHRoZSBjbG91ZCBhc3NlbWJseSBkaXJlY3RvcnlcbiAgICovXG4gIHB1YmxpYyBkZWxldGUoKSB7XG4gICAgZnMucm1TeW5jKHRoaXMub3V0ZGlyLCB7IHJlY3Vyc2l2ZTogdHJ1ZSwgZm9yY2U6IHRydWUgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBmb3Igd2hlbiBgUnVudGltZUluZm9gXG4gKiB3YXMgZGVmaW5lZCBoZXJlLiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIGl0cyB1c2VkIGFzIGFuIGlucHV0IGluIHRoZSBzdGFibGVcbiAqIEBhd3MtY2RrL2NvcmUgbGlicmFyeS5cbiAqXG4gKiBAZGVwcmVjYXRlZCBtb3ZlZCB0byBwYWNrYWdlICdjbG91ZC1hc3NlbWJseS1zY2hlbWEnXG4gKiBAc2VlIGNvcmUuQ29uc3RydWN0Tm9kZS5zeW50aFxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJ1bnRpbWVJbmZvIGV4dGVuZHMgY3hzY2hlbWEuUnVudGltZUluZm8ge1xuXG59XG5cbi8qKlxuICogQmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIHdoZW4gYE1ldGFkYXRhRW50cnlgXG4gKiB3YXMgZGVmaW5lZCBoZXJlLiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIGl0cyB1c2VkIGFzIGFuIGlucHV0IGluIHRoZSBzdGFibGVcbiAqIEBhd3MtY2RrL2NvcmUgbGlicmFyeS5cbiAqXG4gKiBAZGVwcmVjYXRlZCBtb3ZlZCB0byBwYWNrYWdlICdjbG91ZC1hc3NlbWJseS1zY2hlbWEnXG4gKiBAc2VlIGNvcmUuQ29uc3RydWN0Tm9kZS5tZXRhZGF0YVxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1ldGFkYXRhRW50cnkgZXh0ZW5kcyBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5IHtcblxufVxuXG4vKipcbiAqIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGZvciB3aGVuIGBNaXNzaW5nQ29udGV4dGBcbiAqIHdhcyBkZWZpbmVkIGhlcmUuIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgaXRzIHVzZWQgYXMgYW4gaW5wdXQgaW4gdGhlIHN0YWJsZVxuICogQGF3cy1jZGsvY29yZSBsaWJyYXJ5LlxuICpcbiAqIEBkZXByZWNhdGVkIG1vdmVkIHRvIHBhY2thZ2UgJ2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSdcbiAqIEBzZWUgY29yZS5TdGFjay5yZXBvcnRNaXNzaW5nQ29udGV4dFxuICovXG5leHBvcnQgaW50ZXJmYWNlIE1pc3NpbmdDb250ZXh0IHtcbiAgLyoqXG4gICAqIFRoZSBtaXNzaW5nIGNvbnRleHQga2V5LlxuICAgKi9cbiAgcmVhZG9ubHkga2V5OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBwcm92aWRlciBmcm9tIHdoaWNoIHdlIGV4cGVjdCB0aGlzIGNvbnRleHQga2V5IHRvIGJlIG9idGFpbmVkLlxuICAgKlxuICAgKiAoVGhpcyBpcyB0aGUgb2xkIHVudHlwZWQgZGVmaW5pdGlvbiwgd2hpY2ggaXMgbmVjZXNzYXJ5IGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cbiAgICogU2VlIGN4c2NoZW1hIGZvciBhIHR5cGUgZGVmaW5pdGlvbi4pXG4gICAqL1xuICByZWFkb25seSBwcm92aWRlcjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIHNldCBvZiBwcm92aWRlci1zcGVjaWZpYyBvcHRpb25zLlxuICAgKlxuICAgKiAoVGhpcyBpcyB0aGUgb2xkIHVudHlwZWQgZGVmaW5pdGlvbiwgd2hpY2ggaXMgbmVjZXNzYXJ5IGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cbiAgICogU2VlIGN4c2NoZW1hIGZvciBhIHR5cGUgZGVmaW5pdGlvbi4pXG4gICAqL1xuICByZWFkb25seSBwcm9wczogUmVjb3JkPHN0cmluZywgYW55Pjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBc3NlbWJseUJ1aWxkT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBJbmNsdWRlIHRoZSBzcGVjaWZpZWQgcnVudGltZSBpbmZvcm1hdGlvbiAobW9kdWxlIHZlcnNpb25zKSBpbiBtYW5pZmVzdC5cbiAgICogQGRlZmF1bHQgLSBpZiB0aGlzIG9wdGlvbiBpcyBub3Qgc3BlY2lmaWVkLCBydW50aW1lIGluZm8gd2lsbCBub3QgYmUgaW5jbHVkZWRcbiAgICogQGRlcHJlY2F0ZWQgQWxsIHRlbXBsYXRlIG1vZGlmaWNhdGlvbnMgdGhhdCBzaG91bGQgcmVzdWx0IGZyb20gdGhpcyBzaG91bGRcbiAgICogaGF2ZSBhbHJlYWR5IGJlZW4gaW5zZXJ0ZWQgaW50byB0aGUgdGVtcGxhdGUuXG4gICAqL1xuICByZWFkb25seSBydW50aW1lSW5mbz86IFJ1bnRpbWVJbmZvO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBjb3B5IG9mIGBvYmpgIHdpdGhvdXQgdW5kZWZpbmVkIHZhbHVlcyBpbiBtYXBzIG9yIGFycmF5cy5cbiAqL1xuZnVuY3Rpb24gZmlsdGVyVW5kZWZpbmVkKG9iajogYW55KTogYW55IHtcbiAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgIHJldHVybiBvYmouZmlsdGVyKHggPT4geCAhPT0gdW5kZWZpbmVkKS5tYXAoeCA9PiBmaWx0ZXJVbmRlZmluZWQoeCkpO1xuICB9XG5cbiAgaWYgKHR5cGVvZihvYmopID09PSAnb2JqZWN0Jykge1xuICAgIGNvbnN0IHJldDogYW55ID0geyB9O1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgcmV0W2tleV0gPSBmaWx0ZXJVbmRlZm