toolshed-8.x-1.x-dev/js/EventListener.js
js/EventListener.js
"use strict";
(({
Toolshed: ts,
debounce
}) => {
/**
* Creates a queue of callable functions that can get managed and triggered
* together. The main purpose of this for queuing event listeners or
* registering a series of callbacks.
*
* CallList are orderable, and can be used to insert listeners around a
* specified reference point (before or after another callable).
*/
class CallList {
/**
* Ensure that a listener is a valid handler for the event used by this
* EventListener. This test is for checking the listener before adding it
* to the list of active listeners for this event.
*
* @param {Array|function} callable
* The object to test if it is valid for handling this event.
*
* @return {bool}
* Boolean to indicate if this listener is valid for handling this event.
* _true_ IFF this listener can be added and used with this event object.
*/
static isCallable(callable) {
let obj = null;
let func = callable;
if (callable instanceof Array) {
[obj, func] = callable;
}
return typeof func === 'function' && (!obj || obj instanceof Object);
}
/**
* Execute a callable item, with the parameters passed to the underlying
* function or method. A callable is either a function or an array
* (containing an object to use as the "this" and a method to execute).
*
* @param {function|Array} callable
* A callable is either a function that can be called directly or is an
* array that contains an object (used for "this") and a method to call.
* @param {*[]} ...args
* Additional arguments passed with the called item.
*
* @return {*|null}
* The result of the callabable
*/
static callItem(callable, ...args) {
if (callable instanceof Array) {
const [obj, func] = callable;
return func.apply(obj, args);
}
if (typeof callable === 'function') {
return callable(...args);
}
throw new Error('Unable to execute callable method.');
}
/**
* Create a new instance of a callable list of items.
*/
constructor() {
this.list = [];
}
/**
* Get the current size of the callable list.
*
* @return {int}
* The current size of the callables list array.
*/
size() {
return this.list.length;
}
/**
* Make a call to a list of callables.
*
* @param {Event} param
* argument object to pass to each of the callables as they get
* called respectively.
*/
call(param, ...args) {
this.list.forEach(cb => CallList.callItem(cb, param, ...args));
}
/**
* If there is a valid atPos, place the callable at this position,
* otherwise, just add it to the end of the list. This allows some
* flexibility to place callabbles at the start of the list, or
* before other callables.
*
* @param {Array|function} callable
* A callable object to add to the list.
* @param {int} atPos
* Index to add the callable at. This allows callables to be run in
* a different order than they maybe registered in.
*/
add(callable, atPos) {
if (!CallList.isCallable(callable)) {
throw new Error('Trying to add new callback, but it is not a valid callable.');
}
// Ensure that all existing references to this event are removed.
// Prevents the event from being called more than once unintentionally.
this.remove(callable);
if (atPos !== null && atPos >= 0) this.list.splice(atPos - 1, 0, callable);else this.list.push(callable);
}
/**
* Remove the specified callable from the list of callables.
*
* @param {Array|function} callable
* A listener object that requests to get removed.
*/
remove(callable) {
let pos = this.indexOf(callable);
while (pos >= 0) {
this.list.splice(pos, 1);
pos = this.indexOf(callable, pos);
}
}
/**
* Look for an a matching listener in the objects listener registry.
* Listeners can be stored as either function references, or arrays. If
* an array, the first item in the array is the object calling context,
* and the second parameter is function to call.
*
* Matches can be found by function, array (object and function) or just
* by matching the object contexts.
*
* @param {Array|Object|function} needle
* The matching listener to locate in the listeners array. If the param
* is an array, look for the matching object and function. If an object
* is passed in, find the first occurance of the object as the object
* context in the arrays. If a function, just search for the function.
* @param {int} start
* The starting position in the listener array to search for the callback.
*
* @return {int}
* The index where the matching listener was found. If a matching listener
* was not found, return -1 to indicate no match is available.
*/
indexOf(needle, start = 0) {
if (typeof needle === 'function') {
// For functions, matching is direct and straightforward.
return this.list.indexOf(needle, start);
}
const [obj, func] = needle instanceof Array ? needle : [null, needle];
for (; start < this.list.length; ++start) {
const item = this.list[start];
const [context, callback] = item instanceof Array ? item : [null, item];
if (obj === context && (!func || func === callback)) {
return start;
}
}
return -1;
}
}
/**
* Attach DOM and element events, which allow global registration and utilize
* a CallList for event calling and management. These event listeners
* have options for handling debounce, callables (@see CallList) and
* auto registration (only adding the event listener to the DOM when listener
* is added).
*
* Toolshed.EventListener.{eventName} namespace. Some of the events in that
* namespace may have customized event callback. An example of this is defined
* in ./screen-events.es6.js which are used by the Toolshed.Dock.
*/
ts.EventListener = class {
/**
* Constructor for creating of event listeners.
*
* @param {DOMElement} elem
* DOM element that will be the target of the event.
* @param {string} eventName
* The event.
* @param {null|object} options
* method:
* Name of the method to call on all listeners (special cases). Will call
* the default "on[this.eventName]" method if left blank.
* useCapture:
* Use capture instead of bubbling for event propagation.
* passive:
* Event handlers will not call preventDefault() which can enable browser
* optimatization that no longer need to wait for all handlers to complete
* before triggering other events like scrolling.
* debounce:
* Determine if the event only triggers using debounce handling. This means
* that events will only fire off after a short delay.
*
* If null or FALSE, no debounce will be used, and the event registered
* fires off as soon as the event is raised.
*
* If TRUE then use the default debounce delay. If an integer, than use the
* value as the delay in milliseconds.
*/
constructor(elem, eventName, options) {
options = options || {}; // options can be left blank.
this.elem = elem;
this.event = eventName;
this.autoListen = options.autoListen || false;
this.listeners = new CallList();
// Check and properly organize the event options to be used later.
if (options.debounce) {
this.debounce = typeof options.debounce === 'boolean' ? 100 : options.debounce;
}
// Allow for addEventListener options as described here
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener
// I am also employing the https://github.com/WICG/EventListenerOptions
// as a polyfill, but support will not be available for IE8 and earlier.
this.eventOpts = {
capture: options.capture || false,
passive: options.passive || false
};
}
/**
* Trigger the event for all the registered listeners. Custom
* EventListeners are most likely to override this function in order
* to create implement special functionality, triggered by events.
*
* @param {Object} event
* The event object that was generated and passed to the event handler.
*/
_run(event, ...args) {
this.listners.call(event, ...args);
}
/**
* Trigger the event manaully.
*
* @param {Event|null} event
* Event data to use with this event.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
trigger(event, ...args) {
this._run(event || new Event(this.event), args);
return this;
}
/**
* Register the event, and keep track of the callback so it can be removed
* later if we need to disable / remove the listener at a later time.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
listen() {
if (!this.callback && (!this.autoListen || this.listeners.size())) {
this.callback = this.debounce && this.debounce > 0 && debounce ? debounce(this._run.bind(this), this.debounce) : this._run.bind(this);
this.elem.addEventListener(this.event, this.callback, this.eventOpts);
}
return this;
}
/**
* Stop listening for this event, and unregister from any event listeners.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
ignore() {
if (this.callback) {
this.elem.removeEventListener(this.event, this.callback);
delete this.callback;
}
return this;
}
/**
* If there is a valid atPos, place the listener at this position,
* otherwise, just add it to the end of the list. This allows some
* flexibility to place listeners at the start of the list, or
* before other listeners.
*
* @param {Object} listener
* A listener object that contains the a method 'on' + [this.eventName].
* @param {int} atPos
* Index to add the listener at. This allows listeners to be run in
* a different order than they maybe registered in.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
add(listener, atPos) {
this.listeners.add(listener, atPos);
if (this.autoListen) this.listen();
return this;
}
/**
* Add a new listener before an existing listener already in the list.
* If [before] is null, then insert at the start of the list.
*
* @param {Array|function} listener
* A listener object that contains the a method 'on' + [this.eventName].
* @param {Array|function} before
* Listener object that is used to position the new listener.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
addBefore(listener, before) {
const pos = before ? this.listeners.indexOf(before) : 0;
return this.add(listener, pos < 0 ? 0 : pos);
}
/**
* Add a new listener after an existing listener already in the list.
* If [after] is null, then insert at the end of the list.
*
* @param {Array|function} listener
* A listener object that represents a callable.
* @param {Array|function} after
* Listener object that is used to position the new listener.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
addAfter(listener, after) {
let pos = null;
if (after) {
pos = this.listeners.indexOf(after);
pos = pos >= 0 ? pos + 1 : -1;
}
return this.add(listener, pos);
}
/**
* Remove the specified listener from the list of event listeners.
* This assume there should only be one entry pert callback.
*
* @param {Array|function} listener
* A listener object that requests to get removed.
*
* @return {Drupal.Toolshed.EventListener}
* Return this instance of this EventListener for the purpose of chaining.
*/
remove(listener) {
this.listeners.remove(listener);
// If there are no listeners and the autoListen option is on, turn off
// listening. This prevents the event from being called for no reason.
if (this.autoListen && !this.listeners.size()) this.ignore();
return this;
}
/**
* Clean-up events and data.
*/
destroy() {
this.ignore();
}
};
/**
* Event listener for media query listeners.
*/
ts.MediaQueryListener = class {
/**
* Constructs a new Media Query listener instance.
*
* @param {Object[]} breakpoints
* An array of breakpoints in the order they should be checked. Each
* breakpoint object is expected to have an `mq`, `inverted` and `event`
* property which help determine what event to call when a Media Query
* listener triggers.
*/
constructor(breakpoints) {
this.mode = null;
this.curBp = null;
this.bps = new Map();
this.aliases = new Map();
breakpoints.forEach(bp => {
const mql = window.matchMedia(bp.mediaQuery);
if (bp.event && !this.aliases.has(bp.event)) {
this.aliases.set(bp.event, {
on: new CallList(),
off: new CallList()
});
}
this.bps.set(bp.id, {
query: mql,
mode: bp.event || null,
inverted: bp.inverted || false
});
});
}
/**
* Alter the current breakpoint, and trigger the related events.
*
* @param {string} newBp
* The ID of the breakpoint to trigger.
*/
_changeMode(newBp) {
let newMode = null;
// If the mode changed, trigger the appropriate action.
if (newBp === this.curBp) return;
if (this.curBp) {
const offList = this.bps.get(this.curBp);
if (offList && offList.off) offList.off.call(this.curBp, 'off');
}
this.curBp = newBp;
if (newBp) {
const onList = this.bps.get(newBp);
if (onList) {
newMode = onList.mode;
if (onList.on) onList.on.call(this.curBp, 'on');
}
}
if (newMode !== this.mode) {
if (this.mode) {
const offMode = this.aliases.get(this.mode);
if (offMode) offMode.off.call(this.mode, 'off');
}
this.mode = newMode;
if (newMode) {
const onMode = this.aliases.get(newMode);
if (onMode) onMode.on.call(this.mode, 'on');
}
}
}
/**
* Check the registered breakpoints in order to see which one is active.
*
* @return {string|null}
* The query mapped event if a matching breakpoint is found, otherwise
* return null to mean no event.
*/
checkBreakpoints() {
const bps = Array.from(this.bps.entries());
for (let i = 0; i < bps.length; ++i) {
const [id, bp] = bps[i];
if (!bp.query.matches !== !bp.inverted) {
return id;
}
}
return null;
}
/**
* Add a new listener to a breakpoint or mode.
*
* @param {string} bpId
* The ID of the breakpoint to watch for, or the media query event to
* attach the listener callable to.
* @param {[type]} listener
* The callable callback to get called when the breakpoint matches the
* action specified (either on or off).
* @param {string} action
* Either 'on' or 'off' to indicated of the callback should be called
* when the media query is active or deactivated respectively.
*
* @return {Object}
* The current instance of the MediaQueryListener, and the "this" object.
*/
add(bpId, listener, action = 'on') {
if (action === 'on' || action === 'off') {
let target;
let curState;
if (this.aliases.has(bpId)) {
target = this.aliases.get(bpId);
curState = this.mode;
} else if (this.bps.has(bpId)) {
target = this.bps.get(bpId);
curState = this.curBp;
if (!target[action]) target[action] = new CallList();
} else {
throw new Error(`Error adding ${bpId} with action ${action}`);
}
target[action].add(listener);
// Trigger 'on' event when listener is added if current state matches
// screen sizes targeted by added listener.
if (curState === bpId && action === 'on') {
CallList.callItem(listener, bpId, 'on');
}
// Trigger 'off' event when listener is added if current state does not
// match screen sizes targeted by added listener.
else if (curState !== bpId && action === 'off') {
CallList.callItem(listener, bpId, 'off');
}
}
return this;
}
/**
* Listen for changes of the registered breakpoints.
*/
listen() {
let current;
this.bps.forEach((bp, id) => {
if (!bp.callback) {
bp.callback = mql => {
const mode = !mql.matches !== !bp.inverted ? id : this.checkBreakpoints();
this._changeMode(mode);
};
bp.query.addListener(bp.callback);
}
// Stop updating this after the first breakpoint to trigger.
if (!current && !bp.query.matches !== !bp.inverted) {
current = id;
}
});
this._changeMode(current);
}
/**
* Unregister all media query listeners, and ignore all breakpoint events.
*/
ignore() {
this.bps.forEach((id, bp) => {
if (bp.callback) {
bp.query.removeListener(bp.callback);
delete bp.callback;
}
});
}
};
})(Drupal);
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRXZlbnRMaXN0ZW5lci5qcyIsIm5hbWVzIjpbIlRvb2xzaGVkIiwidHMiLCJkZWJvdW5jZSIsIkNhbGxMaXN0IiwiaXNDYWxsYWJsZSIsImNhbGxhYmxlIiwib2JqIiwiZnVuYyIsIkFycmF5IiwiT2JqZWN0IiwiY2FsbEl0ZW0iLCJhcmdzIiwiYXBwbHkiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwibGlzdCIsInNpemUiLCJsZW5ndGgiLCJjYWxsIiwicGFyYW0iLCJmb3JFYWNoIiwiY2IiLCJhZGQiLCJhdFBvcyIsInJlbW92ZSIsInNwbGljZSIsInB1c2giLCJwb3MiLCJpbmRleE9mIiwibmVlZGxlIiwic3RhcnQiLCJpdGVtIiwiY29udGV4dCIsImNhbGxiYWNrIiwiRXZlbnRMaXN0ZW5lciIsImVsZW0iLCJldmVudE5hbWUiLCJvcHRpb25zIiwiZXZlbnQiLCJhdXRvTGlzdGVuIiwibGlzdGVuZXJzIiwiZXZlbnRPcHRzIiwiY2FwdHVyZSIsInBhc3NpdmUiLCJfcnVuIiwibGlzdG5lcnMiLCJ0cmlnZ2VyIiwiRXZlbnQiLCJsaXN0ZW4iLCJiaW5kIiwiYWRkRXZlbnRMaXN0ZW5lciIsImlnbm9yZSIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJsaXN0ZW5lciIsImFkZEJlZm9yZSIsImJlZm9yZSIsImFkZEFmdGVyIiwiYWZ0ZXIiLCJkZXN0cm95IiwiTWVkaWFRdWVyeUxpc3RlbmVyIiwiYnJlYWtwb2ludHMiLCJtb2RlIiwiY3VyQnAiLCJicHMiLCJNYXAiLCJhbGlhc2VzIiwiYnAiLCJtcWwiLCJ3aW5kb3ciLCJtYXRjaE1lZGlhIiwibWVkaWFRdWVyeSIsImhhcyIsInNldCIsIm9uIiwib2ZmIiwiaWQiLCJxdWVyeSIsImludmVydGVkIiwiX2NoYW5nZU1vZGUiLCJuZXdCcCIsIm5ld01vZGUiLCJvZmZMaXN0IiwiZ2V0Iiwib25MaXN0Iiwib2ZmTW9kZSIsIm9uTW9kZSIsImNoZWNrQnJlYWtwb2ludHMiLCJmcm9tIiwiZW50cmllcyIsImkiLCJtYXRjaGVzIiwiYnBJZCIsImFjdGlvbiIsInRhcmdldCIsImN1clN0YXRlIiwiY3VycmVudCIsImFkZExpc3RlbmVyIiwicmVtb3ZlTGlzdGVuZXIiLCJEcnVwYWwiXSwic291cmNlcyI6WyJFdmVudExpc3RlbmVyLmVzNi5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyIoKHsgVG9vbHNoZWQ6IHRzLCBkZWJvdW5jZSB9KSA9PiB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgcXVldWUgb2YgY2FsbGFibGUgZnVuY3Rpb25zIHRoYXQgY2FuIGdldCBtYW5hZ2VkIGFuZCB0cmlnZ2VyZWRcbiAgICogdG9nZXRoZXIuIFRoZSBtYWluIHB1cnBvc2Ugb2YgdGhpcyBmb3IgcXVldWluZyBldmVudCBsaXN0ZW5lcnMgb3JcbiAgICogcmVnaXN0ZXJpbmcgYSBzZXJpZXMgb2YgY2FsbGJhY2tzLlxuICAgKlxuICAgKiBDYWxsTGlzdCBhcmUgb3JkZXJhYmxlLCBhbmQgY2FuIGJlIHVzZWQgdG8gaW5zZXJ0IGxpc3RlbmVycyBhcm91bmQgYVxuICAgKiBzcGVjaWZpZWQgcmVmZXJlbmNlIHBvaW50IChiZWZvcmUgb3IgYWZ0ZXIgYW5vdGhlciBjYWxsYWJsZSkuXG4gICAqL1xuICBjbGFzcyBDYWxsTGlzdCB7XG4gICAgLyoqXG4gICAgICogRW5zdXJlIHRoYXQgYSBsaXN0ZW5lciBpcyBhIHZhbGlkIGhhbmRsZXIgZm9yIHRoZSBldmVudCB1c2VkIGJ5IHRoaXNcbiAgICAgKiBFdmVudExpc3RlbmVyLiBUaGlzIHRlc3QgaXMgZm9yIGNoZWNraW5nIHRoZSBsaXN0ZW5lciBiZWZvcmUgYWRkaW5nIGl0XG4gICAgICogdG8gdGhlIGxpc3Qgb2YgYWN0aXZlIGxpc3RlbmVycyBmb3IgdGhpcyBldmVudC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7QXJyYXl8ZnVuY3Rpb259IGNhbGxhYmxlXG4gICAgICogICBUaGUgb2JqZWN0IHRvIHRlc3QgaWYgaXQgaXMgdmFsaWQgZm9yIGhhbmRsaW5nIHRoaXMgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtib29sfVxuICAgICAqICAgQm9vbGVhbiB0byBpbmRpY2F0ZSBpZiB0aGlzIGxpc3RlbmVyIGlzIHZhbGlkIGZvciBoYW5kbGluZyB0aGlzIGV2ZW50LlxuICAgICAqICAgX3RydWVfIElGRiB0aGlzIGxpc3RlbmVyIGNhbiBiZSBhZGRlZCBhbmQgdXNlZCB3aXRoIHRoaXMgZXZlbnQgb2JqZWN0LlxuICAgICAqL1xuICAgIHN0YXRpYyBpc0NhbGxhYmxlKGNhbGxhYmxlKSB7XG4gICAgICBsZXQgb2JqID0gbnVsbDtcbiAgICAgIGxldCBmdW5jID0gY2FsbGFibGU7XG5cbiAgICAgIGlmIChjYWxsYWJsZSBpbnN0YW5jZW9mIEFycmF5KSB7XG4gICAgICAgIFtvYmosIGZ1bmNdID0gY2FsbGFibGU7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiAodHlwZW9mIGZ1bmMgPT09ICdmdW5jdGlvbicpICYmICghb2JqIHx8IG9iaiBpbnN0YW5jZW9mIE9iamVjdCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRXhlY3V0ZSBhIGNhbGxhYmxlIGl0ZW0sIHdpdGggdGhlIHBhcmFtZXRlcnMgcGFzc2VkIHRvIHRoZSB1bmRlcmx5aW5nXG4gICAgICogZnVuY3Rpb24gb3IgbWV0aG9kLiBBIGNhbGxhYmxlIGlzIGVpdGhlciBhIGZ1bmN0aW9uIG9yIGFuIGFycmF5XG4gICAgICogKGNvbnRhaW5pbmcgYW4gb2JqZWN0IHRvIHVzZSBhcyB0aGUgXCJ0aGlzXCIgYW5kIGEgbWV0aG9kIHRvIGV4ZWN1dGUpLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbnxBcnJheX0gY2FsbGFibGVcbiAgICAgKiAgIEEgY2FsbGFibGUgaXMgZWl0aGVyIGEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgY2FsbGVkIGRpcmVjdGx5IG9yIGlzIGFuXG4gICAgICogICBhcnJheSB0aGF0IGNvbnRhaW5zIGFuIG9iamVjdCAodXNlZCBmb3IgXCJ0aGlzXCIpIGFuZCBhIG1ldGhvZCB0byBjYWxsLlxuICAgICAqIEBwYXJhbSB7KltdfSAuLi5hcmdzXG4gICAgICogICBBZGRpdGlvbmFsIGFyZ3VtZW50cyBwYXNzZWQgd2l0aCB0aGUgY2FsbGVkIGl0ZW0uXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHsqfG51bGx9XG4gICAgICogICBUaGUgcmVzdWx0IG9mIHRoZSBjYWxsYWJhYmxlXG4gICAgICovXG4gICAgc3RhdGljIGNhbGxJdGVtKGNhbGxhYmxlLCAuLi5hcmdzKSB7XG4gICAgICBpZiAoY2FsbGFibGUgaW5zdGFuY2VvZiBBcnJheSkge1xuICAgICAgICBjb25zdCBbb2JqLCBmdW5jXSA9IGNhbGxhYmxlO1xuICAgICAgICByZXR1cm4gZnVuYy5hcHBseShvYmosIGFyZ3MpO1xuICAgICAgfVxuXG4gICAgICBpZiAodHlwZW9mIGNhbGxhYmxlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIHJldHVybiBjYWxsYWJsZSguLi5hcmdzKTtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbmFibGUgdG8gZXhlY3V0ZSBjYWxsYWJsZSBtZXRob2QuJyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIGEgY2FsbGFibGUgbGlzdCBvZiBpdGVtcy5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgIHRoaXMubGlzdCA9IFtdO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCB0aGUgY3VycmVudCBzaXplIG9mIHRoZSBjYWxsYWJsZSBsaXN0LlxuICAgICAqXG4gICAgICogQHJldHVybiB7aW50fVxuICAgICAqICAgVGhlIGN1cnJlbnQgc2l6ZSBvZiB0aGUgY2FsbGFibGVzIGxpc3QgYXJyYXkuXG4gICAgICovXG4gICAgc2l6ZSgpIHtcbiAgICAgIHJldHVybiB0aGlzLmxpc3QubGVuZ3RoO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIE1ha2UgYSBjYWxsIHRvIGEgbGlzdCBvZiBjYWxsYWJsZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0V2ZW50fSBwYXJhbVxuICAgICAqICAgYXJndW1lbnQgb2JqZWN0IHRvIHBhc3MgdG8gZWFjaCBvZiB0aGUgY2FsbGFibGVzIGFzIHRoZXkgZ2V0XG4gICAgICogICBjYWxsZWQgcmVzcGVjdGl2ZWx5LlxuICAgICAqL1xuICAgIGNhbGwocGFyYW0sIC4uLmFyZ3MpIHtcbiAgICAgIHRoaXMubGlzdC5mb3JFYWNoKChjYikgPT4gQ2FsbExpc3QuY2FsbEl0ZW0oY2IsIHBhcmFtLCAuLi5hcmdzKSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSWYgdGhlcmUgaXMgYSB2YWxpZCBhdFBvcywgcGxhY2UgdGhlIGNhbGxhYmxlIGF0IHRoaXMgcG9zaXRpb24sXG4gICAgICogb3RoZXJ3aXNlLCBqdXN0IGFkZCBpdCB0byB0aGUgZW5kIG9mIHRoZSBsaXN0LiBUaGlzIGFsbG93cyBzb21lXG4gICAgICogZmxleGliaWxpdHkgdG8gcGxhY2UgY2FsbGFiYmxlcyBhdCB0aGUgc3RhcnQgb2YgdGhlIGxpc3QsIG9yXG4gICAgICogYmVmb3JlIG90aGVyIGNhbGxhYmxlcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7QXJyYXl8ZnVuY3Rpb259IGNhbGxhYmxlXG4gICAgICogICBBIGNhbGxhYmxlIG9iamVjdCB0byBhZGQgdG8gdGhlIGxpc3QuXG4gICAgICogQHBhcmFtIHtpbnR9IGF0UG9zXG4gICAgICogICBJbmRleCB0byBhZGQgdGhlIGNhbGxhYmxlIGF0LiBUaGlzIGFsbG93cyBjYWxsYWJsZXMgdG8gYmUgcnVuIGluXG4gICAgICogICBhIGRpZmZlcmVudCBvcmRlciB0aGFuIHRoZXkgbWF5YmUgcmVnaXN0ZXJlZCBpbi5cbiAgICAgKi9cbiAgICBhZGQoY2FsbGFibGUsIGF0UG9zKSB7XG4gICAgICBpZiAoIUNhbGxMaXN0LmlzQ2FsbGFibGUoY2FsbGFibGUpKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVHJ5aW5nIHRvIGFkZCBuZXcgY2FsbGJhY2ssIGJ1dCBpdCBpcyBub3QgYSB2YWxpZCBjYWxsYWJsZS4nKTtcbiAgICAgIH1cblxuICAgICAgLy8gRW5zdXJlIHRoYXQgYWxsIGV4aXN0aW5nIHJlZmVyZW5jZXMgdG8gdGhpcyBldmVudCBhcmUgcmVtb3ZlZC5cbiAgICAgIC8vIFByZXZlbnRzIHRoZSBldmVudCBmcm9tIGJlaW5nIGNhbGxlZCBtb3JlIHRoYW4gb25jZSB1bmludGVudGlvbmFsbHkuXG4gICAgICB0aGlzLnJlbW92ZShjYWxsYWJsZSk7XG5cbiAgICAgIGlmIChhdFBvcyAhPT0gbnVsbCAmJiBhdFBvcyA+PSAwKSB0aGlzLmxpc3Quc3BsaWNlKGF0UG9zIC0gMSwgMCwgY2FsbGFibGUpO1xuICAgICAgZWxzZSB0aGlzLmxpc3QucHVzaChjYWxsYWJsZSk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIHRoZSBzcGVjaWZpZWQgY2FsbGFibGUgZnJvbSB0aGUgbGlzdCBvZiBjYWxsYWJsZXMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fGZ1bmN0aW9ufSBjYWxsYWJsZVxuICAgICAqICBBIGxpc3RlbmVyIG9iamVjdCB0aGF0IHJlcXVlc3RzIHRvIGdldCByZW1vdmVkLlxuICAgICAqL1xuICAgIHJlbW92ZShjYWxsYWJsZSkge1xuICAgICAgbGV0IHBvcyA9IHRoaXMuaW5kZXhPZihjYWxsYWJsZSk7XG5cbiAgICAgIHdoaWxlIChwb3MgPj0gMCkge1xuICAgICAgICB0aGlzLmxpc3Quc3BsaWNlKHBvcywgMSk7XG4gICAgICAgIHBvcyA9IHRoaXMuaW5kZXhPZihjYWxsYWJsZSwgcG9zKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBMb29rIGZvciBhbiBhIG1hdGNoaW5nIGxpc3RlbmVyIGluIHRoZSBvYmplY3RzIGxpc3RlbmVyIHJlZ2lzdHJ5LlxuICAgICAqIExpc3RlbmVycyBjYW4gYmUgc3RvcmVkIGFzIGVpdGhlciBmdW5jdGlvbiByZWZlcmVuY2VzLCBvciBhcnJheXMuIElmXG4gICAgICogYW4gYXJyYXksIHRoZSBmaXJzdCBpdGVtIGluIHRoZSBhcnJheSBpcyB0aGUgb2JqZWN0IGNhbGxpbmcgY29udGV4dCxcbiAgICAgKiBhbmQgdGhlIHNlY29uZCBwYXJhbWV0ZXIgaXMgZnVuY3Rpb24gdG8gY2FsbC5cbiAgICAgKlxuICAgICAqIE1hdGNoZXMgY2FuIGJlIGZvdW5kIGJ5IGZ1bmN0aW9uLCBhcnJheSAob2JqZWN0IGFuZCBmdW5jdGlvbikgb3IganVzdFxuICAgICAqIGJ5IG1hdGNoaW5nIHRoZSBvYmplY3QgY29udGV4dHMuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fE9iamVjdHxmdW5jdGlvbn0gbmVlZGxlXG4gICAgICogICBUaGUgbWF0Y2hpbmcgbGlzdGVuZXIgdG8gbG9jYXRlIGluIHRoZSBsaXN0ZW5lcnMgYXJyYXkuIElmIHRoZSBwYXJhbVxuICAgICAqICAgaXMgYW4gYXJyYXksIGxvb2sgZm9yIHRoZSBtYXRjaGluZyBvYmplY3QgYW5kIGZ1bmN0aW9uLiBJZiBhbiBvYmplY3RcbiAgICAgKiAgIGlzIHBhc3NlZCBpbiwgZmluZCB0aGUgZmlyc3Qgb2NjdXJhbmNlIG9mIHRoZSBvYmplY3QgYXMgdGhlIG9iamVjdFxuICAgICAqICAgY29udGV4dCBpbiB0aGUgYXJyYXlzLiBJZiBhIGZ1bmN0aW9uLCBqdXN0IHNlYXJjaCBmb3IgdGhlIGZ1bmN0aW9uLlxuICAgICAqIEBwYXJhbSB7aW50fSBzdGFydFxuICAgICAqICAgVGhlIHN0YXJ0aW5nIHBvc2l0aW9uIGluIHRoZSBsaXN0ZW5lciBhcnJheSB0byBzZWFyY2ggZm9yIHRoZSBjYWxsYmFjay5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge2ludH1cbiAgICAgKiAgIFRoZSBpbmRleCB3aGVyZSB0aGUgbWF0Y2hpbmcgbGlzdGVuZXIgd2FzIGZvdW5kLiBJZiBhIG1hdGNoaW5nIGxpc3RlbmVyXG4gICAgICogICB3YXMgbm90IGZvdW5kLCByZXR1cm4gLTEgdG8gaW5kaWNhdGUgbm8gbWF0Y2ggaXMgYXZhaWxhYmxlLlxuICAgICAqL1xuICAgIGluZGV4T2YobmVlZGxlLCBzdGFydCA9IDApIHtcbiAgICAgIGlmICh0eXBlb2YgbmVlZGxlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIEZvciBmdW5jdGlvbnMsIG1hdGNoaW5nIGlzIGRpcmVjdCBhbmQgc3RyYWlnaHRmb3J3YXJkLlxuICAgICAgICByZXR1cm4gdGhpcy5saXN0LmluZGV4T2YobmVlZGxlLCBzdGFydCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IFtvYmosIGZ1bmNdID0gKG5lZWRsZSBpbnN0YW5jZW9mIEFycmF5KSA/IG5lZWRsZSA6IFtudWxsLCBuZWVkbGVdO1xuICAgICAgZm9yICg7IHN0YXJ0IDwgdGhpcy5saXN0Lmxlbmd0aDsgKytzdGFydCkge1xuICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5saXN0W3N0YXJ0XTtcbiAgICAgICAgY29uc3QgW2NvbnRleHQsIGNhbGxiYWNrXSA9IChpdGVtIGluc3RhbmNlb2YgQXJyYXkpID8gaXRlbSA6IFtudWxsLCBpdGVtXTtcblxuICAgICAgICBpZiAob2JqID09PSBjb250ZXh0ICYmICghZnVuYyB8fCBmdW5jID09PSBjYWxsYmFjaykpIHtcbiAgICAgICAgICByZXR1cm4gc3RhcnQ7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiAtMTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQXR0YWNoIERPTSBhbmQgZWxlbWVudCBldmVudHMsIHdoaWNoIGFsbG93IGdsb2JhbCByZWdpc3RyYXRpb24gYW5kIHV0aWxpemVcbiAgICogYSBDYWxsTGlzdCBmb3IgZXZlbnQgY2FsbGluZyBhbmQgbWFuYWdlbWVudC4gVGhlc2UgZXZlbnQgbGlzdGVuZXJzXG4gICAqIGhhdmUgb3B0aW9ucyBmb3IgaGFuZGxpbmcgZGVib3VuY2UsIGNhbGxhYmxlcyAoQHNlZSBDYWxsTGlzdCkgYW5kXG4gICAqIGF1dG8gcmVnaXN0cmF0aW9uIChvbmx5IGFkZGluZyB0aGUgZXZlbnQgbGlzdGVuZXIgdG8gdGhlIERPTSB3aGVuIGxpc3RlbmVyXG4gICAqIGlzIGFkZGVkKS5cbiAgICpcbiAgICogVG9vbHNoZWQuRXZlbnRMaXN0ZW5lci57ZXZlbnROYW1lfSBuYW1lc3BhY2UuIFNvbWUgb2YgdGhlIGV2ZW50cyBpbiB0aGF0XG4gICAqIG5hbWVzcGFjZSBtYXkgaGF2ZSBjdXN0b21pemVkIGV2ZW50IGNhbGxiYWNrLiBBbiBleGFtcGxlIG9mIHRoaXMgaXMgZGVmaW5lZFxuICAgKiBpbiAuL3NjcmVlbi1ldmVudHMuZXM2LmpzIHdoaWNoIGFyZSB1c2VkIGJ5IHRoZSBUb29sc2hlZC5Eb2NrLlxuICAgKi9cbiAgdHMuRXZlbnRMaXN0ZW5lciA9IGNsYXNzIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RvciBmb3IgY3JlYXRpbmcgb2YgZXZlbnQgbGlzdGVuZXJzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtET01FbGVtZW50fSBlbGVtXG4gICAgICogICBET00gZWxlbWVudCB0aGF0IHdpbGwgYmUgdGhlIHRhcmdldCBvZiB0aGUgZXZlbnQuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGV2ZW50TmFtZVxuICAgICAqICAgVGhlIGV2ZW50LlxuICAgICAqIEBwYXJhbSB7bnVsbHxvYmplY3R9IG9wdGlvbnNcbiAgICAgKiAgIG1ldGhvZDpcbiAgICAgKiAgICAgTmFtZSBvZiB0aGUgbWV0aG9kIHRvIGNhbGwgb24gYWxsIGxpc3RlbmVycyAoc3BlY2lhbCBjYXNlcykuIFdpbGwgY2FsbFxuICAgICAqICAgICB0aGUgZGVmYXVsdCBcIm9uW3RoaXMuZXZlbnROYW1lXVwiIG1ldGhvZCBpZiBsZWZ0IGJsYW5rLlxuICAgICAqICAgdXNlQ2FwdHVyZTpcbiAgICAgKiAgICAgVXNlIGNhcHR1cmUgaW5zdGVhZCBvZiBidWJibGluZyBmb3IgZXZlbnQgcHJvcGFnYXRpb24uXG4gICAgICogICBwYXNzaXZlOlxuICAgICAqICAgICBFdmVudCBoYW5kbGVycyB3aWxsIG5vdCBjYWxsIHByZXZlbnREZWZhdWx0KCkgd2hpY2ggY2FuIGVuYWJsZSBicm93c2VyXG4gICAgICogICAgIG9wdGltYXRpemF0aW9uIHRoYXQgbm8gbG9uZ2VyIG5lZWQgdG8gd2FpdCBmb3IgYWxsIGhhbmRsZXJzIHRvIGNvbXBsZXRlXG4gICAgICogICAgIGJlZm9yZSB0cmlnZ2VyaW5nIG90aGVyIGV2ZW50cyBsaWtlIHNjcm9sbGluZy5cbiAgICAgKiAgIGRlYm91bmNlOlxuICAgICAqICAgICBEZXRlcm1pbmUgaWYgdGhlIGV2ZW50IG9ubHkgdHJpZ2dlcnMgdXNpbmcgZGVib3VuY2UgaGFuZGxpbmcuIFRoaXMgbWVhbnNcbiAgICAgKiAgICAgdGhhdCBldmVudHMgd2lsbCBvbmx5IGZpcmUgb2ZmIGFmdGVyIGEgc2hvcnQgZGVsYXkuXG4gICAgICpcbiAgICAgKiAgICAgSWYgbnVsbCBvciBGQUxTRSwgbm8gZGVib3VuY2Ugd2lsbCBiZSB1c2VkLCBhbmQgdGhlIGV2ZW50IHJlZ2lzdGVyZWRcbiAgICAgKiAgICAgZmlyZXMgb2ZmIGFzIHNvb24gYXMgdGhlIGV2ZW50IGlzIHJhaXNlZC5cbiAgICAgKlxuICAgICAqICAgICBJZiBUUlVFIHRoZW4gdXNlIHRoZSBkZWZhdWx0IGRlYm91bmNlIGRlbGF5LiBJZiBhbiBpbnRlZ2VyLCB0aGFuIHVzZSB0aGVcbiAgICAgKiAgICAgdmFsdWUgYXMgdGhlIGRlbGF5IGluIG1pbGxpc2Vjb25kcy5cbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihlbGVtLCBldmVudE5hbWUsIG9wdGlvbnMpIHtcbiAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9OyAvLyBvcHRpb25zIGNhbiBiZSBsZWZ0IGJsYW5rLlxuXG4gICAgICB0aGlzLmVsZW0gPSBlbGVtO1xuICAgICAgdGhpcy5ldmVudCA9IGV2ZW50TmFtZTtcbiAgICAgIHRoaXMuYXV0b0xpc3RlbiA9IG9wdGlvbnMuYXV0b0xpc3RlbiB8fCBmYWxzZTtcbiAgICAgIHRoaXMubGlzdGVuZXJzID0gbmV3IENhbGxMaXN0KCk7XG5cbiAgICAgIC8vIENoZWNrIGFuZCBwcm9wZXJseSBvcmdhbml6ZSB0aGUgZXZlbnQgb3B0aW9ucyB0byBiZSB1c2VkIGxhdGVyLlxuICAgICAgaWYgKG9wdGlvbnMuZGVib3VuY2UpIHtcbiAgICAgICAgdGhpcy5kZWJvdW5jZSA9ICh0eXBlb2Ygb3B0aW9ucy5kZWJvdW5jZSA9PT0gJ2Jvb2xlYW4nKSA/IDEwMCA6IG9wdGlvbnMuZGVib3VuY2U7XG4gICAgICB9XG5cbiAgICAgIC8vIEFsbG93IGZvciBhZGRFdmVudExpc3RlbmVyIG9wdGlvbnMgYXMgZGVzY3JpYmVkIGhlcmVcbiAgICAgIC8vIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuLVVTL2RvY3MvV2ViL0FQSS9FdmVudFRhcmdldC9hZGRFdmVudExpc3RlbmVyXG4gICAgICAvLyBJIGFtIGFsc28gZW1wbG95aW5nIHRoZSBodHRwczovL2dpdGh1Yi5jb20vV0lDRy9FdmVudExpc3RlbmVyT3B0aW9uc1xuICAgICAgLy8gYXMgYSBwb2x5ZmlsbCwgYnV0IHN1cHBvcnQgd2lsbCBub3QgYmUgYXZhaWxhYmxlIGZvciBJRTggYW5kIGVhcmxpZXIuXG4gICAgICB0aGlzLmV2ZW50T3B0cyA9IHtcbiAgICAgICAgY2FwdHVyZTogb3B0aW9ucy5jYXB0dXJlIHx8IGZhbHNlLFxuICAgICAgICBwYXNzaXZlOiBvcHRpb25zLnBhc3NpdmUgfHwgZmFsc2UsXG4gICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFRyaWdnZXIgdGhlIGV2ZW50IGZvciBhbGwgdGhlIHJlZ2lzdGVyZWQgbGlzdGVuZXJzLiBDdXN0b21cbiAgICAgKiBFdmVudExpc3RlbmVycyBhcmUgbW9zdCBsaWtlbHkgdG8gb3ZlcnJpZGUgdGhpcyBmdW5jdGlvbiBpbiBvcmRlclxuICAgICAqIHRvIGNyZWF0ZSBpbXBsZW1lbnQgc3BlY2lhbCBmdW5jdGlvbmFsaXR5LCB0cmlnZ2VyZWQgYnkgZXZlbnRzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGV2ZW50XG4gICAgICogICBUaGUgZXZlbnQgb2JqZWN0IHRoYXQgd2FzIGdlbmVyYXRlZCBhbmQgcGFzc2VkIHRvIHRoZSBldmVudCBoYW5kbGVyLlxuICAgICAqL1xuICAgIF9ydW4oZXZlbnQsIC4uLmFyZ3MpIHtcbiAgICAgIHRoaXMubGlzdG5lcnMuY2FsbChldmVudCwgLi4uYXJncyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogVHJpZ2dlciB0aGUgZXZlbnQgbWFuYXVsbHkuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0V2ZW50fG51bGx9IGV2ZW50XG4gICAgICogICBFdmVudCBkYXRhIHRvIHVzZSB3aXRoIHRoaXMgZXZlbnQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtEcnVwYWwuVG9vbHNoZWQuRXZlbnRMaXN0ZW5lcn1cbiAgICAgKiAgIFJldHVybiB0aGlzIGluc3RhbmNlIG9mIHRoaXMgRXZlbnRMaXN0ZW5lciBmb3IgdGhlIHB1cnBvc2Ugb2YgY2hhaW5pbmcuXG4gICAgICovXG4gICAgdHJpZ2dlcihldmVudCwgLi4uYXJncykge1xuICAgICAgdGhpcy5fcnVuKGV2ZW50IHx8IG5ldyBFdmVudCh0aGlzLmV2ZW50KSwgYXJncyk7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZWdpc3RlciB0aGUgZXZlbnQsIGFuZCBrZWVwIHRyYWNrIG9mIHRoZSBjYWxsYmFjayBzbyBpdCBjYW4gYmUgcmVtb3ZlZFxuICAgICAqIGxhdGVyIGlmIHdlIG5lZWQgdG8gZGlzYWJsZSAvIHJlbW92ZSB0aGUgbGlzdGVuZXIgYXQgYSBsYXRlciB0aW1lLlxuICAgICAqXG4gICAgICogQHJldHVybiB7RHJ1cGFsLlRvb2xzaGVkLkV2ZW50TGlzdGVuZXJ9XG4gICAgICogICBSZXR1cm4gdGhpcyBpbnN0YW5jZSBvZiB0aGlzIEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBwdXJwb3NlIG9mIGNoYWluaW5nLlxuICAgICAqL1xuICAgIGxpc3RlbigpIHtcbiAgICAgIGlmICghdGhpcy5jYWxsYmFjayAmJiAoIXRoaXMuYXV0b0xpc3RlbiB8fCB0aGlzLmxpc3RlbmVycy5zaXplKCkpKSB7XG4gICAgICAgIHRoaXMuY2FsbGJhY2sgPSAodGhpcy5kZWJvdW5jZSAmJiB0aGlzLmRlYm91bmNlID4gMCAmJiBkZWJvdW5jZSlcbiAgICAgICAgICA/IGRlYm91bmNlKHRoaXMuX3J1bi5iaW5kKHRoaXMpLCB0aGlzLmRlYm91bmNlKSA6IHRoaXMuX3J1bi5iaW5kKHRoaXMpO1xuXG4gICAgICAgIHRoaXMuZWxlbS5hZGRFdmVudExpc3RlbmVyKHRoaXMuZXZlbnQsIHRoaXMuY2FsbGJhY2ssIHRoaXMuZXZlbnRPcHRzKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFN0b3AgbGlzdGVuaW5nIGZvciB0aGlzIGV2ZW50LCBhbmQgdW5yZWdpc3RlciBmcm9tIGFueSBldmVudCBsaXN0ZW5lcnMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHtEcnVwYWwuVG9vbHNoZWQuRXZlbnRMaXN0ZW5lcn1cbiAgICAgKiAgIFJldHVybiB0aGlzIGluc3RhbmNlIG9mIHRoaXMgRXZlbnRMaXN0ZW5lciBmb3IgdGhlIHB1cnBvc2Ugb2YgY2hhaW5pbmcuXG4gICAgICovXG4gICAgaWdub3JlKCkge1xuICAgICAgaWYgKHRoaXMuY2FsbGJhY2spIHtcbiAgICAgICAgdGhpcy5lbGVtLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5ldmVudCwgdGhpcy5jYWxsYmFjayk7XG4gICAgICAgIGRlbGV0ZSB0aGlzLmNhbGxiYWNrO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSWYgdGhlcmUgaXMgYSB2YWxpZCBhdFBvcywgcGxhY2UgdGhlIGxpc3RlbmVyIGF0IHRoaXMgcG9zaXRpb24sXG4gICAgICogb3RoZXJ3aXNlLCBqdXN0IGFkZCBpdCB0byB0aGUgZW5kIG9mIHRoZSBsaXN0LiBUaGlzIGFsbG93cyBzb21lXG4gICAgICogZmxleGliaWxpdHkgdG8gcGxhY2UgbGlzdGVuZXJzIGF0IHRoZSBzdGFydCBvZiB0aGUgbGlzdCwgb3JcbiAgICAgKiBiZWZvcmUgb3RoZXIgbGlzdGVuZXJzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3R9IGxpc3RlbmVyXG4gICAgICogICBBIGxpc3RlbmVyIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBhIG1ldGhvZCAnb24nICsgW3RoaXMuZXZlbnROYW1lXS5cbiAgICAgKiBAcGFyYW0ge2ludH0gYXRQb3NcbiAgICAgKiAgIEluZGV4IHRvIGFkZCB0aGUgbGlzdGVuZXIgYXQuIFRoaXMgYWxsb3dzIGxpc3RlbmVycyB0byBiZSBydW4gaW5cbiAgICAgKiAgIGEgZGlmZmVyZW50IG9yZGVyIHRoYW4gdGhleSBtYXliZSByZWdpc3RlcmVkIGluLlxuICAgICAqXG4gICAgICogQHJldHVybiB7RHJ1cGFsLlRvb2xzaGVkLkV2ZW50TGlzdGVuZXJ9XG4gICAgICogICBSZXR1cm4gdGhpcyBpbnN0YW5jZSBvZiB0aGlzIEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBwdXJwb3NlIG9mIGNoYWluaW5nLlxuICAgICAqL1xuICAgIGFkZChsaXN0ZW5lciwgYXRQb3MpIHtcbiAgICAgIHRoaXMubGlzdGVuZXJzLmFkZChsaXN0ZW5lciwgYXRQb3MpO1xuXG4gICAgICBpZiAodGhpcy5hdXRvTGlzdGVuKSB0aGlzLmxpc3RlbigpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkIGEgbmV3IGxpc3RlbmVyIGJlZm9yZSBhbiBleGlzdGluZyBsaXN0ZW5lciBhbHJlYWR5IGluIHRoZSBsaXN0LlxuICAgICAqIElmIFtiZWZvcmVdIGlzIG51bGwsIHRoZW4gaW5zZXJ0IGF0IHRoZSBzdGFydCBvZiB0aGUgbGlzdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7QXJyYXl8ZnVuY3Rpb259IGxpc3RlbmVyXG4gICAgICogICBBIGxpc3RlbmVyIG9iamVjdCB0aGF0IGNvbnRhaW5zIHRoZSBhIG1ldGhvZCAnb24nICsgW3RoaXMuZXZlbnROYW1lXS5cbiAgICAgKiBAcGFyYW0ge0FycmF5fGZ1bmN0aW9ufSBiZWZvcmVcbiAgICAgKiAgIExpc3RlbmVyIG9iamVjdCB0aGF0IGlzIHVzZWQgdG8gcG9zaXRpb24gdGhlIG5ldyBsaXN0ZW5lci5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge0RydXBhbC5Ub29sc2hlZC5FdmVudExpc3RlbmVyfVxuICAgICAqICAgUmV0dXJuIHRoaXMgaW5zdGFuY2Ugb2YgdGhpcyBFdmVudExpc3RlbmVyIGZvciB0aGUgcHVycG9zZSBvZiBjaGFpbmluZy5cbiAgICAgKi9cbiAgICBhZGRCZWZvcmUobGlzdGVuZXIsIGJlZm9yZSkge1xuICAgICAgY29uc3QgcG9zID0gKGJlZm9yZSkgPyB0aGlzLmxpc3RlbmVycy5pbmRleE9mKGJlZm9yZSkgOiAwO1xuICAgICAgcmV0dXJuIHRoaXMuYWRkKGxpc3RlbmVyLCBwb3MgPCAwID8gMCA6IHBvcyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQWRkIGEgbmV3IGxpc3RlbmVyIGFmdGVyIGFuIGV4aXN0aW5nIGxpc3RlbmVyIGFscmVhZHkgaW4gdGhlIGxpc3QuXG4gICAgICogSWYgW2FmdGVyXSBpcyBudWxsLCB0aGVuIGluc2VydCBhdCB0aGUgZW5kIG9mIHRoZSBsaXN0LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtBcnJheXxmdW5jdGlvbn0gbGlzdGVuZXJcbiAgICAgKiAgQSBsaXN0ZW5lciBvYmplY3QgdGhhdCByZXByZXNlbnRzIGEgY2FsbGFibGUuXG4gICAgICogQHBhcmFtIHtBcnJheXxmdW5jdGlvbn0gYWZ0ZXJcbiAgICAgKiAgTGlzdGVuZXIgb2JqZWN0IHRoYXQgaXMgdXNlZCB0byBwb3NpdGlvbiB0aGUgbmV3IGxpc3RlbmVyLlxuICAgICAqXG4gICAgICogQHJldHVybiB7RHJ1cGFsLlRvb2xzaGVkLkV2ZW50TGlzdGVuZXJ9XG4gICAgICogICBSZXR1cm4gdGhpcyBpbnN0YW5jZSBvZiB0aGlzIEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBwdXJwb3NlIG9mIGNoYWluaW5nLlxuICAgICAqL1xuICAgIGFkZEFmdGVyKGxpc3RlbmVyLCBhZnRlcikge1xuICAgICAgbGV0IHBvcyA9IG51bGw7XG5cbiAgICAgIGlmIChhZnRlcikge1xuICAgICAgICBwb3MgPSB0aGlzLmxpc3RlbmVycy5pbmRleE9mKGFmdGVyKTtcbiAgICAgICAgcG9zID0gcG9zID49IDAgPyBwb3MgKyAxIDogLTE7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5hZGQobGlzdGVuZXIsIHBvcyk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlIHRoZSBzcGVjaWZpZWQgbGlzdGVuZXIgZnJvbSB0aGUgbGlzdCBvZiBldmVudCBsaXN0ZW5lcnMuXG4gICAgICogVGhpcyBhc3N1bWUgdGhlcmUgc2hvdWxkIG9ubHkgYmUgb25lIGVudHJ5IHBlcnQgY2FsbGJhY2suXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0FycmF5fGZ1bmN0aW9ufSBsaXN0ZW5lclxuICAgICAqICBBIGxpc3RlbmVyIG9iamVjdCB0aGF0IHJlcXVlc3RzIHRvIGdldCByZW1vdmVkLlxuICAgICAqXG4gICAgICogQHJldHVybiB7RHJ1cGFsLlRvb2xzaGVkLkV2ZW50TGlzdGVuZXJ9XG4gICAgICogICBSZXR1cm4gdGhpcyBpbnN0YW5jZSBvZiB0aGlzIEV2ZW50TGlzdGVuZXIgZm9yIHRoZSBwdXJwb3NlIG9mIGNoYWluaW5nLlxuICAgICAqL1xuICAgIHJlbW92ZShsaXN0ZW5lcikge1xuICAgICAgdGhpcy5saXN0ZW5lcnMucmVtb3ZlKGxpc3RlbmVyKTtcblxuICAgICAgLy8gSWYgdGhlcmUgYXJlIG5vIGxpc3RlbmVycyBhbmQgdGhlIGF1dG9MaXN0ZW4gb3B0aW9uIGlzIG9uLCB0dXJuIG9mZlxuICAgICAgLy8gbGlzdGVuaW5nLiBUaGlzIHByZXZlbnRzIHRoZSBldmVudCBmcm9tIGJlaW5nIGNhbGxlZCBmb3Igbm8gcmVhc29uLlxuICAgICAgaWYgKHRoaXMuYXV0b0xpc3RlbiAmJiAhdGhpcy5saXN0ZW5lcnMuc2l6ZSgpKSB0aGlzLmlnbm9yZSgpO1xuICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQ2xlYW4tdXAgZXZlbnRzIGFuZCBkYXRhLlxuICAgICAqL1xuICAgIGRlc3Ryb3koKSB7XG4gICAgICB0aGlzLmlnbm9yZSgpO1xuICAgIH1cbiAgfTtcblxuICAvKipcbiAgICogRXZlbnQgbGlzdGVuZXIgZm9yIG1lZGlhIHF1ZXJ5IGxpc3RlbmVycy5cbiAgICovXG4gIHRzLk1lZGlhUXVlcnlMaXN0ZW5lciA9IGNsYXNzIHtcbiAgICAvKipcbiAgICAgKiBDb25zdHJ1Y3RzIGEgbmV3IE1lZGlhIFF1ZXJ5IGxpc3RlbmVyIGluc3RhbmNlLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtPYmplY3RbXX0gYnJlYWtwb2ludHNcbiAgICAgKiAgIEFuIGFycmF5IG9mIGJyZWFrcG9pbnRzIGluIHRoZSBvcmRlciB0aGV5IHNob3VsZCBiZSBjaGVja2VkLiBFYWNoXG4gICAgICogICBicmVha3BvaW50IG9iamVjdCBpcyBleHBlY3RlZCB0byBoYXZlIGFuIGBtcWAsIGBpbnZlcnRlZGAgYW5kIGBldmVudGBcbiAgICAgKiAgIHByb3BlcnR5IHdoaWNoIGhlbHAgZGV0ZXJtaW5lIHdoYXQgZXZlbnQgdG8gY2FsbCB3aGVuIGEgTWVkaWEgUXVlcnlcbiAgICAgKiAgIGxpc3RlbmVyIHRyaWdnZXJzLlxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKGJyZWFrcG9pbnRzKSB7XG4gICAgICB0aGlzLm1vZGUgPSBudWxsO1xuICAgICAgdGhpcy5jdXJCcCA9IG51bGw7XG4gICAgICB0aGlzLmJwcyA9IG5ldyBNYXAoKTtcbiAgICAgIHRoaXMuYWxpYXNlcyA9IG5ldyBNYXAoKTtcblxuICAgICAgYnJlYWtwb2ludHMuZm9yRWFjaCgoYnApID0+IHtcbiAgICAgICAgY29uc3QgbXFsID0gd2luZG93Lm1hdGNoTWVkaWEoYnAubWVkaWFRdWVyeSk7XG5cbiAgICAgICAgaWYgKGJwLmV2ZW50ICYmICF0aGlzLmFsaWFzZXMuaGFzKGJwLmV2ZW50KSkge1xuICAgICAgICAgIHRoaXMuYWxpYXNlcy5zZXQoYnAuZXZlbnQsIHtcbiAgICAgICAgICAgIG9uOiBuZXcgQ2FsbExpc3QoKSxcbiAgICAgICAgICAgIG9mZjogbmV3IENhbGxMaXN0KCksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmJwcy5zZXQoYnAuaWQsIHtcbiAgICAgICAgICBxdWVyeTogbXFsLFxuICAgICAgICAgIG1vZGU6IGJwLmV2ZW50IHx8IG51bGwsXG4gICAgICAgICAgaW52ZXJ0ZWQ6IGJwLmludmVydGVkIHx8IGZhbHNlLFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEFsdGVyIHRoZSBjdXJyZW50IGJyZWFrcG9pbnQsIGFuZCB0cmlnZ2VyIHRoZSByZWxhdGVkIGV2ZW50cy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBuZXdCcFxuICAgICAqICAgVGhlIElEIG9mIHRoZSBicmVha3BvaW50IHRvIHRyaWdnZXIuXG4gICAgICovXG4gICAgX2NoYW5nZU1vZGUobmV3QnApIHtcbiAgICAgIGxldCBuZXdNb2RlID0gbnVsbDtcblxuICAgICAgLy8gSWYgdGhlIG1vZGUgY2hhbmdlZCwgdHJpZ2dlciB0aGUgYXBwcm9wcmlhdGUgYWN0aW9uLlxuICAgICAgaWYgKG5ld0JwID09PSB0aGlzLmN1ckJwKSByZXR1cm47XG5cbiAgICAgIGlmICh0aGlzLmN1ckJwKSB7XG4gICAgICAgIGNvbnN0IG9mZkxpc3QgPSB0aGlzLmJwcy5nZXQodGhpcy5jdXJCcCk7XG4gICAgICAgIGlmIChvZmZMaXN0ICYmIG9mZkxpc3Qub2ZmKSBvZmZMaXN0Lm9mZi5jYWxsKHRoaXMuY3VyQnAsICdvZmYnKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5jdXJCcCA9IG5ld0JwO1xuICAgICAgaWYgKG5ld0JwKSB7XG4gICAgICAgIGNvbnN0IG9uTGlzdCA9IHRoaXMuYnBzLmdldChuZXdCcCk7XG5cbiAgICAgICAgaWYgKG9uTGlzdCkge1xuICAgICAgICAgIG5ld01vZGUgPSBvbkxpc3QubW9kZTtcbiAgICAgICAgICBpZiAob25MaXN0Lm9uKSBvbkxpc3Qub24uY2FsbCh0aGlzLmN1ckJwLCAnb24nKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAobmV3TW9kZSAhPT0gdGhpcy5tb2RlKSB7XG4gICAgICAgIGlmICh0aGlzLm1vZGUpIHtcbiAgICAgICAgICBjb25zdCBvZmZNb2RlID0gdGhpcy5hbGlhc2VzLmdldCh0aGlzLm1vZGUpO1xuICAgICAgICAgIGlmIChvZmZNb2RlKSBvZmZNb2RlLm9mZi5jYWxsKHRoaXMubW9kZSwgJ29mZicpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5tb2RlID0gbmV3TW9kZTtcbiAgICAgICAgaWYgKG5ld01vZGUpIHtcbiAgICAgICAgICBjb25zdCBvbk1vZGUgPSB0aGlzLmFsaWFzZXMuZ2V0KG5ld01vZGUpO1xuICAgICAgICAgIGlmIChvbk1vZGUpIG9uTW9kZS5vbi5jYWxsKHRoaXMubW9kZSwgJ29uJyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayB0aGUgcmVnaXN0ZXJlZCBicmVha3BvaW50cyBpbiBvcmRlciB0byBzZWUgd2hpY2ggb25lIGlzIGFjdGl2ZS5cbiAgICAgKlxuICAgICAqIEByZXR1cm4ge3N0cmluZ3xudWxsfVxuICAgICAqICAgVGhlIHF1ZXJ5IG1hcHBlZCBldmVudCBpZiBhIG1hdGNoaW5nIGJyZWFrcG9pbnQgaXMgZm91bmQsIG90aGVyd2lzZVxuICAgICAqICAgcmV0dXJuIG51bGwgdG8gbWVhbiBubyBldmVudC5cbiAgICAgKi9cbiAgICBjaGVja0JyZWFrcG9pbnRzKCkge1xuICAgICAgY29uc3QgYnBzID0gQXJyYXkuZnJvbSh0aGlzLmJwcy5lbnRyaWVzKCkpO1xuXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGJwcy5sZW5ndGg7ICsraSkge1xuICAgICAgICBjb25zdCBbaWQsIGJwXSA9IGJwc1tpXTtcblxuICAgICAgICBpZiAoIWJwLnF1ZXJ5Lm1hdGNoZXMgIT09ICFicC5pbnZlcnRlZCkge1xuICAgICAgICAgIHJldHVybiBpZDtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBBZGQgYSBuZXcgbGlzdGVuZXIgdG8gYSBicmVha3BvaW50IG9yIG1vZGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge3N0cmluZ30gYnBJZFxuICAgICAqICAgVGhlIElEIG9mIHRoZSBicmVha3BvaW50IHRvIHdhdGNoIGZvciwgb3IgdGhlIG1lZGlhIHF1ZXJ5IGV2ZW50IHRvXG4gICAgICogICBhdHRhY2ggdGhlIGxpc3RlbmVyIGNhbGxhYmxlIHRvLlxuICAgICAqIEBwYXJhbSB7W3R5cGVdfSBsaXN0ZW5lclxuICAgICAqICAgVGhlIGNhbGxhYmxlIGNhbGxiYWNrIHRvIGdldCBjYWxsZWQgd2hlbiB0aGUgYnJlYWtwb2ludCBtYXRjaGVzIHRoZVxuICAgICAqICAgYWN0aW9uIHNwZWNpZmllZCAoZWl0aGVyIG9uIG9yIG9mZikuXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvblxuICAgICAqICAgRWl0aGVyICdvbicgb3IgJ29mZicgdG8gaW5kaWNhdGVkIG9mIHRoZSBjYWxsYmFjayBzaG91bGQgYmUgY2FsbGVkXG4gICAgICogICB3aGVuIHRoZSBtZWRpYSBxdWVyeSBpcyBhY3RpdmUgb3IgZGVhY3RpdmF0ZWQgcmVzcGVjdGl2ZWx5LlxuICAgICAqXG4gICAgICogQHJldHVybiB7T2JqZWN0fVxuICAgICAqICAgVGhlIGN1cnJlbnQgaW5zdGFuY2Ugb2YgdGhlIE1lZGlhUXVlcnlMaXN0ZW5lciwgYW5kIHRoZSBcInRoaXNcIiBvYmplY3QuXG4gICAgICovXG4gICAgYWRkKGJwSWQsIGxpc3RlbmVyLCBhY3Rpb24gPSAnb24nKSB7XG4gICAgICBpZiAoYWN0aW9uID09PSAnb24nIHx8IGFjdGlvbiA9PT0gJ29mZicpIHtcbiAgICAgICAgbGV0IHRhcmdldDtcbiAgICAgICAgbGV0IGN1clN0YXRlO1xuXG4gICAgICAgIGlmICh0aGlzLmFsaWFzZXMuaGFzKGJwSWQpKSB7XG4gICAgICAgICAgdGFyZ2V0ID0gdGhpcy5hbGlhc2VzLmdldChicElkKTtcbiAgICAgICAgICBjdXJTdGF0ZSA9IHRoaXMubW9kZTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLmJwcy5oYXMoYnBJZCkpIHtcbiAgICAgICAgICB0YXJnZXQgPSB0aGlzLmJwcy5nZXQoYnBJZCk7XG4gICAgICAgICAgY3VyU3RhdGUgPSB0aGlzLmN1ckJwO1xuXG4gICAgICAgICAgaWYgKCF0YXJnZXRbYWN0aW9uXSkgdGFyZ2V0W2FjdGlvbl0gPSBuZXcgQ2FsbExpc3QoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEVycm9yIGFkZGluZyAke2JwSWR9IHdpdGggYWN0aW9uICR7YWN0aW9ufWApO1xuICAgICAgICB9XG5cbiAgICAgICAgdGFyZ2V0W2FjdGlvbl0uYWRkKGxpc3RlbmVyKTtcbiAgICAgICAgLy8gVHJpZ2dlciAnb24nIGV2ZW50IHdoZW4gbGlzdGVuZXIgaXMgYWRkZWQgaWYgY3VycmVudCBzdGF0ZSBtYXRjaGVzXG4gICAgICAgIC8vIHNjcmVlbiBzaXplcyB0YXJnZXRlZCBieSBhZGRlZCBsaXN0ZW5lci5cbiAgICAgICAgaWYgKGN1clN0YXRlID09PSBicElkICYmIGFjdGlvbiA9PT0gJ29uJykge1xuICAgICAgICAgIENhbGxMaXN0LmNhbGxJdGVtKGxpc3RlbmVyLCBicElkLCAnb24nKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUcmlnZ2VyICdvZmYnIGV2ZW50IHdoZW4gbGlzdGVuZXIgaXMgYWRkZWQgaWYgY3VycmVudCBzdGF0ZSBkb2VzIG5vdFxuICAgICAgICAvLyBtYXRjaCBzY3JlZW4gc2l6ZXMgdGFyZ2V0ZWQgYnkgYWRkZWQgbGlzdGVuZXIuXG4gICAgICAgIGVsc2UgaWYgKGN1clN0YXRlICE9PSBicElkICYmIGFjdGlvbiA9PT0gJ29mZicpIHtcbiAgICAgICAgICBDYWxsTGlzdC5jYWxsSXRlbShsaXN0ZW5lciwgYnBJZCwgJ29mZicpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIExpc3RlbiBmb3IgY2hhbmdlcyBvZiB0aGUgcmVnaXN0ZXJlZCBicmVha3BvaW50cy5cbiAgICAgKi9cbiAgICBsaXN0ZW4oKSB7XG4gICAgICBsZXQgY3VycmVudDtcblxuICAgICAgdGhpcy5icHMuZm9yRWFjaCgoYnAsIGlkKSA9PiB7XG4gICAgICAgIGlmICghYnAuY2FsbGJhY2spIHtcbiAgICAgICAgICBicC5jYWxsYmFjayA9ICgobXFsKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBtb2RlID0gKCFtcWwubWF0Y2hlcyAhPT0gIWJwLmludmVydGVkKSA/IGlkIDogdGhpcy5jaGVja0JyZWFrcG9pbnRzKCk7XG4gICAgICAgICAgICB0aGlzLl9jaGFuZ2VNb2RlKG1vZGUpO1xuICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgYnAucXVlcnkuYWRkTGlzdGVuZXIoYnAuY2FsbGJhY2spO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU3RvcCB1cGRhdGluZyB0aGlzIGFmdGVyIHRoZSBmaXJzdCBicmVha3BvaW50IHRvIHRyaWdnZXIuXG4gICAgICAgIGlmICghY3VycmVudCAmJiAoIWJwLnF1ZXJ5Lm1hdGNoZXMgIT09ICFicC5pbnZlcnRlZCkpIHtcbiAgICAgICAgICBjdXJyZW50ID0gaWQ7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICB0aGlzLl9jaGFuZ2VNb2RlKGN1cnJlbnQpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVucmVnaXN0ZXIgYWxsIG1lZGlhIHF1ZXJ5IGxpc3RlbmVycywgYW5kIGlnbm9yZSBhbGwgYnJlYWtwb2ludCBldmVudHMuXG4gICAgICovXG4gICAgaWdub3JlKCkge1xuICAgICAgdGhpcy5icHMuZm9yRWFjaCgoaWQsIGJwKSA9PiB7XG4gICAgICAgIGlmIChicC5jYWxsYmFjaykge1xuICAgICAgICAgIGJwLnF1ZXJ5LnJlbW92ZUxpc3RlbmVyKGJwLmNhbGxiYWNrKTtcbiAgICAgICAgICBkZWxldGUgYnAuY2FsbGJhY2s7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cbiAgfTtcbn0pKERydXBhbCk7XG4iXSwibWFwcGluZ3MiOiI7O0FBQUEsQ0FBQyxDQUFDO0VBQUVBLFFBQVEsRUFBRUMsRUFBRTtFQUFFQztBQUFTLENBQUMsS0FBSztFQUMvQjtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0VBQ0UsTUFBTUMsUUFBUSxDQUFDO0lBQ2I7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0lBQ0ksT0FBT0MsVUFBVSxDQUFDQyxRQUFRLEVBQUU7TUFDMUIsSUFBSUMsR0FBRyxHQUFHLElBQUk7TUFDZCxJQUFJQyxJQUFJLEdBQUdGLFFBQVE7TUFFbkIsSUFBSUEsUUFBUSxZQUFZRyxLQUFLLEVBQUU7UUFDN0IsQ0FBQ0YsR0FBRyxFQUFFQyxJQUFJLENBQUMsR0FBR0YsUUFBUTtNQUN4QjtNQUVBLE9BQVEsT0FBT0UsSUFBSSxLQUFLLFVBQVUsS0FBTSxDQUFDRCxHQUFHLElBQUlBLEdBQUcsWUFBWUcsTUFBTSxDQUFDO0lBQ3hFOztJQUVBO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7SUFD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
