saij
Version:
A learning engine.
310 lines (258 loc) • 28.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.bindListener = bindListener;
exports.findListener = findListener;
exports.getListeners = getListeners;
exports.listen = listen;
exports.listenOnce = listenOnce;
exports.unlisten = unlisten;
exports.unlistenByKey = unlistenByKey;
exports.unlistenAll = unlistenAll;
var _object = require("./object.js");
/**
* @module saij/core/utils/events
*/
/* eslint max-len: 0 */
/* eslint no-use-before-define: 0 */
/**
* Key to use with {@link module:saij/core/Observable~Observable#unByKey}.
* @typedef {Object} EventsKey
* @property {Object} [bindTo]
* @property {module:saij/core/utils/events~ListenerFunction} [boundListener]
* @property {boolean} callOnce
* @property {number} [deleteIndex]
* @property {module:saij/core/utils/events~ListenerFunction} listener
* @property {module:saij/core/Target~EventTargetLike} target
* @property {string} type
* @api
*/
/**
* Listener function. This function is called with an event object as argument.
* When the function returns `false`, event propagation will stop.
*
* @typedef {function(module:saij/core/Event)|function(module:saij/core/Event): boolean} ListenerFunction
* @api
*/
/**
* @param {module:saij/core/utils/events~EventsKey} listenerObj Listener object.
* @return {module:saij/core/utils/events~ListenerFunction} Bound listener.
*/
function bindListener(listenerObj) {
const boundListener = evt => {
const listener = listenerObj.listener;
const bindTo = listenerObj.bindTo || listenerObj.target;
if (listenerObj.callOnce) {
unlistenByKey(listenerObj);
} // eslint-disable-next-line
return listener.call(bindTo, evt);
};
listenerObj.boundListener = boundListener;
return boundListener;
}
/**
* Finds the matching {@link module:saij/core/utils/events~EventsKey} in the given listener
* array.
*
* @param {!Array<!module:saij/core/utils/events~EventsKey>} listeners Array of listeners.
* @param {!Function} listener The listener function.
* @param {Object=} opt_this The `this` value inside the listener.
* @param {boolean=} opt_setDeleteIndex Set the deleteIndex on the matching
* listener, for {@link module:saij/core/utils/events~unlistenByKey}.
* @return {module:saij/core/utils/events~EventsKey|undefined} The matching listener object.
*/
function findListener(listeners, listener, opt_this, opt_setDeleteIndex) {
let listenerObj = null;
for (let i = 0, ii = listeners.length; i < ii; i += 1) {
listenerObj = listeners[i];
if (listenerObj.listener === listener && listenerObj.bindTo === opt_this) {
if (opt_setDeleteIndex) {
listenerObj.deleteIndex = i;
}
return listenerObj;
}
}
return undefined;
}
/**
* @param {module:saij/core/Target~EventTargetLike} target Target.
* @param {string} type Type.
* @return {Array<module:saij/core/utils/events~EventsKey>|undefined} Listeners.
*/
function getListeners(target, type) {
const listenerMap = target.saij_lm;
return listenerMap ? listenerMap[type] : undefined;
}
/**
* Get the lookup of listeners. If one does not exist on the target, it is
* created.
* @param {module:saij/core/Target~EventTargetLike} target Target.
* @return {!Object<string, Array<module:saij/core/utils/events~EventsKey>>} Map of
* listeners by event type.
*/
function getListenerMap(target) {
let listenerMap = target.saij_lm;
if (!listenerMap) {
listenerMap = target.saij_lm = {};
}
return listenerMap;
}
/**
* Clean up all listener objects of the given type. All properties on the
* listener objects will be removed, and if no listeners remain in the listener
* map, it will be removed from the target.
* @param {module:saij/core/Target~EventTargetLike} target Target.
* @param {string} type Type.
*/
// eslint-disable-next-line max-statements
function removeListeners(target, type) {
const listeners = getListeners(target, type);
/* istanbul ignore next */
if (listeners) {
for (let i = 0, ii = listeners.length; i < ii; i += 1) {
target.removeEventListener(type, listeners[i].boundListener);
(0, _object.clear)(listeners[i]);
}
listeners.length = 0;
const listenerMap = target.saij_lm;
/* istanbul ignore next */
if (listenerMap) {
Reflect.deleteProperty(listenerMap, type);
if (Object.keys(listenerMap).length === 0) {
// eslint-disable-next-line
delete target.saij_lm;
}
}
}
}
/**
* Registers an event listener on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* This function efficiently binds a `listener` to a `this` object, and returns
* a key for use with {@link module:saij/core/utils/events~unlistenByKey}.
*
* @param {module:saij/core/Target~EventTargetLike} target Event target.
* @param {string} type Event type.
* @param {module:saij/core/utils/events~ListenerFunction} listener Listener.
* @param {Object=} opt_this Object referenced by the `this` keyword in the
* listener. Default is the `target`.
* @param {boolean=} opt_once If true, add the listener as one-off listener.
* @return {module:saij/core/utils/events~EventsKey} Unique key for the listener.
*/
// eslint-disable-next-line max-params, max-statements
function listen(target, type, listener, opt_this, opt_once) {
const listenerMap = getListenerMap(target);
let listeners = listenerMap[type];
if (!listeners) {
listeners = listenerMap[type] = [];
}
let listenerObj = findListener(listeners, listener, opt_this, false);
if (listenerObj) {
if (!opt_once) {
// Turn one-off listener into a permanent one.
listenerObj.callOnce = false;
}
} else {
listenerObj =
/** @type {module:saij/core/utils/events~EventsKey} */
{
bindTo: opt_this,
callOnce: Boolean(opt_once),
listener,
target,
type
};
target.addEventListener(type, bindListener(listenerObj));
listeners.push(listenerObj);
}
return listenerObj;
}
/**
* Registers a one-off event listener on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* This function efficiently binds a `listener` as self-unregistering listener
* to a `this` object, and returns a key for use with
* {@link module:saij/core/utils/events~unlistenByKey} in case the listener needs to be
* unregistered before it is called.
*
* When {@link module:saij/core/utils/events~listen} is called with the same arguments after this
* function, the self-unregistering listener will be turned into a permanent
* listener.
*
* @param {module:saij/core/Target~EventTargetLike} target Event target.
* @param {string} type Event type.
* @param {module:saij/core/utils/events~ListenerFunction} listener Listener.
* @param {Object=} opt_this Object referenced by the `this` keyword in the
* listener. Default is the `target`.
* @return {module:saij/core/utils/events~EventsKey} Key for unlistenByKey.
*/
function listenOnce(target, type, listener, opt_this) {
return listen(target, type, listener, opt_this, true);
}
/**
* Unregisters an event listener on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* To return a listener, this function needs to be called with the exact same
* arguments that were used for a previous {@link module:saij/core/utils/events~listen} call.
*
* @param {module:saij/core/Target~EventTargetLike} target Event target.
* @param {string} type Event type.
* @param {module:saij/core/utils/events~ListenerFunction} listener Listener.
* @param {Object=} opt_this Object referenced by the `this` keyword in the
* listener. Default is the `target`.
*/
function unlisten(target, type, listener, opt_this) {
const listeners = getListeners(target, type);
if (listeners) {
const listenerObj = findListener(listeners, listener, opt_this, true);
/* istanbul ignore next */
if (listenerObj) {
unlistenByKey(listenerObj);
}
}
}
/**
* Unregisters event listeners on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* The argument passed to this function is the key returned from
* {@link module:saij/core/utils/events~listen} or {@link module:saij/core/utils/events~listenOnce}.
*
* @param {module:saij/core/utils/events~EventsKey} key The key.
*/
function unlistenByKey(key) {
/* istanbul ignore next */
if (key && key.target) {
key.target.removeEventListener(key.type, key.boundListener);
const listeners = getListeners(key.target, key.type);
if (listeners) {
const i = 'deleteIndex' in key ? key.deleteIndex : listeners.indexOf(key);
/* istanbul ignore next */
if (i !== -1) {
listeners.splice(i, 1);
}
/* istanbul ignore next */
if (listeners.length === 0) {
removeListeners(key.target, key.type);
}
}
(0, _object.clear)(key);
}
}
/**
* Unregisters all event listeners on an event target. Inspired by
* https://google.github.io/closure-library/api/source/closure/goog/events/events.js.src.html
*
* @param {module:saij/core/Target~EventTargetLike} target Target.
*/
function unlistenAll(target) {
const listenerMap = getListenerMap(target); // eslint-disable-next-line guard-for-in
for (const type in listenerMap) {
removeListeners(target, type);
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zYWlqL2NvcmUvdXRpbHMvZXZlbnRzLmpzIl0sIm5hbWVzIjpbImJpbmRMaXN0ZW5lciIsImxpc3RlbmVyT2JqIiwiYm91bmRMaXN0ZW5lciIsImV2dCIsImxpc3RlbmVyIiwiYmluZFRvIiwidGFyZ2V0IiwiY2FsbE9uY2UiLCJ1bmxpc3RlbkJ5S2V5IiwiY2FsbCIsImZpbmRMaXN0ZW5lciIsImxpc3RlbmVycyIsIm9wdF90aGlzIiwib3B0X3NldERlbGV0ZUluZGV4IiwiaSIsImlpIiwibGVuZ3RoIiwiZGVsZXRlSW5kZXgiLCJ1bmRlZmluZWQiLCJnZXRMaXN0ZW5lcnMiLCJ0eXBlIiwibGlzdGVuZXJNYXAiLCJzYWlqX2xtIiwiZ2V0TGlzdGVuZXJNYXAiLCJyZW1vdmVMaXN0ZW5lcnMiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiUmVmbGVjdCIsImRlbGV0ZVByb3BlcnR5IiwiT2JqZWN0Iiwia2V5cyIsImxpc3RlbiIsIm9wdF9vbmNlIiwiQm9vbGVhbiIsImFkZEV2ZW50TGlzdGVuZXIiLCJwdXNoIiwibGlzdGVuT25jZSIsInVubGlzdGVuIiwia2V5IiwiaW5kZXhPZiIsInNwbGljZSIsInVubGlzdGVuQWxsIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztBQUdBOztBQUhBOzs7O0FBS0E7O0FBQ0E7O0FBR0E7Ozs7Ozs7Ozs7Ozs7QUFjQTs7Ozs7Ozs7QUFTQTs7OztBQUlPLFNBQVNBLFlBQVQsQ0FBc0JDLFdBQXRCLEVBQW1DO0FBQ3hDLFFBQU1DLGFBQWEsR0FBSUMsR0FBRCxJQUFRO0FBQzVCLFVBQU1DLFFBQVEsR0FBR0gsV0FBVyxDQUFDRyxRQUE3QjtBQUNBLFVBQU1DLE1BQU0sR0FBR0osV0FBVyxDQUFDSSxNQUFaLElBQXNCSixXQUFXLENBQUNLLE1BQWpEOztBQUNBLFFBQUlMLFdBQVcsQ0FBQ00sUUFBaEIsRUFBMEI7QUFDeEJDLE1BQUFBLGFBQWEsQ0FBQ1AsV0FBRCxDQUFiO0FBQ0QsS0FMMkIs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Q0FBQ2pCLElBQWpCLENBQWY7QUFDRDtBQUNGOztBQUNELHVCQUFNaUIsR0FBTjtBQUNEO0FBQ0Y7QUFHRDs7Ozs7Ozs7QUFNTyxTQUFTRyxXQUFULENBQXFCbEMsTUFBckIsRUFBNkI7QUFDbEMsUUFBTWUsV0FBVyxHQUFHRSxjQUFjLENBQUNqQixNQUFELENBQWxDLENBRGtDLENBRWxDOztBQUNBLE9BQUssTUFBTWMsSUFBWCxJQUFtQkMsV0FBbkIsRUFBZ0M7QUFDOUJHLElBQUFBLGVBQWUsQ0FBQ2xCLE1BQUQsRUFBU2MsSUFBVCxDQUFmO0FBQ0Q7QUFDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG1vZHVsZSBzYWlqL2NvcmUvdXRpbHMvZXZlbnRzXG4gKi9cbmltcG9ydCB7Y2xlYXJ9IGZyb20gJy4vb2JqZWN0LmpzJztcblxuLyogZXNsaW50IG1heC1sZW46IDAgKi9cbi8qIGVzbGludCBuby11c2UtYmVmb3JlLWRlZmluZTogMCAqL1xuXG5cbi8qKlxuICogS2V5IHRvIHVzZSB3aXRoIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL09ic2VydmFibGV+T2JzZXJ2YWJsZSN1bkJ5S2V5fS5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IEV2ZW50c0tleVxuICogQHByb3BlcnR5IHtPYmplY3R9IFtiaW5kVG9dXG4gKiBAcHJvcGVydHkge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IFtib3VuZExpc3RlbmVyXVxuICogQHByb3BlcnR5IHtib29sZWFufSBjYWxsT25jZVxuICogQHByb3BlcnR5IHtudW1iZXJ9IFtkZWxldGVJbmRleF1cbiAqIEBwcm9wZXJ0eSB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+TGlzdGVuZXJGdW5jdGlvbn0gbGlzdGVuZXJcbiAqIEBwcm9wZXJ0eSB7bW9kdWxlOnNhaWovY29yZS9UYXJnZXR+RXZlbnRUYXJnZXRMaWtlfSB0YXJnZXRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0eXBlXG4gKiBAYXBpXG4gKi9cblxuXG4vKipcbiAqIExpc3RlbmVyIGZ1bmN0aW9uLiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGFuIGV2ZW50IG9iamVjdCBhcyBhcmd1bWVudC5cbiAqIFdoZW4gdGhlIGZ1bmN0aW9uIHJldHVybnMgYGZhbHNlYCwgZXZlbnQgcHJvcGFnYXRpb24gd2lsbCBzdG9wLlxuICpcbiAqIEB0eXBlZGVmIHtmdW5jdGlvbihtb2R1bGU6c2Fpai9jb3JlL0V2ZW50KXxmdW5jdGlvbihtb2R1bGU6c2Fpai9jb3JlL0V2ZW50KTogYm9vbGVhbn0gTGlzdGVuZXJGdW5jdGlvblxuICogQGFwaVxuICovXG5cblxuLyoqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gbGlzdGVuZXJPYmogTGlzdGVuZXIgb2JqZWN0LlxuICogQHJldHVybiB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+TGlzdGVuZXJGdW5jdGlvbn0gQm91bmQgbGlzdGVuZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiaW5kTGlzdGVuZXIobGlzdGVuZXJPYmopIHtcbiAgY29uc3QgYm91bmRMaXN0ZW5lciA9IChldnQpPT4ge1xuICAgIGNvbnN0IGxpc3RlbmVyID0gbGlzdGVuZXJPYmoubGlzdGVuZXI7XG4gICAgY29uc3QgYmluZFRvID0gbGlzdGVuZXJPYmouYmluZFRvIHx8IGxpc3RlbmVyT2JqLnRhcmdldDtcbiAgICBpZiAobGlzdGVuZXJPYmouY2FsbE9uY2UpIHtcbiAgICAgIHVubGlzdGVuQnlLZXkobGlzdGVuZXJPYmopO1xuICAgIH1cblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgIHJldHVybiBsaXN0ZW5lci5jYWxsKGJpbmRUbywgZXZ0KTtcbiAgfTtcbiAgbGlzdGVuZXJPYmouYm91bmRMaXN0ZW5lciA9IGJvdW5kTGlzdGVuZXI7XG4gIHJldHVybiBib3VuZExpc3RlbmVyO1xufVxuXG5cbi8qKlxuICogRmluZHMgdGhlIG1hdGNoaW5nIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35FdmVudHNLZXl9IGluIHRoZSBnaXZlbiBsaXN0ZW5lclxuICogYXJyYXkuXG4gKlxuICogQHBhcmFtIHshQXJyYXk8IW1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleT59IGxpc3RlbmVycyBBcnJheSBvZiBsaXN0ZW5lcnMuXG4gKiBAcGFyYW0geyFGdW5jdGlvbn0gbGlzdGVuZXIgVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBUaGUgYHRoaXNgIHZhbHVlIGluc2lkZSB0aGUgbGlzdGVuZXIuXG4gKiBAcGFyYW0ge2Jvb2xlYW49fSBvcHRfc2V0RGVsZXRlSW5kZXggU2V0IHRoZSBkZWxldGVJbmRleCBvbiB0aGUgbWF0Y2hpbmdcbiAqICAgICBsaXN0ZW5lciwgZm9yIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fS5cbiAqIEByZXR1cm4ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleXx1bmRlZmluZWR9IFRoZSBtYXRjaGluZyBsaXN0ZW5lciBvYmplY3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kTGlzdGVuZXIobGlzdGVuZXJzLCBsaXN0ZW5lciwgb3B0X3RoaXMsIG9wdF9zZXREZWxldGVJbmRleCkge1xuICBsZXQgbGlzdGVuZXJPYmogPSBudWxsO1xuICBmb3IgKGxldCBpID0gMCwgaWkgPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgaWk7IGkgKz0gMSkge1xuICAgIGxpc3RlbmVyT2JqID0gbGlzdGVuZXJzW2ldO1xuICAgIGlmIChsaXN0ZW5lck9iai5saXN0ZW5lciA9PT0gbGlzdGVuZXIgJiZcbiAgICAgICAgbGlzdGVuZXJPYmouYmluZFRvID09PSBvcHRfdGhpcykge1xuICAgICAgaWYgKG9wdF9zZXREZWxldGVJbmRleCkge1xuICAgICAgICBsaXN0ZW5lck9iai5kZWxldGVJbmRleCA9IGk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGlzdGVuZXJPYmo7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIFR5cGUuXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35FdmVudHNLZXk+fHVuZGVmaW5lZH0gTGlzdGVuZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TGlzdGVuZXJzKHRhcmdldCwgdHlwZSkge1xuICBjb25zdCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICByZXR1cm4gbGlzdGVuZXJNYXAgPyBsaXN0ZW5lck1hcFt0eXBlXSA6IHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIEdldCB0aGUgbG9va3VwIG9mIGxpc3RlbmVycy4gIElmIG9uZSBkb2VzIG5vdCBleGlzdCBvbiB0aGUgdGFyZ2V0LCBpdCBpc1xuICogY3JlYXRlZC5cbiAqIEBwYXJhbSB7bW9kdWxlOnNhaWovY29yZS9UYXJnZXR+RXZlbnRUYXJnZXRMaWtlfSB0YXJnZXQgVGFyZ2V0LlxuICogQHJldHVybiB7IU9iamVjdDxzdHJpbmcsIEFycmF5PG1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleT4+fSBNYXAgb2ZcbiAqICAgICBsaXN0ZW5lcnMgYnkgZXZlbnQgdHlwZS5cbiAqL1xuZnVuY3Rpb24gZ2V0TGlzdGVuZXJNYXAodGFyZ2V0KSB7XG4gIGxldCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICBpZiAoIWxpc3RlbmVyTWFwKSB7XG4gICAgbGlzdGVuZXJNYXAgPSB0YXJnZXQuc2Fpal9sbSA9IHt9O1xuICB9XG4gIHJldHVybiBsaXN0ZW5lck1hcDtcbn1cblxuXG4vKipcbiAqIENsZWFuIHVwIGFsbCBsaXN0ZW5lciBvYmplY3RzIG9mIHRoZSBnaXZlbiB0eXBlLiAgQWxsIHByb3BlcnRpZXMgb24gdGhlXG4gKiBsaXN0ZW5lciBvYmplY3RzIHdpbGwgYmUgcmVtb3ZlZCwgYW5kIGlmIG5vIGxpc3RlbmVycyByZW1haW4gaW4gdGhlIGxpc3RlbmVyXG4gKiBtYXAsIGl0IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSB0YXJnZXQuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIFR5cGUuXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtc3RhdGVtZW50c1xuZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXJzKHRhcmdldCwgdHlwZSkge1xuICBjb25zdCBsaXN0ZW5lcnMgPSBnZXRMaXN0ZW5lcnModGFyZ2V0LCB0eXBlKTtcbiAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgaWYgKGxpc3RlbmVycykge1xuICAgIGZvciAobGV0IGkgPSAwLCBpaSA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBpaTsgaSArPSAxKSB7XG4gICAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbaV0uYm91bmRMaXN0ZW5lcik7XG4gICAgICBjbGVhcihsaXN0ZW5lcnNbaV0pO1xuICAgIH1cbiAgICBsaXN0ZW5lcnMubGVuZ3RoID0gMDtcbiAgICBjb25zdCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgaWYgKGxpc3RlbmVyTWFwKSB7XG4gICAgICBSZWZsZWN0LmRlbGV0ZVByb3BlcnR5KGxpc3RlbmVyTWFwLCB0eXBlKTtcbiAgICAgIGlmIChPYmplY3Qua2V5cyhsaXN0ZW5lck1hcCkubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgICAgICBkZWxldGUgdGFyZ2V0LnNhaWpfbG07XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgb24gYW4gZXZlbnQgdGFyZ2V0LiBJbnNwaXJlZCBieVxuICogaHR0cHM6Ly9nb29nbGUuZ2l0aHViLmlvL2Nsb3N1cmUtbGlicmFyeS9hcGkvc291cmNlL2Nsb3N1cmUvZ29vZy9ldmVudHMvZXZlbnRzLmpzLnNyYy5odG1sXG4gKlxuICogVGhpcyBmdW5jdGlvbiBlZmZpY2llbnRseSBiaW5kcyBhIGBsaXN0ZW5lcmAgdG8gYSBgdGhpc2Agb2JqZWN0LCBhbmQgcmV0dXJuc1xuICogYSBrZXkgZm9yIHVzZSB3aXRoIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fS5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IEV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIEV2ZW50IHR5cGUuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IGxpc3RlbmVyIExpc3RlbmVyLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBPYmplY3QgcmVmZXJlbmNlZCBieSB0aGUgYHRoaXNgIGtleXdvcmQgaW4gdGhlXG4gKiAgICAgbGlzdGVuZXIuIERlZmF1bHQgaXMgdGhlIGB0YXJnZXRgLlxuICogQHBhcmFtIHtib29sZWFuPX0gb3B0X29uY2UgSWYgdHJ1ZSwgYWRkIHRoZSBsaXN0ZW5lciBhcyBvbmUtb2ZmIGxpc3RlbmVyLlxuICogQHJldHVybiB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+RXZlbnRzS2V5fSBVbmlxdWUga2V5IGZvciB0aGUgbGlzdGVuZXIuXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtcGFyYW1zLCBtYXgtc3RhdGVtZW50c1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3Rlbih0YXJnZXQsIHR5cGUsIGxpc3RlbmVyLCBvcHRfdGhpcywgb3B0X29uY2UpIHtcbiAgY29uc3QgbGlzdGVuZXJNYXAgPSBnZXRMaXN0ZW5lck1hcCh0YXJnZXQpO1xuICBsZXQgbGlzdGVuZXJzID0gbGlzdGVuZXJNYXBbdHlwZV07XG4gIGlmICghbGlzdGVuZXJzKSB7XG4gICAgbGlzdGVuZXJzID0gbGlzdGVuZXJNYXBbdHlwZV0gPSBbXTtcbiAgfVxuICBsZXQgbGlzdGVuZXJPYmogPSBmaW5kTGlzdGVuZXIobGlzdGVuZXJzLCBsaXN0ZW5lciwgb3B0X3RoaXMsIGZhbHNlKTtcbiAgaWYgKGxpc3RlbmVyT2JqKSB7XG4gICAgaWYgKCFvcHRfb25jZSkge1xuICAgICAgLy8gVHVybiBvbmUtb2ZmIGxpc3RlbmVyIGludG8gYSBwZXJtYW5lbnQgb25lLlxuICAgICAgbGlzdGVuZXJPYmouY2FsbE9uY2UgPSBmYWxzZTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgbGlzdGVuZXJPYmogPSAvKiogQHR5cGUge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gKi8gKHtcbiAgICAgIGJpbmRUbzogb3B0X3RoaXMsXG4gICAgICBjYWxsT25jZTogQm9vbGVhbihvcHRfb25jZSksXG4gICAgICBsaXN0ZW5lcixcbiAgICAgIHRhcmdldCxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBiaW5kTGlzdGVuZXIobGlzdGVuZXJPYmopKTtcbiAgICBsaXN0ZW5lcnMucHVzaChsaXN0ZW5lck9iaik7XG4gIH1cblxuICByZXR1cm4gbGlzdGVuZXJPYmo7XG59XG5cblxuLyoqXG4gKiBSZWdpc3RlcnMgYSBvbmUtb2ZmIGV2ZW50IGxpc3RlbmVyIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRoaXMgZnVuY3Rpb24gZWZmaWNpZW50bHkgYmluZHMgYSBgbGlzdGVuZXJgIGFzIHNlbGYtdW5yZWdpc3RlcmluZyBsaXN0ZW5lclxuICogdG8gYSBgdGhpc2Agb2JqZWN0LCBhbmQgcmV0dXJucyBhIGtleSBmb3IgdXNlIHdpdGhcbiAqIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fSBpbiBjYXNlIHRoZSBsaXN0ZW5lciBuZWVkcyB0byBiZVxuICogdW5yZWdpc3RlcmVkIGJlZm9yZSBpdCBpcyBjYWxsZWQuXG4gKlxuICogV2hlbiB7QGxpbmsgbW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+bGlzdGVufSBpcyBjYWxsZWQgd2l0aCB0aGUgc2FtZSBhcmd1bWVudHMgYWZ0ZXIgdGhpc1xuICogZnVuY3Rpb24sIHRoZSBzZWxmLXVucmVnaXN0ZXJpbmcgbGlzdGVuZXIgd2lsbCBiZSB0dXJuZWQgaW50byBhIHBlcm1hbmVudFxuICogbGlzdGVuZXIuXG4gKlxuICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL1RhcmdldH5FdmVudFRhcmdldExpa2V9IHRhcmdldCBFdmVudCB0YXJnZXQuXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSBFdmVudCB0eXBlLlxuICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35MaXN0ZW5lckZ1bmN0aW9ufSBsaXN0ZW5lciBMaXN0ZW5lci5cbiAqIEBwYXJhbSB7T2JqZWN0PX0gb3B0X3RoaXMgT2JqZWN0IHJlZmVyZW5jZWQgYnkgdGhlIGB0aGlzYCBrZXl3b3JkIGluIHRoZVxuICogICAgIGxpc3RlbmVyLiBEZWZhdWx0IGlzIHRoZSBgdGFyZ2V0YC5cbiAqIEByZXR1cm4ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gS2V5IGZvciB1bmxpc3RlbkJ5S2V5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdGVuT25jZSh0YXJnZXQsIHR5cGUsIGxpc3RlbmVyLCBvcHRfdGhpcykge1xuICByZXR1cm4gbGlzdGVuKHRhcmdldCwgdHlwZSwgbGlzdGVuZXIsIG9wdF90aGlzLCB0cnVlKTtcbn1cblxuXG4vKipcbiAqIFVucmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRvIHJldHVybiBhIGxpc3RlbmVyLCB0aGlzIGZ1bmN0aW9uIG5lZWRzIHRvIGJlIGNhbGxlZCB3aXRoIHRoZSBleGFjdCBzYW1lXG4gKiBhcmd1bWVudHMgdGhhdCB3ZXJlIHVzZWQgZm9yIGEgcHJldmlvdXMge0BsaW5rIG1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfmxpc3Rlbn0gY2FsbC5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IEV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIEV2ZW50IHR5cGUuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IGxpc3RlbmVyIExpc3RlbmVyLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBPYmplY3QgcmVmZXJlbmNlZCBieSB0aGUgYHRoaXNgIGtleXdvcmQgaW4gdGhlXG4gKiAgICAgbGlzdGVuZXIuIERlZmF1bHQgaXMgdGhlIGB0YXJnZXRgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5saXN0ZW4odGFyZ2V0LCB0eXBlLCBsaXN0ZW5lciwgb3B0X3RoaXMpIHtcbiAgY29uc3QgbGlzdGVuZXJzID0gZ2V0TGlzdGVuZXJzKHRhcmdldCwgdHlwZSk7XG4gIGlmIChsaXN0ZW5lcnMpIHtcbiAgICBjb25zdCBsaXN0ZW5lck9iaiA9IGZpbmRMaXN0ZW5lcihsaXN0ZW5lcnMsIGxpc3RlbmVyLCBvcHRfdGhpcywgdHJ1ZSk7XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICBpZiAobGlzdGVuZXJPYmopIHtcbiAgICAgIHVubGlzdGVuQnlLZXkobGlzdGVuZXJPYmopO1xuICAgIH1cbiAgfVxufVxuXG5cbi8qKlxuICogVW5yZWdpc3RlcnMgZXZlbnQgbGlzdGVuZXJzIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRoZSBhcmd1bWVudCBwYXNzZWQgdG8gdGhpcyBmdW5jdGlvbiBpcyB0aGUga2V5IHJldHVybmVkIGZyb21cbiAqIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35saXN0ZW59IG9yIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35saXN0ZW5PbmNlfS5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0ga2V5IFRoZSBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmxpc3RlbkJ5S2V5KGtleSkge1xuICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICBpZiAoa2V5ICYmIGtleS50YXJnZXQpIHtcbiAgICBrZXkudGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoa2V5LnR5cGUsIGtleS5ib3VuZExpc3RlbmVyKTtcbiAgICBjb25zdCBsaXN0ZW5lcnMgPSBnZXRMaXN0ZW5lcnMoa2V5LnRhcmdldCwga2V5LnR5cGUpO1xuICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgIGNvbnN0IGkgPSAnZGVsZXRlSW5kZXgnIGluIGtleSA/IGtleS5kZWxldGVJbmRleCA6IGxpc3RlbmVycy5pbmRleE9mKGtleSk7XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgIGxpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICB9XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgaWYgKGxpc3RlbmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmVtb3ZlTGlzdGVuZXJzKGtleS50YXJnZXQsIGtleS50eXBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgY2xlYXIoa2V5KTtcbiAgfVxufVxuXG5cbi8qKlxuICogVW5yZWdpc3RlcnMgYWxsIGV2ZW50IGxpc3RlbmVycyBvbiBhbiBldmVudCB0YXJnZXQuIEluc3BpcmVkIGJ5XG4gKiBodHRwczovL2dvb2dsZS5naXRodWIuaW8vY2xvc3VyZS1saWJyYXJ5L2FwaS9zb3VyY2UvY2xvc3VyZS9nb29nL2V2ZW50cy9ldmVudHMuanMuc3JjLmh0bWxcbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVubGlzdGVuQWxsKHRhcmdldCkge1xuICBjb25zdCBsaXN0ZW5lck1hcCA9IGdldExpc3RlbmVyTWFwKHRhcmdldCk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBndWFyZC1mb3ItaW5cbiAgZm9yIChjb25zdCB0eXBlIGluIGxpc3RlbmVyTWFwKSB7XG4gICAgcmVtb3ZlTGlzdGVuZXJzKHRhcmdldCwgdHlwZSk7XG4gIH1cbn1cbiJdfQ==