aws-cdk-lib
Version:
Version 2 of the AWS Cloud Development Kit library
374 lines • 50.9 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.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) {
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xvdWQtYXNzZW1ibHkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjbG91ZC1hc3NlbWJseS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFBQSx5QkFBeUI7QUFDekIseUJBQXlCO0FBQ3pCLDZCQUE2QjtBQUU3QiwrREFBK0Q7QUFDL0QsaUZBQWtGO0FBQ2xGLCtGQUF5RjtBQUN6Rix5RUFBb0U7QUFDcEUscURBQWlEO0FBQ2pELDJDQUFxRDtBQUNyRCxpREFBcUQ7QUFFckQsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLCtCQUErQixDQUFDLENBQUM7QUFFMUU7O0dBRUc7QUFDSCxNQUFNLGFBQWEsR0FBRyxlQUFlLENBQUM7QUFFdEM7O0dBRUc7QUFDSCxNQUFhLGFBQWE7SUFDeEI7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBTTtRQUNsQyxPQUFPLENBQUMsS0FBSyxJQUFJLElBQUksT0FBTSxDQUFDLENBQUMsQ0FBQyxLQUFLLFFBQVEsSUFBSSxxQkFBcUIsSUFBSSxDQUFDLENBQUM7SUFDNUUsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0F1Q0c7SUFDSSxNQUFNLENBQUMsMkJBQTJCO1FBQ3ZDLEtBQUssTUFBTSxHQUFHLElBQUksdUJBQXVCLEVBQUUsQ0FBQztZQUMxQyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFDbkQsQ0FBQztRQUNELHVCQUF1QixDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsdUJBQXVCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEUsQ0FBQztJQTJCRDs7O09BR0c7SUFDSCxZQUFZLFNBQWlCLEVBQUUsV0FBMEM7UUFDdkUsSUFBSSxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFFM0IsSUFBSSxDQUFDLFFB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SUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JDLE9BQU8sTUFBTSxJQUFJLE1BQU0sQ0FBQztBQUMxQixDQUFDO0FBRUQsU0FBUyxhQUFhLENBQUMsR0FBVztJQUNoQyxJQUFJLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ3BDLE1BQU0sSUFBSSwwQkFBa0IsQ0FBQyxHQUFHLEdBQUcsc0JBQXNCLENBQUMsQ0FBQztRQUM3RCxDQUFDO0lBQ0gsQ0FBQztTQUFNLENBQUM7UUFDTixFQUFFLENBQUMsU0FBUyxDQUFDLEdBQUcsRUFBRSxFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7QUFDSCxDQUFDO0FBRUQsNkRBQTZEO0FBQzdELE1BQU0sdUJBQXVCLEdBQWEsRUFBRSxDQUFDO0FBQzdDLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLGFBQWEsQ0FBQywyQkFBMkIsRUFBRSxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyBvcyBmcm9tICdvcyc7XG5pbXBvcnQgKiBhcyBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHR5cGUgeyBJQ2xvdWRBc3NlbWJseSB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkLWFzc2VtYmx5LXNjaGVtYSc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEvbGliJztcbmltcG9ydCB7IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCB9IGZyb20gJy4vYXJ0aWZhY3RzL2Nsb3VkZm9ybWF0aW9uLWFydGlmYWN0JztcbmltcG9ydCB7IE5lc3RlZENsb3VkQXNzZW1ibHlBcnRpZmFjdCB9IGZyb20gJy4vYXJ0aWZhY3RzL25lc3RlZC1jbG91ZC1hc3NlbWJseS1hcnRpZmFjdCc7XG5pbXBvcnQgeyBUcmVlQ2xvdWRBcnRpZmFjdCB9IGZyb20gJy4vYXJ0aWZhY3RzL3RyZWUtY2xvdWQtYXJ0aWZhY3QnO1xuaW1wb3J0IHsgQ2xvdWRBcnRpZmFjdCB9IGZyb20gJy4vY2xvdWQtYXJ0aWZhY3QnO1xuaW1wb3J0IHsgQ2xvdWRBc3NlbWJseUVycm9yIH0gZnJvbSAnLi9wcml2YXRlL2Vycm9yJztcbmltcG9ydCB7IHRvcG9sb2dpY2FsU29ydCB9IGZyb20gJy4vcHJpdmF0ZS90b3Bvc29ydCc7XG5cbmNvbnN0IENMT1VEX0FTU0VNQkxZX1NZTUJPTCA9IFN5bWJvbC5mb3IoJ0Bhd3MtY2RrL2N4LWFwaS5DbG91ZEFzc2VtYmx5Jyk7XG5cbi8qKlxuICogVGhlIG5hbWUgb2YgdGhlIHJvb3QgbWFuaWZlc3QgZmlsZSBvZiB0aGUgYXNzZW1ibHkuXG4gKi9cbmNvbnN0IE1BTklGRVNUX0ZJTEUgPSAnbWFuaWZlc3QuanNvbic7XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIGRlcGxveWFibGUgY2xvdWQgYXBwbGljYXRpb24uXG4gKi9cbmV4cG9ydCBjbGFzcyBDbG91ZEFzc2VtYmx5IGltcGxlbWVudHMgSUNsb3VkQXNzZW1ibHkge1xuICAvKipcbiAgICogUmV0dXJuIHdoZXRoZXIgdGhlIGdpdmVuIG9iamVjdCBpcyBhIENsb3VkQXNzZW1ibHkuXG4gICAqXG4gICAqIFdlIGRvIGF0dHJpYnV0ZSBkZXRlY3Rpb24gc2luY2Ugd2UgY2FuJ3QgcmVsaWFibHkgdXNlICdpbnN0YW5jZW9mJy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgaXNDbG91ZEFzc2VtYmx5KHg6IGFueSk6IHggaXMgQ2xvdWRBc3NlbWJseSB7XG4gICAgcmV0dXJuIHggIT09IG51bGwgJiYgdHlwZW9mKHgpID09PSAnb2JqZWN0JyAmJiBDTE9VRF9BU1NFTUJMWV9TWU1CT0wgaW4geDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDbGVhbnMgdXAgYW55IHRlbXBvcmFyeSBhc3NlbWJseSBkaXJlY3RvcmllcyB0aGF0IGdvdCBjcmVhdGVkIGluIHRoaXMgcHJvY2Vzc1xuICAgKlxuICAgKiBJZiBhIENsb3VkIEFzc2VtYmx5IGlzIGVtaXR0ZWQgdG8gYSB0ZW1wb3JhcnkgZGlyZWN0b3J5LCBpdHMgZGlyZWN0b3J5IGdldHNcbiAgICogYWRkZWQgdG8gYSBsaXN0LiBUaGlzIGZ1bmN0aW9uIGl0ZXJhdGVzIG92ZXIgdGhhdCBsaXN0IGFuZCBkZWxldGVzIGVhY2hcbiAgICogZGlyZWN0b3J5IGluIGl0LCB0byBmcmVlIHVwIGRpc2sgc3BhY2UuXG4gICAqXG4gICAqIFRoaXMgZnVuY3Rpb24gd2lsbCBub3JtYWxseSBiZSBjYWxsZWQgYXV0b21hdGljYWxseSBkdXJpbmcgTm9kZSBwcm9jZXNzXG4gICAqIGV4aXQgYW5kIHNvIHlvdSBkb24ndCBuZWVkIHRvIGNhbGwgdGhpcy4gSG93ZXZlciwgc29tZSB0ZXN0IGVudmlyb25tZW50cyBkb1xuICAgKiBub3QgcHJvcGVybHkgdHJpZ2dlciBOb2RlJ3MgYGV4aXRgIGV2ZW50LiBOb3RhYmx5OiBKZXN0IGRvZXMgbm90IHRyaWdnZXJcbiAgICogdGhlIGBleGl0YCBldmVudCAoPGh0dHBzOi8vZ2l0aHViLmNvbS9qZXN0anMvamVzdC9pc3N1ZXMvMTA5Mjc+KS5cbiAgICpcbiAgICogIyMgQ2xlYW5pbmcgdXAgdGVtcG9yYXJ5IGRpcmVjdG9yaWVzIGluIGplc3RcbiAgICpcbiAgICogRm9yIEplc3QsIHlvdSBoYXZlIHRvIG1ha2Ugc3VyZSB0aGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBhdCB0aGUgZW5kIG9mIHRoZVxuICAgKiB0ZXN0IHN1aXRlIGluc3RlYWQ6XG4gICAqXG4gICAqIGBgYGpzXG4gICAqIGltcG9ydCB7IENsb3VkQXNzZW1ibHkgfSBmcm9tICdhd3MtY2RrLWxpYi9jeC1hcGknO1xuICAgKlxuICAgKiBhZnRlckFsbChDbG91ZEFzc2VtYmx5LmNsZWFudXBUZW1wb3JhcnlEaXJlY3Rvcmllcyk7XG4gICAqIGBgYFxuICAgKlxuICAgKiBBbHRlcm5hdGl2ZWx5LCB5b3UgY2FuIHVzZSB0aGUgYHNldHVwRmlsZXNBZnRlckVudmAgZmVhdHVyZSBhbmQgdXNlIGFcbiAgICogcHJvdmlkZWQgaGVscGVyIHNjcmlwdCB0byBhdXRvbWF0aWNhbGx5IGluamVjdCB0aGUgYWJvdmUgaW50byBldmVyeVxuICAgKiB0ZXN0IGZpbGUsIHNvIHlvdSBkb24ndCBoYXZlIHRvIGRvIGl0IGJ5IGhhbmQuXG4gICAqXG4gICAqIGBgYFxuICAgKiAkIG5weCBqZXN0IC0tc2V0dXBGaWxlc0FmdGVyRW52IGF3cy1jZGstbGliL3Rlc3RoZWxwZXJzL2plc3QtYXV0b2NsZWFuXG4gICAqIGBgYFxuICAgKlxuICAgKiBPciBwdXQgdGhlIGZvbGxvd2luZyBpbnRvIGBqZXN0LmNvbmZpZy5qc2A6XG4gICAqXG4gICAqIGBgYGpzXG4gICAqIG1vZHVsZS5leHBvcnRzID0ge1xuICAgKiAgIC8vIC4uLlxuICAgKiAgIHNldHVwRmlsZXNBZnRlckVudjogWydhd3MtY2RrLWxpYi90ZXN0aGVscGVycy9qZXN0LWNsZWFudXAnXSxcbiAgICogfTtcbiAgICogYGBgXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGNsZWFudXBUZW1wb3JhcnlEaXJlY3RvcmllcygpIHtcbiAgICBmb3IgKGNvbnN0IGRpciBvZiBURU1QT1JBUllfQVNTRU1CTFlfRElSUykge1xuICAgICAgZnMucm1TeW5jKGRpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICAgIH1cbiAgICBURU1QT1JBUllfQVNTRU1CTFlfRElSUy5zcGxpY2UoMCwgVEVNUE9SQVJZX0FTU0VNQkxZX0RJUlMubGVuZ3RoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhlIGNsb3VkIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGRpcmVjdG9yeTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgc2NoZW1hIHZlcnNpb24gb2YgdGhlIGFzc2VtYmx5IG1hbmlmZXN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHZlcnNpb246IHN0cmluZztcblxuICAvKipcbiAgICogQWxsIGFydGlmYWN0cyBpbmNsdWRlZCBpbiB0aGlzIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFydGlmYWN0czogQ2xvdWRBcnRpZmFjdFtdO1xuXG4gIC8qKlxuICAgKiBSdW50aW1lIGluZm9ybWF0aW9uIHN1Y2ggYXMgbW9kdWxlIHZlcnNpb25zIHVzZWQgdG8gc3ludGhlc2l6ZSB0aGlzIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IHJ1bnRpbWU6IGN4c2NoZW1hLlJ1bnRpbWVJbmZvO1xuXG4gIC8qKlxuICAgKiBUaGUgcmF3IGFzc2VtYmx5IG1hbmlmZXN0LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IG1hbmlmZXN0OiBjeHNjaGVtYS5Bc3NlbWJseU1hbmlmZXN0O1xuXG4gIC8qKlxuICAgKiBSZWFkcyBhIGNsb3VkIGFzc2VtYmx5IGZyb20gdGhlIHNwZWNpZmllZCBkaXJlY3RvcnkuXG4gICAqIEBwYXJhbSBkaXJlY3RvcnkgLSBUaGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhlIGFzc2VtYmx5LlxuICAgKi9cbiAgY29uc3RydWN0b3IoZGlyZWN0b3J5OiBzdHJpbmcsIGxvYWRPcHRpb25zPzogY3hzY2hlbWEuTG9hZE1hbmlmZXN0T3B0aW9ucykge1xuICAgIHRoaXMuZGlyZWN0b3J5ID0gZGlyZWN0b3J5O1xuXG4gICAgdGhpcy5tYW5pZmVzdCA9IGN4c2NoZW1hLk1hbmlmZXN0LmxvYWRBc3NlbWJseU1hbmlmZXN0KHBhdGguam9pbihkaXJlY3RvcnksIE1BTklGRVNUX0ZJTEUpLCBsb2FkT3B0aW9ucyk7XG4gICAgdGhpcy52ZXJzaW9uID0gdGhpcy5tYW5pZmVzdC52ZXJzaW9uO1xuICAgIHRoaXMuYXJ0aWZhY3RzID0gdGhpcy5yZW5kZXJBcnRpZmFjdHMobG9hZE9wdGlvbnM/LnRvcG9Tb3J0ID8/IHRydWUpO1xuICAgIHRoaXMucnVudGltZSA9IHRoaXMubWFuaWZlc3QucnVudGltZSB8fCB7IGxpYnJhcmllczogeyB9IH07XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgQ0xPVURfQVNTRU1CTFlfU1lNQk9MLCB7IHZhbHVlOiB0cnVlIH0pO1xuXG4gICAgLy8gZm9yY2UgdmFsaWRhdGlvbiBvZiBkZXBzIGJ5IGFjY2Vzc2luZyAnZGVwZW5kcycgb24gYWxsIGFydGlmYWN0c1xuICAgIHRoaXMudmFsaWRhdGVEZXBzKCk7XG4gIH1cblxuICAvKipcbiAgICogQXR0ZW1wdHMgdG8gZmluZCBhbiBhcnRpZmFjdCB3aXRoIGEgc3BlY2lmaWMgaWRlbnRpdHkuXG4gICAqIEByZXR1cm5zIEEgYENsb3VkQXJ0aWZhY3RgIG9iamVjdCBvciBgdW5kZWZpbmVkYCBpZiB0aGUgYXJ0aWZhY3QgZG9lcyBub3QgZXhpc3QgaW4gdGhpcyBhc3NlbWJseS5cbiAgICogQHBhcmFtIGlkIC0gVGhlIGFydGlmYWN0IElEXG4gICAqL1xuICBwdWJsaWMgdHJ5R2V0QXJ0aWZhY3QoaWQ6IHN0cmluZyk6IENsb3VkQXJ0aWZhY3QgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLmFydGlmYWN0cy5maW5kKGEgPT4gYS5pZCA9PT0gaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBDbG91ZEZvcm1hdGlvbiBzdGFjayBhcnRpZmFjdCBmcm9tIHRoaXMgYXNzZW1ibHkuXG4gICAqXG4gICAqIFdpbGwgb25seSBzZWFyY2ggdGhlIGN1cnJlbnQgYXNzZW1ibHkuXG4gICAqXG4gICAqIEBwYXJhbSBzdGFja05hbWUgLSB0aGUgbmFtZSBvZiB0aGUgQ2xvdWRGb3JtYXRpb24gc3RhY2suXG4gICAqIEB0aHJvd3MgaWYgdGhlcmUgaXMgbm8gc3RhY2sgYXJ0aWZhY3QgYnkgdGhhdCBuYW1lXG4gICAqIEB0aHJvd3MgaWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBzdGFjayB3aXRoIHRoZSBzYW1lIHN0YWNrIG5hbWUuIFlvdSBjYW5cbiAgICogdXNlIGBnZXRTdGFja0FydGlmYWN0KHN0YWNrLmFydGlmYWN0SWQpYCBpbnN0ZWFkLlxuICAgKiBAcmV0dXJucyBhIGBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RgIG9iamVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXRTdGFja0J5TmFtZShzdGFja05hbWU6IHN0cmluZyk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCB7XG4gICAgY29uc3QgYXJ0aWZhY3RzID0gdGhpcy5hcnRpZmFjdHMuZmlsdGVyKGEgPT4gYSBpbnN0YW5jZW9mIENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCAmJiBhLnN0YWNrTmFtZSA9PT0gc3RhY2tOYW1lKTtcbiAgICBpZiAoIWFydGlmYWN0cyB8fCBhcnRpZmFjdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBVbmFibGUgdG8gZmluZCBzdGFjayB3aXRoIHN0YWNrIG5hbWUgXCIke3N0YWNrTmFtZX1cImApO1xuICAgIH1cblxuICAgIGlmIChhcnRpZmFjdHMubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgVGhlcmUgYXJlIG11bHRpcGxlIHN0YWNrcyB3aXRoIHRoZSBzdGFjayBuYW1lIFwiJHtzdGFja05hbWV9XCIgKCR7YXJ0aWZhY3RzLm1hcChhID0+IGEuaWQpLmpvaW4oJywnKX0pLiBVc2UgXCJnZXRTdGFja0FydGlmYWN0KGlkKVwiIGluc3RlYWRgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXJ0aWZhY3RzWzBdIGFzIENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgQ2xvdWRGb3JtYXRpb24gc3RhY2sgYXJ0aWZhY3QgYnkgbmFtZSBmcm9tIHRoaXMgYXNzZW1ibHkuXG4gICAqIEBkZXByZWNhdGVkIHJlbmFtZWQgdG8gYGdldFN0YWNrQnlOYW1lYCAob3IgYGdldFN0YWNrQXJ0aWZhY3QoaWQpYClcbiAgICovXG4gIHB1YmxpYyBnZXRTdGFjayhzdGFja05hbWU6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLmdldFN0YWNrQnlOYW1lKHN0YWNrTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIENsb3VkRm9ybWF0aW9uIHN0YWNrIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICpcbiAgICogQHBhcmFtIGFydGlmYWN0SWQgLSB0aGUgYXJ0aWZhY3QgaWQgb2YgdGhlIHN0YWNrIChjYW4gYmUgb2J0YWluZWQgdGhyb3VnaCBgc3RhY2suYXJ0aWZhY3RJZGApLlxuICAgKiBAdGhyb3dzIGlmIHRoZXJlIGlzIG5vIHN0YWNrIGFydGlmYWN0IHdpdGggdGhhdCBpZFxuICAgKiBAcmV0dXJucyBhIGBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3RgIG9iamVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXRTdGFja0FydGlmYWN0KGFydGlmYWN0SWQ6IHN0cmluZyk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCB7XG4gICAgY29uc3QgYXJ0aWZhY3QgPSB0aGlzLnRyeUdldEFydGlmYWN0UmVjdXJzaXZlbHkoYXJ0aWZhY3RJZCk7XG5cbiAgICBpZiAoIWFydGlmYWN0KSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBVbmFibGUgdG8gZmluZCBhcnRpZmFjdCB3aXRoIGlkIFwiJHthcnRpZmFjdElkfVwiYCk7XG4gICAgfVxuXG4gICAgaWYgKCEoYXJ0aWZhY3QgaW5zdGFuY2VvZiBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QpKSB7XG4gICAgICB0aHJvdyBuZXcgQ2xvdWRBc3NlbWJseUVycm9yKGBBcnRpZmFjdCAke2FydGlmYWN0SWR9IGlzIG5vdCBhIENsb3VkRm9ybWF0aW9uIHN0YWNrYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFydGlmYWN0O1xuICB9XG5cbiAgcHJpdmF0ZSB0cnlHZXRBcnRpZmFjdFJlY3Vyc2l2ZWx5KGFydGlmYWN0SWQ6IHN0cmluZyk6IENsb3VkQXJ0aWZhY3QgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLnN0YWNrc1JlY3Vyc2l2ZWx5LmZpbmQoYSA9PiBhLmlkID09PSBhcnRpZmFjdElkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFsbCB0aGUgc3RhY2tzLCBpbmNsdWRpbmcgdGhlIG9uZXMgaW4gbmVzdGVkIGFzc2VtYmxpZXNcbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tzUmVjdXJzaXZlbHkoKTogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0W10ge1xuICAgIGZ1bmN0aW9uIHNlYXJjaChzdGFja0FydGlmYWN0czogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0W10sIGFzc2VtYmxpZXM6IENsb3VkQXNzZW1ibHlbXSk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdFtdIHtcbiAgICAgIGlmIChhc3NlbWJsaWVzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gc3RhY2tBcnRpZmFjdHM7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IFtoZWFkLCAuLi50YWlsXSA9IGFzc2VtYmxpZXM7XG4gICAgICBjb25zdCBuZXN0ZWRBc3NlbWJsaWVzID0gaGVhZC5uZXN0ZWRBc3NlbWJsaWVzLm1hcChhc20gPT4gYXNtLm5lc3RlZEFzc2VtYmx5KTtcbiAgICAgIHJldHVybiBzZWFyY2goc3RhY2tBcnRpZmFjdHMuY29uY2F0KGhlYWQuc3RhY2tzKSwgdGFpbC5jb25jYXQobmVzdGVkQXNzZW1ibGllcykpO1xuICAgIH1cblxuICAgIHJldHVybiBzZWFyY2goW10sIFt0aGlzXSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIG5lc3RlZCBhc3NlbWJseSBhcnRpZmFjdC5cbiAgICpcbiAgICogQHBhcmFtIGFydGlmYWN0SWQgLSBUaGUgYXJ0aWZhY3QgSUQgb2YgdGhlIG5lc3RlZCBhc3NlbWJseVxuICAgKi9cbiAgcHVibGljIGdldE5lc3RlZEFzc2VtYmx5QXJ0aWZhY3QoYXJ0aWZhY3RJZDogc3RyaW5nKTogTmVzdGVkQ2xvdWRBc3NlbWJseUFydGlmYWN0IHtcbiAgICBjb25zdCBhcnRpZmFjdCA9IHRoaXMudHJ5R2V0QXJ0aWZhY3QoYXJ0aWZhY3RJZCk7XG4gICAgaWYgKCFhcnRpZmFjdCkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgVW5hYmxlIHRvIGZpbmQgYXJ0aWZhY3Qgd2l0aCBpZCBcIiR7YXJ0aWZhY3RJZH1cImApO1xuICAgIH1cblxuICAgIGlmICghKGFydGlmYWN0IGluc3RhbmNlb2YgTmVzdGVkQ2xvdWRBc3NlbWJseUFydGlmYWN0KSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgRm91bmQgYXJ0aWZhY3QgJyR7YXJ0aWZhY3RJZH0nIGJ1dCBpdCdzIG5vdCBhIG5lc3RlZCBjbG91ZCBhc3NlbWJseWApO1xuICAgIH1cblxuICAgIHJldHVybiBhcnRpZmFjdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgbmVzdGVkIGFzc2VtYmx5LlxuICAgKlxuICAgKiBAcGFyYW0gYXJ0aWZhY3RJZCAtIFRoZSBhcnRpZmFjdCBJRCBvZiB0aGUgbmVzdGVkIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0TmVzdGVkQXNzZW1ibHkoYXJ0aWZhY3RJZDogc3RyaW5nKTogQ2xvdWRBc3NlbWJseSB7XG4gICAgcmV0dXJuIHRoaXMuZ2V0TmVzdGVkQXNzZW1ibHlBcnRpZmFjdChhcnRpZmFjdElkKS5uZXN0ZWRBc3NlbWJseTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSB0cmVlIG1ldGFkYXRhIGFydGlmYWN0IGZyb20gdGhpcyBhc3NlbWJseS5cbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBubyBtZXRhZGF0YSBhcnRpZmFjdCBieSB0aGF0IG5hbWVcbiAgICogQHJldHVybnMgYSBgVHJlZUNsb3VkQXJ0aWZhY3RgIG9iamVjdCBpZiB0aGVyZSBpcyBvbmUgZGVmaW5lZCBpbiB0aGUgbWFuaWZlc3QsIGB1bmRlZmluZWRgIG90aGVyd2lzZS5cbiAgICovXG4gIHB1YmxpYyB0cmVlKCk6IFRyZWVDbG91ZEFydGlmYWN0IHwgdW5kZWZpbmVkIHtcbiAgICBjb25zdCB0cmVlcyA9IHRoaXMuYXJ0aWZhY3RzLmZpbHRlcihhID0+IGEubWFuaWZlc3QudHlwZSA9PT0gY3hzY2hlbWEuQXJ0aWZhY3RUeXBlLkNES19UUkVFKTtcbiAgICBpZiAodHJlZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH0gZWxzZSBpZiAodHJlZXMubGVuZ3RoID4gMSkge1xuICAgICAgdGhyb3cgbmV3IENsb3VkQXNzZW1ibHlFcnJvcihgTXVsdGlwbGUgYXJ0aWZhY3RzIG9mIHR5cGUgJHtjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQ0RLX1RSRUV9IGZvdW5kIGluIG1hbmlmZXN0YCk7XG4gICAgfVxuICAgIGNvbnN0IHRyZWUgPSB0cmVlc1swXTtcblxuICAgIGlmICghKHRyZWUgaW5zdGFuY2VvZiBUcmVlQ2xvdWRBcnRpZmFjdCkpIHtcbiAgICAgIHRocm93IG5ldyBDbG91ZEFzc2VtYmx5RXJyb3IoJ1wiVHJlZVwiIGFydGlmYWN0IGlzIG5vdCBvZiBleHBlY3RlZCB0eXBlJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRyZWU7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMgYWxsIHRoZSBDbG91ZEZvcm1hdGlvbiBzdGFjayBhcnRpZmFjdHMgdGhhdCBhcmUgaW5jbHVkZWQgaW4gdGhpcyBhc3NlbWJseS5cbiAgICovXG4gIHB1YmxpYyBnZXQgc3RhY2tzKCk6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdFtdIHtcbiAgICByZXR1cm4gdGhpcy5hcnRpZmFjdHMuZmlsdGVyKGlzQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0KTtcblxuICAgIGZ1bmN0aW9uIGlzQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0KHg6IGFueSk6IHggaXMgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0IHtcbiAgICAgIHJldHVybiB4IGluc3RhbmNlb2YgQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0O1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgbmVzdGVkIGFzc2VtYmx5IGFydGlmYWN0cyBpbiB0aGlzIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgZ2V0IG5lc3RlZEFzc2VtYmxpZXMoKTogTmVzdGVkQ2xvdWRBc3NlbWJseUFydGlmYWN0W10ge1xuICAgIHJldHVybiB0aGlzLmFydGlmYWN0cy5maWx0ZXIoaXNOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QpO1xuXG4gICAgZnVuY3Rpb24gaXNOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3QoeDogYW55KTogeCBpcyBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Qge1xuICAgICAgcmV0dXJuIHggaW5zdGFuY2VvZiBOZXN0ZWRDbG91ZEFzc2VtYmx5QXJ0aWZhY3Q7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZURlcHMoKSB7XG4gICAgZm9yIChjb25zdCBhcnRpZmFjdCBvZiB0aGlzLmFydGlmYWN0cykge1xuICAgICAgaWdub3JlKGFydGlmYWN0LmRlcGVuZGVuY2llcyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZW5kZXJBcnRpZmFjdHModG9wb1NvcnQ6IGJvb2xlYW4pIHtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8Q2xvdWRBcnRpZmFjdD4oKTtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBhcnRpZmFjdF0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5tYW5pZmVzdC5hcnRpZmFjdHMgfHwgeyB9KSkge1xuICAgICAgY29uc3QgY2xvdWRhcnRpZmFjdCA9IENsb3VkQXJ0aWZhY3QuZnJvbU1hbmlmZXN0KHRoaXMsIG5hbWUsIGFydGlmYWN0KTtcbiAgICAgIGlmIChjbG91ZGFydGlmYWN0KSB7XG4gICAgICAgIHJlc3VsdC5wdXNoKGNsb3VkYXJ0aWZhY3QpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0b3BvU29ydCA/IHRvcG9sb2dpY2FsU29ydChyZXN1bHQsIHggPT4geC5pZCwgeCA9PiB4Ll9kZXBlbmRlbmN5SURzKSA6IHJlc3VsdDtcbiAgfVxufVxuXG4vKipcbiAqIENvbnN0cnVjdGlvbiBwcm9wZXJ0aWVzIGZvciBDbG91ZEFzc2VtYmx5QnVpbGRlclxuICovXG5leHBvcnQgaW50ZXJmYWNlIENsb3VkQXNzZW1ibHlCdWlsZGVyUHJvcHMge1xuICAvKipcbiAgICogVXNlIHRoZSBnaXZlbiBhc3NldCBvdXRwdXQgZGlyZWN0b3J5XG4gICAqXG4gICAqIEBkZWZhdWx0IC0gU2FtZSBhcyB0aGUgbWFuaWZlc3Qgb3V0ZGlyXG4gICAqL1xuICByZWFkb25seSBhc3NldE91dGRpcj86IHN0cmluZztcblxuICAvKipcbiAgICogSWYgdGhpcyBidWlsZGVyIGlzIGZvciBhIG5lc3RlZCBhc3NlbWJseSwgdGhlIHBhcmVudCBhc3NlbWJseSBidWlsZGVyXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gVGhpcyBpcyBhIHJvb3QgYXNzZW1ibHlcbiAgICovXG4gIHJlYWRvbmx5IHBhcmVudEJ1aWxkZXI/OiBDbG91ZEFzc2VtYmx5QnVpbGRlcjtcbn1cblxuLyoqXG4gKiBDYW4gYmUgdXNlZCB0byBidWlsZCBhIGNsb3VkIGFzc2VtYmx5LlxuICovXG5leHBvcnQgY2xhc3MgQ2xvdWRBc3NlbWJseUJ1aWxkZXIge1xuICAvKipcbiAgICogVGhlIHJvb3QgZGlyZWN0b3J5IG9mIHRoZSByZXN1bHRpbmcgY2xvdWQgYXNzZW1ibHkuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgb3V0ZGlyOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBkaXJlY3Rvcnkgd2hlcmUgYXNzZXRzIG9mIHRoaXMgQ2xvdWQgQXNzZW1ibHkgc2hvdWxkIGJlIHN0b3JlZFxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFzc2V0T3V0ZGlyOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBhcnRpZmFjdHM6IHsgW2lkOiBzdHJpbmddOiBjeHNjaGVtYS5BcnRpZmFjdE1hbmlmZXN0IH0gPSB7IH07XG4gIHByaXZhdGUgcmVhZG9ubHkgbWlzc2luZyA9IG5ldyBBcnJheTxjeHNjaGVtYS5NaXNzaW5nQ29udGV4dD4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBwYXJlbnRCdWlsZGVyPzogQ2xvdWRBc3NlbWJseUJ1aWxkZXI7XG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemVzIGEgY2xvdWQgYXNzZW1ibHkgYnVpbGRlci5cbiAgICogQHBhcmFtIG91dGRpciAtIFRoZSBvdXRwdXQgZGlyZWN0b3J5LCB1c2VzIHRlbXBvcmFyeSBkaXJlY3RvcnkgaWYgdW5kZWZpbmVkXG4gICAqL1xuICBjb25zdHJ1Y3RvcihvdXRkaXI/OiBzdHJpbmcsIHByb3BzOiBDbG91ZEFzc2VtYmx5QnVpbGRlclByb3BzID0ge30pIHtcbiAgICB0aGlzLm91dGRpciA9IGRldGVybWluZU91dHB1dERpcmVjdG9yeShvdXRkaXIpO1xuICAgIHRoaXMuYXNzZXRPdXRkaXIgPSBwcm9wcy5hc3NldE91dGRpciA/PyB0aGlzLm91dGRpcjtcbiAgICB0aGlzLnBhcmVudEJ1aWxkZXIgPSBwcm9wcy5wYXJlbnRCdWlsZGVyO1xuXG4gICAgLy8gd2UgbGV2ZXJhZ2UgdGhlIGZhY3QgdGhhdCBvdXRkaXIgaXMgbG9uZy1saXZlZCB0byBhdm9pZCBzdGFnaW5nIGFzc2V0cyBpbnRvIGl0XG4gICAgLy8gdGhhdCB3ZXJlIGFscmVhZHkgc3RhZ2VkIChjb3B5aW5nIGNhbiBiZSBleHBlbnNpdmUpLiB0aGlzIGlzIGFjaGlldmVkIGJ5IHRoZSBmYWN0XG4gICAgLy8gdGhhdCBhc3NldHMgdXNlIGEgc291cmNlIGhhc2ggYXMgdGhlaXIgbmFtZS4gb3RoZXIgYXJ0aWZhY3RzLCBhbmQgdGhlIG1hbmlmZXN0IGl0c2VsZixcbiAgICAvLyB3aWxsIG92ZXJ3cml0ZSBleGlzdGluZyBmaWxlcyBhcyBuZWVkZWQuXG4gICAgZW5zdXJlRGlyU3luYyh0aGlzLm91dGRpcik7XG4gIH1cblxuICAvKipcbiAgICogQWRkcyBhbiBhcnRpZmFjdCBpbnRvIHRoZSBjbG91ZCBhc3NlbWJseS5cbiAgICogQHBhcmFtIGlkIC0gVGhlIElEIG9mIHRoZSBhcnRpZmFjdC5cbiAgICogQHBhcmFtIG1hbmlmZXN0IC0gVGhlIGFydGlmYWN0IG1hbmlmZXN0XG4gICAqL1xuICBwdWJsaWMgYWRkQXJ0aWZhY3QoaWQ6IHN0cmluZywgbWFuaWZlc3Q6IGN4c2NoZW1hLkFydGlmYWN0TWFuaWZlc3QpIHtcbiAgICB0aGlzLmFydGlmYWN0c1tpZF0gPSBmaWx0ZXJVbmRlZmluZWQobWFuaWZlc3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlcG9ydHMgdGhhdCBzb21lIGNvbnRleHQgaXMgbWlzc2luZyBpbiBvcmRlciBmb3IgdGhpcyBjbG91ZCBhc3NlbWJseSB0byBiZSBmdWxseSBzeW50aGVzaXplZC5cbiAgICogQHBhcmFtIG1pc3NpbmcgLSBNaXNzaW5nIGNvbnRleHQgaW5mb3JtYXRpb24uXG4gICAqL1xuICBwdWJsaWMgYWRkTWlzc2luZyhtaXNzaW5nOiBjeHNjaGVtYS5NaXNzaW5nQ29udGV4dCkge1xuICAgIGlmICh0aGlzLm1pc3NpbmcuZXZlcnkobSA9PiBtLmtleSAhPT0gbWlzc2luZy5rZXkpKSB7XG4gICAgICB0aGlzLm1pc3NpbmcucHVzaChtaXNzaW5nKTtcbiAgICB9XG4gICAgLy8gQWxzbyByZXBvcnQgaW4gcGFyZW50XG4gICAgdGhpcy5wYXJlbnRCdWlsZGVyPy5hZGRNaXNzaW5nKG1pc3NpbmcpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplcyB0aGUgY2xvdWQgYXNzZW1ibHkgaW50byB0aGUgb3V0cHV0IGRpcmVjdG9yeSByZXR1cm5zIGFcbiAgICogYENsb3VkQXNzZW1ibHlgIG9iamVjdCB0aGF0IGNhbiBiZSB1c2VkIHRvIGluc3BlY3QgdGhlIGFzc2VtYmx5LlxuICAgKi9cbiAgcHVibGljIGJ1aWxkQXNzZW1ibHkob3B0aW9uczogQXNzZW1ibHlCdWlsZE9wdGlvbnMgPSB7IH0pOiBDbG91ZEFzc2VtYmx5IHtcbiAgICAvLyBleHBsaWNpdGx5IGluaXRpYWxpemluZyB0aGlzIHR5cGUgd2lsbCBoZWxwIHVzIGRldGVjdFxuICAgIC8vIGJyZWFraW5nIGNoYW5nZXMuIChGb3IgZXhhbXBsZSBhZGRpbmcgYSByZXF1aXJlZCBwcm9wZXJ0eSB3aWxsIGJyZWFrIGNvbXBpbGF0aW9uKS5cbiAgICBsZXQgbWFuaWZlc3Q6IGN4c2NoZW1hLkFzc2VtYmx5TWFuaWZlc3QgPSB7XG4gICAgICB2ZXJzaW9uOiBjeHNjaGVtYS5NYW5pZmVzdC52ZXJzaW9uKCksXG4gICAgICBhcnRpZmFjdHM6IHRoaXMuYXJ0aWZhY3RzLFxuICAgICAgcnVudGltZTogb3B0aW9ucy5ydW50aW1lSW5mbyxcbiAgICAgIG1pc3Npbmc6IHRoaXMubWlzc2luZy5sZW5ndGggPiAwID8gdGhpcy5taXNzaW5nIDogdW5kZWZpbmVkLFxuICAgIH07XG5cbiAgICAvLyBub3cgd2UgY2FuIGZpbHRlclxuICAgIG1hbmlmZXN0ID0gZmlsdGVyVW5kZWZpbmVkKG1hbmlmZXN0KTtcblxuICAgIGNvbnN0IG1hbmlmZXN0RmlsZVBhdGggPSBwYXRoLmpvaW4odGhpcy5vdXRkaXIsIE1BTklGRVNUX0ZJTEUpO1xuICAgIGN4c2NoZW1hLk1hbmlmZXN0LnNhdmVBc3NlbWJseU1hbmlmZXN0KG1hbmlmZXN0LCBtYW5pZmVzdEZpbGVQYXRoKTtcblxuICAgIC8vIFwiYmFja3dhcmRzIGNvbXBhdGliaWxpdHlcIjogaW4gb3JkZXIgZm9yIHRoZSBvbGQgQ0xJIHRvIHRlbGwgdGhlIHVzZXIgdGhleVxuICAgIC8vIG5lZWQgYSBuZXcgdmVyc2lvbiwgd2UnbGwgZW1pdCB0aGUgbGVnYWN5IG1hbmlmZXN0IHdpdGggb25seSBcInZlcnNpb25cIi5cbiAgICAvLyB0aGlzIHdpbGwgcmVzdWx0IGluIGFuIGVycm9yIFwiQ0RLIFRvb2xraXQgPj0gQ0xPVURfQVNTRU1CTFlfVkVSU0lPTiBpcyByZXF1aXJlZCBpbiBvcmRlciB0byBpbnRlcmFjdCB3aXRoIHRoaXMgcHJvZ3JhbS5cIlxuICAgIGZzLndyaXRlRmlsZVN5bmMocGF0aC5qb2luKHRoaXMub3V0ZGlyLCAnY2RrLm91dCcpLCBKU09OLnN0cmluZ2lmeSh7IHZlcnNpb246IG1hbmlmZXN0LnZlcnNpb24gfSkpO1xuXG4gICAgcmV0dXJuIG5ldyBDbG91ZEFzc2VtYmx5KHRoaXMub3V0ZGlyKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmVzdGVkIGNsb3VkIGFzc2VtYmx5XG4gICAqL1xuICBwdWJsaWMgY3JlYXRlTmVzdGVkQXNzZW1ibHkoYXJ0aWZhY3RJZDogc3RyaW5nLCBkaXNwbGF5TmFtZTogc3RyaW5nKSB7XG4gICAgY29uc3QgZGlyZWN0b3J5TmFtZSA9IGFydGlmYWN0SWQ7XG4gICAgY29uc3QgaW5uZXJBc21EaXIgPSBwYXRoLmpvaW4odGhpcy5vdXRkaXIsIGRpcmVjdG9yeU5hbWUpO1xuXG4gICAgdGhpcy5hZGRBcnRpZmFjdChhcnRpZmFjdElkLCB7XG4gICAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuTkVTVEVEX0NMT1VEX0FTU0VNQkxZLFxuICAgICAgcHJvcGVydGllczoge1xuICAgICAgICBkaXJlY3RvcnlOYW1lLFxuICAgICAgICBkaXNwbGF5TmFtZSxcbiAgICAgIH0gYXMgY3hzY2hlbWEuTmVzdGVkQ2xvdWRBc3NlbWJseVByb3BlcnRpZXMsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gbmV3IENsb3VkQXNzZW1ibHlCdWlsZGVyKGlubmVyQXNtRGlyLCB7XG4gICAgICAvLyBSZXVzZSB0aGUgc2FtZSBhc3NldCBvdXRwdXQgZGlyZWN0b3J5IGFzIHRoZSBjdXJyZW50IENhc20gYnVpbGRlclxuICAgICAgYXNzZXRPdXRkaXI6IHRoaXMuYXNzZXRPdXRkaXIsXG4gICAgICBwYXJlbnRCdWlsZGVyOiB0aGlzLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSB0aGUgY2xvdWQgYXNzZW1ibHkgZGlyZWN0b3J5XG4gICAqL1xuICBwdWJsaWMgZGVsZXRlKCkge1xuICAgIGZzLnJtU3luYyh0aGlzLm91dGRpciwgeyByZWN1cnNpdmU6IHRydWUsIGZvcmNlOiB0cnVlIH0pO1xuICB9XG59XG5cbi8qKlxuICogQmFja3dhcmRzIGNvbXBhdGliaWxpdHkgZm9yIHdoZW4gYFJ1bnRpbWVJbmZvYFxuICogd2FzIGRlZmluZWQgaGVyZS4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBpdHMgdXNlZCBhcyBhbiBpbnB1dCBpbiB0aGUgc3RhYmxlXG4gKiBAYXdzLWNkay9jb3JlIGxpYnJhcnkuXG4gKlxuICogQGRlcHJlY2F0ZWQgbW92ZWQgdG8gcGFja2FnZSAnY2xvdWQtYXNzZW1ibHktc2NoZW1hJ1xuICogQHNlZSBjb3JlLkNvbnN0cnVjdE5vZGUuc3ludGhcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBSdW50aW1lSW5mbyBleHRlbmRzIGN4c2NoZW1hLlJ1bnRpbWVJbmZvIHtcblxufVxuXG4vKipcbiAqIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGZvciB3aGVuIGBNZXRhZGF0YUVudHJ5YFxuICogd2FzIGRlZmluZWQgaGVyZS4gVGhpcyBpcyBuZWNlc3NhcnkgYmVjYXVzZSBpdHMgdXNlZCBhcyBhbiBpbnB1dCBpbiB0aGUgc3RhYmxlXG4gKiBAYXdzLWNkay9jb3JlIGxpYnJhcnkuXG4gKlxuICogQGRlcHJlY2F0ZWQgbW92ZWQgdG8gcGFja2FnZSAnY2xvdWQtYXNzZW1ibHktc2NoZW1hJ1xuICogQHNlZSBjb3JlLkNvbnN0cnVjdE5vZGUubWV0YWRhdGFcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNZXRhZGF0YUVudHJ5IGV4dGVuZHMgY3hzY2hlbWEuTWV0YWRhdGFFbnRyeSB7XG5cbn1cblxuLyoqXG4gKiBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSBmb3Igd2hlbiBgTWlzc2luZ0NvbnRleHRgXG4gKiB3YXMgZGVmaW5lZCBoZXJlLiBUaGlzIGlzIG5lY2Vzc2FyeSBiZWNhdXNlIGl0cyB1c2VkIGFzIGFuIGlucHV0IGluIHRoZSBzdGFibGVcbiAqIEBhd3MtY2RrL2NvcmUgbGlicmFyeS5cbiAqXG4gKiBAZGVwcmVjYXRlZCBtb3ZlZCB0byBwYWNrYWdlICdjbG91ZC1hc3NlbWJseS1zY2hlbWEnXG4gKiBAc2VlIGNvcmUuU3RhY2sucmVwb3J0TWlzc2luZ0NvbnRleHRcbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNaXNzaW5nQ29udGV4dCB7XG4gIC8qKlxuICAgKiBUaGUgbWlzc2luZyBjb250ZXh0IGtleS5cbiAgICovXG4gIHJlYWRvbmx5IGtleTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgcHJvdmlkZXIgZnJvbSB3aGljaCB3ZSBleHBlY3QgdGhpcyBjb250ZXh0IGtleSB0byBiZSBvYnRhaW5lZC5cbiAgICpcbiAgICogKFRoaXMgaXMgdGhlIG9sZCB1bnR5cGVkIGRlZmluaXRpb24sIHdoaWNoIGlzIG5lY2Vzc2FyeSBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkuXG4gICAqIFNlZSBjeHNjaGVtYSBmb3IgYSB0eXBlIGRlZmluaXRpb24uKVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvdmlkZXI6IHN0cmluZztcblxuICAvKipcbiAgICogQSBzZXQgb2YgcHJvdmlkZXItc3BlY2lmaWMgb3B0aW9ucy5cbiAgICpcbiAgICogKFRoaXMgaXMgdGhlIG9sZCB1bnR5cGVkIGRlZmluaXRpb24sIHdoaWNoIGlzIG5lY2Vzc2FyeSBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkuXG4gICAqIFNlZSBjeHNjaGVtYSBmb3IgYSB0eXBlIGRlZmluaXRpb24uKVxuICAgKi9cbiAgcmVhZG9ubHkgcHJvcHM6IFJlY29yZDxzdHJpbmcsIGFueT47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQXNzZW1ibHlCdWlsZE9wdGlvbnMge1xuICAvKipcbiAgICogSW5jbHVkZSB0aGUgc3BlY2lmaWVkIHJ1bnRpbWUgaW5mb3JtYXRpb24gKG1vZHVsZSB2ZXJzaW9ucykgaW4gbWFuaWZlc3QuXG4gICAqIEBkZWZhdWx0IC0gaWYgdGhpcyBvcHRpb24gaXMgbm90IHNwZWNpZmllZCwgcnVudGltZSBpbmZvIHdpbGwgbm90IGJlIGluY2x1ZGVkXG4gICAqIEBkZXByZWNhdGVkIEFsbCB0ZW1wbGF0ZSBtb2RpZmljYXRpb25zIHRoYXQgc2hvdWxkIHJlc3VsdCBmcm9tIHRoaXMgc2hvdWxkXG4gICAqIGhhdmUgYWxyZWFkeSBiZWVuIGluc2VydGVkIGludG8gdGhlIHRlbXBsYXRlLlxuICAgKi9cbiAgcmVhZG9ubHkgcnVudGltZUluZm8/OiBSdW50aW1lSW5mbztcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgY29weSBvZiBgb2JqYCB3aXRob3V0IHVuZGVmaW5lZCB2YWx1ZXMgaW4gbWFwcyBvciBhcnJheXMuXG4gKi9cbmZ1bmN0aW9uIGZpbHRlclVuZGVmaW5lZChvYmo6IGFueSk6IGFueSB7XG4gIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHtcbiAgICByZXR1cm4gb2JqLmZpbHRlcih4ID0+IHggIT09IHVuZGVmaW5lZCkubWFwKHggPT4gZmlsdGVyVW5kZWZpbmVkKHgpKTtcbiAgfVxuXG4gIGlmICh0eXBlb2Yob2JqKSA9PT0gJ29iamVjdCcpIHtcbiAgICBjb25zdCByZXQ6IGFueSA9IHsgfTtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvYmopKSB7XG4gICAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIHJldFtrZXldID0gZmlsdGVyVW5kZWZpbmVkKHZhbHVlKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHJldHVybiBvYmo7XG59XG5cbmZ1bmN0aW9uIGlnbm9yZShfeDogYW55KSB7XG4gIHJldHVybjtcbn1cblxuLyoqXG4gKiBUdXJuIHRoZSBnaXZlbiBvcHRpb25hbCBvdXRwdXQgZGlyZWN0b3J5IGludG8gYSBmaXhlZCBvdXRwdXQgZGlyZWN0b3J5XG4gKi9cbmZ1bmN0aW9uIGRldGVybWluZU91dHB1dERpcmVjdG9yeShvdXRkaXI/OiBzdHJpbmcpIHtcbiAgaWYgKG91dGRpcikge1xuICAgIHJldHVybiBvdXRkaXI7XG4gIH1cblxuICAvLyBNYWtlIGEgdGVt