@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
542 lines • 61.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const cxapi = require("@aws-cdk/cx-api");
const dependency_1 = require("./dependency");
const uniqueid_1 = require("./private/uniqueid");
const stack_trace_1 = require("./stack-trace");
const token_1 = require("./token");
const CONSTRUCT_SYMBOL = Symbol.for('@aws-cdk/core.Construct');
/**
* Represents the construct node in the scope tree.
*/
class ConstructNode {
constructor(host, scope, id) {
this.host = host;
this._locked = false; // if this is "true", addChild will fail
this._aspects = [];
this._children = {};
this._context = {};
this._metadata = new Array();
this._references = new Set();
this._dependencies = new Set();
this.invokedAspects = [];
id = id || ''; // if undefined, convert to empty string
this.id = sanitizeId(id);
this.scope = scope;
// We say that scope is required, but root scopes will bypass the type
// checks and actually pass in 'undefined'.
if (scope != null) {
if (id === '') {
throw new Error('Only root constructs may have an empty name');
}
// Has side effect so must be very last thing in constructor
scope.node.addChild(host, this.id);
}
else {
// This is a root construct.
this.id = id;
}
if (token_1.Token.isUnresolved(id)) {
throw new Error(`Cannot use tokens in construct ID: ${id}`);
}
}
/**
* Synthesizes a CloudAssembly from a construct tree.
* @param root The root of the construct tree.
* @param options Synthesis options.
*/
static synth(root, options = {}) {
const builder = new cxapi.CloudAssemblyBuilder(options.outdir);
// the three holy phases of synthesis: prepare, validate and synthesize
// prepare
this.prepare(root);
// do not allow adding children after this stage
root._lock();
try {
// validate
const validate = options.skipValidation === undefined ? true : !options.skipValidation;
if (validate) {
const errors = this.validate(root);
if (errors.length > 0) {
const errorList = errors.map(e => `[${e.source.node.path}] ${e.message}`).join('\n ');
throw new Error(`Validation failed with the following errors:\n ${errorList}`);
}
}
// synthesize (leaves first)
for (const construct of root.findAll(ConstructOrder.POSTORDER)) {
construct.synthesize({ assembly: builder }); // "as any" is needed because we want to keep "synthesize" protected
}
}
finally {
root._unlock();
}
// write session manifest and lock store
return builder.buildAssembly(options);
}
/**
* Invokes "prepare" on all constructs (depth-first, post-order) in the tree under `node`.
* @param node The root node
*/
static prepare(node) {
const constructs = node.findAll(ConstructOrder.PREORDER);
// Aspects are applied root to leaf
for (const construct of constructs) {
construct.node.invokeAspects();
}
// Use .reverse() to achieve post-order traversal
for (const construct of constructs.reverse()) {
if (Construct.isConstruct(construct)) {
construct.prepare(); // "as any" is needed because we want to keep "prepare" protected
}
}
}
/**
* Invokes "validate" on all constructs in the tree (depth-first, pre-order) and returns
* the list of all errors. An empty list indicates that there are no errors.
*
* @param node The root node
*/
static validate(node) {
let errors = new Array();
for (const child of node.children) {
errors = errors.concat(this.validate(child.node));
}
const localErrors = node.host.validate(); // "as any" is needed because we want to keep "validate" protected
return errors.concat(localErrors.map(msg => ({ source: node.host, message: msg })));
}
/**
* The full, absolute path of this construct in the tree.
*
* Components are separated by '/'.
*/
get path() {
const components = this.scopes.slice(1).map(c => c.node.id);
return components.join(ConstructNode.PATH_SEP);
}
/**
* A tree-global unique alphanumeric identifier for this construct.
* Includes all components of the tree.
*/
get uniqueId() {
const components = this.scopes.slice(1).map(c => c.node.id);
return components.length > 0 ? uniqueid_1.makeUniqueId(components) : '';
}
/**
* 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"`
* @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(node) {
if (order === ConstructOrder.PREORDER) {
ret.push(node);
}
for (const child of node.node.children) {
visit(child);
}
if (order === ConstructOrder.POSTORDER) {
ret.push(node);
}
}
}
/**
* 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 (token_1.Token.isUnresolved(key)) {
throw new Error(`Invalid context key "${key}". It contains unresolved tokens`);
}
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(','));
}
this._context[key] = value;
}
/**
* 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 thie key.
*/
tryGetContext(key) {
if (token_1.Token.isUnresolved(key)) {
throw new Error(`Invalid context key "${key}". It contains unresolved tokens`);
}
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.
*
* @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 from a function under which to restrict the metadata entry's stack trace (defaults to this.addMetadata)
*/
addMetadata(type, data, from) {
if (data == null) {
return;
}
const trace = this.tryGetContext(cxapi.DISABLE_METADATA_STACK_TRACE) ? undefined : stack_trace_1.captureStackTrace(from || this.addMetadata);
this._metadata.push({ type, data, trace });
}
/**
* Adds a { "aws:cdk:info": <message> } metadata entry to this construct.
* The toolkit will display the info message when apps are synthesized.
* @param message The info message.
*/
addInfo(message) {
this.addMetadata(cxapi.INFO_METADATA_KEY, message);
}
/**
* Adds a { warning: <message> } metadata entry to this construct.
* The toolkit will display the warning when an app is synthesized, or fail
* if run in --strict mode.
* @param message The warning message.
*/
addWarning(message) {
this.addMetadata(cxapi.WARNING_METADATA_KEY, message);
}
/**
* Adds an { error: <message> } metadata entry to this construct.
* The toolkit will fail synthesis when errors are reported.
* @param message The error message.
*/
addError(message) {
this.addMetadata(cxapi.ERROR_METADATA_KEY, message);
}
/**
* Applies the aspect to this Constructs node
*/
applyAspect(aspect) {
this._aspects.push(aspect);
return;
}
/**
* 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 && curr.node.scope;
}
return ret;
}
/**
* @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;
}
/**
* Record a reference originating from this construct node
*/
addReference(...refs) {
for (const ref of refs) {
if (reference_1.Reference.isReference(ref)) {
this._references.add(ref);
}
}
}
/**
* Return all references originating from this node or any of its children
*/
get references() {
const ret = new Set();
function recurse(node) {
for (const reference of node._references) {
ret.add({ source: node.host, reference });
}
for (const child of node.children) {
recurse(child.node);
}
}
recurse(this);
return Array.from(ret);
}
/**
* Add an ordering dependency on another Construct.
*
* All constructs in the dependency's scope will be deployed before any
* construct in this construct's scope.
*/
addDependency(...dependencies) {
for (const dependency of dependencies) {
this._dependencies.add(dependency);
}
}
/**
* Return all dependencies registered on this node or any of its children
*/
get dependencies() {
const found = new Map(); // Deduplication map
const ret = new Array();
for (const source of this.findAll()) {
for (const dependable of source.node._dependencies) {
for (const target of dependency_1.DependableTrait.get(dependable).dependencyRoots) {
let foundTargets = found.get(source);
if (!foundTargets) {
found.set(source, foundTargets = new Set());
}
if (!foundTargets.has(target)) {
ret.push({ source, target });
foundTargets.add(target);
}
}
}
}
return ret;
}
/**
* 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.
* @internal
*/
_lock() {
this._locked = true;
}
/**
* Unlocks this costruct and allows mutations (adding children).
* @internal
*/
_unlock() {
this._locked = false;
}
/**
* 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 (childName in this._children) {
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;
}
/**
* Triggers each aspect to invoke visit
*/
invokeAspects() {
const descendants = this.findAll();
for (const aspect of this._aspects) {
if (this.invokedAspects.includes(aspect)) {
continue;
}
descendants.forEach(member => aspect.visit(member));
this.invokedAspects.push(aspect);
}
}
}
exports.ConstructNode = ConstructNode;
/**
* Separator used to delimit construct path components.
*/
ConstructNode.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 {
/**
* 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) {
Object.defineProperty(this, CONSTRUCT_SYMBOL, { value: true });
this.node = new ConstructNode(this, scope, id);
// implement IDependable privately
dependency_1.DependableTrait.implement(this, {
dependencyRoots: [this]
});
}
/**
* Return whether the given object is a Construct
*/
static isConstruct(x) {
return typeof x === 'object' && x !== null && CONSTRUCT_SYMBOL in x;
}
/**
* Returns a string representation of this construct.
*/
toString() {
return this.node.path || '<root>';
}
/**
* Validate the current construct.
*
* This method can be implemented by derived constructs in order to perform
* validation logic. It is called on all constructs before synthesis.
*
* @returns An array of validation error messages, or an empty array if there the construct is valid.
*/
validate() {
return [];
}
/**
* Perform final modifications before synthesis
*
* This method can be implemented by derived constructs in order to perform
* final changes before synthesis. prepare() will be called after child
* constructs have been prepared.
*
* This is an advanced framework feature. Only use this if you
* understand the implications.
*/
prepare() {
return;
}
/**
* Allows this construct to emit artifacts into the cloud assembly during synthesis.
*
* This method is usually implemented by framework-level constructs such as `Stack` and `Asset`
* as they participate in synthesizing the cloud assembly.
*
* @param session The synthesis session.
*/
synthesize(session) {
ignore(session);
}
}
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 || (exports.ConstructOrder = {}));
function ignore(_x) {
return;
}
// Import this _after_ everything else to help node work the classes out in the correct order...
const reference_1 = require("./reference");
const PATH_SEP_REGEX = new RegExp(`${ConstructNode.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, '--');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29uc3RydWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiY29uc3RydWN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEseUNBQTBDO0FBRTFDLDZDQUE0RDtBQUM1RCxpREFBa0Q7QUFFbEQsK0NBQWtEO0FBQ2xELG1DQUFnQztBQUVoQyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMseUJBQXlCLENBQUMsQ0FBQztBQVkvRDs7R0FFRztBQUNILE1BQWEsYUFBYTtJQTBHeEIsWUFBNkIsSUFBZSxFQUFFLEtBQWlCLEVBQUUsRUFBVTtRQUE5QyxTQUFJLEdBQUosSUFBSSxDQUFXO1FBVnBDLFlBQU8sR0FBRyxLQUFLLENBQUMsQ0FBQyx3Q0FBd0M7UUFDaEQsYUFBUSxHQUFjLEVBQUUsQ0FBQztRQUN6QixjQUFTLEdBQWlDLEVBQUcsQ0FBQztRQUM5QyxhQUFRLEdBQTJCLEVBQUcsQ0FBQztRQUN2QyxjQUFTLEdBQUcsSUFBSSxLQUFLLEVBQXVCLENBQUM7UUFDN0MsZ0JBQVcsR0FBRyxJQUFJLEdBQUcsRUFBYSxDQUFDO1FBQ25DLGtCQUFhLEdBQUcsSUFBSSxHQUFHLEVBQWUsQ0FBQztRQUN2QyxtQkFBYyxHQUFjLEVBQUUsQ0FBQztRQUk5QyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLHdDQUF3QztRQUV2RCxJQUFJLENBQUMsRUFBRSxHQUFHLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN6QixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUVuQixzRUFBc0U7UUFDdEUsMkNBQTJDO1FBQzNDLElBQUksS0FBSyxJQUFJLElBQUksRUFBRTtZQUNqQixJQUFJLEVBQUUsS0FBSyxFQUFFLEVBQUU7Z0JBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFDO2FBQ2hFO1lBRUQsNERBQTREO1lBQzVELEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUks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LENBQUMsV0FBVyxDQUFDLENBQU07UUFDOUIsT0FBTyxPQUFPLENBQUMsS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLElBQUksSUFBSSxnQkFBZ0IsSUFBSSxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQTBCRDs7T0FFRztJQUNJLFFBQVE7UUFDYixPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLFFBQVEsQ0FBQztJQUNwQyxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNPLFFBQVE7UUFDaEIsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQ7Ozs7Ozs7OztPQVNHO0lBQ08sT0FBTztRQUNmLE9BQU87SUFDVCxDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNPLFVBQVUsQ0FBQyxPQUEwQjtRQUM3QyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDbEIsQ0FBQztDQUNGO0FBNUVELDhCQTRFQztBQWlCRDs7R0FFRztBQUNILElBQVksY0FVWDtBQVZELFdBQVksY0FBYztJQUN4Qjs7T0FFRztJQUNILDJEQUFRLENBQUE7SUFFUjs7T0FFRztJQUNILDZEQUFTLENBQUE7QUFDWCxDQUFDLEVBVlcsY0FBYyxHQUFkLHNCQUFjLEtBQWQsc0JBQWMsUUFVekI7QUEyREQsU0FBUyxNQUFNLENBQUMsRUFBTztJQUNyQixPQUFPO0FBQ1QsQ0FBQztBQUVELGdHQUFnRztBQUVoRywyQ0FBd0M7QUFFeEMsTUFBTSxjQUFjLEdBQUcsSUFBSSxNQUFNLENBQUMsR0FBRyxhQUFhLENBQUMsUUFBUSxFQUFFLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFFcEU7O0dBRUc7QUFDSCxTQUFTLFVBQVUsQ0FBQyxFQUFVO0lBQzVCLG9DQUFvQztJQUNwQyxPQUFPLEVBQUUsQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxDQUFDO0FBQzFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgY3hhcGkgPSByZXF1aXJlKCdAYXdzLWNkay9jeC1hcGknKTtcbmltcG9ydCB7IElBc3BlY3QgfSBmcm9tICcuL2FzcGVjdCc7XG5pbXBvcnQgeyBEZXBlbmRhYmxlVHJhaXQsIElEZXBlbmRhYmxlIH0gZnJvbSAnLi9kZXBlbmRlbmN5JztcbmltcG9ydCB7IG1ha2VVbmlxdWVJZCB9IGZyb20gJy4vcHJpdmF0ZS91bmlxdWVpZCc7XG5pbXBvcnQgeyBJUmVzb2x2YWJsZSB9IGZyb20gJy4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBjYXB0dXJlU3RhY2tUcmFjZSB9IGZyb20gJy4vc3RhY2stdHJhY2UnO1xuaW1wb3J0IHsgVG9rZW4gfSBmcm9tICcuL3Rva2VuJztcblxuY29uc3QgQ09OU1RSVUNUX1NZTUJPTCA9IFN5bWJvbC5mb3IoJ0Bhd3MtY2RrL2NvcmUuQ29uc3RydWN0Jyk7XG5cbi8qKlxuICogUmVwcmVzZW50cyBhIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBJQ29uc3RydWN0IGV4dGVuZHMgSURlcGVuZGFibGUge1xuICAvKipcbiAgICogVGhlIGNvbnN0cnVjdCBub2RlIGluIHRoZSB0cmVlLlxuICAgKi9cbiAgcmVhZG9ubHkgbm9kZTogQ29uc3RydWN0Tm9kZTtcbn1cblxuLyoqXG4gKiBSZXByZXNlbnRzIHRoZSBjb25zdHJ1Y3Qgbm9kZSBpbiB0aGUgc2NvcGUgdHJlZS5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbnN0cnVjdE5vZGUge1xuICAvKipcbiAgICogU2VwYXJhdG9yIHVzZWQgdG8gZGVsaW1pdCBjb25zdHJ1Y3QgcGF0aCBjb21wb25lbnRzLlxuICAgKi9cbiAgcHVibGljIHN0YXRpYyByZWFkb25seSBQQVRIX1NFUCA9ICcvJztcblxuICAvKipcbiAgICogU3ludGhlc2l6ZXMgYSBDbG91ZEFzc2VtYmx5IGZyb20gYSBjb25zdHJ1Y3QgdHJlZS5cbiAgICogQHBhcmFtIHJvb3QgVGhlIHJvb3Qgb2YgdGhlIGNvbnN0cnVjdCB0cmVlLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBTeW50aGVzaXMgb3B0aW9ucy5cbiAgICovXG4gIHB1YmxpYyBzdGF0aWMgc3ludGgocm9vdDogQ29uc3RydWN0Tm9kZSwgb3B0aW9uczogU3ludGhlc2lzT3B0aW9ucyA9IHsgfSk6IGN4YXBpLkNsb3VkQXNzZW1ibHkge1xuICAgIGNvbnN0IGJ1aWxkZXIgPSBuZXcgY3hhcGkuQ2xvdWRBc3NlbWJseUJ1aWxkZXIob3B0aW9ucy5vdXRkaXIpO1xuXG4gICAgLy8gdGhlIHRocmVlIGhvbHkgcGhhc2VzIG9mIHN5bnRoZXNpczogcHJlcGFyZSwgdmFsaWRhdGUgYW5kIHN5bnRoZXNpemVcblxuICAgIC8vIHByZXBhcmVcbiAgICB0aGlzLnByZXBhcmUocm9vdCk7XG5cbiAgICAvLyBkbyBub3QgYWxsb3cgYWRkaW5nIGNoaWxkcmVuIGFmdGVyIHRoaXMgc3RhZ2VcbiAgICByb290Ll9sb2NrKCk7XG5cbiAgICB0cnkge1xuICAgICAgLy8gdmFsaWRhdGVcbiAgICAgIGNvbnN0IHZhbGlkYXRlID0gb3B0aW9ucy5za2lwVmFsaWRhdGlvbiA9PT0gdW5kZWZpbmVkID8gdHJ1ZSA6ICFvcHRpb25zLnNraXBWYWxpZGF0aW9uO1xuICAgICAgaWYgKHZhbGlkYXRlKSB7XG4gICAgICAgIGNvbnN0IGVycm9ycyA9IHRoaXMudmFsaWRhdGUocm9vdCk7XG4gICAgICAgIGlmIChlcnJvcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgIGNvbnN0IGVycm9yTGlzdCA9IGVycm9ycy5tYXAoZSA9PiBgWyR7ZS5zb3VyY2Uubm9kZS5wYXRofV0gJHtlLm1lc3NhZ2V9YCkuam9pbignXFxuICAnKTtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFZhbGlkYXRpb24gZmFpbGVkIHdpdGggdGhlIGZvbGxvd2luZyBlcnJvcnM6XFxuICAke2Vycm9yTGlzdH1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBzeW50aGVzaXplIChsZWF2ZXMgZmlyc3QpXG4gICAgICBmb3IgKGNvbnN0IGNvbnN0cnVjdCBvZiByb290LmZpbmRBbGwoQ29uc3RydWN0T3JkZXIuUE9TVE9SREVSKSkge1xuICAgICAgICAoY29uc3RydWN0IGFzIGFueSkuc3ludGhlc2l6ZSh7IGFzc2VtYmx5OiBidWlsZGVyIH0pOyAvLyBcImFzIGFueVwiIGlzIG5lZWRlZCBiZWNhdXNlIHdlIHdhbnQgdG8ga2VlcCBcInN5bnRoZXNpemVcIiBwcm90ZWN0ZWRcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgcm9vdC5fdW5sb2NrKCk7XG4gICAgfVxuXG4gICAgLy8gd3JpdGUgc2Vzc2lvbiBtYW5pZmVzdCBhbmQgbG9jayBzdG9yZVxuICAgIHJldHVybiBidWlsZGVyLmJ1aWxkQXNzZW1ibHkob3B0aW9ucyk7XG4gIH1cblxuICAvKipcbiAgICogSW52b2tlcyBcInByZXBhcmVcIiBvbiBhbGwgY29uc3RydWN0cyAoZGVwdGgtZmlyc3QsIHBvc3Qtb3JkZXIpIGluIHRoZSB0cmVlIHVuZGVyIGBub2RlYC5cbiAgICogQHBhcmFtIG5vZGUgVGhlIHJvb3Qgbm9kZVxuICAgKi9cbiAgcHVibGljIHN0YXRpYyBwcmVwYXJlKG5vZGU6IENvbnN0cnVjdE5vZGUpIHtcbiAgICBjb25zdCBjb25zdHJ1Y3RzID0gbm9kZS5maW5kQWxsKENvbnN0cnVjdE9yZGVyLlBSRU9SREVSKTtcblxuICAgIC8vIEFzcGVjdHMgYXJlIGFwcGxpZWQgcm9vdCB0byBsZWFmXG4gICAgZm9yIChjb25zdCBjb25zdHJ1Y3Qgb2YgY29uc3RydWN0cykge1xuICAgICAgY29uc3RydWN0Lm5vZGUuaW52b2tlQXNwZWN0cygpO1xuICAgIH1cblxuICAgIC8vIFVzZSAucmV2ZXJzZSgpIHRvIGFjaGlldmUgcG9zdC1vcmRlciB0cmF2ZXJzYWxcbiAgICBmb3IgKGNvbnN0IGNvbnN0cnVjdCBvZiBjb25zdHJ1Y3RzLnJldmVyc2UoKSkge1xuICAgICAgaWYgKENvbnN0cnVjdC5pc0NvbnN0cnVjdChjb25zdHJ1Y3QpKSB7XG4gICAgICAgIChjb25zdHJ1Y3QgYXMgYW55KS5wcmVwYXJlKCk7IC8vIFwiYXMgYW55XCIgaXMgbmVlZGVkIGJlY2F1c2Ugd2Ugd2FudCB0byBrZWVwIFwicHJlcGFyZVwiIHByb3RlY3RlZFxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnZva2VzIFwidmFsaWRhdGVcIiBvbiBhbGwgY29uc3RydWN0cyBpbiB0aGUgdHJlZSAoZGVwdGgtZmlyc3QsIHByZS1vcmRlcikgYW5kIHJldHVybnNcbiAgICogdGhlIGxpc3Qgb2YgYWxsIGVycm9ycy4gQW4gZW1wdHkgbGlzdCBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBhcmUgbm8gZXJyb3JzLlxuICAgKlxuICAgKiBAcGFyYW0gbm9kZSBUaGUgcm9vdCBub2RlXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIHZhbGlkYXRlKG5vZGU6IENvbnN0cnVjdE5vZGUpIHtcbiAgICBsZXQgZXJyb3JzID0gbmV3IEFycmF5PFZhbGlkYXRpb25FcnJvcj4oKTtcblxuICAgIGZvciAoY29uc3QgY2hpbGQgb2Ygbm9kZS5jaGlsZHJlbikge1xuICAgICAgZXJyb3JzID0gZXJyb3JzLmNvbmNhdCh0aGlzLnZhbGlkYXRlKGNoaWxkLm5vZGUpKTtcbiAgICB9XG5cbiAgICBjb25zdCBsb2NhbEVycm9yczogc3RyaW5nW10gPSAobm9kZS5ob3N0IGFzIGFueSkudmFsaWRhdGUoKTsgLy8gXCJhcyBhbnlcIiBpcyBuZWVkZWQgYmVjYXVzZSB3ZSB3YW50IHRvIGtlZXAgXCJ2YWxpZGF0ZVwiIHByb3RlY3RlZFxuICAgIHJldHVybiBlcnJvcnMuY29uY2F0KGxvY2FsRXJyb3JzLm1hcChtc2cgPT4gKHsgc291cmNlOiBub2RlLmhvc3QsIG1lc3NhZ2U6IG1zZyB9KSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHNjb3BlIGluIHdoaWNoIHRoaXMgY29uc3RydWN0IGlzIGRlZmluZWQuXG4gICAqXG4gICAqIFRoZSB2YWx1ZSBpcyBgdW5kZWZpbmVkYCBhdCB0aGUgcm9vdCBvZiB0aGUgY29uc3RydWN0IHNjb3BlIHRyZWUuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgc2NvcGU/OiBJQ29uc3RydWN0O1xuXG4gIC8qKlxuICAgKiBUaGUgaWQgb2YgdGhpcyBjb25zdHJ1Y3Qgd2l0aGluIHRoZSBjdXJyZW50IHNjb3BlLlxuICAgKlxuICAgKiBUaGlzIGlzIGEgYSBzY29wZS11bmlxdWUgaWQuIFRvIG9idGFpbiBhbiBhcHAtdW5pcXVlIGlkIGZvciB0aGlzIGNvbnN0cnVjdCwgdXNlIGB1bmlxdWVJZGAuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaWQ6IHN0cmluZztcblxuICBwcml2YXRlIF9sb2NrZWQgPSBmYWxzZTsgLy8gaWYgdGhpcyBpcyBcInRydWVcIiwgYWRkQ2hpbGQgd2lsbCBmYWlsXG4gIHByaXZhdGUgcmVhZG9ubHkgX2FzcGVjdHM6IElBc3BlY3RbXSA9IFtdO1xuICBwcml2YXRlIHJlYWRvbmx5IF9jaGlsZHJlbjogeyBbaWQ6IHN0cmluZ106IElDb25zdHJ1Y3QgfSA9IHsgfTtcbiAgcHJpdmF0ZSByZWFkb25seSBfY29udGV4dDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHsgfTtcbiAgcHJpdmF0ZSByZWFkb25seSBfbWV0YWRhdGEgPSBuZXcgQXJyYXk8Y3hhcGkuTWV0YWRhdGFFbnRyeT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBfcmVmZXJlbmNlcyA9IG5ldyBTZXQ8UmVmZXJlbmNlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9kZXBlbmRlbmNpZXMgPSBuZXcgU2V0PElEZXBlbmRhYmxlPigpO1xuICBwcml2YXRlIHJlYWRvbmx5IGludm9rZWRBc3BlY3RzOiBJQXNwZWN0W10gPSBbXTtcbiAgcHJpdmF0ZSBfZGVmYXVsdENoaWxkOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgaG9zdDogQ29uc3RydWN0LCBzY29wZTogSUNvbnN0cnVjdCwgaWQ6IHN0cmluZykge1xuICAgIGlkID0gaWQgfHwgJyc7IC8vIGlmIHVuZGVmaW5lZCwgY29udmVydCB0byBlbXB0eSBzdHJpbmdcblxuICAgIHRoaXMuaWQgPSBzYW5pdGl6ZUlkKGlkKTtcbiAgICB0aGlzLnNjb3BlID0gc2NvcGU7XG5cbiAgICAvLyBXZSBzYXkgdGhhdCBzY29wZSBpcyByZXF1aXJlZCwgYnV0IHJvb3Qgc2NvcGVzIHdpbGwgYnlwYXNzIHRoZSB0eXBlXG4gICAgLy8gY2hlY2tzIGFuZCBhY3R1YWxseSBwYXNzIGluICd1bmRlZmluZWQnLlxuICAgIGlmIChzY29wZSAhPSBudWxsKSB7XG4gICAgICBpZiAoaWQgPT09ICcnKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignT25seSByb290IGNvbnN0cnVjdHMgbWF5IGhhdmUgYW4gZW1wdHkgbmFtZScpO1xuICAgICAgfVxuXG4gICAgICAvLyBIYXMgc2lkZSBlZmZlY3Qgc28gbXVzdCBiZSB2ZXJ5IGxhc3QgdGhpbmcgaW4gY29uc3RydWN0b3JcbiAgICAgIHNjb3BlLm5vZGUuYWRkQ2hpbGQoaG9zdCwgdGhpcy5pZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIFRoaXMgaXMgYSByb290IGNvbnN0cnVjdC5cbiAgICAgIHRoaXMuaWQgPSBpZDtcbiAgICB9XG5cbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKGlkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgdXNlIHRva2VucyBpbiBjb25zdHJ1Y3QgSUQ6ICR7aWR9YCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBmdWxsLCBhYnNvbHV0ZSBwYXRoIG9mIHRoaXMgY29uc3RydWN0IGluIHRoZSB0cmVlLlxuICAgKlxuICAgKiBDb21wb25lbnRzIGFyZSBzZXBhcmF0ZWQgYnkgJy8nLlxuICAgKi9cbiAgcHVibGljIGdldCBwYXRoKCk6IHN0cmluZyB7XG4gICAgY29uc3QgY29tcG9uZW50cyA9IHRoaXMuc2NvcGVzLnNsaWNlKDEpLm1hcChjID0+IGMubm9kZS5pZCk7XG4gICAgcmV0dXJuIGNvbXBvbmVudHMuam9pbihDb25zdHJ1Y3ROb2RlLlBBVEhfU0VQKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBIHRyZWUtZ2xvYmFsIHVuaXF1ZSBhbHBoYW51bWVyaWMgaWRlbnRpZmllciBmb3IgdGhpcyBjb25zdHJ1Y3QuXG4gICAqIEluY2x1ZGVzIGFsbCBjb21wb25lbnRzIG9mIHRoZSB0cmVlLlxuICAgKi9cbiAgcHVibGljIGdldCB1bmlxdWVJZCgpOiBzdHJpbmcge1xuICAgIGNvbnN0IGNvbXBvbmVudHMgPSB0aGlzLnNjb3Blcy5zbGljZSgxKS5tYXAoYyA9PiBjLm5vZGUuaWQpO1xuICAgIHJldHVybiBjb21wb25lbnRzLmxlbmd0aCA+IDAgPyBtYWtlVW5pcXVlSWQoY29tcG9uZW50cykgOiAnJztcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYSBkaXJlY3QgY2hpbGQgYnkgaWQsIG9yIHVuZGVmaW5lZFxuICAgKlxuICAgKiBAcGFyYW0gaWQgSWRlbnRpZmllciBvZiBkaXJlY3QgY2hpbGRcbiAgICogQHJldHVybnMgdGhlIGNoaWxkIGlmIGZvdW5kLCBvciB1bmRlZmluZWRcbiAgICovXG4gIHB1YmxpYyB0cnlGaW5kQ2hpbGQoaWQ6IHN0cmluZyk6IElDb25zdHJ1Y3QgfCB1bmRlZmluZWQge1xuICAgIHJldHVybiB0aGlzLl9jaGlsZHJlbltzYW5pdGl6ZUlkKGlkKV07XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGEgZGlyZWN0IGNoaWxkIGJ5IGlkXG4gICAqXG4gICAqIFRocm93cyBhbiBlcnJvciBpZiB0aGUgY2hpbGQgaXMgbm90IGZvdW5kLlxuICAgKlxuICAgKiBAcGFyYW0gaWQgSWRlbnRpZmllciBvZiBkaXJlY3QgY2hpbGRcbiAgICogQHJldHVybnMgQ2hpbGQgd2l0aCB0aGUgZ2l2ZW4gaWQuXG4gICAqL1xuICBwdWJsaWMgZmluZENoaWxkKGlkOiBzdHJpbmcpOiBJQ29uc3RydWN0IHtcbiAgICBjb25zdCByZXQgPSB0aGlzLnRyeUZpbmRDaGlsZChpZCk7XG4gICAgaWYgKCFyZXQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gY2hpbGQgd2l0aCBpZDogJyR7aWR9J2ApO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIGNoaWxkIGNvbnN0cnVjdCB0aGF0IGhhcyB0aGUgaWQgYERlZmF1bHRgIG9yIGBSZXNvdXJjZVwiYFxuICAgKiBAdGhyb3dzIGlmIHRoZXJlIGlzIG1vcmUgdGhhbiBvbmUgY2hpbGRcbiAgICogQHJldHVybnMgYSBjb25zdHJ1Y3Qgb3IgdW5kZWZpbmVkIGlmIHRoZXJlIGlzIG5vIGRlZmF1bHQgY2hpbGRcbiAgICovXG4gIHB1YmxpYyBnZXQgZGVmYXVsdENoaWxkKCk6IElDb25zdHJ1Y3QgfCB1bmRlZmluZWQge1xuICAgIGlmICh0aGlzLl9kZWZhdWx0Q2hpbGQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHRoaXMuX2RlZmF1bHRDaGlsZDtcbiAgICB9XG5cbiAgICBjb25zdCByZXNvdXJjZUNoaWxkID0gdGhpcy50cnlGaW5kQ2hpbGQoJ1Jlc291cmNlJyk7XG4gICAgY29uc3QgZGVmYXVsdENoaWxkID0gdGhpcy50cnlGaW5kQ2hpbGQoJ0RlZmF1bHQnKTtcbiAgICBpZiAocmVzb3VyY2VDaGlsZCAmJiBkZWZhdWx0Q2hpbGQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IGRldGVybWluZSBkZWZhdWx0IGNoaWxkIGZvciAke3RoaXMucGF0aH0uIFRoZXJlIGlzIGJvdGggYSBjaGlsZCB3aXRoIGlkIFwiUmVzb3VyY2VcIiBhbmQgaWQgXCJEZWZhdWx0XCJgKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZGVmYXVsdENoaWxkIHx8IHJlc291cmNlQ2hpbGQ7XG4gIH1cblxuICAvKipcbiAgICogT3ZlcnJpZGUgdGhlIGRlZmF1bHRDaGlsZCBwcm9wZXJ0eS5cbiAgICpcbiAgICogVGhpcyBzaG91bGQgb25seSBiZSB1c2VkIGluIHRoZSBjYXNlcyB3aGVyZSB0aGUgY29ycmVjdFxuICAgKiBkZWZhdWx0IGNoaWxkIGlzIG5vdCBuYW1lZCAnUmVzb3VyY2UnIG9yICdEZWZhdWx0JyBhcyBpdFxuICAgKiBzaG91bGQgYmUuXG4gICAqXG4gICAqIElmIHlvdSBzZXQgdGhpcyB0byB1bmRlZmluZWQsIHRoZSBkZWZhdWx0IGJlaGF2aW9yIG9mIGZpbmRpbmdcbiAgICogdGhlIGNoaWxkIG5hbWVkICdSZXNvdXJjZScgb3IgJ0RlZmF1bHQnIHdpbGwgYmUgdXNlZC5cbiAgICovXG4gIHB1YmxpYyBzZXQgZGVmYXVsdENoaWxkKHZhbHVlOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5fZGVmYXVsdENoaWxkID0gdmFsdWU7XG4gIH1cblxuICAvKipcbiAgICogQWxsIGRpcmVjdCBjaGlsZHJlbiBvZiB0aGlzIGNvbnN0cnVjdC5cbiAgICovXG4gIHB1YmxpYyBnZXQgY2hpbGRyZW4oKSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5fY2hpbGRyZW4pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGlzIGNvbnN0cnVjdCBhbmQgYWxsIG9mIGl0cyBjaGlsZHJlbiBpbiB0aGUgZ2l2ZW4gb3JkZXJcbiAgICovXG4gIHB1YmxpYyBmaW5kQWxsKG9yZGVyOiBDb25zdHJ1Y3RPcmRlciA9IENvbnN0cnVjdE9yZGVyLlBSRU9SREVSKTogSUNvbnN0cnVjdFtdIHtcbiAgICBjb25zdCByZXQgPSBuZXcgQXJyYXk8SUNvbnN0cnVjdD4oKTtcbiAgICB2aXNpdCh0aGlzLmhvc3QpO1xuICAgIHJldHVybiByZXQ7XG5cbiAgICBmdW5jdGlvbiB2aXNpdChub2RlOiBJQ29uc3RydWN0KSB7XG4gICAgICBpZiAob3JkZXIgPT09IENvbnN0cnVjdE9yZGVyLlBSRU9SREVSKSB7XG4gICAgICAgIHJldC5wdXNoKG5vZGUpO1xuICAgICAgfVxuXG4gICAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIG5vZGUubm9kZS5jaGlsZHJlbikge1xuICAgICAgICB2aXNpdChjaGlsZCk7XG4gICAgICB9XG5cbiAgICAgIGlmIChvcmRlciA9PT0gQ29uc3RydWN0T3JkZXIuUE9TVE9SREVSKSB7XG4gICAgICAgIHJldC5wdXNoKG5vZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBUaGlzIGNhbiBiZSB1c2VkIHRvIHNldCBjb250ZXh0dWFsIHZhbHVlcy5cbiAgICogQ29udGV4dCBtdXN0IGJlIHNldCBiZWZvcmUgYW55IGNoaWxkcmVuIGFyZSBhZGRlZCwgc2luY2UgY2hpbGRyZW4gbWF5IGNvbnN1bHQgY29udGV4dCBpbmZvIGR1cmluZyBjb25zdHJ1Y3Rpb24uXG4gICAqIElmIHRoZSBrZXkgYWxyZWFkeSBleGlzdHMsIGl0IHdpbGwgYmUgb3ZlcnJpZGRlbi5cbiAgICogQHBhcmFtIGtleSBUaGUgY29udGV4dCBrZXlcbiAgICogQHBhcmFtIHZhbHVlIFRoZSBjb250ZXh0IHZhbHVlXG4gICAqL1xuICBwdWJsaWMgc2V0Q29udGV4dChrZXk6IHN0cmluZywgdmFsdWU6IGFueSkge1xuICAgIGlmIChUb2tlbi5pc1VucmVzb2x2ZWQoa2V5KSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNvbnRleHQga2V5IFwiJHtrZXl9XCIuIEl0IGNvbnRhaW5zIHVucmVzb2x2ZWQgdG9rZW5zYCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgbmFtZXMgPSB0aGlzLmNoaWxkcmVuLm1hcChjID0+IGMubm9kZS5pZCk7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBzZXQgY29udGV4dCBhZnRlciBjaGlsZHJlbiBoYXZlIGJlZW4gYWRkZWQ6ICcgKyBuYW1lcy5qb2luKCcsJykpO1xuICAgIH1cbiAgICB0aGlzLl9jb250ZXh0W2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXRyaWV2ZXMgYSB2YWx1ZSBmcm9tIHRyZWUgY29udGV4dC5cbiAgICpcbiAgICogQ29udGV4dCBpcyB1c3VhbGx5IGluaXRpYWxpemVkIGF0IHRoZSByb290LCBidXQgY2FuIGJlIG92ZXJyaWRkZW4gYXQgYW55IHBvaW50IGluIHRoZSB0cmVlLlxuICAgKlxuICAgKiBAcGFyYW0ga2V5IFRoZSBjb250ZXh0IGtleVxuICAgKiBAcmV0dXJucyBUaGUgY29udGV4dCB2YWx1ZSBvciBgdW5kZWZpbmVkYCBpZiB0aGVyZSBpcyBubyBjb250ZXh0IHZhbHVlIGZvciB0aGllIGtleS5cbiAgICovXG4gIHB1YmxpYyB0cnlHZXRDb250ZXh0KGtleTogc3RyaW5nKTogYW55IHtcbiAgICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKGtleSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBjb250ZXh0IGtleSBcIiR7a2V5fVwiLiBJdCBjb250YWlucyB1bnJlc29sdmVkIHRva2Vuc2ApO1xuICAgIH1cblxuICAgIGNvbnN0IHZhbHVlID0gdGhpcy5fY29udGV4dFtrZXldO1xuICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7IHJldHVybiB2YWx1ZTsgfVxuXG4gICAgcmV0dXJuIHRoaXMuc2NvcGUgJiYgdGhpcy5zY29wZS5ub2RlLnRyeUdldENvbnRleHQoa2V5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBpbW11dGFibGUgYXJyYXkgb2YgbWV0YWRhdGEgb2JqZWN0cyBhc3NvY2lhdGVkIHdpdGggdGhpcyBjb25zdHJ1Y3QuXG4gICAqIFRoaXMgY2FuIGJlIHVzZWQsIGZvciBleGFtcGxlLCB0byBpbXBsZW1lbnQgc3VwcG9ydCBmb3IgZGVwcmVjYXRpb24gbm90aWNlcywgc291cmNlIG1hcHBpbmcsIGV0Yy5cbiAgICovXG4gIHB1YmxpYyBnZXQgbWV0YWRhdGEoKSB7XG4gICAgcmV0dXJuIFsgLi4udGhpcy5fbWV0YWRhdGEgXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgbWV0YWRhdGEgZW50cnkgdG8gdGhpcyBjb25zdHJ1Y3QuXG4gICAqIEVudHJpZXMgYXJlIGFyYml0cmFyeSB2YWx1ZXMgYW5kIHdpbGwgYWxzbyBpbmNsdWRlIGEgc3RhY2sgdHJhY2UgdG8gYWxsb3cgdHJhY2luZyBiYWNrIHRvXG4gICAqIHRoZSBjb2RlIGxvY2F0aW9uIGZvciB3aGVuIHRoZSBlbnRyeSB3YXMgYWRkZWQuIEl0IGNhbiBiZSB1c2VkLCBmb3IgZXhhbXBsZSwgdG8gaW5jbHVkZSBzb3VyY2VcbiAgICogbWFwcGluZyBpbiBDbG91ZEZvcm1hdGlvbiB0ZW1wbGF0ZXMgdG8gaW1wcm92ZSBkaWFnbm9zdGljcy5cbiAgICpcbiAgICogQHBhcmFtIHR5cGUgYSBzdHJpbmcgZGVub3RpbmcgdGhlIHR5cGUgb2YgbWV0YWRhdGFcbiAgICogQHBhcmFtIGRhdGEgdGhlIHZhbHVlIG9mIHRoZSBtZXRhZGF0YSAoY2FuIGJlIGEgVG9rZW4pLiBJZiBudWxsL3VuZGVmaW5lZCwgbWV0YWRhdGEgd2lsbCBub3QgYmUgYWRkZWQuXG4gICAqIEBwYXJhbSBmcm9tIGEgZnVuY3Rpb24gdW5kZXIgd2hpY2ggdG8gcmVzdHJpY3QgdGhlIG1ldGFkYXRhIGVudHJ5J3Mgc3RhY2sgdHJhY2UgKGRlZmF1bHRzIHRvIHRoaXMuYWRkTWV0YWRhdGEpXG4gICAqL1xuICBwdWJsaWMgYWRkTWV0YWRhdGEodHlwZTogc3RyaW5nLCBkYXRhOiBhbnksIGZyb20/OiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoZGF0YSA9PSBudWxsKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgdHJhY2UgPSB0aGlzLnRyeUdldENvbnRleHQoY3hhcGkuRElTQUJMRV9NRVRBREFUQV9TVEFDS19UUkFDRSkgPyB1bmRlZmluZWQgOiBjYXB0dXJlU3RhY2tUcmFjZShmcm9tIHx8IHRoaXMuYWRkTWV0YWRhdGEpO1xuICAgIHRoaXMuX21ldGFkYXRhLnB1c2goeyB0eXBlLCBkYXRhLCB0cmFjZSB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGEgeyBcImF3czpjZGs6aW5mb1wiOiA8bWVzc2FnZT4gfSBtZXRhZGF0YSBlbnRyeSB0byB0aGlzIGNvbnN0cnVjdC5cbiAgICogVGhlIHRvb2xraXQgd2lsbCBkaXNwbGF5IHRoZSBpbmZvIG1lc3NhZ2Ugd2hlbiBhcHBzIGFyZSBzeW50aGVzaXplZC5cbiAgICogQHBhcmFtIG1lc3NhZ2UgVGhlIGluZm8gbWVzc2FnZS5cbiAgICovXG4gIHB1YmxpYyBhZGRJbmZvKG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMuYWRkTWV0YWRhdGEoY3hhcGkuSU5GT19NRVRBREFUQV9LRVksIG1lc3NhZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZHMgYSB7IHdhcm5pbmc6IDxtZXNzYWdlPiB9IG1ldGFkYXRhIGVudHJ5IHRvIHRoaXMgY29uc3RydWN0LlxuICAgKiBUaGUgdG9vbGtpdCB3aWxsIGRpc3BsYXkgdGhlIHdhcm5pbmcgd2hlbiBhbiBhcHAgaXMgc3ludGhlc2l6ZWQsIG9yIGZhaWxcbiAgICogaWYgcnVuIGluIC0tc3RyaWN0IG1vZGUuXG4gICAqIEBwYXJhbSBtZXNzYWdlIFRoZSB3YXJuaW5nIG1lc3NhZ2UuXG4gICAqL1xuICBwdWJsaWMgYWRkV2FybmluZyhtZXNzYWdlOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLmFkZE1ldGFkYXRhKGN4YXBpLldBUk5JTkdfTUVUQURBVEFfS0VZLCBtZXNzYWdlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFuIHsgZXJyb3I6IDxtZXNzYWdlPiB9IG1ldGFkYXRhIGVudHJ5IHRvIHRoaXMgY29uc3RydWN0LlxuICAgKiBUaGUgdG9vbGtpdCB3aWxsIGZhaWwgc3ludGhlc2lzIHdoZW4gZXJyb3JzIGFyZSByZXBvcnRlZC5cbiAgICogQHBhcmFtIG1lc3NhZ2UgVGhlIGVycm9yIG1lc3NhZ2UuXG4gICAqL1xuICBwdWJsaWMgYWRkRXJyb3IobWVzc2FnZTogc3RyaW5nKSB7XG4gICAgdGhpcy5hZGRNZXRhZGF0YShjeGFwaS5FUlJPUl9NRVRBREFUQV9LRVksIG1lc3NhZ2UpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFwcGxpZXMgdGhlIGFzcGVjdCB0byB0aGlzIENvbnN0cnVjdHMgbm9kZVxuICAgKi9cbiAgcHVibGljIGFwcGx5QXNwZWN0KGFzcGVjdDogSUFzcGVjdCk6IHZvaWQge1xuICAgIHRoaXMuX2FzcGVjdHMucHVzaChhc3BlY3QpO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGwgcGFyZW50IHNjb3BlcyBvZiB0aGlzIGNvbnN0cnVjdC5cbiAgICpcbiAgICogQHJldHVybnMgYSBsaXN0IG9mIHBhcmVudCBzY29wZXMuIFRoZSBsYXN0IGVsZW1lbnQgaW4gdGhlIGxpc3Qgd2lsbCBhbHdheXNcbiAgICogYmUgdGhlIGN1cnJlbnQgY29uc3RydWN0IGFuZCB0aGUgZmlyc3QgZWxlbWVudCB3aWxsIGJlIHRoZSByb290IG9mIHRoZVxuICAgKiB0cmVlLlxuICAgKi9cbiAgcHVibGljIGdldCBzY29wZXMoKTogSUNvbnN0cnVjdFtdIHtcbiAgICBjb25zdCByZXQgPSBuZXcgQXJyYXk8SUNvbnN0cnVjdD4oKTtcblxuICAgIGxldCBjdXJyOiBJQ29uc3RydWN0IHwgdW5kZWZpbmVkID0gdGhpcy5ob3N0O1xuICAgIHdoaWxlIChjdXJyKSB7XG4gICAgICByZXQudW5zaGlmdChjdXJyKTtcbiAgICAgIGN1cnIgPSBjdXJyLm5vZGUgJiYgY3Vyci5ub2RlLnNjb3BlO1xuICAgIH1cblxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybnMgVGhlIHJvb3Qgb2YgdGhlIGNvbnN0cnVjdCB0cmVlLlxuICAgKi9cbiAgcHVibGljIGdldCByb290KCkge1xuICAgIHJldHVybiB0aGlzLnNjb3Blc1swXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhpcyBjb25zdHJ1Y3Qgb3IgdGhlIHNjb3BlcyBpbiB3aGljaCBpdCBpcyBkZWZpbmVkIGFyZVxuICAgKiBsb2NrZW