constructs
Version:
A programming model for software-defined state
561 lines • 60.7 kB
JavaScript
"use strict";
var _a, _b, _c;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RootConstruct = exports.ConstructOrder = exports.Construct = exports.Node = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const dependency_1 = require("./dependency");
const stack_trace_1 = require("./private/stack-trace");
const uniqueid_1 = require("./private/uniqueid");
const CONSTRUCT_SYM = Symbol.for('constructs.Construct');
/**
* Represents the construct node in the scope tree.
*/
class Node {
/**
* Returns the node associated with a construct.
* @param construct the construct
*
* @deprecated use `construct.node` instead
*/
static of(construct) {
return construct.node;
}
constructor(host, scope, id) {
this.host = host;
this._locked = false; // if this is "true", addChild will fail
id = id ?? ''; // if undefined, convert to empty string
this.id = sanitizeId(id);
this.scope = scope;
if (scope && !this.id) {
throw new Error('Only root constructs may have an empty ID');
}
// add to parent scope
scope?.node.addChild(host, this.id);
}
/**
* The full, absolute path of this construct in the tree.
*
* Components are separated by '/'.
*/
get path() {
const components = [];
for (const scope of this.scopes) {
if (scope.node.id) {
components.push(scope.node.id);
}
}
return components.join(Node.PATH_SEP);
}
/**
* Returns an opaque tree-unique address for this construct.
*
* Addresses are 42 characters hexadecimal strings. They begin with "c8"
* followed by 40 lowercase hexadecimal characters (0-9a-f).
*
* Addresses are calculated using a SHA-1 of the components of the construct
* path.
*
* To enable refactoring of construct trees, constructs with the ID `Default`
* will be excluded from the calculation. In those cases constructs in the
* same tree may have the same address.
*
* @example c83a2846e506bcc5f10682b564084bca2d275709ee
*/
get addr() {
if (!this._addr) {
this._addr = (0, uniqueid_1.addressOf)(this.scopes.map(c => c.node.id));
}
return this._addr;
}
/**
* Return a direct child by id, or undefined
*
* @param id Identifier of direct child
* @returns the child if found, or undefined
*/
tryFindChild(id) {
return this._children?.[sanitizeId(id)];
}
/**
* Return a direct child by id
*
* Throws an error if the child is not found.
*
* @param id Identifier of direct child
* @returns Child with the given id.
*/
findChild(id) {
const ret = this.tryFindChild(id);
if (!ret) {
throw new Error(`No child with id: '${id}'`);
}
return ret;
}
/**
* Returns the child construct that has the id `Default` or `Resource`.
* This is usually the construct that provides the bulk of the underlying functionality.
* Useful for modifications of the underlying construct that are not available at the higher levels.
*
* @throws if there is more than one child
* @returns a construct or undefined if there is no default child
*/
get defaultChild() {
if (this._defaultChild !== undefined) {
return this._defaultChild;
}
const resourceChild = this.tryFindChild('Resource');
const defaultChild = this.tryFindChild('Default');
if (resourceChild && defaultChild) {
throw new Error(`Cannot determine default child for ${this.path}. There is both a child with id "Resource" and id "Default"`);
}
return defaultChild || resourceChild;
}
/**
* Override the defaultChild property.
*
* This should only be used in the cases where the correct
* default child is not named 'Resource' or 'Default' as it
* should be.
*
* If you set this to undefined, the default behavior of finding
* the child named 'Resource' or 'Default' will be used.
*/
set defaultChild(value) {
this._defaultChild = value;
}
/**
* All direct children of this construct.
*/
get children() {
return Object.values(this._children ?? {});
}
/**
* Return this construct and all of its children in the given order
*/
findAll(order = ConstructOrder.PREORDER) {
const ret = new Array();
visit(this.host);
return ret;
function visit(c) {
if (order === ConstructOrder.PREORDER) {
ret.push(c);
}
for (const child of c.node.children) {
visit(child);
}
if (order === ConstructOrder.POSTORDER) {
ret.push(c);
}
}
}
/**
* This can be used to set contextual values.
* Context must be set before any children are added, since children may consult context info during construction.
* If the key already exists, it will be overridden.
* @param key The context key
* @param value The context value
*/
setContext(key, value) {
if (this.children.length > 0) {
const names = this.children.map(c => c.node.id);
throw new Error('Cannot set context after children have been added: ' + names.join(','));
}
if (!this._context) {
this._context = {};
}
this._context[key] = value;
}
/**
* Retrieves a value from tree context if present. Otherwise, would throw an error.
*
* Context is usually initialized at the root, but can be overridden at any point in the tree.
*
* @param key The context key
* @returns The context value or throws error if there is no context value for this key
*/
getContext(key) {
const value = this._context?.[key];
if (value !== undefined) {
return value;
}
if (value === undefined && !this.scope?.node) {
throw new Error(`No context value present for ${key} key`);
}
return this.scope && this.scope.node.getContext(key);
}
/**
* Retrieves the all context of a node from tree context.
*
* Context is usually initialized at the root, but can be overridden at any point in the tree.
*
* @param defaults Any keys to override the retrieved context
* @returns The context object or an empty object if there is discovered context
*/
getAllContext(defaults) {
return this.scopes.reverse()
.reduce((a, s) => ({ ...(s.node._context), ...a }), { ...defaults });
}
/**
* Retrieves a value from tree context.
*
* Context is usually initialized at the root, but can be overridden at any point in the tree.
*
* @param key The context key
* @returns The context value or `undefined` if there is no context value for this key.
*/
tryGetContext(key) {
const value = this._context?.[key];
if (value !== undefined) {
return value;
}
return this.scope && this.scope.node.tryGetContext(key);
}
/**
* An immutable array of metadata objects associated with this construct.
* This can be used, for example, to implement support for deprecation notices, source mapping, etc.
*/
get metadata() {
return [...this._metadata ?? []];
}
/**
* Adds a metadata entry to this construct.
* Entries are arbitrary values and will also include a stack trace to allow tracing back to
* the code location for when the entry was added. It can be used, for example, to include source
* mapping in CloudFormation templates to improve diagnostics.
* Note that construct metadata is not the same as CloudFormation resource metadata and is never written to the CloudFormation template.
* The metadata entries are written to the Cloud Assembly Manifest if the `treeMetadata` property is specified in the props of the App that contains this Construct.
*
* @param type a string denoting the type of metadata
* @param data the value of the metadata (can be a Token). If null/undefined, metadata will not be added.
* @param options options
*/
addMetadata(type, data, options = {}) {
if (data == null) {
return;
}
const node = this;
function getTrace() {
if (options.stackTraceOverride && options.stackTraceOverride.length > 0) {
return options.stackTraceOverride;
}
const shouldTrace = options.stackTrace ?? false;
return shouldTrace ? (0, stack_trace_1.captureStackTrace)(options.traceFromFunction ?? node.addMetadata) : undefined;
}
if (!this._metadata) {
this._metadata = [];
}
this._metadata.push({ type, data, trace: getTrace() });
}
/**
* All parent scopes of this construct.
*
* @returns a list of parent scopes. The last element in the list will always
* be the current construct and the first element will be the root of the
* tree.
*/
get scopes() {
const ret = new Array();
let curr = this.host;
while (curr) {
ret.unshift(curr);
curr = curr.node.scope;
}
return ret;
}
/**
* Returns the root of the construct tree.
* @returns The root of the construct tree.
*/
get root() {
return this.scopes[0];
}
/**
* Returns true if this construct or the scopes in which it is defined are
* locked.
*/
get locked() {
if (this._locked) {
return true;
}
if (this.scope && this.scope.node.locked) {
return true;
}
return false;
}
/**
* Add an ordering dependency on a Dependable (a construct or set of constructs)
*
* It is up to the target document language to decide what an ordering
* relationship means and how it should be rendered; for example, in the AWS
* CDK for CloudFormation it means a dependency from every resource in scope
* of the current construct to every resource in scope of the target set
* of constructs, that get realized as either stack dependencies or
* `DependsOn` relationships in the synthesized template.
*
* `IDependable` is a marker interface that indicates that a class has used
* `Dependable.implement()` to implement the `IDependable` interface. It
* can be used to make the target object represent more than one set of
* constructs at a time. For example, a `DependencyGroup` uses this
* interface to represent an explicit list of 0 or more constructs that should
* be involved in the dependency relationship.
*/
addDependency(...deps) {
if (!this._dependencies) {
this._dependencies = new Set();
}
for (const d of deps) {
this._dependencies.add(d);
}
}
/**
* Remove an ordering dependency on a Dependenable (a construct or set of constructs)
*
* This removes any dependency added using `node.addDependency()`. It must
* use the exact same object that was involved in the `addDependency()` call.
*/
removeDependency(...deps) {
if (!this._dependencies) {
this._dependencies = new Set();
}
for (const d of deps) {
this._dependencies.delete(d);
}
}
/**
* Constructs that this construct depends on directly
*
* This expands the sets of `Dependables` to the set of `Constructs` that they
* represent.
*/
get dependencies() {
const result = new Array();
if (this._dependencies) {
for (const dep of this._dependencies) {
for (const root of dependency_1.Dependable.of(dep).dependencyRoots) {
result.push(root);
}
}
}
return result;
}
/**
* Remove the child with the given name, if present.
*
* @returns Whether a child with the given name was deleted.
*/
tryRemoveChild(childName) {
if (!this._children || !(childName in this._children)) {
return false;
}
delete this._children[childName];
return true;
}
/**
* Adds a validation to this construct.
*
* When `node.validate()` is called, the `validate()` method will be called on
* all validations and all errors will be returned.
*
* @param validation The validation object
*/
addValidation(validation) {
if (!this._validations) {
this._validations = [];
}
this._validations.push(validation);
}
/**
* Validates this construct.
*
* Invokes the `validate()` method on all validations added through
* `addValidation()`.
*
* @returns an array of validation error messages associated with this
* construct.
*/
validate() {
return (this._validations ?? []).flatMap(v => v.validate());
}
/**
* Locks this construct from allowing more children to be added. After this
* call, no more children can be added to this construct or to any children.
*/
lock() {
this._locked = true;
}
/**
* Applies one or more mixins to this construct.
*
* Mixins are applied in order. The list of constructs is captured at the
* start of the call, so constructs added by a mixin will not be visited.
* Use multiple `with()` calls if subsequent mixins should apply to added
* constructs.
*
* @param mixins The mixins to apply
* @returns This construct for chaining
*/
with(...mixins) {
const allConstructs = this.findAll();
for (const mixin of mixins) {
for (const construct of allConstructs) {
if (mixin.supports(construct)) {
mixin.applyTo(construct);
}
}
}
return this.host;
}
;
/**
* Adds a child construct to this node.
*
* @param child The child construct
* @param childName The type name of the child construct.
* @returns The resolved path part name of the child
*/
addChild(child, childName) {
if (this.locked) {
// special error if root is locked
if (!this.path) {
throw new Error('Cannot add children during synthesis');
}
throw new Error(`Cannot add children to "${this.path}" during synthesis`);
}
if (!this._children) {
this._children = {};
}
if (this._children[childName]) {
const name = this.id ?? '';
const typeName = this.host.constructor.name;
throw new Error(`There is already a Construct with name '${childName}' in ${typeName}${name.length > 0 ? ' [' + name + ']' : ''}`);
}
this._children[childName] = child;
}
}
exports.Node = Node;
_a = JSII_RTTI_SYMBOL_1;
Node[_a] = { fqn: "constructs.Node", version: "10.7.0" };
/**
* Separator used to delimit construct path components.
*/
Node.PATH_SEP = '/';
/**
* Represents the building block of the construct graph.
*
* All constructs besides the root construct must be created within the scope of
* another construct.
*/
class Construct {
/**
* Checks if `x` is a construct.
*
* Use this method instead of `instanceof` to properly detect `Construct`
* instances, even when the construct library is symlinked.
*
* Explanation: in JavaScript, multiple copies of the `constructs` library on
* disk are seen as independent, completely different libraries. As a
* consequence, the class `Construct` in each copy of the `constructs` library
* is seen as a different class, and an instance of one class will not test as
* `instanceof` the other class. `npm install` will not create installations
* like this, but users may manually symlink construct libraries together or
* use a monorepo tool: in those cases, multiple copies of the `constructs`
* library can be accidentally installed, and `instanceof` will behave
* unpredictably. It is safest to avoid using `instanceof`, and using
* this type-testing method instead.
*
* @returns true if `x` is an object created from a class which extends `Construct`.
* @param x Any object
*/
static isConstruct(x) {
return x && typeof x === 'object' && x[CONSTRUCT_SYM];
}
/**
* Creates a new construct node.
*
* @param scope The scope in which to define this construct
* @param id The scoped construct ID. Must be unique amongst siblings. If
* the ID includes a path separator (`/`), then it will be replaced by double
* dash `--`.
*/
constructor(scope, id) {
this.node = new Node(this, scope, id);
// implement IDependable privately
dependency_1.Dependable.implement(this, {
dependencyRoots: [this],
});
}
/**
* Applies one or more mixins to this construct.
*
* Mixins are applied in order. The list of constructs is captured at the
* start of the call, so constructs added by a mixin will not be visited.
* Use multiple `with()` calls if subsequent mixins should apply to added
* constructs.
*
* @param mixins The mixins to apply
* @returns This construct for chaining
*/
with(...mixins) {
return this.node.with(...mixins);
}
;
/**
* Returns a string representation of this construct.
*/
toString() {
return this.node.path || '<root>';
}
}
exports.Construct = Construct;
_b = JSII_RTTI_SYMBOL_1;
Construct[_b] = { fqn: "constructs.Construct", version: "10.7.0" };
/**
* In what order to return constructs
*/
var ConstructOrder;
(function (ConstructOrder) {
/**
* Depth-first, pre-order
*/
ConstructOrder[ConstructOrder["PREORDER"] = 0] = "PREORDER";
/**
* Depth-first, post-order (leaf nodes first)
*/
ConstructOrder[ConstructOrder["POSTORDER"] = 1] = "POSTORDER";
})(ConstructOrder || (exports.ConstructOrder = ConstructOrder = {}));
const PATH_SEP_REGEX = new RegExp(`${Node.PATH_SEP}`, 'g');
/**
* Return a sanitized version of an arbitrary string, so it can be used as an ID
*/
function sanitizeId(id) {
// Escape path seps as double dashes
return id.replace(PATH_SEP_REGEX, '--');
}
// Mark all instances of 'Construct'
Object.defineProperty(Construct.prototype, CONSTRUCT_SYM, {
value: true,
enumerable: false,
writable: false,
});
/**
* Creates a new root construct node.
*
* The root construct represents the top of the construct tree and is not contained within a parent scope itself.
* For root constructs, the id is optional.
*/
class RootConstruct extends Construct {
/**
* Creates a new root construct node.
*
* @param id The scoped construct ID. Must be unique amongst siblings. If
* the ID includes a path separator (`/`), then it will be replaced by double
* dash `--`.
*/
constructor(id) {
super(undefined, id ?? '');
}
}
exports.RootConstruct = RootConstruct;
_c = JSII_RTTI_SYMBOL_1;
RootConstruct[_c] = { fqn: "constructs.RootConstruct", version: "10.7.0" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RydWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnN0cnVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUNBLDZDQUEwQztBQUcxQyx1REFBMEQ7QUFDMUQsaURBQStDO0FBRS9DLE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsc0JBQXNCLENBQUMsQ0FBQztBQXVCekQ7O0dBRUc7QUFDSCxNQUFhLElBQUk7SUFNZjs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxFQUFFLENBQUMsU0FBcUI7UUFDcEMsT0FBTyxTQUFTLENBQUMsSUFBSSxDQUFDO0lBQ3hCLENBQUM7SUF5QkQsWUFBb0MsSUFBZSxFQUFFLEtBQWlCLEVBQUUsRUFBVTtRQUE5QyxTQUFJLEdBQUosSUFBSSxDQUFXO1FBVDNDLFlBQU8sR0FBRyxLQUFLLENBQUMsQ0FBQyx3Q0FBd0M7UUFVL0QsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyx3Q0FBd0M7UUFFdkQsSUFBSSxDQUFDLEVBQUUsR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDekIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFFbkIsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQywyQ0FBMkMsQ0FBQyxDQUFDO1FBQy9ELENBQUM7UUFFRCxzQkFBc0I7UUFDdEIsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILElBQVcsSUFBSTtRQUNiLE1BQU0sVUFBVSxHQUFHLEVBQUUsQ0FBQztRQUN0QixLQUFLLE1BQU0sS0FBSyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMs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QztBQUNwQyxNQUFNLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsYUFBYSxFQUFFO0lBQ3hELEtBQUssRUFBRSxJQUFJO0lBQ1gsVUFBVSxFQUFFLEtBQUs7SUFDakIsUUFBUSxFQUFFLEtBQUs7Q0FDaEIsQ0FBQyxDQUFDO0FBRUg7Ozs7O0dBS0c7QUFDSCxNQUFhLGFBQWMsU0FBUSxTQUFTO0lBQzFDOzs7Ozs7T0FNRztJQUNILFlBQVksRUFBVztRQUNyQixLQUFLLENBQUMsU0FBZ0IsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEMsQ0FBQzs7QUFWSCxzQ0FXQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgSURlcGVuZGFibGUgfSBmcm9tICcuL2RlcGVuZGVuY3knO1xuaW1wb3J0IHsgRGVwZW5kYWJsZSB9IGZyb20gJy4vZGVwZW5kZW5jeSc7XG5pbXBvcnQgdHlwZSB7IE1ldGFkYXRhRW50cnkgfSBmcm9tICcuL21ldGFkYXRhJztcbmltcG9ydCB0eXBlIHsgSU1peGluIH0gZnJvbSAnLi9taXhpbic7XG5pbXBvcnQgeyBjYXB0dXJlU3RhY2tUcmFjZSB9IGZyb20gJy4vcHJpdmF0ZS9zdGFjay10cmFjZSc7XG5pbXBvcnQgeyBhZGRyZXNzT2YgfSBmcm9tICcuL3ByaXZhdGUvdW5pcXVlaWQnO1xuXG5jb25zdCBDT05TVFJVQ1RfU1lNID0gU3ltYm9sLmZvcignY29uc3RydWN0cy5Db25zdHJ1Y3QnKTtcblxuLyoqXG4gKiBSZXByZXNlbnRzIGEgY29uc3RydWN0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIElDb25zdHJ1Y3QgZXh0ZW5kcyBJRGVwZW5kYWJsZSB7XG4gIC8qKlxuICAgKiBUaGUgdHJlZSBub2RlLlxuICAgKi9cbiAgcmVhZG9ubHkgbm9kZTogTm9kZTtcblxuICAvKipcbiAgICogQXBwbGllcyBvbmUgb3IgbW9yZSBtaXhpbnMgdG8gdGhpcyBjb25zdHJ1Y3QuXG4gICAqXG4gICAqIE1peGlucyBhcmUgYXBwbGllZCBpbiBvcmRlci4gVGhlIGxpc3Qgb2YgY29uc3RydWN0cyBpcyBjYXB0dXJlZCBhdCB0aGVcbiAgICogc3RhcnQgb2YgdGhlIGNhbGwsIHNvIGNvbnN0cnVjdHMgYWRkZWQgYnkgYSBtaXhpbiB3aWxsIG5vdCBiZSB2aXNpdGVkLlxuICAgKlxuICAgKiBAcGFyYW0gbWl4aW5zIFRoZSBtaXhpbnMgdG8gYXBwbHlcbiAgICogQHJldHVybnMgVGhpcyBjb25zdHJ1Y3QgZm9yIGNoYWluaW5nXG4gICAqL1xuICB3aXRoKC4uLm1peGluczogSU1peGluW10pOiBJQ29uc3RydWN0O1xufVxuXG4vKipcbiAqIFJlcHJlc2VudHMgdGhlIGNvbnN0cnVjdCBub2RlIGluIHRoZSBzY29wZSB0cmVlLlxuICovXG5leHBvcnQgY2xhc3MgTm9kZSB7XG4gIC8qKlxuICAgKiBTZXBhcmF0b3IgdXNlZCB0byBkZWxpbWl0IGNvbnN0cnVjdCBwYXRoIGNvbXBvbmVudHMuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IFBBVEhfU0VQID0gJy8nO1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBub2RlIGFzc29jaWF0ZWQgd2l0aCBhIGNvbnN0cnVjdC5cbiAgICogQHBhcmFtIGNvbnN0cnVjdCB0aGUgY29uc3RydWN0XG4gICAqXG4gICAqIEBkZXByZWNhdGVkIHVzZSBgY29uc3RydWN0Lm5vZGVgIGluc3RlYWRcbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgb2YoY29uc3RydWN0OiBJQ29uc3RydWN0KTogTm9kZSB7XG4gICAgcmV0dXJuIGNvbnN0cnVjdC5ub2RlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNjb3BlIGluIHdoaWNoIHRoaXMgY29uc3RydWN0IGlzIGRlZmluZWQuXG4gICAqXG4gICAqIFRoZSB2YWx1ZSBpcyBgdW5kZWZpbmVkYCBhdCB0aGUgcm9vdCBvZiB0aGUgY29uc3RydWN0IHNjb3BlIHRyZWUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc2NvcGU/OiBJQ29uc3RydWN0O1xuXG4gIC8qKlxuICAgKiBUaGUgaWQgb2YgdGhpcyBjb25zdHJ1Y3Qgd2l0aGluIHRoZSBjdXJyZW50IHNjb3BlLlxuICAgKlxuICAgKiBUaGlzIGlzIGEgc2NvcGUtdW5pcXVlIGlkLiBUbyBvYnRhaW4gYW4gYXBwLXVuaXF1ZSBpZCBmb3IgdGhpcyBjb25zdHJ1Y3QsIHVzZSBgYWRkcmAuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcblxuICBwcml2YXRlIF9sb2NrZWQgPSBmYWxzZTsgLy8gaWYgdGhpcyBpcyBcInRydWVcIiwgYWRkQ2hpbGQgd2lsbCBmYWlsXG4gIHByaXZhdGUgX2NoaWxkcmVuOiB7IFtpZDogc3RyaW5nXTogSUNvbnN0cnVjdCB9IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIF9jb250ZXh0OiB7IFtrZXk6IHN0cmluZ106IGFueSB9IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIF9tZXRhZGF0YTogQXJyYXk8TWV0YWRhdGFFbnRyeT4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgX2RlcGVuZGVuY2llczogU2V0PElEZXBlbmRhYmxlPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfZGVmYXVsdENoaWxkOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIF92YWxpZGF0aW9uczogQXJyYXk8SVZhbGlkYXRpb24+IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIF9hZGRyPzogc3RyaW5nOyAvLyBjYWNoZVxuXG4gIHB1YmxpYyBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IGhvc3Q6IENvbnN0cnVjdCwgc2NvcGU6IElDb25zdHJ1Y3QsIGlkOiBzdHJpbmcpIHtcbiAgICBpZCA9IGlkID8/ICcnOyAvLyBpZiB1bmRlZmluZWQsIGNvbnZlcnQgdG8gZW1wdHkgc3RyaW5nXG5cbiAgICB0aGlzLmlkID0gc2FuaXRpemVJZChpZCk7XG4gICAgdGhpcy5zY29wZSA9IHNjb3BlO1xuXG4gICAgaWYgKHNjb3BlICYmICF0aGlzLmlkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ09ubHkgcm9vdCBjb25zdHJ1Y3RzIG1heSBoYXZlIGFuIGVtcHR5IElEJyk7XG4gICAgfVxuXG4gICAgLy8gYWRkIHRvIHBhcmVudCBzY29wZVxuICAgIHNjb3BlPy5ub2RlLmFkZENoaWxkKGhvc3QsIHRoaXMuaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBmdWxsLCBhYnNvbHV0ZSBwYXRoIG9mIHRoaXMgY29uc3RydWN0IGluIHRoZSB0cmVlLlxuICAgKlxuICAgKiBDb21wb25lbnRzIGFyZSBzZXBhcmF0ZWQgYnkgJy8nLlxuICAgKi9cbiAgcHVibGljIGdldCBwYXRoKCk6IHN0cmluZyB7XG4gICAgY29uc3QgY29tcG9uZW50cyA9IFtdO1xuICAgIGZvciAoY29uc3Qgc2NvcGUgb2YgdGhpcy5zY29wZXMpIHtcbiAgICAgIGlmIChzY29wZS5ub2RlLmlkKSB7XG4gICAgICAgIGNvbXBvbmVudHMucHVzaChzY29wZS5ub2RlLmlkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNvbXBvbmVudHMuam9pbihOb2RlLlBBVEhfU0VQKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGFuIG9wYXF1ZSB0cmVlLXVuaXF1ZSBhZGRyZXNzIGZvciB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogQWRkcmVzc2VzIGFyZSA0MiBjaGFyYWN0ZXJzIGhleGFkZWNpbWFsIHN0cmluZ3MuIFRoZXkgYmVnaW4gd2l0aCBcImM4XCJcbiAgICogZm9sbG93ZWQgYnkgNDAgbG93ZXJjYXNlIGhleGFkZWNpbWFsIGNoYXJhY3RlcnMgKDAtOWEtZikuXG4gICAqXG4gICAqIEFkZHJlc3NlcyBhcmUgY2FsY3VsYXRlZCB1c2luZyBhIFNIQS0xIG9mIHRoZSBjb21wb25lbnRzIG9mIHRoZSBjb25zdHJ1Y3RcbiAgICogcGF0aC5cbiAgICpcbiAgICogVG8gZW5hYmxlIHJlZmFjdG9yaW5nIG9mIGNvbnN0cnVjdCB0cmVlcywgY29uc3RydWN0cyB3aXRoIHRoZSBJRCBgRGVmYXVsdGBcbiAgICogd2lsbCBiZSBleGNsdWRlZCBmcm9tIHRoZSBjYWxjdWxhdGlvbi4gSW4gdGhvc2UgY2FzZXMgY29uc3RydWN0cyBpbiB0aGVcbiAgICogc2FtZSB0cmVlIG1heSBoYXZlIHRoZSBzYW1lIGFkZHJlc3MuXG4gICAqXG4gICAqIEBleGFtcGxlIGM4M2EyODQ2ZTUwNmJjYzVmMTA2ODJiNTY0MDg0YmNhMmQyNzU3MDllZVxuICAgKi9cbiAgcHVibGljIGdldCBhZGRyKCk6IHN0cmluZyB7XG4gICAgaWYgKCF0aGlzLl9hZGRyKSB7XG4gICAgICB0aGlzLl9hZGRyID0gYWRkcmVzc09mKHRoaXMuc2NvcGVzLm1hcChjID0+IGMubm9kZS5pZCkpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl9hZGRyO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGRpcmVjdCBjaGlsZCBieSBpZCwgb3IgdW5kZWZpbmVkXG4gICAqXG4gICAqIEBwYXJhbSBpZCBJZGVudGlmaWVyIG9mIGRpcmVjdCBjaGlsZFxuICAgKiBAcmV0dXJucyB0aGUgY2hpbGQgaWYgZm91bmQsIG9yIHVuZGVmaW5lZFxuICAgKi9cbiAgcHVibGljIHRyeUZpbmRDaGlsZChpZDogc3RyaW5nKTogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2NoaWxkcmVuPy5bc2FuaXRpemVJZChpZCldO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGRpcmVjdCBjaGlsZCBieSBpZFxuICAgKlxuICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGNoaWxkIGlzIG5vdCBmb3VuZC5cbiAgICpcbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgb2YgZGlyZWN0IGNoaWxkXG4gICAqIEByZXR1cm5zIENoaWxkIHdpdGggdGhlIGdpdmVuIGlkLlxuICAgKi9cbiAgcHVibGljIGZpbmRDaGlsZChpZDogc3RyaW5nKTogSUNvbnN0cnVjdCB7XG4gICAgY29uc3QgcmV0ID0gdGhpcy50cnlGaW5kQ2hpbGQoaWQpO1xuICAgIGlmICghcmV0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGNoaWxkIHdpdGggaWQ6ICcke2lkfSdgKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjaGlsZCBjb25zdHJ1Y3QgdGhhdCBoYXMgdGhlIGlkIGBEZWZhdWx0YCBvciBgUmVzb3VyY2VgLlxuICAgKiBUaGlzIGlzIHVzdWFsbHkgdGhlIGNvbnN0cnVjdCB0aGF0IHByb3ZpZGVzIHRoZSBidWxrIG9mIHRoZSB1bmRlcmx5aW5nIGZ1bmN0aW9uYWxpdHkuXG4gICAqIFVzZWZ1bCBmb3IgbW9kaWZpY2F0aW9ucyBvZiB0aGUgdW5kZXJseWluZyBjb25zdHJ1Y3QgdGhhdCBhcmUgbm90IGF2YWlsYWJsZSBhdCB0aGUgaGlnaGVyIGxldmVscy5cbiAgICpcbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIGNoaWxkXG4gICAqIEByZXR1cm5zIGEgY29uc3RydWN0IG9yIHVuZGVmaW5lZCBpZiB0aGVyZSBpcyBubyBkZWZhdWx0IGNoaWxkXG4gICAqL1xuICBwdWJsaWMgZ2V0IGRlZmF1bHRDaGlsZCgpOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAodGhpcy5fZGVmYXVsdENoaWxkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0aGlzLl9kZWZhdWx0Q2hpbGQ7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzb3VyY2VDaGlsZCA9IHRoaXMudHJ5RmluZENoaWxkKCdSZXNvdXJjZScpO1xuICAgIGNvbnN0IGRlZmF1bHRDaGlsZCA9IHRoaXMudHJ5RmluZENoaWxkKCdEZWZhdWx0Jyk7XG4gICAgaWYgKHJlc291cmNlQ2hpbGQgJiYgZGVmYXVsdENoaWxkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBkZXRlcm1pbmUgZGVmYXVsdCBjaGlsZCBmb3IgJHt0aGlzLnBhdGh9LiBUaGVyZSBpcyBib3RoIGEgY2hpbGQgd2l0aCBpZCBcIlJlc291cmNlXCIgYW5kIGlkIFwiRGVmYXVsdFwiYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlZmF1bHRDaGlsZCB8fCByZXNvdXJjZUNoaWxkO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSBkZWZhdWx0Q2hpbGQgcHJvcGVydHkuXG4gICAqXG4gICAqIFRoaXMgc2hvdWxkIG9ubHkgYmUgdXNlZCBpbiB0aGUgY2FzZXMgd2hlcmUgdGhlIGNvcnJlY3RcbiAgICogZGVmYXVsdCBjaGlsZCBpcyBub3QgbmFtZWQgJ1Jlc291cmNlJyBvciAnRGVmYXVsdCcgYXMgaXRcbiAgICogc2hvdWxkIGJlLlxuICAgKlxuICAgKiBJZiB5b3Ugc2V0IHRoaXMgdG8gdW5kZWZpbmVkLCB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZiBmaW5kaW5nXG4gICAqIHRoZSBjaGlsZCBuYW1lZCAnUmVzb3VyY2UnIG9yICdEZWZhdWx0JyB3aWxsIGJlIHVzZWQuXG4gICAqL1xuICBwdWJsaWMgc2V0IGRlZmF1bHRDaGlsZCh2YWx1ZTogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX2RlZmF1bHRDaGlsZCA9IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbCBkaXJlY3QgY2hpbGRyZW4gb2YgdGhpcyBjb25zdHJ1Y3QuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGNoaWxkcmVuKCkge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMuX2NoaWxkcmVuID8/IHt9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhpcyBjb25zdHJ1Y3QgYW5kIGFsbCBvZiBpdHMgY2hpbGRyZW4gaW4gdGhlIGdpdmVuIG9yZGVyXG4gICAqL1xuICBwdWJsaWMgZmluZEFsbChvcmRlcjogQ29uc3RydWN0T3JkZXIgPSBDb25zdHJ1Y3RPcmRlci5QUkVPUkRFUik6IElDb25zdHJ1Y3RbXSB7XG4gICAgY29uc3QgcmV0ID0gbmV3IEFycmF5PElDb25zdHJ1Y3Q+KCk7XG4gICAgdmlzaXQodGhpcy5ob3N0KTtcbiAgICByZXR1cm4gcmV0O1xuXG4gICAgZnVuY3Rpb24gdmlzaXQoYzogSUNvbnN0cnVjdCkge1xuICAgICAgaWYgKG9yZGVyID09PSBDb25zdHJ1Y3RPcmRlci5QUkVPUkRFUikge1xuICAgICAgICByZXQucHVzaChjKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBjLm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgICAgdmlzaXQoY2hpbGQpO1xuICAgICAgfVxuXG4gICAgICBpZiAob3JkZXIgPT09IENvbnN0cnVjdE9yZGVyLlBPU1RPUkRFUikge1xuICAgICAgICByZXQucHVzaChjKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBjYW4gYmUgdXNlZCB0byBzZXQgY29udGV4dHVhbCB2YWx1ZXMuXG4gICAqIENvbnRleHQgbXVzdCBiZSBzZXQgYmVmb3JlIGFueSBjaGlsZHJlbiBhcmUgYWRkZWQsIHNpbmNlIGNoaWxkcmVuIG1heSBjb25zdWx0IGNvbnRleHQgaW5mbyBkdXJpbmcgY29uc3RydWN0aW9uLlxuICAgKiBJZiB0aGUga2V5IGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIG92ZXJyaWRkZW4uXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgY29udGV4dCB2YWx1ZVxuICAgKi9cbiAgcHVibGljIHNldENvbnRleHQoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpIHtcbiAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBuYW1lcyA9IHRoaXMuY2hpbGRyZW4ubWFwKGMgPT4gYy5ub2RlLmlkKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHNldCBjb250ZXh0IGFmdGVyIGNoaWxkcmVuIGhhdmUgYmVlbiBhZGRlZDogJyArIG5hbWVzLmpvaW4oJywnKSk7XG4gICAgfVxuICAgIGlmICghdGhpcy5fY29udGV4dCkge1xuICAgICAgdGhpcy5fY29udGV4dCA9IHt9O1xuICAgIH1cbiAgICB0aGlzLl9jb250ZXh0W2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHRyZWUgY29udGV4dCBpZiBwcmVzZW50LiBPdGhlcndpc2UsIHdvdWxkIHRocm93IGFuIGVycm9yLlxuICAgKlxuICAgKiBDb250ZXh0IGlzIHVzdWFsbHkgaW5pdGlhbGl6ZWQgYXQgdGhlIHJvb3QsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBhdCBhbnkgcG9pbnQgaW4gdGhlIHRyZWUuXG4gICAqXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEByZXR1cm5zIFRoZSBjb250ZXh0IHZhbHVlIG9yIHRocm93cyBlcnJvciBpZiB0aGVyZSBpcyBubyBjb250ZXh0IHZhbHVlIGZvciB0aGlzIGtleVxuICAgKi9cbiAgcHVibGljIGdldENvbnRleHQoa2V5OiBzdHJpbmcpOiBhbnkge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fY29udGV4dD8uW2tleV07XG5cbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkgeyByZXR1cm4gdmFsdWU7IH1cblxuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkICYmICF0aGlzLnNjb3BlPy5ub2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbnRleHQgdmFsdWUgcHJlc2VudCBmb3IgJHtrZXl9IGtleWApO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnNjb3BlICYmIHRoaXMuc2NvcGUubm9kZS5nZXRDb250ZXh0KGtleSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBhbGwgY29udGV4dCBvZiBhIG5vZGUgZnJvbSB0cmVlIGNvbnRleHQuXG4gICAqXG4gICAqIENvbnRleHQgaXMgdXN1YWxseSBpbml0aWFsaXplZCBhdCB0aGUgcm9vdCwgYnV0IGNhbiBiZSBvdmVycmlkZGVuIGF0IGFueSBwb2ludCBpbiB0aGUgdHJlZS5cbiAgICpcbiAgICogQHBhcmFtIGRlZmF1bHRzIEFueSBrZXlzIHRvIG92ZXJyaWRlIHRoZSByZXRyaWV2ZWQgY29udGV4dFxuICAgKiBAcmV0dXJucyBUaGUgY29udGV4dCBvYmplY3Qgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZXJlIGlzIGRpc2NvdmVyZWQgY29udGV4dFxuICAgKi9cbiAgcHVibGljIGdldEFsbENvbnRleHQoZGVmYXVsdHM/OiBvYmplY3QpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLnNjb3Blcy5yZXZlcnNlKClcbiAgICAgIC5yZWR1Y2UoKGEsIHMpID0+ICh7IC4uLihzLm5vZGUuX2NvbnRleHQpLCAuLi5hIH0pLCB7IC4uLmRlZmF1bHRzIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHZhbHVlIGZyb20gdHJlZSBjb250ZXh0LlxuICAgKlxuICAgKiBDb250ZXh0IGlzIHVzdWFsbHkgaW5pdGlhbGl6ZWQgYXQgdGhlIHJvb3QsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBhdCBhbnkgcG9pbnQgaW4gdGhlIHRyZWUuXG4gICAqXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEByZXR1cm5zIFRoZSBjb250ZXh0IHZhbHVlIG9yIGB1bmRlZmluZWRgIGlmIHRoZXJlIGlzIG5vIGNvbnRleHQgdmFsdWUgZm9yIHRoaXMga2V5LlxuICAgKi9cbiAgcHVibGljIHRyeUdldENvbnRleHQoa2V5OiBzdHJpbmcpOiBhbnkge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fY29udGV4dD8uW2tleV07XG4gICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIHsgcmV0dXJuIHZhbHVlOyB9XG5cbiAgICByZXR1cm4gdGhpcy5zY29wZSAmJiB0aGlzLnNjb3BlLm5vZGUudHJ5R2V0Q29udGV4dChrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFuIGltbXV0YWJsZSBhcnJheSBvZiBtZXRhZGF0YSBvYmplY3RzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbnN0cnVjdC5cbiAgICogVGhpcyBjYW4gYmUgdXNlZCwgZm9yIGV4YW1wbGUsIHRvIGltcGxlbWVudCBzdXBwb3J0IGZvciBkZXByZWNhdGlvbiBub3RpY2VzLCBzb3VyY2UgbWFwcGluZywgZXRjLlxuICAgKi9cbiAgcHVibGljIGdldCBtZXRhZGF0YSgpIHtcbiAgICByZXR1cm4gWy4uLnRoaXMuX21ldGFkYXRhID8/IFtdXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgbWV0YWRhdGEgZW50cnkgdG8gdGhpcyBjb25zdHJ1Y3QuXG4gICAqIEVudHJpZXMgYXJlIGFyYml0cmFyeSB2YWx1ZXMgYW5kIHdpbGwgYWxzbyBpbmNsdWRlIGEgc3RhY2sgdHJhY2UgdG8gYWxsb3cgdHJhY2luZyBiYWNrIHRvXG4gICAqIHRoZSBjb2RlIGxvY2F0aW9uIGZvciB3aGVuIHRoZSBlbnRyeSB3YXMgYWRkZWQuIEl0IGNhbiBiZSB1c2VkLCBmb3IgZXhhbXBsZSwgdG8gaW5jbHVkZSBzb3VyY2VcbiAgICogbWFwcGluZyBpbiBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZXMgdG8gaW1wcm92ZSBkaWFnbm9zdGljcy5cbiAgICogTm90ZSB0aGF0IGNvbnN0cnVjdCBtZXRhZGF0YSBpcyBub3QgdGhlIHNhbWUgYXMgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgbWV0YWRhdGEgYW5kIGlzIG5ldmVyIHdyaXR0ZW4gdG8gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlLlxuICAgKiBUaGUgbWV0YWRhdGEgZW50cmllcyBhcmUgd3JpdHRlbiB0byB0aGUgQ2xvdWQgQXNzZW1ibHkgTWFuaWZlc3QgaWYgdGhlIGB0cmVlTWV0YWRhdGFgIHByb3BlcnR5IGlzIHNwZWNpZmllZCBpbiB0aGUgcHJvcHMgb2YgdGhlIEFwcCB0aGF0IGNvbnRhaW5zIHRoaXMgQ29uc3RydWN0LlxuICAgKlxuICAgKiBAcGFyYW0gdHlwZSBhIHN0cmluZyBkZW5vdGluZyB0aGUgdHlwZSBvZiBtZXRhZGF0YVxuICAgKiBAcGFyYW0gZGF0YSB0aGUgdmFsdWUgb2YgdGhlIG1ldGFkYXRhIChjYW4gYmUgYSBUb2tlbikuIElmIG51bGwvdW5kZWZpbmVkLCBtZXRhZGF0YSB3aWxsIG5vdCBiZSBhZGRlZC5cbiAgICogQHBhcmFtIG9wdGlvbnMgb3B0aW9uc1xuICAgKi9cbiAgcHVibGljIGFkZE1ldGFkYXRhKHR5cGU6IHN0cmluZywgZGF0YTogYW55LCBvcHRpb25zOiBNZXRhZGF0YU9wdGlvbnMgPSB7IH0pOiB2b2lkIHtcbiAgICBpZiAoZGF0YSA9PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZSA9IHRoaXM7XG4gICAgZnVuY3Rpb24gZ2V0VHJhY2UoKSB7XG4gICAgICBpZiAob3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGUgJiYgb3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGUubGVuZ3RoID4gMCkge1xuICAgICAgICByZXR1cm4gb3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGU7XG4gICAgICB9XG4gICAgICBjb25zdCBzaG91bGRUcmFjZSA9IG9wdGlvbnMuc3RhY2tUcmFjZSA/PyBmYWxzZTtcbiAgICAgIHJldHVybiBzaG91bGRUcmFjZSA/IGNhcHR1cmVTdGFja1RyYWNlKG9wdGlvbnMudHJhY2VGcm9tRnVuY3Rpb24gPz8gbm9kZS5hZGRNZXRhZGF0YSkgOiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLl9tZXRhZGF0YSkge1xuICAgICAgdGhpcy5fbWV0YWRhdGEgPSBbXTtcbiAgICB9XG4gICAgdGhpcy5fbWV0YWRhdGEucHVzaCh7IHR5cGUsIGRhdGEsIHRyYWNlOiBnZXRUcmFjZSgpIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbCBwYXJlbnQgc2NvcGVzIG9mIHRoaXMgY29uc3RydWN0LlxuICAgKlxuICAgKiBAcmV0dXJucyBhIGxpc3Qgb2YgcGFyZW50IHNjb3Blcy4gVGhlIGxhc3QgZWxlbWVudCBpbiB0aGUgbGlzdCB3aWxsIGFsd2F5c1xuICAgKiBiZSB0aGUgY3VycmVudCBjb25zdHJ1Y3QgYW5kIHRoZSBmaXJzdCBlbGVtZW50IHdpbGwgYmUgdGhlIHJvb3Qgb2YgdGhlXG4gICAqIHRyZWUuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHNjb3BlcygpOiBJQ29uc3RydWN0W10ge1xuICAgIGNvbnN0IHJldCA9IG5ldyBBcnJheTxJQ29uc3RydWN0PigpO1xuXG4gICAgbGV0IGN1cnI6IElDb25zdHJ1Y3QgfCB1bmRlZmluZWQgPSB0aGlzLmhvc3Q7XG4gICAgd2hpbGUgKGN1cnIpIHtcbiAgICAgIHJldC51bnNoaWZ0KGN1cnIpO1xuICAgICAgY3VyciA9IGN1cnIubm9kZS5zY29wZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHJvb3Qgb2YgdGhlIGNvbnN0cnVjdCB0cmVlLlxuICAgKiBAcmV0dXJucyBUaGUgcm9vdCBvZiB0aGUgY29uc3RydWN0IHRyZWUuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHJvb3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuc2NvcGVzWzBdO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGlzIGNvbnN0cnVjdCBvciB0aGUgc2NvcGVzIGluIHdoaWNoIGl0IGlzIGRlZmluZWQgYXJlXG4gICAqIGxvY2tlZC5cbiAgICovXG4gIHB1YmxpYyBnZXQgbG9ja2VkKCkge1xuICAgIGlmICh0aGlzLl9sb2NrZWQpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnNjb3BlICYmIHRoaXMuc2NvcGUubm9kZS5sb2NrZWQpIHtcbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYW4gb3JkZXJpbmcgZGVwZW5kZW5jeSBvbiBhIERlcGVuZGFibGUgKGEgY29uc3RydWN0IG9yIHNldCBvZiBjb25zdHJ1Y3RzKVxuICAgKlxuICAgKiBJdCBpcyB1cCB0byB0aGUgdGFyZ2V0IGRvY3VtZW50IGxhbmd1YWdlIHRvIGRlY2lkZSB3aGF0IGFuIG9yZGVyaW5nXG4gICAqIHJlbGF0aW9uc2hpcCBtZWFucyBhbmQgaG93IGl0IHNob3VsZCBiZSByZW5kZXJlZDsgZm9yIGV4YW1wbGUsIGluIHRoZSBBV1NcbiAgICogQ0RLIGZvciBDbG91ZEZvcm1hdGlvbiBpdCBtZWFucyBhIGRlcGVuZGVuY3kgZnJvbSBldmVyeSByZXNvdXJjZSBpbiBzY29wZVxuICAgKiBvZiB0aGUgY3VycmVudCBjb25zdHJ1Y3QgdG8gZXZlcnkgcmVzb3VyY2UgaW4gc2NvcGUgb2YgdGhlIHRhcmdldCBzZXRcbiAgICogb2YgY29uc3RydWN0cywgdGhhdCBnZXQgcmVhbGl6ZWQgYXMgZWl0aGVyIHN0YWNrIGRlcGVuZGVuY2llcyBvclxuICAgKiBgRGVwZW5kc09uYCByZWxhdGlvbnNoaXBzIGluIHRoZSBzeW50aGVzaXplZCB0ZW1wbGF0ZS5cbiAgICpcbiAgICogYElEZXBlbmRhYmxlYCBpcyBhIG1hcmtlciBpbnRlcmZhY2UgdGhhdCBpbmRpY2F0ZXMgdGhhdCBhIGNsYXNzIGhhcyB1c2VkXG4gICAqIGBEZXBlbmRhYmxlLmltcGxlbWVudCgpYCB0byBpbXBsZW1lbnQgdGhlIGBJRGVwZW5kYWJsZWAgaW50ZXJmYWNlLiBJdFxuICAgKiBjYW4gYmUgdXNlZCB0byBtYWtlIHRoZSB0YXJnZXQgb2JqZWN0IHJlcHJlc2VudCBtb3JlIHRoYW4gb25lIHNldCBvZlxuICAgKiBjb25zdHJ1Y3RzIGF0IGEgdGltZS4gRm9yIGV4YW1wbGUsIGEgYERlcGVuZGVuY3lHcm91cGAgdXNlcyB0aGlzXG4gICAqIGludGVyZmFjZSB0byByZXByZXNlbnQgYW4gZXhwbGljaXQgbGlzdCBvZiAwIG9yIG1vcmUgY29uc3RydWN0cyB0aGF0IHNob3VsZFxuICAgKiBiZSBpbnZvbHZlZCBpbiB0aGUgZGVwZW5kZW5jeSByZWxhdGlvbnNoaXAuXG4gICAqL1xuICBwdWJsaWMgYWRkRGVwZW5kZW5jeSguLi5kZXBzOiBJRGVwZW5kYWJsZVtdKSB7XG4gICAgaWYgKCF0aGlzLl9kZXBlbmRlbmNpZXMpIHtcbiAgICAgIHRoaXMuX2RlcGVuZGVuY2llcyA9IG5ldyBTZXQoKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBkIG9mIGRlcHMpIHtcbiAgICAgIHRoaXMuX2RlcGVuZGVuY2llcy5hZGQoZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBhbiBvcmRlcmluZyBkZXBlbmRlbmN5IG9uIGEgRGVwZW5kZW5hYmxlIChhIGNvbnN0cnVjdCBvciBzZXQgb2YgY29uc3RydWN0cylcbiAgICpcbiAgICogVGhpcyByZW1vdmVzIGFueSBkZXBlbmRlbmN5IGFkZGVkIHVzaW5nIGBub2RlLmFkZERlcGVuZGVuY3koKWAuIEl0IG11c3RcbiAgICogdXNlIHRoZSBleGFjdCBzYW1lIG9iamVjdCB0aGF0IHdhcyBpbnZvbHZlZCBpbiB0aGUgYGFkZERlcGVuZGVuY3koKWAgY2FsbC5cbiAgICovXG4gIHB1YmxpYyByZW1vdmVEZXBlbmRlbmN5KC4uLmRlcHM6IElEZXBlbmRhYmxlW10pIHtcbiAgICBpZiAoIXRoaXMuX2RlcGVuZGVuY2llcykge1xuICAgICAgdGhpcy5fZGVwZW5kZW5jaWVzID0gbmV3IFNldCgpO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGQgb2YgZGVwcykge1xuICAgICAgdGhpcy5fZGVwZW5kZW5jaWVzLmRlbGV0ZShkKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQ29uc3RydWN0cyB0aGF0IHRoaXMgY29uc3RydWN0IGRlcGVuZHMgb24gZGlyZWN0bHlcbiAgICpcbiAgICogVGhpcyBleHBhbmRzIHRoZSBzZXRzIG9mIGBEZXBlbmRhYmxlc2AgdG8gdGhlIHNldCBvZiBgQ29uc3RydWN0c2AgdGhhdCB0aGV5XG4gICAqIHJlcHJlc2VudC5cbiAgICovXG4gIHB1YmxpYyBnZXQgZGVwZW5kZW5jaWVzKCk6IElDb25zdHJ1Y3RbXSB7XG4gICAgY29uc3QgcmVzdWx0ID0gbmV3IEFycmF5PElDb25zdHJ1Y3Q+KCk7XG4gICAgaWYgKHRoaXMuX2RlcGVuZGVuY2llcykge1xuICAgICAgZm9yIChjb25zdCBkZXAgb2YgdGhpcy5fZGVwZW5kZW5jaWVzKSB7XG4gICAgICAgIGZvciAoY29uc3Qgcm9vdCBvZiBEZXBlbmRhYmxlLm9mKGRlcCkuZGVwZW5kZW5jeVJvb3RzKSB7XG4gICA