UNPKG

constructs

Version:

A programming model for software-defined state

594 lines 64.1 kB
"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=