aws-cdk-lib
Version:
Version 2 of the AWS Cloud Development Kit library
375 lines • 51.3 kB
JavaScript
"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