UNPKG

constructs

Version:

A programming model for software-defined state

561 lines • 60.7 kB
"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