constructs
Version:
A programming model for software-defined state
594 lines • 64.1 kB
JavaScript
"use strict";
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 node_addr_1 = require("./private/node-addr");
const stack_trace_1 = require("./private/stack-trace");
const CONSTRUCT_SYM = Symbol.for('constructs.Construct');
/**
* Represents the construct node in the scope tree.
*/
class Node {
host;
static [JSII_RTTI_SYMBOL_1] = { fqn: "constructs.Node", version: "10.8.1" };
/**
* Separator used to delimit construct path components.
*/
static PATH_SEP = '/';
/**
* Returns the node associated with a construct.
* @param construct the construct
*
* @deprecated use `construct.node` instead
*/
static of(construct) {
return construct.node;
}
/**
* Returns the scope in which this construct is defined.
*
* The value is `undefined` at the root of the construct scope tree.
*/
scope;
/**
* The id of this construct within the current scope.
*
* This is a scope-unique id. To obtain an id that reflects the full location
* of this construct in the tree, use `path` or `addr`.
*/
id;
/**
* The full, absolute path of this construct in the tree.
*
* Components are separated by '/'.
*/
path;
_locked = false; // if this is "true", addChild will fail
_children;
_context;
_metadata;
_dependencies;
_defaultChild;
_validations;
_addr; // cache
_scopes;
constructor(host, scope, id) {
this.host = host;
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');
}
if (scope) {
scope.node.addChild(host, this.id);
this.path = scope.node.path ? `${scope.node.path}${Node.PATH_SEP}${this.id}` : this.id;
this._scopes = [...scope.node._scopes, this.host];
}
else {
this.path = this.id;
this._scopes = [this.host];
}
}
/**
* 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() {
// Needs to return a copy to make sure callers can't accidentally mutate
// internal state. jsii doesn't support ReadonlyArray.
return [...this._scopes];
}
/**
* An opaque, deterministic address for this construct, derived from its path.
*
* The address is a 42 character string: the prefix "c8" followed by 40
* lowercase hexadecimal characters (0-9a-f). It is a SHA-1 over the ids of
* the constructs on the path from the root of the tree down to this
* construct.
*
* To enable refactoring of construct trees, constructs with the ID `Default`
* are excluded from the calculation. Within a tree, `a/Default/b` and `a/b`
* have the same address.
*
* This means the address is *not* guaranteed to identify a construct uniquely:
*
* - Any construct whose path is made up of the same ids has the same address.
* Two trees that are shaped alike therefore hand out the same addresses.
* - As described above, a construct under a `Default` scope has the same
* address as its counterpart outside of that scope.
* - The digest is of fixed width, so even distinct paths can in principle hash
* to the same address. SHA-1 in particular is no longer collision resistant.
*
* Use an address to derive stable, deterministic names from the location of a
* construct in the tree. Do not use it as the identity of a construct:
* instead, compare construct instances or use the `path`.
*
* @example c83a2846e506bcc5f10682b564084bca2d275709ee
*/
get addr() {
if (!this._addr) {
this._addr = (0, node_addr_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) {
const ret = { ...defaults };
for (const scope of this._scopes) {
Object.assign(ret, scope.node._context);
}
return ret;
}
/**
* 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() });
}
/**
* 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;
/**
* 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 {
static [JSII_RTTI_SYMBOL_1] = { fqn: "constructs.Construct", version: "10.8.1" };
/**
* 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];
}
/**
* The tree node.
*/
node;
/**
* 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 (`/`) or a newline, 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;
/**
* 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 SEP_REGEX = new RegExp(`[${Node.PATH_SEP}${node_addr_1.ADDR_SEP}]`, 'g');
/**
* Return a sanitized version of an arbitrary string, so it can be used as an ID
*/
function sanitizeId(id) {
// Escape the separators used by `path` and by `addr` as double dashes, so a
// single id never looks like multiple path components in either of them.
return id.replace(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 {
static [JSII_RTTI_SYMBOL_1] = { fqn: "constructs.RootConstruct", version: "10.8.1" };
/**
* Creates a new root construct node.
*
* @param id The scoped construct ID. Must be unique amongst siblings. If
* the ID includes a path separator (`/`) or a newline, then it will be
* replaced by double dash `--`.
*/
constructor(id) {
super(undefined, id ?? '');
}
}
exports.RootConstruct = RootConstruct;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RydWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2NvbnN0cnVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQ0EsNkNBQTBDO0FBRzFDLG1EQUEwRDtBQUMxRCx1REFBMEQ7QUFFMUQsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0FBdUJ6RDs7R0FFRztBQUNILE1BQWEsSUFBSTtJQWlEcUI7O0lBaERwQzs7T0FFRztJQUNJLE1BQU0sQ0FBVSxRQUFRLEdBQUcsR0FBRyxDQUFDO0lBRXRDOzs7OztPQUtHO0lBQ0ksTUFBTSxDQUFDLEVBQUUsQ0FBQyxTQUFxQjtRQUNwQyxPQUFPLFNBQVMsQ0FBQyxJQUFJLENBQUM7SUFDeEIsQ0FBQztJQUVEOzs7O09BSUc7SUFDYSxLQUFLLENBQWM7SUFFbkM7Ozs7O09BS0c7SUFDYSxFQUFFLENBQVM7SUFFM0I7Ozs7T0FJRztJQUNhLElBQUksQ0FBUztJQUVyQixPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUMsd0NBQXdDO0lBQ3pELFNBQVMsQ0FBMkM7SUFDcEQsUUFBUSxDQUFxQztJQUM3QyxTQUFTLENBQW1DO0lBQzVDLGFBQWEsQ0FBK0I7SUFDNUMsYUFBYSxDQUF5QjtJQUN0QyxZQUFZLENBQWlDO0lBQzdDLEtBQUssQ0FBVSxDQUFDLFFBQVE7SUFDeEIsT0FBTyxDQUF3QjtJQUd2QyxZQUFvQyxJQUFlLEVBQUUsS0FBaUIsRUFBRSxFQUFVO1FBQTlDLFNBQUksR0FBSixJQUFJLENBQVc7UUFDakQsRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyx3Q0FBd0M7UUFFdkQsSUFBSSxDQUFDLEVBQUUsR0FBRyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDekIsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUM7UUFFbkIsSUFBSSxLQUFLLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7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Y0FBYyw4QkFBZCxjQUFjLFFBVXpCO0FBRUQsTUFBTSxTQUFTLEdBQUcsSUFBSSxNQUFNLENBQUMsSUFBSSxJQUFJLENBQUMsUUFBUSxHQUFHLG9CQUFRLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztBQUVuRTs7R0FFRztBQUNILFNBQVMsVUFBVSxDQUFDLEVBQVU7SUFDNUIsNEVBQTRFO0lBQzVFLHlFQUF5RTtJQUN6RSxPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQ3JDLENBQUM7QUE0QkQsb0NBQW9DO0FBQ3BDLE1BQU0sQ0FBQyxjQUFjLENBQUMsU0FBUyxDQUFDLFNBQVMsRUFBRSxhQUFhLEVBQUU7SUFDeEQsS0FBSyxFQUFFLElBQUk7SUFDWCxVQUFVLEVBQUUsS0FBSztJQUNqQixRQUFRLEVBQUUsS0FBSztDQUNoQixDQUFDLENBQUM7QUFFSDs7Ozs7R0FLRztBQUNILE1BQWEsYUFBYyxTQUFRLFNBQVM7O0lBQzFDOzs7Ozs7T0FNRztJQUNILFlBQVksRUFBVztRQUNyQixLQUFLLENBQUMsU0FBZ0IsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDcEMsQ0FBQzs7QUFWSCxzQ0FXQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgSURlcGVuZGFibGUgfSBmcm9tICcuL2RlcGVuZGVuY3knO1xuaW1wb3J0IHsgRGVwZW5kYWJsZSB9IGZyb20gJy4vZGVwZW5kZW5jeSc7XG5pbXBvcnQgdHlwZSB7IE1ldGFkYXRhRW50cnkgfSBmcm9tICcuL21ldGFkYXRhJztcbmltcG9ydCB0eXBlIHsgSU1peGluIH0gZnJvbSAnLi9taXhpbic7XG5pbXBvcnQgeyBBRERSX1NFUCwgYWRkcmVzc09mIH0gZnJvbSAnLi9wcml2YXRlL25vZGUtYWRkcic7XG5pbXBvcnQgeyBjYXB0dXJlU3RhY2tUcmFjZSB9IGZyb20gJy4vcHJpdmF0ZS9zdGFjay10cmFjZSc7XG5cbmNvbnN0IENPTlNUUlVDVF9TWU0gPSBTeW1ib2wuZm9yKCdjb25zdHJ1Y3RzLkNvbnN0cnVjdCcpO1xuXG4vKipcbiAqIFJlcHJlc2VudHMgYSBjb25zdHJ1Y3QuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSUNvbnN0cnVjdCBleHRlbmRzIElEZXBlbmRhYmxlIHtcbiAgLyoqXG4gICAqIFRoZSB0cmVlIG5vZGUuXG4gICAqL1xuICByZWFkb25seSBub2RlOiBOb2RlO1xuXG4gIC8qKlxuICAgKiBBcHBsaWVzIG9uZSBvciBtb3JlIG1peGlucyB0byB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogTWl4aW5zIGFyZSBhcHBsaWVkIGluIG9yZGVyLiBUaGUgbGlzdCBvZiBjb25zdHJ1Y3RzIGlzIGNhcHR1cmVkIGF0IHRoZVxuICAgKiBzdGFydCBvZiB0aGUgY2FsbCwgc28gY29uc3RydWN0cyBhZGRlZCBieSBhIG1peGluIHdpbGwgbm90IGJlIHZpc2l0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSBtaXhpbnMgVGhlIG1peGlucyB0byBhcHBseVxuICAgKiBAcmV0dXJucyBUaGlzIGNvbnN0cnVjdCBmb3IgY2hhaW5pbmdcbiAgICovXG4gIHdpdGgoLi4ubWl4aW5zOiBJTWl4aW5bXSk6IElDb25zdHJ1Y3Q7XG59XG5cbi8qKlxuICogUmVwcmVzZW50cyB0aGUgY29uc3RydWN0IG5vZGUgaW4gdGhlIHNjb3BlIHRyZWUuXG4gKi9cbmV4cG9ydCBjbGFzcyBOb2RlIHtcbiAgLyoqXG4gICAqIFNlcGFyYXRvciB1c2VkIHRvIGRlbGltaXQgY29uc3RydWN0IHBhdGggY29tcG9uZW50cy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgUEFUSF9TRVAgPSAnLyc7XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIG5vZGUgYXNzb2NpYXRlZCB3aXRoIGEgY29uc3RydWN0LlxuICAgKiBAcGFyYW0gY29uc3RydWN0IHRoZSBjb25zdHJ1Y3RcbiAgICpcbiAgICogQGRlcHJlY2F0ZWQgdXNlIGBjb25zdHJ1Y3Qubm9kZWAgaW5zdGVhZFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBvZihjb25zdHJ1Y3Q6IElDb25zdHJ1Y3QpOiBOb2RlIHtcbiAgICByZXR1cm4gY29uc3RydWN0Lm5vZGU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyB0aGUgc2NvcGUgaW4gd2hpY2ggdGhpcyBjb25zdHJ1Y3QgaXMgZGVmaW5lZC5cbiAgICpcbiAgICogVGhlIHZhbHVlIGlzIGB1bmRlZmluZWRgIGF0IHRoZSByb290IG9mIHRoZSBjb25zdHJ1Y3Qgc2NvcGUgdHJlZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBzY29wZT86IElDb25zdHJ1Y3Q7XG5cbiAgLyoqXG4gICAqIFRoZSBpZCBvZiB0aGlzIGNvbnN0cnVjdCB3aXRoaW4gdGhlIGN1cnJlbnQgc2NvcGUuXG4gICAqXG4gICAqIFRoaXMgaXMgYSBzY29wZS11bmlxdWUgaWQuIFRvIG9idGFpbiBhbiBpZCB0aGF0IHJlZmxlY3RzIHRoZSBmdWxsIGxvY2F0aW9uXG4gICAqIG9mIHRoaXMgY29uc3RydWN0IGluIHRoZSB0cmVlLCB1c2UgYHBhdGhgIG9yIGBhZGRyYC5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBpZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZnVsbCwgYWJzb2x1dGUgcGF0aCBvZiB0aGlzIGNvbnN0cnVjdCBpbiB0aGUgdHJlZS5cbiAgICpcbiAgICogQ29tcG9uZW50cyBhcmUgc2VwYXJhdGVkIGJ5ICcvJy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwYXRoOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSBfbG9ja2VkID0gZmFsc2U7IC8vIGlmIHRoaXMgaXMgXCJ0cnVlXCIsIGFkZENoaWxkIHdpbGwgZmFpbFxuICBwcml2YXRlIF9jaGlsZHJlbjogeyBbaWQ6IHN0cmluZ106IElDb25zdHJ1Y3QgfSB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfY29udGV4dDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfbWV0YWRhdGE6IEFycmF5PE1ldGFkYXRhRW50cnk+IHwgdW5kZWZpbmVkO1xuICBwcml2YXRlIF9kZXBlbmRlbmNpZXM6IFNldDxJRGVwZW5kYWJsZT4gfCB1bmRlZmluZWQ7XG4gIHByaXZhdGUgX2RlZmF1bHRDaGlsZDogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfdmFsaWRhdGlvbnM6IEFycmF5PElWYWxpZGF0aW9uPiB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSBfYWRkcj86IHN0cmluZzsgLy8gY2FjaGVcbiAgcHJpdmF0ZSBfc2NvcGVzOiByZWFkb25seSBJQ29uc3RydWN0W107XG5cblxuICBwdWJsaWMgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBob3N0OiBDb25zdHJ1Y3QsIHNjb3BlOiBJQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gICAgaWQgPSBpZCA/PyAnJzsgLy8gaWYgdW5kZWZpbmVkLCBjb252ZXJ0IHRvIGVtcHR5IHN0cmluZ1xuXG4gICAgdGhpcy5pZCA9IHNhbml0aXplSWQoaWQpO1xuICAgIHRoaXMuc2NvcGUgPSBzY29wZTtcblxuICAgIGlmIChzY29wZSAmJiAhdGhpcy5pZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdPbmx5IHJvb3QgY29uc3RydWN0cyBtYXkgaGF2ZSBhbiBlbXB0eSBJRCcpO1xuICAgIH1cblxuICAgIGlmIChzY29wZSkge1xuICAgICAgc2NvcGUubm9kZS5hZGRDaGlsZChob3N0LCB0aGlzLmlkKTtcbiAgICAgIHRoaXMucGF0aCA9IHNjb3BlLm5vZGUucGF0aCA/IGAke3Njb3BlLm5vZGUucGF0aH0ke05vZGUuUEFUSF9TRVB9JHt0aGlzLmlkfWAgOiB0aGlzLmlkO1xuICAgICAgdGhpcy5fc2NvcGVzID0gWy4uLnNjb3BlLm5vZGUuX3Njb3BlcywgdGhpcy5ob3N0XTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5wYXRoID0gdGhpcy5pZDtcbiAgICAgIHRoaXMuX3Njb3BlcyA9IFt0aGlzLmhvc3RdO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBbGwgcGFyZW50IHNjb3BlcyBvZiB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogQHJldHVybnMgYSBsaXN0IG9mIHBhcmVudCBzY29wZXMuIFRoZSBsYXN0IGVsZW1lbnQgaW4gdGhlIGxpc3Qgd2lsbCBhbHdheXNcbiAgICogYmUgdGhlIGN1cnJlbnQgY29uc3RydWN0IGFuZCB0aGUgZmlyc3QgZWxlbWVudCB3aWxsIGJlIHRoZSByb290IG9mIHRoZVxuICAgKiB0cmVlLlxuICAgKi9cbiAgcHVibGljIGdldCBzY29wZXMoKTogSUNvbnN0cnVjdFtdIHtcbiAgICAvLyBOZWVkcyB0byByZXR1cm4gYSBjb3B5IHRvIG1ha2Ugc3VyZSBjYWxsZXJzIGNhbid0IGFjY2lkZW50YWxseSBtdXRhdGVcbiAgICAvLyBpbnRlcm5hbCBzdGF0ZS4ganNpaSBkb2Vzbid0IHN1cHBvcnQgUmVhZG9ubHlBcnJheS5cbiAgICByZXR1cm4gWy4uLnRoaXMuX3Njb3Blc107XG4gIH1cblxuICAvKipcbiAgICogQW4gb3BhcXVlLCBkZXRlcm1pbmlzdGljIGFkZHJlc3MgZm9yIHRoaXMgY29uc3RydWN0LCBkZXJpdmVkIGZyb20gaXRzIHBhdGguXG4gICAqXG4gICAqIFRoZSBhZGRyZXNzIGlzIGEgNDIgY2hhcmFjdGVyIHN0cmluZzogdGhlIHByZWZpeCBcImM4XCIgZm9sbG93ZWQgYnkgNDBcbiAgICogbG93ZXJjYXNlIGhleGFkZWNpbWFsIGNoYXJhY3RlcnMgKDAtOWEtZikuIEl0IGlzIGEgU0hBLTEgb3ZlciB0aGUgaWRzIG9mXG4gICAqIHRoZSBjb25zdHJ1Y3RzIG9uIHRoZSBwYXRoIGZyb20gdGhlIHJvb3Qgb2YgdGhlIHRyZWUgZG93biB0byB0aGlzXG4gICAqIGNvbnN0cnVjdC5cbiAgICpcbiAgICogVG8gZW5hYmxlIHJlZmFjdG9yaW5nIG9mIGNvbnN0cnVjdCB0cmVlcywgY29uc3RydWN0cyB3aXRoIHRoZSBJRCBgRGVmYXVsdGBcbiAgICogYXJlIGV4Y2x1ZGVkIGZyb20gdGhlIGNhbGN1bGF0aW9uLiBXaXRoaW4gYSB0cmVlLCBgYS9EZWZhdWx0L2JgIGFuZCBgYS9iYFxuICAgKiBoYXZlIHRoZSBzYW1lIGFkZHJlc3MuXG4gICAqXG4gICAqIFRoaXMgbWVhbnMgdGhlIGFkZHJlc3MgaXMgKm5vdCogZ3VhcmFudGVlZCB0byBpZGVudGlmeSBhIGNvbnN0cnVjdCB1bmlxdWVseTpcbiAgICpcbiAgICogLSBBbnkgY29uc3RydWN0IHdob3NlIHBhdGggaXMgbWFkZSB1cCBvZiB0aGUgc2FtZSBpZHMgaGFzIHRoZSBzYW1lIGFkZHJlc3MuXG4gICAqICAgVHdvIHRyZWVzIHRoYXQgYXJlIHNoYXBlZCBhbGlrZSB0aGVyZWZvcmUgaGFuZCBvdXQgdGhlIHNhbWUgYWRkcmVzc2VzLlxuICAgKiAtIEFzIGRlc2NyaWJlZCBhYm92ZSwgYSBjb25zdHJ1Y3QgdW5kZXIgYSBgRGVmYXVsdGAgc2NvcGUgaGFzIHRoZSBzYW1lXG4gICAqICAgYWRkcmVzcyBhcyBpdHMgY291bnRlcnBhcnQgb3V0c2lkZSBvZiB0aGF0IHNjb3BlLlxuICAgKiAtIFRoZSBkaWdlc3QgaXMgb2YgZml4ZWQgd2lkdGgsIHNvIGV2ZW4gZGlzdGluY3QgcGF0aHMgY2FuIGluIHByaW5jaXBsZSBoYXNoXG4gICAqICAgdG8gdGhlIHNhbWUgYWRkcmVzcy4gU0hBLTEgaW4gcGFydGljdWxhciBpcyBubyBsb25nZXIgY29sbGlzaW9uIHJlc2lzdGFudC5cbiAgICpcbiAgICogVXNlIGFuIGFkZHJlc3MgdG8gZGVyaXZlIHN0YWJsZSwgZGV0ZXJtaW5pc3RpYyBuYW1lcyBmcm9tIHRoZSBsb2NhdGlvbiBvZiBhXG4gICAqIGNvbnN0cnVjdCBpbiB0aGUgdHJlZS4gRG8gbm90IHVzZSBpdCBhcyB0aGUgaWRlbnRpdHkgb2YgYSBjb25zdHJ1Y3Q6XG4gICAqIGluc3RlYWQsIGNvbXBhcmUgY29uc3RydWN0IGluc3RhbmNlcyBvciB1c2UgdGhlIGBwYXRoYC5cbiAgICpcbiAgICogQGV4YW1wbGUgYzgzYTI4NDZlNTA2YmNjNWYxMDY4MmI1NjQwODRiY2EyZDI3NTcwOWVlXG4gICAqL1xuICBwdWJsaWMgZ2V0IGFkZHIoKTogc3RyaW5nIHtcbiAgICBpZiAoIXRoaXMuX2FkZHIpIHtcbiAgICAgIHRoaXMuX2FkZHIgPSBhZGRyZXNzT2YodGhpcy5fc2NvcGVzLm1hcChjID0+IGMubm9kZS5pZCkpO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLl9hZGRyO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGRpcmVjdCBjaGlsZCBieSBpZCwgb3IgdW5kZWZpbmVkXG4gICAqXG4gICAqIEBwYXJhbSBpZCBJZGVudGlmaWVyIG9mIGRpcmVjdCBjaGlsZFxuICAgKiBAcmV0dXJucyB0aGUgY2hpbGQgaWYgZm91bmQsIG9yIHVuZGVmaW5lZFxuICAgKi9cbiAgcHVibGljIHRyeUZpbmRDaGlsZChpZDogc3RyaW5nKTogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuX2NoaWxkcmVuPy5bc2FuaXRpemVJZChpZCldO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhIGRpcmVjdCBjaGlsZCBieSBpZFxuICAgKlxuICAgKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGNoaWxkIGlzIG5vdCBmb3VuZC5cbiAgICpcbiAgICogQHBhcmFtIGlkIElkZW50aWZpZXIgb2YgZGlyZWN0IGNoaWxkXG4gICAqIEByZXR1cm5zIENoaWxkIHdpdGggdGhlIGdpdmVuIGlkLlxuICAgKi9cbiAgcHVibGljIGZpbmRDaGlsZChpZDogc3RyaW5nKTogSUNvbnN0cnVjdCB7XG4gICAgY29uc3QgcmV0ID0gdGhpcy50cnlGaW5kQ2hpbGQoaWQpO1xuICAgIGlmICghcmV0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGNoaWxkIHdpdGggaWQ6ICcke2lkfSdgKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBjaGlsZCBjb25zdHJ1Y3QgdGhhdCBoYXMgdGhlIGlkIGBEZWZhdWx0YCBvciBgUmVzb3VyY2VgLlxuICAgKiBUaGlzIGlzIHVzdWFsbHkgdGhlIGNvbnN0cnVjdCB0aGF0IHByb3ZpZGVzIHRoZSBidWxrIG9mIHRoZSB1bmRlcmx5aW5nIGZ1bmN0aW9uYWxpdHkuXG4gICAqIFVzZWZ1bCBmb3IgbW9kaWZpY2F0aW9ucyBvZiB0aGUgdW5kZXJseWluZyBjb25zdHJ1Y3QgdGhhdCBhcmUgbm90IGF2YWlsYWJsZSBhdCB0aGUgaGlnaGVyIGxldmVscy5cbiAgICpcbiAgICogQHRocm93cyBpZiB0aGVyZSBpcyBtb3JlIHRoYW4gb25lIGNoaWxkXG4gICAqIEByZXR1cm5zIGEgY29uc3RydWN0IG9yIHVuZGVmaW5lZCBpZiB0aGVyZSBpcyBubyBkZWZhdWx0IGNoaWxkXG4gICAqL1xuICBwdWJsaWMgZ2V0IGRlZmF1bHRDaGlsZCgpOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkIHtcbiAgICBpZiAodGhpcy5fZGVmYXVsdENoaWxkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB0aGlzLl9kZWZhdWx0Q2hpbGQ7XG4gICAgfVxuXG4gICAgY29uc3QgcmVzb3VyY2VDaGlsZCA9IHRoaXMudHJ5RmluZENoaWxkKCdSZXNvdXJjZScpO1xuICAgIGNvbnN0IGRlZmF1bHRDaGlsZCA9IHRoaXMudHJ5RmluZENoaWxkKCdEZWZhdWx0Jyk7XG4gICAgaWYgKHJlc291cmNlQ2hpbGQgJiYgZGVmYXVsdENoaWxkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBkZXRlcm1pbmUgZGVmYXVsdCBjaGlsZCBmb3IgJHt0aGlzLnBhdGh9LiBUaGVyZSBpcyBib3RoIGEgY2hpbGQgd2l0aCBpZCBcIlJlc291cmNlXCIgYW5kIGlkIFwiRGVmYXVsdFwiYCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlZmF1bHRDaGlsZCB8fCByZXNvdXJjZUNoaWxkO1xuICB9XG5cbiAgLyoqXG4gICAqIE92ZXJyaWRlIHRoZSBkZWZhdWx0Q2hpbGQgcHJvcGVydHkuXG4gICAqXG4gICAqIFRoaXMgc2hvdWxkIG9ubHkgYmUgdXNlZCBpbiB0aGUgY2FzZXMgd2hlcmUgdGhlIGNvcnJlY3RcbiAgICogZGVmYXVsdCBjaGlsZCBpcyBub3QgbmFtZWQgJ1Jlc291cmNlJyBvciAnRGVmYXVsdCcgYXMgaXRcbiAgICogc2hvdWxkIGJlLlxuICAgKlxuICAgKiBJZiB5b3Ugc2V0IHRoaXMgdG8gdW5kZWZpbmVkLCB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZiBmaW5kaW5nXG4gICAqIHRoZSBjaGlsZCBuYW1lZCAnUmVzb3VyY2UnIG9yICdEZWZhdWx0JyB3aWxsIGJlIHVzZWQuXG4gICAqL1xuICBwdWJsaWMgc2V0IGRlZmF1bHRDaGlsZCh2YWx1ZTogSUNvbnN0cnVjdCB8IHVuZGVmaW5lZCkge1xuICAgIHRoaXMuX2RlZmF1bHRDaGlsZCA9IHZhbHVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbCBkaXJlY3QgY2hpbGRyZW4gb2YgdGhpcyBjb25zdHJ1Y3QuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGNoaWxkcmVuKCkge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMuX2NoaWxkcmVuID8/IHt9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhpcyBjb25zdHJ1Y3QgYW5kIGFsbCBvZiBpdHMgY2hpbGRyZW4gaW4gdGhlIGdpdmVuIG9yZGVyXG4gICAqL1xuICBwdWJsaWMgZmluZEFsbChvcmRlcjogQ29uc3RydWN0T3JkZXIgPSBDb25zdHJ1Y3RPcmRlci5QUkVPUkRFUik6IElDb25zdHJ1Y3RbXSB7XG4gICAgY29uc3QgcmV0ID0gbmV3IEFycmF5PElDb25zdHJ1Y3Q+KCk7XG4gICAgdmlzaXQodGhpcy5ob3N0KTtcbiAgICByZXR1cm4gcmV0O1xuXG4gICAgZnVuY3Rpb24gdmlzaXQoYzogSUNvbnN0cnVjdCkge1xuICAgICAgaWYgKG9yZGVyID09PSBDb25zdHJ1Y3RPcmRlci5QUkVPUkRFUikge1xuICAgICAgICByZXQucHVzaChjKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjaGlsZCBvZiBjLm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgICAgdmlzaXQoY2hpbGQpO1xuICAgICAgfVxuXG4gICAgICBpZiAob3JkZXIgPT09IENvbnN0cnVjdE9yZGVyLlBPU1RPUkRFUikge1xuICAgICAgICByZXQucHVzaChjKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBjYW4gYmUgdXNlZCB0byBzZXQgY29udGV4dHVhbCB2YWx1ZXMuXG4gICAqIENvbnRleHQgbXVzdCBiZSBzZXQgYmVmb3JlIGFueSBjaGlsZHJlbiBhcmUgYWRkZWQsIHNpbmNlIGNoaWxkcmVuIG1heSBjb25zdWx0IGNvbnRleHQgaW5mbyBkdXJpbmcgY29uc3RydWN0aW9uLlxuICAgKiBJZiB0aGUga2V5IGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIG92ZXJyaWRkZW4uXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgY29udGV4dCB2YWx1ZVxuICAgKi9cbiAgcHVibGljIHNldENvbnRleHQoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpIHtcbiAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiAwKSB7XG4gICAgICBjb25zdCBuYW1lcyA9IHRoaXMuY2hpbGRyZW4ubWFwKGMgPT4gYy5ub2RlLmlkKTtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHNldCBjb250ZXh0IGFmdGVyIGNoaWxkcmVuIGhhdmUgYmVlbiBhZGRlZDogJyArIG5hbWVzLmpvaW4oJywnKSk7XG4gICAgfVxuICAgIGlmICghdGhpcy5fY29udGV4dCkge1xuICAgICAgdGhpcy5fY29udGV4dCA9IHt9O1xuICAgIH1cbiAgICB0aGlzLl9jb250ZXh0W2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHRyZWUgY29udGV4dCBpZiBwcmVzZW50LiBPdGhlcndpc2UsIHdvdWxkIHRocm93IGFuIGVycm9yLlxuICAgKlxuICAgKiBDb250ZXh0IGlzIHVzdWFsbHkgaW5pdGlhbGl6ZWQgYXQgdGhlIHJvb3QsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBhdCBhbnkgcG9pbnQgaW4gdGhlIHRyZWUuXG4gICAqXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEByZXR1cm5zIFRoZSBjb250ZXh0IHZhbHVlIG9yIHRocm93cyBlcnJvciBpZiB0aGVyZSBpcyBubyBjb250ZXh0IHZhbHVlIGZvciB0aGlzIGtleVxuICAgKi9cbiAgcHVibGljIGdldENvbnRleHQoa2V5OiBzdHJpbmcpOiBhbnkge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fY29udGV4dD8uW2tleV07XG5cbiAgICBpZiAodmFsdWUgIT09IHVuZGVmaW5lZCkgeyByZXR1cm4gdmFsdWU7IH1cblxuICAgIGlmICh2YWx1ZSA9PT0gdW5kZWZpbmVkICYmICF0aGlzLnNjb3BlPy5ub2RlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIGNvbnRleHQgdmFsdWUgcHJlc2VudCBmb3IgJHtrZXl9IGtleWApO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzLnNjb3BlICYmIHRoaXMuc2NvcGUubm9kZS5nZXRDb250ZXh0KGtleSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0cmlldmVzIHRoZSBhbGwgY29udGV4dCBvZiBhIG5vZGUgZnJvbSB0cmVlIGNvbnRleHQuXG4gICAqXG4gICAqIENvbnRleHQgaXMgdXN1YWxseSBpbml0aWFsaXplZCBhdCB0aGUgcm9vdCwgYnV0IGNhbiBiZSBvdmVycmlkZGVuIGF0IGFueSBwb2ludCBpbiB0aGUgdHJlZS5cbiAgICpcbiAgICogQHBhcmFtIGRlZmF1bHRzIEFueSBrZXlzIHRvIG92ZXJyaWRlIHRoZSByZXRyaWV2ZWQgY29udGV4dFxuICAgKiBAcmV0dXJucyBUaGUgY29udGV4dCBvYmplY3Qgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZXJlIGlzIGRpc2NvdmVyZWQgY29udGV4dFxuICAgKi9cbiAgcHVibGljIGdldEFsbENvbnRleHQoZGVmYXVsdHM/OiBvYmplY3QpOiBhbnkge1xuICAgIGNvbnN0IHJldCA9IHsgLi4uZGVmYXVsdHMgfTtcbiAgICBmb3IgKGNvbnN0IHNjb3BlIG9mIHRoaXMuX3Njb3Blcykge1xuICAgICAgT2JqZWN0LmFzc2lnbihyZXQsIHNjb3BlLm5vZGUuX2NvbnRleHQpO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHJpZXZlcyBhIHZhbHVlIGZyb20gdHJlZSBjb250ZXh0LlxuICAgKlxuICAgKiBDb250ZXh0IGlzIHVzdWFsbHkgaW5pdGlhbGl6ZWQgYXQgdGhlIHJvb3QsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBhdCBhbnkgcG9pbnQgaW4gdGhlIHRyZWUuXG4gICAqXG4gICAqIEBwYXJhbSBrZXkgVGhlIGNvbnRleHQga2V5XG4gICAqIEByZXR1cm5zIFRoZSBjb250ZXh0IHZhbHVlIG9yIGB1bmRlZmluZWRgIGlmIHRoZXJlIGlzIG5vIGNvbnRleHQgdmFsdWUgZm9yIHRoaXMga2V5LlxuICAgKi9cbiAgcHVibGljIHRyeUdldENvbnRleHQoa2V5OiBzdHJpbmcpOiBhbnkge1xuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fY29udGV4dD8uW2tleV07XG4gICAgaWYgKHZhbHVlICE9PSB1bmRlZmluZWQpIHsgcmV0dXJuIHZhbHVlOyB9XG5cbiAgICByZXR1cm4gdGhpcy5zY29wZSAmJiB0aGlzLnNjb3BlLm5vZGUudHJ5R2V0Q29udGV4dChrZXkpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFuIGltbXV0YWJsZSBhcnJheSBvZiBtZXRhZGF0YSBvYmplY3RzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIGNvbnN0cnVjdC5cbiAgICogVGhpcyBjYW4gYmUgdXNlZCwgZm9yIGV4YW1wbGUsIHRvIGltcGxlbWVudCBzdXBwb3J0IGZvciBkZXByZWNhdGlvbiBub3RpY2VzLCBzb3VyY2UgbWFwcGluZywgZXRjLlxuICAgKi9cbiAgcHVibGljIGdldCBtZXRhZGF0YSgpIHtcbiAgICByZXR1cm4gWy4uLnRoaXMuX21ldGFkYXRhID8/IFtdXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgbWV0YWRhdGEgZW50cnkgdG8gdGhpcyBjb25zdHJ1Y3QuXG4gICAqIEVudHJpZXMgYXJlIGFyYml0cmFyeSB2YWx1ZXMgYW5kIHdpbGwgYWxzbyBpbmNsdWRlIGEgc3RhY2sgdHJhY2UgdG8gYWxsb3cgdHJhY2luZyBiYWNrIHRvXG4gICAqIHRoZSBjb2RlIGxvY2F0aW9uIGZvciB3aGVuIHRoZSBlbnRyeSB3YXMgYWRkZWQuIEl0IGNhbiBiZSB1c2VkLCBmb3IgZXhhbXBsZSwgdG8gaW5jbHVkZSBzb3VyY2VcbiAgICogbWFwcGluZyBpbiBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZXMgdG8gaW1wcm92ZSBkaWFnbm9zdGljcy5cbiAgICogTm90ZSB0aGF0IGNvbnN0cnVjdCBtZXRhZGF0YSBpcyBub3QgdGhlIHNhbWUgYXMgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgbWV0YWRhdGEgYW5kIGlzIG5ldmVyIHdyaXR0ZW4gdG8gdGhlIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlLlxuICAgKiBUaGUgbWV0YWRhdGEgZW50cmllcyBhcmUgd3JpdHRlbiB0byB0aGUgQ2xvdWQgQXNzZW1ibHkgTWFuaWZlc3QgaWYgdGhlIGB0cmVlTWV0YWRhdGFgIHByb3BlcnR5IGlzIHNwZWNpZmllZCBpbiB0aGUgcHJvcHMgb2YgdGhlIEFwcCB0aGF0IGNvbnRhaW5zIHRoaXMgQ29uc3RydWN0LlxuICAgKlxuICAgKiBAcGFyYW0gdHlwZSBhIHN0cmluZyBkZW5vdGluZyB0aGUgdHlwZSBvZiBtZXRhZGF0YVxuICAgKiBAcGFyYW0gZGF0YSB0aGUgdmFsdWUgb2YgdGhlIG1ldGFkYXRhIChjYW4gYmUgYSBUb2tlbikuIElmIG51bGwvdW5kZWZpbmVkLCBtZXRhZGF0YSB3aWxsIG5vdCBiZSBhZGRlZC5cbiAgICogQHBhcmFtIG9wdGlvbnMgb3B0aW9uc1xuICAgKi9cbiAgcHVibGljIGFkZE1ldGFkYXRhKHR5cGU6IHN0cmluZywgZGF0YTogYW55LCBvcHRpb25zOiBNZXRhZGF0YU9wdGlvbnMgPSB7IH0pOiB2b2lkIHtcbiAgICBpZiAoZGF0YSA9PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZSA9IHRoaXM7XG4gICAgZnVuY3Rpb24gZ2V0VHJhY2UoKSB7XG4gICAgICBpZiAob3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGUgJiYgb3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGUubGVuZ3RoID4gMCkge1xuICAgICAgICByZXR1cm4gb3B0aW9ucy5zdGFja1RyYWNlT3ZlcnJpZGU7XG4gICAgICB9XG4gICAgICBjb25zdCBzaG91bGRUcmFjZSA9IG9wdGlvbnMuc3RhY2tUcmFjZSA/PyBmYWxzZTtcbiAgICAgIHJldHVybiBzaG91bGRUcmFjZSA/IGNhcHR1cmVTdGFja1RyYWNlKG9wdGlvbnMudHJhY2VGcm9tRnVuY3Rpb24gPz8gbm9kZS5hZGRNZXRhZGF0YSkgOiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLl9tZXRhZGF0YSkge1xuICAgICAgdGhpcy5fbWV0YWRhdGEgPSBbXTtcbiAgICB9XG4gICAgdGhpcy5fbWV0YWRhdGEucHVzaCh7IHR5cGUsIGRhdGEsIHRyYWNlOiBnZXRUcmFjZSgpIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHJvb3Qgb2YgdGhlIGNvbnN0cnVjdCB0cmVlLlxuICAgKiBAcmV0dXJucyBUaGUgcm9vdCBvZiB0aGUgY29uc3RydWN0IHRyZWUuXG4gICAqL1xuICBwdWJsaWMgZ2V0IHJvb3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuX3Njb3Blc1swXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBjb25zdHJ1Y3Qgb3IgdGhlIHNjb3BlcyBpbiB3aGljaCBpdCBpcyBkZWZpbmVkIGFyZVxuICAgKiBsb2NrZWQuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGxvY2tlZCgpIHtcbiAgICBpZiAodGhpcy5fbG9ja2VkKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5zY29wZSAmJiB0aGlzLnNjb3BlLm5vZGUubG9ja2VkKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGFuIG9yZGVyaW5nIGRlcGVuZGVuY3kgb24gYSBEZXBlbmRhYmxlIChhIGNvbnN0cnVjdCBvciBzZXQgb2YgY29uc3RydWN0cylcbiAgICpcbiAgICogSXQgaXMgdXAgdG8gdGhlIHRhcmdldCBkb2N1bWVudCBsYW5ndWFnZSB0byBkZWNpZGUgd2hhdCBhbiBvcmRlcmluZ1xuICAgKiByZWxhdGlvbnNoaXAgbWVhbnMgYW5kIGhvdyBpdCBzaG91bGQgYmUgcmVuZGVyZWQ7IGZvciBleGFtcGxlLCBpbiB0aGUgQVdTXG4gICAqIENESyBmb3IgQ2xvdWRGb3JtYXRpb24gaXQgbWVhbnMgYSBkZXBlbmRlbmN5IGZyb20gZXZlcnkgcmVzb3VyY2UgaW4gc2NvcGVcbiAgICogb2YgdGhlIGN1cnJlbnQgY29uc3RydWN0IHRvIGV2ZXJ5IHJlc291cmNlIGluIHNjb3BlIG9mIHRoZSB0YXJnZXQgc2V0XG4gICAqIG9mIGNvbnN0cnVjdHMsIHRoYXQgZ2V0IHJlYWxpemVkIGFzIGVpdGhlciBzdGFjayBkZXBlbmRlbmNpZXMgb3JcbiAgICogYERlcGVuZHNPbmAgcmVsYXRpb25zaGlwcyBpbiB0aGUgc3ludGhlc2l6ZWQgdGVtcGxhdGUuXG4gICAqXG4gICAqIGBJRGVwZW5kYWJsZWAgaXMgYSBtYXJrZXIgaW50ZXJmYWNlIHRoYXQgaW5kaWNhdGVzIHRoYXQgYSBjbGFzcyBoYXMgdXNlZFxuICAgKiBgRGVwZW5kYWJsZS5pbXBsZW1lbnQoKWAgdG8gaW1wbGVtZW50IHRoZSBgSURlcGVuZGFibGVgIGludGVyZmFjZS4gSXRcbiAgICogY2FuIGJlIHVzZWQgdG8gbWFrZSB0aGUgdGFyZ2V0IG9iamVjdCByZXByZXNlbnQgbW9yZSB0aGFuIG9uZSBzZXQgb2ZcbiAgICogY29uc3RydWN0cyBhdCBhIHRpbWUuIEZvciBleGFtcGxlLCBhIGBEZXBlbmRlbmN5R3JvdXBgIHVzZXMgdGhpc1xuICAgKiBpbnRlcmZhY2UgdG8gcmVwcmVzZW50IGFuIGV4cGxpY2l0IGxpc3Qgb2YgMCBvciBtb3JlIGNvbnN0cnVjdHMgdGhhdCBzaG91bGRcbiAgICogYmUgaW52b2x2ZWQgaW4gdGhlIGRlcGVuZGVuY3kgcmVsYXRpb25zaGlwLlxuICAgKi9cbiAgcHVibGljIGFkZERlcGVuZGVuY3koLi4uZGVwczogSURlcGVuZGFibGVbXSkge1xuICAgIGlmICghdGhpcy5fZGVwZW5kZW5jaWVzKSB7XG4gICAgICB0aGlzLl9kZXBlbmRlbmNpZXMgPSBuZXcgU2V0KCk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgZCBvZiBkZXBzKSB7XG4gICAgICB0aGlzLl9kZXBlbmRlbmNpZXMuYWRkKGQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYW4gb3JkZXJpbmcgZGVwZW5kZW5jeSBvbiBhIERlcGVuZGVuYWJsZSAoYSBjb25zdHJ1Y3Qgb3Igc2V0IG9mIGNvbnN0cnVjdHMpXG4gICAqXG4gICAqIFRoaXMgcmVtb3ZlcyBhbnkgZGVwZW5kZW5jeSBhZGRlZCB1c2luZyBgbm9kZS5hZGREZXBlbmRlbmN5KClgLiBJdCBtdXN0XG4gICAqIHVzZSB0aGUgZXhhY3Qgc2FtZSBvYmplY3QgdGhhdCB3YXMgaW52b2x2ZWQgaW4gdGhlIGBhZGREZXBlbmRlbmN5KClgIGNhbGwuXG4gICAqL1xuICBwdWJsaWMgcmVtb3ZlRGVwZW5kZW5jeSguLi5kZXBzOiBJRGVwZW5kYWJsZVtdKSB7XG4gICAgaWYgKCF0aGlzLl9kZXBlbmRlbmNpZXMpIHtcbiAgICAgIHRoaXMuX2RlcGVuZGVuY2llcyA9IG5ldyBTZXQoKTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBkIG9mIGRlcHMpIHtcbiAgICAgIHRoaXMuX2RlcGVuZGVuY2llcy5kZWxldGUoZCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIENvbnN0cnVjdHMgdGhhdCB0aGlzIGNvbnN0cnVjdCBkZXBlbmRzIG9uIGRpcmVjdGx5XG4gICAqXG4gICAqIFRoaXMgZXhwYW5kcyB0aGUgc2V0cyBvZiBgRGVwZW5kYWJsZXNgIHRvIHRoZSBzZXQgb2YgYENvbnN0cnVjdHNgIHRoYXQgdGhleVxuICAgKiByZXByZXNlbnQuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGRlcGVuZGVuY2llcygpOiBJQ29uc3RydWN0W10ge1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheTxJQ29uc3RydWN0PigpO1xuICAgIGlmICh0aGlzLl9kZXBlbmRlbmNpZXMpIHtcbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIHRoaXMuX2RlcGVuZGVuY2llcykge1xuICAgICAgICBmb3IgKGNvbnN0IHJvb3Qgb2YgRGVwZW5kYWJsZS5vZihkZXApLmRlcGVuZGVuY3lSb290cykge1xuICAgICAgICAgIHJlc3VsdC5wdXNoKHJvb3QpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBjaGlsZCB3aXRoIHRoZSBnaXZlbiBuYW1lLCBpZiBwcmVzZW50LlxuICAgKlxuICAgKiBAcmV0dXJucyBXaGV0aGVyIGEgY2hpbGQgd2l0aCB0aGUgZ2l2ZW4gbmFtZSB3YXMgZGVsZXRlZC5cbiAgICovXG4gIHB1YmxpYyB0cnlSZW1vdmVDaGlsZChjaGlsZE5hbWU6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmICghdGhpcy5fY2hpbGRyZW4gfHwgIShjaGlsZE5hbWUgaW4gdGhpcy5fY2hpbGRyZW4pKSB7IHJldHVybiBmYWxzZTsgfVxuICAgIGRlbGV0ZSB0aGlzLl9jaGlsZHJlbltjaGlsZE5hbWVdO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSB2YWxpZGF0aW9uIHRvIHRoaXMgY29uc3RydWN0LlxuICAgKlxuICAgKiBXaGVuIGBub2RlLnZhbGlkYXRlKClgIGlzIGNhbGxlZCwgdGhlIGB2YWxpZGF0ZSgpYCBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgb25cbiAgICogYWxsIHZhbGlkYXRpb25zIGFuZCBhbGwgZXJyb3JzIHdpbGwgYmUgcmV0dXJuZWQuXG4gICAqXG4gICAqIEBwYXJhbSB2YWxpZGF0aW9uIFRoZSB2YWxpZGF0aW9uIG9iamVjdFxuICAgKi9cbiAgcHVibGljIGFkZFZhbGlkYXRpb24odmFsaWRhdGlvbjogSVZhbGlkYXRpb24pIHtcbiAgICBpZiAoIXRoaXMuX3ZhbGlkYXRpb25zKSB7XG4gICAgICB0aGlzLl92YWxpZGF0aW9ucyA9IFtdO1xuICAgIH1cbiAgICB0aGlzLl92YWxpZGF0aW9ucy5wdXNoKHZhbGlkYXRpb24pO1xuICB9XG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogSW52b2tlcyB0aGUgYHZhbGlkYXRlKClgIG1ldGhvZCBvbiBhbGwgdmFsaWRhdGlvbnMgYWRkZWQgdGhyb3VnaFxuICAgKiBgYWRkVmFsaWRhdGlvbigpYC5cbiAgICpcbiAgICogQHJldHVybnMgYW4gYXJyYXkgb2YgdmFsaWRhdGlvbiBlcnJvciBtZXNzYWdlcyBhc3NvY2lhdGVkIHdpdGggdGhpc1xuICAgKiBjb25zdHJ1Y3QuXG4gICAqL1xuICBwdWJsaWMgdmFsaWRhdGUoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiAodGhpcy5fdmFsaWRhdGlvbnMgPz8gW10pLmZsYXRNYXAodiA9PiB2LnZhbGlkYXRlKCkpO1xuICB9XG5cbiAgLyoqXG4gICAqIExvY2tzIHRoaXMgY29uc3RydWN0IGZyb20gYWxsb3dpbmcgbW9yZSBjaGlsZHJlbiB0byBiZSBhZGRlZC4gQWZ0ZXIgdGhpc1xuICAgKiBjYWxsLCBubyBtb3JlIGNoaWxkcmVuIGNhbiBiZSBhZGRlZCB0byB0aGlzIGNvbnN0cnVjdCBvciB0byBhbnkgY2hpbGRyZW4uXG4gICAqL1xuICBwdWJsaWMgbG9jaygpIHtcbiAgICB0aGlzLl9sb2NrZWQgPSB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgb25lIG9yIG1vcmUgbWl4aW5zIHRvIHRoaXMgY29uc3RydWN0LlxuICAgKlxuICAgKiBNaXhpbnMgYXJlIGFwcGxpZWQgaW4gb3JkZXIuIFRoZSBsaXN0IG9mIGNvbnN0cnVjdHMgaXMgY2FwdHVyZWQgYXQgdGhlXG4gICAqIHN0YXJ0IG9mIHRoZSBjYWxsLCBzbyBjb25zdHJ1Y3RzIGFkZGVkIGJ5IGEgbWl4aW4gd2lsbCBub3QgYmUgdmlzaXRlZC5cbiAgICogVXNlIG11bHRpcGxlIGB3aXRoKClgIGNhbGxzIGlmIHN1YnNlcXVlbnQgbWl4aW5zIHNob3VsZCBhcHBseSB0byBhZGRlZFxuICAgKiBjb25zdHJ1Y3RzLlxuICAgKlxuICAgKiBAcGFyYW0gbWl4aW5zIFRoZSBtaXhpbnMgdG8gYXBwbHlcbiAgICogQHJldHVybnMgVGhpcyBjb25zdHJ1Y3QgZm9yIGNoYWluaW5nXG4gICAqL1xuICBwdWJsaWMgd2l0aCguLi5taXhpbnM6IElNaXhpbltdKTogSUNvbnN0cnVjdCB7XG4gICAgY29uc3QgYWxsQ29uc3RydWN0cyA9IHRoaXMuZmluZEFsbCgpO1xuICAgIGZvciAoY29uc3QgbWl4aW4gb2YgbWl4aW5zKSB7XG4gICAgICBmb3IgKGNvbnN0IGNvbnN0cnVjdCBvZiBhbGxDb25zdHJ1Y3RzKSB7XG4gICAgICAgIGlmIChtaXhpbi5zdXBwb3J0cyhjb25zdHJ1Y3QpKSB7XG4gICAgICAgICAgbWl4aW4uYXBwbHlUbyhjb25zdHJ1Y3QpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmhvc3Q7XG4gIH07XG5cbiAgLyoqXG4gICAqIEFkZHMgYSBjaGlsZCBjb25zdHJ1Y3QgdG8gdGhpcyBub2RlLlxuICAgKlxuICAgKiBAcGFyYW0gY2hpbGQgVGhlIGNoaWxkIGNvbnN0cnVjdFxuICAgKiBAcGFyYW0gY2hpbGROYW1lIFRoZSB0eXBlIG5hbWUgb2YgdGhlIGNoaWxkIGNvbnN0cnVjdC5cbiAgICogQHJldHVybnMgVGhlIHJlc29sdmVkIHBhdGggcGFydCBuYW1lIG9mIHRoZSBjaGlsZFxuICAgKi9cbiAgcHJpdmF0ZSBhZGRDaGlsZChjaGlsZDogQ29uc3RydWN0LCBjaGlsZE5hbWU6IHN0cmluZykge1xuICAgIGlmICh0aGlzLmxvY2tlZCkge1xuXG4gICAgICAvLyBzcGVjaWFsIGVycm9yIGlmIHJvb3QgaXMgbG9ja2VkXG4gICAgICBpZiAoIXRoaXMucGF0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBhZGQgY2hpbGRyZW4gZHVyaW5nIHN5bnRoZXNpcycpO1xuICAgICAgfVxuXG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBhZGQgY2hpbGRyZW4gdG8gXCIke3RoaXMucGF0aH1cIiBkdXJpbmcgc3ludGhlc2lzYCk7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLl9jaGlsZHJlbikge1xuICAgICAgdGhpcy5fY2hpbGRyZW4gPSB7fTtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fY2hpbGRyZW5bY2hpbGROYW1lXSkge1xuICAgICAgY29uc3QgbmFtZSA9IHRoaXMuaWQgPz8gJyc7XG4gICAgICBjb25zdCB0eXBlTmFtZSA9IHRoaXMuaG9zdC5jb25zdHJ1Y3Rvci5uYW1lO1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUaGVyZSBpcyBhbHJlYWR5IGEgQ29uc3RydWN0IHdpdGggbmFtZSAnJHtjaGlsZE5hbWV9JyBpbiAke3R5cGVOYW1lfSR7bmFtZS5sZW5ndGggPiAwID8gJyBbJyArIG5hbWUgKyAnXScgOiAnJ31gKTtcbiAgICB9XG5cbiAgICB0aGlzLl9jaGlsZHJlbltjaGlsZE5hbWVdID0gY2hpbGQ7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIHRoZSBidWlsZGluZyBibG9jayBvZiB0aGUgY29uc3RydWN0IGdyYXBoLlxuICpcbiAqIEFsbCBjb25zdHJ1Y3RzIGJlc2lkZXMgdGhlIHJvb3QgY29uc3RydWN0IG11c3QgYmUgY3JlYXRlZCB3aXRoaW4gdGhlIHNjb3BlIG9mXG4gKiBhbm90aGVyIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbnN0cnVjdCBpbXBsZW1lbnRzIElDb25zdHJ1Y3Qge1xuICAvKipcbiAgICogQ2hlY2tzIGlmIGB4YCBpcyBhIGNvbnN0cnVjdC5cbiAgICpcbiAgICogVXNlIHRoaXMgbWV0aG9kIGluc3RlYWQgb2YgYGluc3RhbmNlb2ZgIHRvIHByb3Blcmx5IGRldGVjdCBgQ29uc3RydWN0YFxuICAgKiBpbnN0YW5jZXMsIGV2ZW4gd2hlbiB0aGUgY29uc3RydWN0IGxpYnJhcnkgaXMgc3ltbGlua2VkLlxuICAgKlxuICAgKiBFeHBsYW5hdGlvbjogaW4gSmF2YVNjcmlwdCwgbXVsdGlwbGUgY29waWVzIG9mIHRoZSBgY29uc3RydWN0c2AgbGlicmFyeSBvblxuICAgKiBkaXNrIGFyZSBzZWVuIGFzIGluZGVwZW5kZW50LCBjb21wbGV0ZWx5IGRpZmZlcmVudCBsaWJyYXJpZXMuIEFzIGFcbiAgICogY29uc2VxdWVuY2UsIHRoZSBjbGFzcyBgQ29uc3RydWN0YCBpbiBlYWNoIGNvcHkgb2YgdGhlIGBjb25zdHJ1Y3RzYCBsaWJyYXJ5XG4gICAqIGlzIHNlZW4gYXMgYSBkaWZmZXJlbnQgY2xhc3MsIGFuZCBhbiBpbnN0YW5jZSBvZiBvbmUgY2xhc3Mgd2lsbCBub3QgdGVzdCBhc1xuICAgKiBgaW5zdGFuY2VvZmAgdGhlIG90aGVyIGNsYXNzLiBgbnBtIGluc3RhbGxgIHdpbGwgbm90IGNyZWF0ZSBpbnN0YWxsYXRpb25zXG4gICAqIGxpa2UgdGhpcywgYnV0IHVzZXJzIG1heSBtYW51YWxseSBzeW1saW5rIGNvbnN0cnVjdCBsaWJyYXJpZXMgdG9nZXRoZXIgb3JcbiAgICogdXNlIGEgbW9ub3JlcG8gdG9vbDogaW4gdGhvc2UgY2FzZXMsIG11bHRpcGxlIGNvcGllcyBvZiB0aGUgYGNvbnN0cnVjdHNgXG4gICAqIGxpYnJhcnkgY2FuIGJlIGFjY2lkZW50YWxseSBpbnN0YWxsZWQsIGFuZCBgaW5zdGFuY2VvZmAgd2lsbCBiZWhhdmVcbiAgICogdW5wcmVkaWN0YWJseS4gSXQgaXMgc2FmZXN0IHRvIGF2b2lkIHVzaW5nIGBpbnN0YW5jZW9mYCwgYW5kIHVzaW5nXG4gICAqIHRoaXMgdHlwZS10ZXN0aW5nIG1ldGhvZCBpbnN0ZWFkLlxuICAgKlxuICAgKiBAcmV0dXJucyB0cnVlIGlmIGB4YCBpcyBhbiBvYmplY3QgY3JlYXRlZCBmcm9tIGEgY2xhc3Mgd2hpY2ggZXh0ZW5kcyBgQ29uc3RydWN0YC5cbiAgICogQHBhcmFtIHggQW55IG9iamVjdFxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBpc0NvbnN0cnVjdCh4OiBhbnkpOiB4IGlzIENvbnN0cnVjdCB7XG4gICAgcmV0dXJuIHggJiYgdHlwZW9mIHggPT09ICdvYmplY3QnICYmIHhbQ09OU1RSVUNUX1NZTV07XG4gIH1cblxuICAvKipcbiAgICogVGhlIHRyZWUgbm9kZS5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBub2RlOiBOb2RlO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IGNvbnN0cnVjdCBub2RlLlxuICAgKlxuICAgKiBAcGFyYW0gc2NvcGUgVGhlIHNjb3BlIGluIHdoaWNoIHRvIGRlZmluZSB0aGlzIGNvbnN0cnVjdFxuICAgKiBAcGFyYW0gaWQgVGhlIHNjb3BlZCBjb25zdHJ1Y3QgSUQuIE11c3QgYmUgdW5pcXVlIGFtb25nc3Qgc2libGluZ3MuIElmXG4gICAqIHRoZSBJRCBpbmNsdWRlcyBhIHBhdGggc2VwYXJhdG9yIChgL2ApIG9yIGEgbmV3bGluZSwgdGhlbiBpdCB3aWxsIGJlXG4gICAqIHJlcGxhY2VkIGJ5IGRvdWJsZSBkYXNoIGAtLWAuXG4gICAqL1xuICBjb25zdHJ1Y3RvcihzY29wZTogQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gICAgdGhpcy5ub2RlID0gbmV3IE5vZGUodGhpcywgc2NvcGUsIGlkKTtcblxuICAgIC8vIGltcGxlbWVudCBJRGVwZW5kYWJsZSBwcml2YXRlbHlcbiAgICBEZXBlbmRhYmxlLmltcGxlbWVudCh0aGlzLCB7XG4gICAgICBkZXBlbmRlbmN5Um9vdHM6IFt0aGlzXSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBcHBsaWVzIG9uZSBvciBtb3JlIG1peGlucyB0byB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogTWl4aW5zIGFyZSBhcHBsaWVkIGluIG9yZGVyLiBUaGUgbGlzdCBvZiBjb25zdHJ1Y3RzIGlzIGNhcHR1cmVkIGF0IHRoZVxuICAgKiBzdGFydCBvZiB0aGUgY2FsbCwgc28gY29uc3RydWN0cyBhZGRlZCBieSBhIG1peGluIHdpbGwgbm90IGJlIHZpc2l0ZWQuXG4gICAqIFVzZSBtdWx0aXBsZSBgd2l0aCgpYCBjYWxscyBpZiBzdWJzZXF1ZW50IG1peGlucyBzaG91bGQgYXBwbHkgdG8gYWRkZWRcbiAgICogY29uc3RydWN0cy5cbiAgICpcbiAgICogQHBhcmFtIG1peGlucyBUaGUgbWl4aW5zIHRvIGFwcGx5XG4gICAqIEByZXR1cm5zIFRoaXMgY29uc3RydWN0IGZvciBjaGFpbmluZ1xuICAgKi9cbiAgcHVibGljIHdpdGgoLi4ubWl4aW5zOiBJTWl4aW5bXSk6IElDb25zdHJ1Y3Qge1xuICAgIHJldHVybiB0aGlzLm5vZGUud2l0aCguLi5taXhpbnMpO1xuICB9O1xuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoaXMgY29uc3RydWN0LlxuICAgKi9cbiAgcHVibGljIHRvU3RyaW5nKCkge1xuICAgIHJldHVybiB0aGlzLm5vZGUucGF0aCB8fCAnPHJvb3Q+JztcbiAgfVxufVxuXG4vKipcbiAqIEltcGxlbWVudCB0aGlzIGludGVyZmFjZSBpbiBvcmRlciBmb3IgdGhlIGNvbnN0cnVjdCB0byBiZSBhYmxlIHRvIHZhbGlkYXRlIGl0c2VsZi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJVmFsaWRhdGlvbiB7XG4gIC8qKlxuICAgKiBWYWxpZGF0ZSB0aGUgY3VycmVudCBjb25zdHJ1Y3QuXG4gICAqXG4gICAqIFRoaXMgbWV0aG9kIGNhbiBiZSBpbXBsZW1lbnRlZCBieSBkZXJpdmVkIGNvbnN0cnVjdHMgaW4gb3JkZXIgdG8gcGVyZm9ybVxuICAgKiB2YWxpZGF0aW9uIGxvZ2ljLiBJdCBpcyBjYWxsZWQgb24gYWxsIGNvbnN0cnVjdHMgYmVmb3JlIHN5bnRoZXNpcy5cbiAgICpcbiAgICogQHJldHVybnMgQW4gYXJyYXkgb2YgdmFsaWRhdGlvbiBlcnJvciBtZXNzYWdlcywgb3IgYW4gZW1wdHkgYXJyYXkgaWYgdGhlcmUgdGhlIGNvbnN0cnVjdCBpcyB2YWxpZC5cbiAgICovXG4gIHZhbGlkYXRlKCk6IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEluIHdoYXQgb3JkZXIgdG8gcmV0dXJuIGNvbnN0cnVjdHNcbiAqL1xuZXhwb3J0IGVudW0gQ29uc3RydWN0T3JkZXIge1xuICAvKipcbiAgICogRGVwdGgtZmlyc3QsIHByZS1vcmRlclxuICAgKi9cbiAgUFJFT1JERVIsXG5cbiAgLyoqXG4gICAqIERlcHRoLWZpcnN0LCBwb3N0LW9yZGVyIChsZWFmIG5vZGVzIGZpcnN0KVxuICAgKi9cbiAgUE9TVE9SREVSLFxufVxuXG5jb25zdCBTRVBfUkVHRVggPSBuZXcgUmVnRXhwKGBbJHtOb2RlLlBBVEhfU0VQfSR7QUREUl9TRVB9XWAsICdnJyk7XG5cbi8qKlxuICogUmV0dXJuIGEgc2FuaXRpemVkIHZlcnNpb24gb2YgYW4gYXJiaXRyYXJ5IHN0cmluZywgc28gaXQgY2FuIGJlIHVzZWQgYXMgYW4gSURcbiAqL1xuZnVuY3Rpb24gc2FuaXRpemVJZChpZDogc3RyaW5nKSB7XG4gIC8vIEVzY2FwZSB0aGUgc2VwYXJhdG9ycyB1c2VkIGJ5IGBwYXRoYCBhbmQgYnkgYGFkZHJgIGFzIGRvdWJsZSBkYXNoZXMsIHNvIGFcbiAgLy8gc2luZ2xlIGlkIG5ldmVyIGxvb2tzIGxpa2UgbXVsdGlwbGUgcGF0aCBjb21wb25lbnRzIGluIGVpdGhlciBvZiB0aGVtLlxuICByZXR1cm4gaWQucmVwbGFjZShTRVBfUkVHRVgsICctLScpO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBjb25zdHJ1Y3QuYWRkTWV0YWRhdGEoKWAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgTWV0YWRhdGFPcHRpb25zIHtcbiAgLyoqXG4gICAqIEluY2x1ZGUgc3RhY2sgdHJhY2Ugd2l0aCBtZXRhZGF0YSBlbnRyeS5cbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IHN0YWNrVHJhY2U/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBIEphdmFTY3JpcHQgZnVuY3Rpb24gdG8gYmVnaW4gdHJhY2luZyBmcm9tLlxuICAgKlxuICAgKiBUaGlzIG9wdGlvbiBpcyBpZ25vcmVkIHVubGVzcyBgc3RhY2tUcmFjZWAgaXMgYHRydWVgLlxuICAgKlxuICAgKiBAZGVmYXVsdCBhZGRNZXRhZGF0YSgpXG4gICAqL1xuICByZWFkb25seSB0cmFjZUZyb21GdW5jdGlvbj86IGFueTtcblxuICAvKipcbiAgICogVGhlIGFjdHVhbCBzdGFjayB0cmFjZSB0byBiZSBhZGRlZCB0byB0aGUgbWV0YWRhdGEuIElmIHRoaXNcbiAgICogcGFyYW1ldGVyIGlzIHBhc3NlZCwgdGhlIHN0YWNrVHJhY2UgcGFyYW1ldGVyIGlzIGlnbm9yZWQuXG4gICAqL1xuICByZWFkb25seSBzdGFja1RyYWNlT3ZlcnJpZGU/OiBzdHJpbmdbXTtcbn1cblxuLy8gTWFyayBhbGwgaW5zdGFuY2VzIG9mICdDb25zdHJ1Y3QnXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoQ29uc3RydWN0LnByb3RvdHlwZSwgQ09OU1RSVUNUX1NZTSwge1xuICB2YWx1ZTogdHJ1ZSxcbiAgZW51bWVyYWJsZTogZmFsc2UsXG4gIHdyaXRhYmxlOiBmYWxzZSxcbn0pO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgcm9vdCBjb25zdHJ1Y3Qgbm9kZS5cbiAqXG4gKiBUaGUgcm9vdCBjb25zdHJ1Y3QgcmVwcmVzZW50cyB0aGUgdG9wIG9mIHRoZSBjb25zdHJ1Y3QgdHJlZSBhbmQgaXMgbm90IGNvbnRhaW5lZCB3aXRoaW4gYSBwYXJlbnQgc2NvcGUgaXRzZWxmLlxuICogRm9yIHJvb3QgY29uc3RydWN0cywgdGhlIGlkIGlzIG9wdGlvbmFsLlxuICovXG5leHBvcnQgY2xhc3MgUm9vdENvbnN0cnVjdCBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IHJvb3QgY29uc3RydWN0IG5vZGUuXG4gICAqXG4gICAqIEBwYXJhbSBpZCBUaGUgc2NvcGVkIGNvbnN0cnVjdCBJRC4gTXVzdCBiZSB1bmlxdWUgYW1vbmdzdCBzaWJsaW5ncy4gSWZcbiAgICogdGhlIElEIGluY2x1ZGVzIGEgcGF0aCBzZXBhcmF0b3IgKGAvYCkgb3IgYSBuZXdsaW5lLCB0aGVuIGl0IHdpbGwgYmVcbiAgICogcmVwbGFjZWQgYnkgZG91YmxlIGRhc2ggYC0tYC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKGlkPzogc3RyaW5nKSB7XG4gICAgc3VwZXIodW5kZWZpbmVkIGFzIGFueSwgaWQgPz8gJycpO1xuICB9XG59XG4iXX0=