UNPKG

@aws-cdk/cx-api

Version:

Cloud executable protocol

434 lines 53.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CloudAssemblyBuilder = exports.CloudAssembly = void 0; const jsiiDeprecationWarnings = require("../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const fs = require("fs"); const os = require("os"); const path = require("path"); 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 toposort_1 = require("./toposort"); const cxschema = require("@aws-cdk/cloud-assembly-schema"); const error_1 = require("./private/error"); 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 { static [JSII_RTTI_SYMBOL_1] = { fqn: "@aws-cdk/cx-api.CloudAssembly", version: "2.233.0" }; /** * 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); } /** * The root directory of the cloud assembly. */ directory; /** * The schema version of the assembly manifest. */ version; /** * All artifacts included in this assembly. */ artifacts; /** * Runtime information such as module versions used to synthesize this assembly. */ runtime; /** * The raw assembly manifest. */ manifest; /** * Reads a cloud assembly from the specified directory. * @param directory The root directory of the assembly. */ constructor(directory, loadOptions) { this.directory = directory; this.manifest = cxschema.Manifest.loadAssemblyManifest(path.join(directory, MANIFEST_FILE), loadOptions); this.version = this.manifest.version; this.artifacts = this.renderArtifacts(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) { try { jsiiDeprecationWarnings.print("@aws-cdk/cx-api.CloudAssembly#getStack", "renamed to `getStackByName` (or `getStackArtifact(id)`)"); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.getStack); } throw error; } 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 { static [JSII_RTTI_SYMBOL_1] = { fqn: "@aws-cdk/cx-api.CloudAssemblyBuilder", version: "2.233.0" }; /** * The root directory of the resulting cloud assembly. */ outdir; /** * The directory where assets of this Cloud Assembly should be stored */ assetOutdir; artifacts = {}; missing = new Array(); parentBuilder; /** * Initializes a cloud assembly builder. * @param outdir The output directory, uses temporary directory if undefined */ constructor(outdir, props = {}) { try { jsiiDeprecationWarnings._aws_cdk_cx_api_CloudAssemblyBuilderProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, CloudAssemblyBuilder); } throw error; } 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 = {}) { try { jsiiDeprecationWarnings._aws_cdk_cx_api_AssemblyBuildOptions(options); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.buildAssembly); } throw error; } // 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWQtYXNzZW1ibHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbG91ZC1hc3NlbWJseS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHlCQUF5QjtBQUN6Qix5QkFBeUI7QUFDekIsNkJBQTZCO0FBSzdCLGlGQUFrRjtBQUNsRiwrRkFBeUY7QUFDekYseUVBQW9FO0FBQ3BFLHFEQUFpRDtBQUNqRCx5Q0FBNkM7QUFDN0MsMkRBQTJEO0FBQzNELDJDQUFxRDtBQUVyRCxNQUFNLHFCQUFxQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsK0JBQStCLENBQUMsQ0FBQztBQUUxRTs7R0FFRztBQUNILE1BQU0sYUFBYSxHQUFHLGVBQWUsQ0FBQztBQUV0Qzs7R0FFRztBQUNILE1BQWEsYUFBYTs7SUFDeEI7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBTTtRQUNsQyxPQUFPLENBQUMsS0FBSyxJQUFJLElBQUksT0FBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsSUFBSSxxQkFBcUIsSUFBSSxDQUFDLENBQUM7S0FDM0U7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09BdUNHO0lBQ0ksTUFBTSxDQUFDLDJCQUEyQjtRQUN2QyxLQUFLLE1BQU0sR0FBRyxJQUFJLHVCQUF1QixFQUFFLENBQUM7WUFDMUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELENBQUM7UUFDRCx1QkFBdUIsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQ25FO0lBRUQ7O09BRUc7SUFDYSxTQUFTLENBQVM7SUFFbEM7O09BRUc7SUFDYSxPQUFPLENBQVM7SUFFaEM7O09BRUc7SUFDYSxTQUFTLENBQWtCO0lBRTNDOztPQUVHO0lBQ2EsT0FB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QU0sR0FBRyxFQUFFLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQ2xGLHVCQUF1QixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNyQyxPQUFPLE1BQU0sSUFBSSxNQUFNLENBQUM7QUFDMUIsQ0FBQztBQUVELFNBQVMsYUFBYSxDQUFDLEdBQVc7SUFDaEMsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLENBQUMsV0FBVyxFQUFFLEVBQUUsQ0FBQztZQUNwQyxNQUFNLElBQUksMEJBQWtCLENBQUMsR0FBRyxHQUFHLHNCQUFzQixDQUFDLENBQUM7UUFDN0QsQ0FBQztJQUNILENBQUM7U0FBTSxDQUFDO1FBQ04sRUFBRSxDQUFDLFNBQVMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQztJQUN6QyxDQUFDO0FBQ0gsQ0FBQztBQUVELDZEQUE2RDtBQUM3RCxNQUFNLHVCQUF1QixHQUFhLEVBQUUsQ0FBQztBQUM3QyxPQUFPLENBQUMsRUFBRSxDQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxhQUFhLENBQUMsMkJBQTJCLEVBQUUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgZnMgZnJvbSAnZnMnO1xuaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgcGF0aCBmcm9tICdwYXRoJztcbi8vIFRoaXMgaXMgZGVsaWJlcmF0ZWx5IGltcG9ydGluZyB0aGUgaW50ZXJmYWNlIGZyb20gdGhlIGV4dGVybmFsIHBhY2thZ2UuXG4vLyBXZSB3YW50IHRoaXMsIHNvIHRoYXQganNpaSBsYW5ndWFnZSBwYWNrYWdlcyBjYW4gZGVwZW5kIG9uIEBhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYVxuLy8gaW5zdGVhZCBvZiBiZWluZyBmb3JjZWQgdG8gdGFrZSBhIGRlcGVuZGVuY3kgb24gdGhlIG11Y2ggbGFyZ2VyIGF3cy1jZGstbGliLlxuaW1wb3J0IHR5cGUgeyBJQ2xvdWRBc3NlbWJseSB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSc7XG5pbXBvcnQgeyBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QgfSBmcm9tICcuL2FydGlmYWN0cy9jbG91ZGZvcm1hdGlvbi1hcnRpZmFjdCc7XG5pbXBvcnQgeyBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QgfSBmcm9tICcuL2FydGlmYWN0cy9uZXN0ZWQtY2xvdWQtYXNzZW1ibHktYXJ0aWZhY3QnO1xuaW1wb3J0IHsgVHJlZUNsb3VkQXJ0aWZhY3QgfSBmcm9tICcuL2FydGlmYWN0cy90cmVlLWNsb3VkLWFydGlmYWN0JztcbmltcG9ydCB7IENsb3VkQXJ0aWZhY3QgfSBmcm9tICcuL2Nsb3VkLWFydGlmYWN0JztcbmltcG9ydCB7IHRvcG9sb2dpY2FsU29ydCB9IGZyb20gJy4vdG9wb3NvcnQnO1xuaW1wb3J0ICogYXMgY3hzY2hlbWEgZnJvbSAnQGF3cy1jZGsvY2xvdWQtYXNzZW1ibHktc2NoZW1hJztcbmltcG9ydCB7IENsb3VkQXNzZW1ibHlFcnJvciB9IGZyb20gJy4vcHJpdmF0ZS9lcnJvcic7XG5cbmNvbnN0IENMT1VEX0FTU0VNQkxZX1NZTUJPTCA9IFN5bWJvbC5mb3IoJ0Bhd3MtY2RrL2N4LWFwaS5DbG91ZEFzc2VtYmx5Jyk7XG5cbi8qKlxuICogVGhlIG5hbWUgb2YgdGhlIHJvb3QgbWFuaWZlc3QgZmlsZSBvZiB0aGUgYXNzZW1ibHkuXG4gKi9cbmNvbnN0IE1BTklGRVNUX0ZJTEUgPSAnbWFuaWZlc3QuanNvbic7XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIGRlcGxveWFibGUgY2xvdWQgYXBwbGljYXRpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBDbG91ZEFzc2VtYmx5IGltcGxlbWVudHMgSUNsb3VkQXNzZW1ibHkge1xuICAvKipcbiAgICogUmV0dXJuIHdoZXRoZXIgdGhlIGdpdmVuIG9iamVjdCBpcyBhIENsb3VkQXNzZW1ibHkuXG4gICAqXG4gICAqIFdlIGRvIGF0dHJpYnV0ZSBkZXRlY3Rpb24gc2luY2Ugd2UgY2FuJ3QgcmVsaWFibHkgdXNlICdpbnN0YW5jZW9mJy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXNDbG91ZEFzc2VtYmx5KHg6IGFueSk6IHggaXMgQ2xvdWRBc3NlbWJseSB7XG4gICAgcmV0dXJuIHggIT09IG51bGwgJiYgdHlwZW9mKHgpID09PSAnb2JqZWN0JyAmJiBDTE9VRF9BU1NFTUJMWV9TWU1CT0wgaW4geDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnMgdXAgYW55IHRlbXBvcmFyeSBhc3NlbWJseSBkaXJlY3RvcmllcyB0aGF0IGdvdCBjcmVhdGVkIGluIHRoaXMgcHJvY2Vzc1xuICAgKlxuICAgKiBJZiBhIENsb3VkIEFzc2VtYmx5IGlzIGVtaXR0ZWQgdG8gYSB0ZW1wb3JhcnkgZGlyZWN0b3J5LCBpdHMgZGlyZWN0b3J5IGdldHNcbiAgICogYWRkZWQgdG8gYSBsaXN0LiBUaGlzIGZ1bmN0aW9uIGl0ZXJhdGVzIG92ZXIgdGhhdCBsaXN0IGFuZCBkZWxldGVzIGVhY2hcbiAgICogZGlyZWN0b3J5IGluIGl0LCB0byBmcmVlIHVwIGRpc2sgc3BhY2UuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gd2lsbCBub3JtYWxseSBiZSBjYWxsZWQgYXV0b21hdGljYWxseSBkdXJpbmcgTm9kZSBwcm9jZXNzXG4gICAqIGV4aXQgYW5kIHNvIHlvdSBkb24ndCBuZWVkIHRvIGNhbGwgdGhpcy4gSG93ZXZlciwgc29tZSB0ZXN0IGVudmlyb25tZW50cyBkb1xuICAgKiBub3QgcHJvcGVybHkgdHJpZ2dlciBOb2RlJ3MgYGV4aXRgIGV2ZW50LiBOb3RhYmx5OiBKZXN0IGRvZXMgbm90IHRyaWdnZXJcbiAgICogdGhlIGBleGl0YCBldmVudCAoPGh0dHBzOi8vZ2l0aHViLmNvbS9qZXN0anMvamVzdC9pc3N1ZXMvMTA5Mjc+KS5cbiAgICpcbiAgICogIyMgQ2xlYW5pbmcgdXAgdGVtcG9yYXJ5IGRpcmVjdG9yaWVzIGluIGplc3RcbiAgICpcbiAgICogRm9yIEplc3QsIHlvdSBoYXZlIHRvIG1ha2Ugc3VyZSB0aGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBhdCB0aGUgZW5kIG9mIHRoZVxuICAgKiB0ZXN0IHN1aXRlIGluc3RlYWQ6XG4gICAqXG4gICAqIGBgYGpzXG4gICAqIGltcG9ydCB7IENsb3VkQXNzZW1ibHkgfSBmcm9tICdhd3MtY2RrLWxpYi9jeC1hcGknO1xuICAgKlxuICAgKiBhZnRlckFsbChDbG91ZEFzc2VtYmx5LmNsZWFudXBUZW1wb3JhcnlEaXJlY3Rvcmllcyk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHVzZSB0aGUgYHNldHVwRmlsZXNBZnRlckVudmAgZmVhdHVyZSBhbmQgdXNlIGFcbiAgICogcHJvdmlkZWQgaGVscGVyIHNjcmlwdCB0byBhdXRvbWF0aWNhbGx5IGluamVjdCB0aGUgYWJvdmUgaW50byBldmVyeVxuICAgKiB0ZXN0IGZpbGUsIHNvIHlvdSBkb24ndCBoYXZlIHRvIGRvIGl0IGJ5IGhhbmQuXG4gICAqXG4gICAqIGBgYFxuICAgKiAkIG5weCBqZXN0IC0tc2V0dXBGaWxlc0FmdGVyRW52IGF3cy1jZGstbGliL3Rlc3RoZWxwZXJzL2plc3QtYXV0b2NsZWFuXG4gICAqIGBgYFxuICAgKlxuICAgKiBPciBwdXQgdGhlIGZvbGxvd2luZyBpbnRvIGBqZXN0LmNvbmZpZy5qc2A6XG4gICAqXG4gICAqIGBgYGpzXG4gICAqIG1vZHVsZS5leHBvcnRzID0ge1xuICAgKiAgIC8vIC4uLlxuICAgKiAgIHNldHVwRmlsZXNBZnRlckVudjogWydhd3MtY2RrLWxpYi90ZXN0aGVscGVycy9qZXN0LWNsZWFudXAnXSxcbiAgICogfTtcbiAgICogYGBgXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNsZWFudXBUZW1wb3JhcnlEaXJlY3RvcmllcygpIHtcbiAgICBmb3IgKGNvbnN0IGRpciBvZiBURU1QT1JBUllfQVNTRU1CTFlfRElSUykge1xuICAgICAgZnMucm1TeW5jKGRpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIH1cbiAgICBURU1QT1JBUllfQVNTRU1CTFlfRElSUy5zcGxpY2UoMCwgVEVNUE9SQVJZX0FTU0VNQkxZX0RJUlMubGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhlIGNsb3VkIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgc2NoZW1hIHZlcnNpb24gb2YgdGhlIGFzc2VtYmx5IG1hbmlmZXN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZlcnNpb246IHN0cmluZztcblxuICAvKipcbiAgICogQWxsIGFydGlmYWN0cyBpbmNsdWRlZCBpbiB0aGlzIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFydGlmYWN0czogQ2xvdWRBcnRpZmFjdFtdO1xuXG4gIC8qKlxuICAgKiBSdW50aW1lIGluZm9ybWF0aW9uIHN1Y2ggYXMgbW9kdWxlIHZlcnNpb25zIHVzZWQgdG8gc3ludGhlc2l6ZSB0aGlzIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJ1bnRpbWU6IGN4c2NoZW1hLlJ1bnRpbWVJbmZvO1xuXG4gIC8qKlxuICAgKiBUaGUgcmF3IGFzc2VtYmx5IG1hbmlmZXN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG1hbmlmZXN0OiBjeHNjaGVtYS5Bc3NlbWJseU1hbmlmZXN0O1xuXG4gIC8qKlxuICAgKiBSZWFkcyBhIGNsb3VkIGFzc2VtYmx5IGZyb20gdGhlIHNwZWNpZmllZCBkaXJlY3RvcnkuXG4gICAqIEBwYXJhbSBkaXJlY3RvcnkgVGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoZSBhc3NlbWJseS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGRpcmVjdG9yeTogc3RyaW5nLCBsb2FkT3B0aW9ucz86IGN4c2NoZW1hLkxvYWRNYW5pZmVzdE9wdGlvbnMpIHtcbiAgICB0aGlzLmRpcmVjdG9yeSA9IGRpcmVjdG9yeTtcblxuICAgIHRoaXMubWFuaWZlc3QgPSBjeHNjaGVtYS5NYW5pZmVzdC5sb2FkQXNzZW1ibHlNYW5pZmVzdChwYXRoLmpvaW4oZGlyZWN0b3J5LCBNQU5JRkVTVF9GSUxFKSwgbG9hZE9wdGlvbnMpO1xuICAgIHRoaXMudmVyc2lvbiA9IHRoaXMubWFuaWZlc3QudmVyc2lvbjtcbiAgICB0aGlzLmFydGlmYWN0cyA9IHRoaXMucmVuZGVyQXJ0aWZhY3RzKGxvYWRPcHRpb25zPy50b3BvU29ydCA/PyB0cnVlKTtcbiAgICB0aGlzLnJ1bnRpbWUgPSB0aGlzLm1hbmlmZXN0LnJ1bnRpbWUgfHwgeyBsaWJyYXJpZXM6IHsgfSB9O1xuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIENMT1VEX0FTU0VNQkxZX1NZTUJPTCwgeyB2YWx1ZTogdHJ1ZSB9KTtcblxuICAgIC8vIGZvcmNlIHZhbGlkYXRpb24gb2YgZGVwcyBieSBhY2Nlc3NpbmcgJ2RlcGVuZHMnIG9uIGFsbCBhcnRpZmFjdHNcbiAgICB0aGlzLnZhbGlkYXRlRGVwcygpO1xuICB9XG5cbiAgLyoqXG4gICAqIEF0dGVtcHRzIHRvIGZpbmQgYW4gYXJ0aWZhY3Qgd2l0aCBhIHNwZWNpZmljIGlkZW50aXR5LlxuICAgKiBAcmV0dXJucyBBIGBDbG91ZEFydGlmYWN0YCBvYmplY3Qgb3IgYHVuZGVmaW5lZGAgaWYgdGhlIGFydGlmYWN0IGRvZXMgbm90IGV4aXN0IGluIHRoaXMgYXNzZW1ibHkuXG4gICAqIEBwYXJhbSBpZCBUaGUgYXJ0aWZhY3QgSURcbiAgICovXG4gIHB1YmxpYyB0cnlHZXRBcnRpZmFjdChpZDogc3RyaW5nKTogQ2xvdWRBcnRpZmFjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuYXJ0aWZhY3RzLmZpbmQoYSA9PiBhLmlkID09PSBpZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICpcbiAgICogV2lsbCBvbmx5IHNlYXJjaCB0aGUgY3VycmVudCBhc3NlbWJseS5cbiAgICpcbiAgICogQHBhcmFtIHN0YWNrTmFtZSB0aGUgbmFtZSBvZiB0aGUgQ2xvdWRGb3JtYXRpb24gc3RhY2suXG4gICAqIEB0aHJvd3MgaWYgdGhlcmUgaXMgbm8gc3RhY2sgYXJ0aWZhY3QgYnkgdGhhdCBuYW1lXG4gICAqIEB0aHJvd3MgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBzdGFjayB3aXRoIHRoZSBzYW1lIHN0YWNrIG5hbWUuIFlvdSBjYW5cbiAgICogdXNlIGBnZXRTdGFja0FydGlmYWN0KHN0YWNrLmFydGlmYWN0SWQpYCBpbnN0ZWFkLlxuICAgKiBAcmV0dXJucyBhIGBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RgIG9iamVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXRTdGFja0J5TmFtZShzdGFja05hbWU6IHN0cmluZyk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCB7XG4gICAgY29uc3QgYXJ0aWZhY3RzID0gdGhpcy5hcnRpZmFjdHMuZmlsdGVyKGEgPT4gYSBpbnN0YW5jZW9mIENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCAmJiBhLnN0YWNrTmFtZSA9PT0gc3RhY2tOYW1lKTtcbiAgICBpZiAoIWFydGlmYWN0cyB8fCBhcnRpZmFjdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBVbmFibGUgdG8gZmluZCBzdGFjayB3aXRoIHN0YWNrIG5hbWUgXCIke3N0YWNrTmFtZX1cImApO1xuICAgIH1cblxuICAgIGlmIChhcnRpZmFjdHMubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgVGhlcmUgYXJlIG11bHRpcGxlIHN0YWNrcyB3aXRoIHRoZSBzdGFjayBuYW1lIFwiJHtzdGFja05hbWV9XCIgKCR7YXJ0aWZhY3RzLm1hcChhID0+IGEuaWQpLmpvaW4oJywnKX0pLiBVc2UgXCJnZXRTdGFja0FydGlmYWN0KGlkKVwiIGluc3RlYWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJ0aWZhY3RzWzBdIGFzIENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgQ2xvdWRGb3JtYXRpb24gc3RhY2sgYXJ0aWZhY3QgYnkgbmFtZSBmcm9tIHRoaXMgYXNzZW1ibHkuXG4gICAqIEBkZXByZWNhdGVkIHJlbmFtZWQgdG8gYGdldFN0YWNrQnlOYW1lYCAob3IgYGdldFN0YWNrQXJ0aWZhY3QoaWQpYClcbiAgICovXG4gIHB1YmxpYyBnZXRTdGFjayhzdGFja05hbWU6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLmdldFN0YWNrQnlOYW1lKHN0YWNrTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICpcbiAgICogQHBhcmFtIGFydGlmYWN0SWQgdGhlIGFydGlmYWN0IGlkIG9mIHRoZSBzdGFjayAoY2FuIGJlIG9idGFpbmVkIHRocm91Z2ggYHN0YWNrLmFydGlmYWN0SWRgKS5cbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBubyBzdGFjayBhcnRpZmFjdCB3aXRoIHRoYXQgaWRcbiAgICogQHJldHVybnMgYSBgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0YCBvYmplY3QuXG4gICAqL1xuICBwdWJsaWMgZ2V0U3RhY2tBcnRpZmFjdChhcnRpZmFjdElkOiBzdHJpbmcpOiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3Qge1xuICAgIGNvbnN0IGFydGlmYWN0ID0gdGhpcy50cnlHZXRBcnRpZmFjdFJlY3Vyc2l2ZWx5KGFydGlmYWN0SWQpO1xuXG4gICAgaWYgKCFhcnRpZmFjdCkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgVW5hYmxlIHRvIGZpbmQgYXJ0aWZhY3Qgd2l0aCBpZCBcIiR7YXJ0aWZhY3RJZH1cImApO1xuICAgIH1cblxuICAgIGlmICghKGFydGlmYWN0IGluc3RhbmNlb2YgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0KSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgQXJ0aWZhY3QgJHthcnRpZmFjdElkfSBpcyBub3QgYSBDbG91ZEZvcm1hdGlvbiBzdGFja2ApO1xuICAgIH1cblxuICAgIHJldHVybiBhcnRpZmFjdDtcbiAgfVxuXG4gIHByaXZhdGUgdHJ5R2V0QXJ0aWZhY3RSZWN1cnNpdmVseShhcnRpZmFjdElkOiBzdHJpbmcpOiBDbG91ZEFydGlmYWN0IHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5zdGFja3NSZWN1cnNpdmVseS5maW5kKGEgPT4gYS5pZCA9PT0gYXJ0aWZhY3RJZCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhbGwgdGhlIHN0YWNrcywgaW5jbHVkaW5nIHRoZSBvbmVzIGluIG5lc3RlZCBhc3NlbWJsaWVzXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN0YWNrc1JlY3Vyc2l2ZWx5KCk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdFtdIHtcbiAgICBmdW5jdGlvbiBzZWFyY2goc3RhY2tBcnRpZmFjdHM6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdFtdLCBhc3NlbWJsaWVzOiBDbG91ZEFzc2VtYmx5W10pOiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RbXSB7XG4gICAgICBpZiAoYXNzZW1ibGllcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIHN0YWNrQXJ0aWZhY3RzO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBbaGVhZCwgLi4udGFpbF0gPSBhc3NlbWJsaWVzO1xuICAgICAgY29uc3QgbmVzdGVkQXNzZW1ibGllcyA9IGhlYWQubmVzdGVkQXNzZW1ibGllcy5tYXAoYXNtID0+IGFzbS5uZXN0ZWRBc3NlbWJseSk7XG4gICAgICByZXR1cm4gc2VhcmNoKHN0YWNrQXJ0aWZhY3RzLmNvbmNhdChoZWFkLnN0YWNrcyksIHRhaWwuY29uY2F0KG5lc3RlZEFzc2VtYmxpZXMpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gc2VhcmNoKFtdLCBbdGhpc10pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBuZXN0ZWQgYXNzZW1ibHkgYXJ0aWZhY3QuXG4gICAqXG4gICAqIEBwYXJhbSBhcnRpZmFjdElkIFRoZSBhcnRpZmFjdCBJRCBvZiB0aGUgbmVzdGVkIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0TmVzdGVkQXNzZW1ibHlBcnRpZmFjdChhcnRpZmFjdElkOiBzdHJpbmcpOiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Qge1xuICAgIGNvbnN0IGFydGlmYWN0ID0gdGhpcy50cnlHZXRBcnRpZmFjdChhcnRpZmFjdElkKTtcbiAgICBpZiAoIWFydGlmYWN0KSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBVbmFibGUgdG8gZmluZCBhcnRpZmFjdCB3aXRoIGlkIFwiJHthcnRpZmFjdElkfVwiYCk7XG4gICAgfVxuXG4gICAgaWYgKCEoYXJ0aWZhY3QgaW5zdGFuY2VvZiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QpKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBGb3VuZCBhcnRpZmFjdCAnJHthcnRpZmFjdElkfScgYnV0IGl0J3Mgbm90IGEgbmVzdGVkIGNsb3VkIGFzc2VtYmx5YCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFydGlmYWN0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBuZXN0ZWQgYXNzZW1ibHkuXG4gICAqXG4gICAqIEBwYXJhbSBhcnRpZmFjdElkIFRoZSBhcnRpZmFjdCBJRCBvZiB0aGUgbmVzdGVkIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0TmVzdGVkQXNzZW1ibHkoYXJ0aWZhY3RJZDogc3RyaW5nKTogQ2xvdWRBc3NlbWJseSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TmVzdGVkQXNzZW1ibHlBcnRpZmFjdChhcnRpZmFjdElkKS5uZXN0ZWRBc3NlbWJseTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB0cmVlIG1ldGFkYXRhIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBubyBtZXRhZGF0YSBhcnRpZmFjdCBieSB0aGF0IG5hbWVcbiAgICogQHJldHVybnMgYSBgVHJlZUNsb3VkQXJ0aWZhY3RgIG9iamVjdCBpZiB0aGVyZSBpcyBvbmUgZGVmaW5lZCBpbiB0aGUgbWFuaWZlc3QsIGB1bmRlZmluZWRgIG90aGVyd2lzZS5cbiAgICovXG4gIHB1YmxpYyB0cmVlKCk6IFRyZWVDbG91ZEFydGlmYWN0IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCB0cmVlcyA9IHRoaXMuYXJ0aWZhY3RzLmZpbHRlcihhID0+IGEubWFuaWZlc3QudHlwZSA9PT0gY3hzY2hlbWEuQXJ0aWZhY3RUeXBlLkNES19UUkVFKTtcbiAgICBpZiAodHJlZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSBpZiAodHJlZXMubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgTXVsdGlwbGUgYXJ0aWZhY3RzIG9mIHR5cGUgJHtjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQ0RLX1RSRUV9IGZvdW5kIGluIG1hbmlmZXN0YCk7XG4gICAgfVxuICAgIGNvbnN0IHRyZWUgPSB0cmVlc1swXTtcblxuICAgIGlmICghKHRyZWUgaW5zdGFuY2VvZiBUcmVlQ2xvdWRBcnRpZmFjdCkpIHtcbiAgICAgIHRocm93IG5ldyBDbG91ZEFzc2VtYmx5RXJyb3IoJ1wiVHJlZVwiIGFydGlmYWN0IGlzIG5vdCBvZiBleHBlY3RlZCB0eXBlJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyZWU7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMgYWxsIHRoZSBDbG91ZEZvcm1hdGlvbiBzdGFjayBhcnRpZmFjdHMgdGhhdCBhcmUgaW5jbHVkZWQgaW4gdGhpcyBhc3NlbWJseS5cbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tzKCk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdFtdIHtcbiAgICByZXR1cm4gdGhpcy5hcnRpZmFjdHMuZmlsdGVyKGlzQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0KTtcblxuICAgIGZ1bmN0aW9uIGlzQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0KHg6IGFueSk6IHggaXMgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IHtcbiAgICAgIHJldHVybiB4IGluc3RhbmNlb2YgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbmVzdGVkIGFzc2VtYmx5IGFydGlmYWN0cyBpbiB0aGlzIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0IG5lc3RlZEFzc2VtYmxpZXMoKTogTmVzdGVkQ2xvdWRBc3NlbWJseUFydGlmYWN0W10ge1xuICAgIHJldHVybiB0aGlzLmFydGlmYWN0cy5maWx0ZXIoaXNOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QpO1xuXG4gICAgZnVuY3Rpb24gaXNOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QoeDogYW55KTogeCBpcyBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Qge1xuICAgICAgcmV0dXJuIHggaW5zdGFuY2VvZiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Q7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZURlcHMoKSB7XG4gICAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiB0aGlzLmFydGlmYWN0cykge1xuICAgICAgaWdub3JlKGFydGlmYWN0LmRlcGVuZGVuY2llcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJBcnRpZmFjdHModG9wb1NvcnQ6IGJvb2xlYW4pIHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8Q2xvdWRBcnRpZmFjdD4oKTtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBhcnRpZmFjdF0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5tYW5pZmVzdC5hcnRpZmFjdHMgfHwgeyB9KSkge1xuICAgICAgY29uc3QgY2xvdWRhcnRpZmFjdCA9IENsb3VkQXJ0aWZhY3QuZnJvbU1hbmlmZXN0KHRoaXMsIG5hbWUsIGFydGlmYWN0KTtcbiAgICAgIGlmIChjbG91ZGFydGlmYWN0KSB7XG4gICAgICAgIHJlc3VsdC5wdXNoKGNsb3VkYXJ0aWZhY3QpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0b3BvU29ydCA/IHRvcG9sb2dpY2FsU29ydChyZXN1bHQsIHggPT4geC5pZCwgeCA9PiB4Ll9kZXBlbmRlbmN5SURzKSA6IHJlc3VsdDtcbiAgfVxufVxuXG4vKipcbiAqIENvbnN0cnVjdGlvbiBwcm9wZXJ0aWVzIGZvciBDbG91ZEFzc2VtYmx5QnVpbGRlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkQXNzZW1ibHlCdWlsZGVyUHJvcHMge1xuICAvKipcbiAgICogVXNlIHRoZSBnaXZlbiBhc3NldCBvdXRwdXQgZGlyZWN0b3J5XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU2FtZSBhcyB0aGUgbWFuaWZlc3Qgb3V0ZGlyXG4gICAqL1xuICByZWFkb25seSBhc3NldE91dGRpcj86IHN0cmluZztcblxuICAvKipcbiAgICogSWYgdGhpcyBidWlsZGVyIGlzIGZvciBhIG5lc3RlZCBhc3NlbWJseSwgdGhlIHBhcmVudCBhc3NlbWJseSBidWlsZGVyXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhpcyBpcyBhIHJvb3QgYXNzZW1ibHlcbiAgICovXG4gIHJlYWRvbmx5IHBhcmVudEJ1aWxkZXI/OiBDbG91ZEFzc2VtYmx5QnVpbGRlcjtcbn1cblxuLyoqXG4gKiBDYW4gYmUgdXNlZCB0byBidWlsZCBhIGNsb3VkIGFzc2VtYmx5LlxuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRBc3NlbWJseUJ1aWxkZXIge1xuICAvKipcbiAgICogVGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoZSByZXN1bHRpbmcgY2xvdWQgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgb3V0ZGlyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBkaXJlY3Rvcnkgd2hlcmUgYXNzZXRzIG9mIHRoaXMgQ2xvdWQgQXNzZW1ibHkgc2hvdWxkIGJlIHN0b3JlZFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFzc2V0T3V0ZGlyOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBhcnRpZmFjdHM6IHsgW2lkOiBzdHJpbmddOiBjeHNjaGVtYS5BcnRpZmFjdE1hbmlmZXN0IH0gPSB7IH07XG4gIHByaXZhdGUgcmVhZG9ubHkgbWlzc2luZyA9IG5ldyBBcnJheTxjeHNjaGVtYS5NaXNzaW5nQ29udGV4dD4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwYXJlbnRCdWlsZGVyPzogQ2xvdWRBc3NlbWJseUJ1aWxkZXI7XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIGEgY2xvdWQgYXNzZW1ibHkgYnVpbGRlci5cbiAgICogQHBhcmFtIG91dGRpciBUaGUgb3V0cHV0IGRpcmVjdG9yeSwgdXNlcyB0ZW1wb3JhcnkgZGlyZWN0b3J5IGlmIHVuZGVmaW5lZFxuICAgKi9cbiAgY29uc3RydWN0b3Iob3V0ZGlyPzogc3RyaW5nLCBwcm9wczogQ2xvdWRBc3NlbWJseUJ1aWxkZXJQcm9wcyA9IHt9KSB7XG4gICAgdGhpcy5vdXRkaXIgPSBkZXRlcm1pbmVPdXRwdXREaXJlY3Rvcnkob3V0ZGlyKTtcbiAgICB0aGlzLmFzc2V0T3V0ZGlyID0gcHJvcHMuYXNzZXRPdXRkaXIgPz8gdGhpcy5vdXRkaXI7XG4gICAgdGhpcy5wYXJlbnRCdWlsZGVyID0gcHJvcHMucGFyZW50QnVpbGRlcjtcblxuICAgIC8vIHdlIGxldmVyYWdlIHRoZSBmYWN0IHRoYXQgb3V0ZGlyIGlzIGxvbmctbGl2ZWQgdG8gYXZvaWQgc3RhZ2luZyBhc3NldHMgaW50byBpdFxuICAgIC8vIHRoYXQgd2VyZSBhbHJlYWR5IHN0YWdlZCAoY29weWluZyBjYW4gYmUgZXhwZW5zaXZlKS4gdGhpcyBpcyBhY2hpZXZlZCBieSB0aGUgZmFjdFxuICAgIC8vIHRoYXQgYXNzZXRzIHVzZSBhIHNvdXJjZSBoYXNoIGFzIHRoZWlyIG5hbWUuIG90aGVyIGFydGlmYWN0cywgYW5kIHRoZSBtYW5pZmVzdCBpdHNlbGYsXG4gICAgLy8gd2lsbCBvdmVyd3JpdGUgZXhpc3RpbmcgZmlsZXMgYXMgbmVlZGVkLlxuICAgIGVuc3VyZURpclN5bmModGhpcy5vdXRkaXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYW4gYXJ0aWZhY3QgaW50byB0aGUgY2xvdWQgYXNzZW1ibHkuXG4gICAqIEBwYXJhbSBpZCBUaGUgSUQgb2YgdGhlIGFydGlmYWN0LlxuICAgKiBAcGFyYW0gbWFuaWZlc3QgVGhlIGFydGlmYWN0IG1hbmlmZXN0XG4gICAqL1xuICBwdWJsaWMgYWRkQXJ0aWZhY3QoaWQ6IHN0cmluZywgbWFuaWZlc3Q6IGN4c2NoZW1hLkFydGlmYWN0TWFuaWZlc3QpIHtcbiAgICB0aGlzLmFydGlmYWN0c1tpZF0gPSBmaWx0ZXJVbmRlZmluZWQobWFuaWZlc3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgdGhhdCBzb21lIGNvbnRleHQgaXMgbWlzc2luZyBpbiBvcmRlciBmb3IgdGhpcyBjbG91ZCBhc3NlbWJseSB0byBiZSBmdWxseSBzeW50aGVzaXplZC5cbiAgICogQHBhcmFtIG1pc3NpbmcgTWlzc2luZyBjb250ZXh0IGluZm9ybWF0aW9uLlxuICAgKi9cbiAgcHVibGljIGFkZE1pc3NpbmcobWlzc2luZzogY3hzY2hlbWEuTWlzc2luZ0NvbnRleHQpIHtcbiAgICBpZiAodGhpcy5taXNzaW5nLmV2ZXJ5KG0gPT4gbS5rZXkgIT09IG1pc3Npbmcua2V5KSkge1xuICAgICAgdGhpcy5taXNzaW5nLnB1c2gobWlzc2luZyk7XG4gICAgfVxuICAgIC8vIEFsc28gcmVwb3J0IGluIHBhcmVudFxuICAgIHRoaXMucGFyZW50QnVpbGRlcj8uYWRkTWlzc2luZyhtaXNzaW5nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZXMgdGhlIGNsb3VkIGFzc2VtYmx5IGludG8gdGhlIG91dHB1dCBkaXJlY3RvcnkgcmV0dXJucyBhXG4gICAqIGBDbG91ZEFzc2VtYmx5YCBvYmplY3QgdGhhdCBjYW4gYmUgdXNlZCB0byBpbnNwZWN0IHRoZSBhc3NlbWJseS5cbiAgICovXG4gIHB1YmxpYyBidWlsZEFzc2VtYmx5KG9wdGlvbnM6IEFzc2VtYmx5QnVpbGRPcHRpb25zID0geyB9KTogQ2xvdWRBc3NlbWJseSB7XG4gICAgLy8gZXhwbGljaXRseSBpbml0aWFsaXppbmcgdGhpcyB0eXBlIHdpbGwgaGVscCB1cyBkZXRlY3RcbiAgICAvLyBicmVha2luZyBjaGFuZ2VzLiAoRm9yIGV4YW1wbGUgYWRkaW5nIGEgcmVxdWlyZWQgcHJvcGVydHkgd2lsbCBicmVhayBjb21waWxhdGlvbikuXG4gICAgbGV0IG1hbmlmZXN0OiBjeHNjaGVtYS5Bc3NlbWJseU1hbmlmZXN0ID0ge1xuICAgICAgdmVyc2lvbjogY3hzY2hlbWEuTWFuaWZlc3QudmVyc2lvbigpLFxuICAgICAgYXJ0aWZhY3RzOiB0aGlzLmFydGlmYWN0cyxcbiAgICAgIHJ1bnRpbWU6IG9wdGlvbnMucnVudGltZUluZm8sXG4gICAgICBtaXNzaW5nOiB0aGlzLm1pc3NpbmcubGVuZ3RoID4gMCA/IHRoaXMubWlzc2luZyA6IHVuZGVmaW5lZCxcbiAgICB9O1xuXG4gICAgLy8gbm93IHdlIGNhbiBmaWx0ZXJcbiAgICBtYW5pZmVzdCA9IGZpbHRlclVuZGVmaW5lZChtYW5pZmVzdCk7XG5cbiAgICBjb25zdCBtYW5pZmVzdEZpbGVQYXRoID0gcGF0aC5qb2luKHRoaXMub3V0ZGlyLCBNQU5JRkVTVF9GSUxFKTtcbiAgICBjeHNjaGVtYS5NYW5pZmVzdC5zYXZlQXNzZW1ibHlNYW5pZmVzdChtYW5pZmVzdCwgbWFuaWZlc3RGaWxlUGF0aCk7XG5cbiAgICAvLyBcImJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XCI6IGluIG9yZGVyIGZvciB0aGUgb2xkIENMSSB0byB0ZWxsIHRoZSB1c2VyIHRoZXlcbiAgICAvLyBuZWVkIGEgbmV3IHZlcnNpb24sIHdlJ2xsIGVtaXQgdGhlIGxlZ2FjeSBtYW5pZmVzdCB3aXRoIG9ubHkgXCJ2ZXJzaW9uXCIuXG4gICAgLy8gdGhpcyB3aWxsIHJlc3VsdCBpbiBhbiBlcnJvciBcIkNESyBUb29sa2l0ID49IENMT1VEX0FTU0VNQkxZX1ZFUlNJT04gaXMgcmVxdWlyZWQgaW4gb3JkZXIgdG8gaW50ZXJhY3Qgd2l0aCB0aGlzIHByb2dyYW0uXCJcbiAgICBmcy53cml0ZUZpbGVTeW5jKHBhdGguam9pbih0aGlzLm91dGRpciwgJ2Nkay5vdXQnKSwgSlNPTi5zdHJpbmdpZnkoeyB2ZXJzaW9uOiBtYW5pZmVzdC52ZXJzaW9uIH0pKTtcblxuICAgIHJldHVybiBuZXcgQ2xvdWRBc3NlbWJseSh0aGlzLm91dGRpcik7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlcyBhIG5lc3RlZCBjbG91ZCBhc3NlbWJseVxuICAgKi9cbiAgcHVibGljIGNyZWF0ZU5lc3RlZEFzc2VtYmx5KGFydGlmYWN0SWQ6IHN0cmluZywgZGlzcGxheU5hbWU6IHN0cmluZykge1xuICAgIGNvbnN0IGRpcmVjdG9yeU5hbWUgPSBhcnRpZmFjdElkO1xuICAgIGNvbnN0IGlubmVyQXNtRGlyID0gcGF0aC5qb2luKHRoaXMub3V0ZGlyLCBkaXJlY3RvcnlOYW1lKTtcblxuICAgIHRoaXMuYWRkQXJ0aWZhY3QoYXJ0aWZhY3RJZCwge1xuICAgICAgdHlwZTogY3hzY2hlbWEuQXJ0aWZhY3RUeXBlLk5FU1RFRF9DTE9VRF9BU1NFTUJMWSxcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgZGlyZWN0b3J5TmFtZSxcbiAgICAgICAgZGlzcGxheU5hbWUsXG4gICAgICB9IGFzIGN4c2NoZW1hLk5lc3RlZENsb3VkQXNzZW1ibHlQcm9wZXJ0aWVzLFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIG5ldyBDbG91ZEFzc2VtYmx5QnVpbGRlcihpbm5lckFzbURpciwge1xuICAgICAgLy8gUmV1c2UgdGhlIHNhbWUgYXNzZXQgb3V0cHV0IGRpcmVjdG9yeSBhcyB0aGUgY3VycmVudCBDYXNtIGJ1aWxkZXJcbiAgICAgIGFzc2V0T3V0ZGlyOiB0aGlzLmFzc2V0T3V0ZGlyLFxuICAgICAgcGFyZW50QnVpbGRlcjogdGhpcyxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWxldGUgdGhlIGNsb3VkIGFzc2VtYmx5IGRpcmVjdG9yeVxuICAgKi9cbiAgcHVibGljIGRlbGV0ZSgpIHtcbiAgICBmcy5ybVN5bmModGhpcy5vdXRkaXIsIHsgcmVjdXJzaXZlOiB0cnVlLCBmb3JjZTogdHJ1ZSB9KTtcbiAgfVxufVxuXG4vKipcbiAqIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGZvciB3aGVuIGBSdW50aW1lSW5mb2BcbiAqIHdhcyBkZWZpbmVkIGhlcmUuIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgaXRzIHVzZWQgYXMgYW4gaW5wdXQgaW4gdGhlIHN0YWJsZVxuICogQGF3cy1jZGsvY29yZSBsaWJyYXJ5LlxuICpcbiAqIEBkZXByZWNhdGVkIG1vdmVkIHRvIHBhY2thZ2UgJ2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSdcbiAqIEBzZWUgY29yZS5Db25zdHJ1Y3ROb2RlLnN5bnRoXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUnVudGltZUluZm8gZXh0ZW5kcyBjeHNjaGVtYS5SdW50aW1lSW5mbyB7XG5cbn1cblxuLyoqXG4gKiBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBmb3Igd2hlbiBgTWV0YWRhdGFFbnRyeWBcbiAqIHdhcyBkZWZpbmVkIGhlcmUuIFRoaXMgaXMgbmVjZXNzYXJ5IGJlY2F1c2UgaXRzIHVzZWQgYXMgYW4gaW5wdXQgaW4gdGhlIHN0YWJsZVxuICogQGF3cy1jZGsvY29yZSBsaWJyYXJ5LlxuICpcbiAqIEBkZXByZWNhdGVkIG1vdmVkIHRvIHBhY2thZ2UgJ2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSdcbiAqIEBzZWUgY29yZS5Db25zdHJ1Y3ROb2RlLm1ldGFkYXRhXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0YWRhdGFFbnRyeSBleHRlbmRzIGN4c2NoZW1hLk1ldGFkYXRhRW50cnkge1xuXG59XG5cbi8qKlxuICogQmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIHdoZW4gYE1pc3NpbmdDb250ZXh0YFxuICogd2FzIGRlZmluZWQgaGVyZS4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBpdHMgdXNlZCBhcyBhbiBpbnB1dCBpbiB0aGUgc3RhYmxlXG4gKiBAYXdzLWNkay9jb3JlIGxpYnJhcnkuXG4gKlxuICogQGRlcHJlY2F0ZWQgbW92ZWQgdG8gcGFja