@aws-cdk/cx-api
Version:
Cloud executable protocol
434 lines • 53.3 kB
JavaScript
"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