UNPKG

saij

Version:
310 lines (258 loc) 28.7 kB
"use strict"; 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9zYWlqL2NvcmUvdXRpbHMvZXZlbnRzLmpzIl0sIm5hbWVzIjpbImJpbmRMaXN0ZW5lciIsImxpc3RlbmVyT2JqIiwiYm91bmRMaXN0ZW5lciIsImV2dCIsImxpc3RlbmVyIiwiYmluZFRvIiwidGFyZ2V0IiwiY2FsbE9uY2UiLCJ1bmxpc3RlbkJ5S2V5IiwiY2FsbCIsImZpbmRMaXN0ZW5lciIsImxpc3RlbmVycyIsIm9wdF90aGlzIiwib3B0X3NldERlbGV0ZUluZGV4IiwiaSIsImlpIiwibGVuZ3RoIiwiZGVsZXRlSW5kZXgiLCJ1bmRlZmluZWQiLCJnZXRMaXN0ZW5lcnMiLCJ0eXBlIiwibGlzdGVuZXJNYXAiLCJzYWlqX2xtIiwiZ2V0TGlzdGVuZXJNYXAiLCJyZW1vdmVMaXN0ZW5lcnMiLCJyZW1vdmVFdmVudExpc3RlbmVyIiwiUmVmbGVjdCIsImRlbGV0ZVByb3BlcnR5IiwiT2JqZWN0Iiwia2V5cyIsImxpc3RlbiIsIm9wdF9vbmNlIiwiQm9vbGVhbiIsImFkZEV2ZW50TGlzdGVuZXIiLCJwdXNoIiwibGlzdGVuT25jZSIsInVubGlzdGVuIiwia2V5IiwiaW5kZXhPZiIsInNwbGljZSIsInVubGlzdGVuQWxsIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7OztBQUdBOztBQUhBOzs7O0FBS0E7O0FBQ0E7O0FBR0E7Ozs7Ozs7Ozs7Ozs7QUFjQTs7Ozs7Ozs7QUFTQTs7OztBQUlPLFNBQVNBLFlBQVQsQ0FBc0JDLFdBQXRCLEVBQW1DO0FBQ3hDLFFBQU1DLGFBQWEsR0FBSUMsR0FBRCxJQUFRO0FBQzVCLFVBQU1DLFFBQVEsR0FBR0gsV0FBVyxDQUFDRyxRQUE3QjtBQUNBLFVBQU1DLE1BQU0sR0FBR0osV0FBVyxDQUFDSSxNQUFaLElBQXNCSixXQUFXLENBQUNLLE1BQWpEOztBQUNBLFFBQUlMLFdBQVcsQ0FBQ00sUUFBaEIsRUFBMEI7QUFDeEJDLE1BQUFBLGFBQWEsQ0FBQ1AsV0FBRCxDQUFiO0FBQ0QsS0FMMkIsQ0FPNUI7OztBQUNBLFdBQU9HLFFBQVEsQ0FBQ0ssSUFBVCxDQUFjSixNQUFkLEVBQXNCRixHQUF0QixDQUFQO0FBQ0QsR0FURDs7QUFVQUYsRUFBQUEsV0FBVyxDQUFDQyxhQUFaLEdBQTRCQSxhQUE1QjtBQUNBLFNBQU9BLGFBQVA7QUFDRDtBQUdEOzs7Ozs7Ozs7Ozs7O0FBV08sU0FBU1EsWUFBVCxDQUFzQkMsU0FBdEIsRUFBaUNQLFFBQWpDLEVBQTJDUSxRQUEzQyxFQUFxREMsa0JBQXJELEVBQXlFO0FBQzlFLE1BQUlaLFdBQVcsR0FBRyxJQUFsQjs7QUFDQSxPQUFLLElBQUlhLENBQUMsR0FBRyxDQUFSLEVBQVdDLEVBQUUsR0FBR0osU0FBUyxDQUFDSyxNQUEvQixFQUF1Q0YsQ0FBQyxHQUFHQyxFQUEzQyxFQUErQ0QsQ0FBQyxJQUFJLENBQXBELEVBQXVEO0FBQ3JEYixJQUFBQSxXQUFXLEdBQUdVLFNBQVMsQ0FBQ0csQ0FBRCxDQUF2Qjs7QUFDQSxRQUFJYixXQUFXLENBQUNHLFFBQVosS0FBeUJBLFFBQXpCLElBQ0FILFdBQVcsQ0FBQ0ksTUFBWixLQUF1Qk8sUUFEM0IsRUFDcUM7QUFDbkMsVUFBSUMsa0JBQUosRUFBd0I7QUFDdEJaLFFBQUFBLFdBQVcsQ0FBQ2dCLFdBQVosR0FBMEJILENBQTFCO0FBQ0Q7O0FBQ0QsYUFBT2IsV0FBUDtBQUNEO0FBQ0Y7O0FBQ0QsU0FBT2lCLFNBQVA7QUFDRDtBQUdEOzs7Ozs7O0FBS08sU0FBU0MsWUFBVCxDQUFzQmIsTUFBdEIsRUFBOEJjLElBQTlCLEVBQW9DO0FBQ3pDLFFBQU1DLFdBQVcsR0FBR2YsTUFBTSxDQUFDZ0IsT0FBM0I7QUFDQSxTQUFPRCxXQUFXLEdBQUdBLFdBQVcsQ0FBQ0QsSUFBRCxDQUFkLEdBQXVCRixTQUF6QztBQUNEO0FBR0Q7Ozs7Ozs7OztBQU9BLFNBQVNLLGNBQVQsQ0FBd0JqQixNQUF4QixFQUFnQztBQUM5QixNQUFJZSxXQUFXLEdBQUdmLE1BQU0sQ0FBQ2dCLE9BQXpCOztBQUNBLE1BQUksQ0FBQ0QsV0FBTCxFQUFrQjtBQUNoQkEsSUFBQUEsV0FBVyxHQUFHZixNQUFNLENBQUNnQixPQUFQLEdBQWlCLEVBQS9CO0FBQ0Q7O0FBQ0QsU0FBT0QsV0FBUDtBQUNEO0FBR0Q7Ozs7Ozs7QUFPQTs7O0FBQ0EsU0FBU0csZUFBVCxDQUF5QmxCLE1BQXpCLEVBQWlDYyxJQUFqQyxFQUF1QztBQUNyQyxRQUFNVCxTQUFTLEdBQUdRLFlBQVksQ0FBQ2IsTUFBRCxFQUFTYyxJQUFULENBQTlCO0FBQ0E7O0FBQ0EsTUFBSVQsU0FBSixFQUFlO0FBQ2IsU0FBSyxJQUFJRyxDQUFDLEdBQUcsQ0FBUixFQUFXQyxFQUFFLEdBQUdKLFNBQVMsQ0FBQ0ssTUFBL0IsRUFBdUNGLENBQUMsR0FBR0MsRUFBM0MsRUFBK0NELENBQUMsSUFBSSxDQUFwRCxFQUF1RDtBQUNyRFIsTUFBQUEsTUFBTSxDQUFDbUIsbUJBQVAsQ0FBMkJMLElBQTNCLEVBQWlDVCxTQUFTLENBQUNHLENBQUQsQ0FBVCxDQUFhWixhQUE5QztBQUNBLHlCQUFNUyxTQUFTLENBQUNHLENBQUQsQ0FBZjtBQUNEOztBQUNESCxJQUFBQSxTQUFTLENBQUNLLE1BQVYsR0FBbUIsQ0FBbkI7QUFDQSxVQUFNSyxXQUFXLEdBQUdmLE1BQU0sQ0FBQ2dCLE9BQTNCO0FBQ0E7O0FBQ0EsUUFBSUQsV0FBSixFQUFpQjtBQUNmSyxNQUFBQSxPQUFPLENBQUNDLGNBQVIsQ0FBdUJOLFdBQXZCLEVBQW9DRCxJQUFwQzs7QUFDQSxVQUFJUSxNQUFNLENBQUNDLElBQVAsQ0FBWVIsV0FBWixFQUF5QkwsTUFBekIsS0FBb0MsQ0FBeEMsRUFBMkM7QUFDekM7QUFDQSxlQUFPVixNQUFNLENBQUNnQixPQUFkO0FBQ0Q7QUFDRjtBQUNGO0FBQ0Y7QUFHRDs7Ozs7Ozs7Ozs7Ozs7O0FBZUE7OztBQUNPLFNBQVNRLE1BQVQsQ0FBZ0J4QixNQUFoQixFQUF3QmMsSUFBeEIsRUFBOEJoQixRQUE5QixFQUF3Q1EsUUFBeEMsRUFBa0RtQixRQUFsRCxFQUE0RDtBQUNqRSxRQUFNVixXQUFXLEdBQUdFLGNBQWMsQ0FBQ2pCLE1BQUQsQ0FBbEM7QUFDQSxNQUFJSyxTQUFTLEdBQUdVLFdBQVcsQ0FBQ0QsSUFBRCxDQUEzQjs7QUFDQSxNQUFJLENBQUNULFNBQUwsRUFBZ0I7QUFDZEEsSUFBQUEsU0FBUyxHQUFHVSxXQUFXLENBQUNELElBQUQsQ0FBWCxHQUFvQixFQUFoQztBQUNEOztBQUNELE1BQUluQixXQUFXLEdBQUdTLFlBQVksQ0FBQ0MsU0FBRCxFQUFZUCxRQUFaLEVBQXNCUSxRQUF0QixFQUFnQyxLQUFoQyxDQUE5Qjs7QUFDQSxNQUFJWCxXQUFKLEVBQWlCO0FBQ2YsUUFBSSxDQUFDOEIsUUFBTCxFQUFlO0FBQ2I7QUFDQTlCLE1BQUFBLFdBQVcsQ0FBQ00sUUFBWixHQUF1QixLQUF2QjtBQUNEO0FBQ0YsR0FMRCxNQUtPO0FBQ0xOLElBQUFBLFdBQVc7QUFBRztBQUF3RDtBQUNwRUksTUFBQUEsTUFBTSxFQUFFTyxRQUQ0RDtBQUVwRUwsTUFBQUEsUUFBUSxFQUFFeUIsT0FBTyxDQUFDRCxRQUFELENBRm1EO0FBR3BFM0IsTUFBQUEsUUFIb0U7QUFJcEVFLE1BQUFBLE1BSm9FO0FBS3BFYyxNQUFBQTtBQUxvRSxLQUF0RTtBQU9BZCxJQUFBQSxNQUFNLENBQUMyQixnQkFBUCxDQUF3QmIsSUFBeEIsRUFBOEJwQixZQUFZLENBQUNDLFdBQUQsQ0FBMUM7QUFDQVUsSUFBQUEsU0FBUyxDQUFDdUIsSUFBVixDQUFlakMsV0FBZjtBQUNEOztBQUVELFNBQU9BLFdBQVA7QUFDRDtBQUdEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBb0JPLFNBQVNrQyxVQUFULENBQW9CN0IsTUFBcEIsRUFBNEJjLElBQTVCLEVBQWtDaEIsUUFBbEMsRUFBNENRLFFBQTVDLEVBQXNEO0FBQzNELFNBQU9rQixNQUFNLENBQUN4QixNQUFELEVBQVNjLElBQVQsRUFBZWhCLFFBQWYsRUFBeUJRLFFBQXpCLEVBQW1DLElBQW5DLENBQWI7QUFDRDtBQUdEOzs7Ozs7Ozs7Ozs7Ozs7QUFhTyxTQUFTd0IsUUFBVCxDQUFrQjlCLE1BQWxCLEVBQTBCYyxJQUExQixFQUFnQ2hCLFFBQWhDLEVBQTBDUSxRQUExQyxFQUFvRDtBQUN6RCxRQUFNRCxTQUFTLEdBQUdRLFlBQVksQ0FBQ2IsTUFBRCxFQUFTYyxJQUFULENBQTlCOztBQUNBLE1BQUlULFNBQUosRUFBZTtBQUNiLFVBQU1WLFdBQVcsR0FBR1MsWUFBWSxDQUFDQyxTQUFELEVBQVlQLFFBQVosRUFBc0JRLFFBQXRCLEVBQWdDLElBQWhDLENBQWhDO0FBQ0E7O0FBQ0EsUUFBSVgsV0FBSixFQUFpQjtBQUNmTyxNQUFBQSxhQUFhLENBQUNQLFdBQUQsQ0FBYjtBQUNEO0FBQ0Y7QUFDRjtBQUdEOzs7Ozs7Ozs7OztBQVNPLFNBQVNPLGFBQVQsQ0FBdUI2QixHQUF2QixFQUE0QjtBQUNqQztBQUNBLE1BQUlBLEdBQUcsSUFBSUEsR0FBRyxDQUFDL0IsTUFBZixFQUF1QjtBQUNyQitCLElBQUFBLEdBQUcsQ0FBQy9CLE1BQUosQ0FBV21CLG1CQUFYLENBQStCWSxHQUFHLENBQUNqQixJQUFuQyxFQUF5Q2lCLEdBQUcsQ0FBQ25DLGFBQTdDO0FBQ0EsVUFBTVMsU0FBUyxHQUFHUSxZQUFZLENBQUNrQixHQUFHLENBQUMvQixNQUFMLEVBQWErQixHQUFHLENBQUNqQixJQUFqQixDQUE5Qjs7QUFDQSxRQUFJVCxTQUFKLEVBQWU7QUFDYixZQUFNRyxDQUFDLEdBQUcsaUJBQWlCdUIsR0FBakIsR0FBdUJBLEdBQUcsQ0FBQ3BCLFdBQTNCLEdBQXlDTixTQUFTLENBQUMyQixPQUFWLENBQWtCRCxHQUFsQixDQUFuRDtBQUNBOztBQUNBLFVBQUl2QixDQUFDLEtBQUssQ0FBQyxDQUFYLEVBQWM7QUFDWkgsUUFBQUEsU0FBUyxDQUFDNEIsTUFBVixDQUFpQnpCLENBQWpCLEVBQW9CLENBQXBCO0FBQ0Q7QUFDRDs7O0FBQ0EsVUFBSUgsU0FBUyxDQUFDSyxNQUFWLEtBQXFCLENBQXpCLEVBQTRCO0FBQzFCUSxRQUFBQSxlQUFlLENBQUNhLEdBQUcsQ0FBQy9CLE1BQUwsRUFBYStCLEdBQUcsQ0FBQ2pCLElBQWpCLENBQWY7QUFDRDtBQUNGOztBQUNELHVCQUFNaUIsR0FBTjtBQUNEO0FBQ0Y7QUFHRDs7Ozs7Ozs7QUFNTyxTQUFTRyxXQUFULENBQXFCbEMsTUFBckIsRUFBNkI7QUFDbEMsUUFBTWUsV0FBVyxHQUFHRSxjQUFjLENBQUNqQixNQUFELENBQWxDLENBRGtDLENBRWxDOztBQUNBLE9BQUssTUFBTWMsSUFBWCxJQUFtQkMsV0FBbkIsRUFBZ0M7QUFDOUJHLElBQUFBLGVBQWUsQ0FBQ2xCLE1BQUQsRUFBU2MsSUFBVCxDQUFmO0FBQ0Q7QUFDRiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQG1vZHVsZSBzYWlqL2NvcmUvdXRpbHMvZXZlbnRzXG4gKi9cbmltcG9ydCB7Y2xlYXJ9IGZyb20gJy4vb2JqZWN0LmpzJztcblxuLyogZXNsaW50IG1heC1sZW46IDAgKi9cbi8qIGVzbGludCBuby11c2UtYmVmb3JlLWRlZmluZTogMCAqL1xuXG5cbi8qKlxuICogS2V5IHRvIHVzZSB3aXRoIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL09ic2VydmFibGV+T2JzZXJ2YWJsZSN1bkJ5S2V5fS5cbiAqIEB0eXBlZGVmIHtPYmplY3R9IEV2ZW50c0tleVxuICogQHByb3BlcnR5IHtPYmplY3R9IFtiaW5kVG9dXG4gKiBAcHJvcGVydHkge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IFtib3VuZExpc3RlbmVyXVxuICogQHByb3BlcnR5IHtib29sZWFufSBjYWxsT25jZVxuICogQHByb3BlcnR5IHtudW1iZXJ9IFtkZWxldGVJbmRleF1cbiAqIEBwcm9wZXJ0eSB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+TGlzdGVuZXJGdW5jdGlvbn0gbGlzdGVuZXJcbiAqIEBwcm9wZXJ0eSB7bW9kdWxlOnNhaWovY29yZS9UYXJnZXR+RXZlbnRUYXJnZXRMaWtlfSB0YXJnZXRcbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSB0eXBlXG4gKiBAYXBpXG4gKi9cblxuXG4vKipcbiAqIExpc3RlbmVyIGZ1bmN0aW9uLiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCB3aXRoIGFuIGV2ZW50IG9iamVjdCBhcyBhcmd1bWVudC5cbiAqIFdoZW4gdGhlIGZ1bmN0aW9uIHJldHVybnMgYGZhbHNlYCwgZXZlbnQgcHJvcGFnYXRpb24gd2lsbCBzdG9wLlxuICpcbiAqIEB0eXBlZGVmIHtmdW5jdGlvbihtb2R1bGU6c2Fpai9jb3JlL0V2ZW50KXxmdW5jdGlvbihtb2R1bGU6c2Fpai9jb3JlL0V2ZW50KTogYm9vbGVhbn0gTGlzdGVuZXJGdW5jdGlvblxuICogQGFwaVxuICovXG5cblxuLyoqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gbGlzdGVuZXJPYmogTGlzdGVuZXIgb2JqZWN0LlxuICogQHJldHVybiB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+TGlzdGVuZXJGdW5jdGlvbn0gQm91bmQgbGlzdGVuZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBiaW5kTGlzdGVuZXIobGlzdGVuZXJPYmopIHtcbiAgY29uc3QgYm91bmRMaXN0ZW5lciA9IChldnQpPT4ge1xuICAgIGNvbnN0IGxpc3RlbmVyID0gbGlzdGVuZXJPYmoubGlzdGVuZXI7XG4gICAgY29uc3QgYmluZFRvID0gbGlzdGVuZXJPYmouYmluZFRvIHx8IGxpc3RlbmVyT2JqLnRhcmdldDtcbiAgICBpZiAobGlzdGVuZXJPYmouY2FsbE9uY2UpIHtcbiAgICAgIHVubGlzdGVuQnlLZXkobGlzdGVuZXJPYmopO1xuICAgIH1cblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgIHJldHVybiBsaXN0ZW5lci5jYWxsKGJpbmRUbywgZXZ0KTtcbiAgfTtcbiAgbGlzdGVuZXJPYmouYm91bmRMaXN0ZW5lciA9IGJvdW5kTGlzdGVuZXI7XG4gIHJldHVybiBib3VuZExpc3RlbmVyO1xufVxuXG5cbi8qKlxuICogRmluZHMgdGhlIG1hdGNoaW5nIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35FdmVudHNLZXl9IGluIHRoZSBnaXZlbiBsaXN0ZW5lclxuICogYXJyYXkuXG4gKlxuICogQHBhcmFtIHshQXJyYXk8IW1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleT59IGxpc3RlbmVycyBBcnJheSBvZiBsaXN0ZW5lcnMuXG4gKiBAcGFyYW0geyFGdW5jdGlvbn0gbGlzdGVuZXIgVGhlIGxpc3RlbmVyIGZ1bmN0aW9uLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBUaGUgYHRoaXNgIHZhbHVlIGluc2lkZSB0aGUgbGlzdGVuZXIuXG4gKiBAcGFyYW0ge2Jvb2xlYW49fSBvcHRfc2V0RGVsZXRlSW5kZXggU2V0IHRoZSBkZWxldGVJbmRleCBvbiB0aGUgbWF0Y2hpbmdcbiAqICAgICBsaXN0ZW5lciwgZm9yIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fS5cbiAqIEByZXR1cm4ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleXx1bmRlZmluZWR9IFRoZSBtYXRjaGluZyBsaXN0ZW5lciBvYmplY3QuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBmaW5kTGlzdGVuZXIobGlzdGVuZXJzLCBsaXN0ZW5lciwgb3B0X3RoaXMsIG9wdF9zZXREZWxldGVJbmRleCkge1xuICBsZXQgbGlzdGVuZXJPYmogPSBudWxsO1xuICBmb3IgKGxldCBpID0gMCwgaWkgPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgaWk7IGkgKz0gMSkge1xuICAgIGxpc3RlbmVyT2JqID0gbGlzdGVuZXJzW2ldO1xuICAgIGlmIChsaXN0ZW5lck9iai5saXN0ZW5lciA9PT0gbGlzdGVuZXIgJiZcbiAgICAgICAgbGlzdGVuZXJPYmouYmluZFRvID09PSBvcHRfdGhpcykge1xuICAgICAgaWYgKG9wdF9zZXREZWxldGVJbmRleCkge1xuICAgICAgICBsaXN0ZW5lck9iai5kZWxldGVJbmRleCA9IGk7XG4gICAgICB9XG4gICAgICByZXR1cm4gbGlzdGVuZXJPYmo7XG4gICAgfVxuICB9XG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cblxuLyoqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIFR5cGUuXG4gKiBAcmV0dXJuIHtBcnJheTxtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35FdmVudHNLZXk+fHVuZGVmaW5lZH0gTGlzdGVuZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TGlzdGVuZXJzKHRhcmdldCwgdHlwZSkge1xuICBjb25zdCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICByZXR1cm4gbGlzdGVuZXJNYXAgPyBsaXN0ZW5lck1hcFt0eXBlXSA6IHVuZGVmaW5lZDtcbn1cblxuXG4vKipcbiAqIEdldCB0aGUgbG9va3VwIG9mIGxpc3RlbmVycy4gIElmIG9uZSBkb2VzIG5vdCBleGlzdCBvbiB0aGUgdGFyZ2V0LCBpdCBpc1xuICogY3JlYXRlZC5cbiAqIEBwYXJhbSB7bW9kdWxlOnNhaWovY29yZS9UYXJnZXR+RXZlbnRUYXJnZXRMaWtlfSB0YXJnZXQgVGFyZ2V0LlxuICogQHJldHVybiB7IU9iamVjdDxzdHJpbmcsIEFycmF5PG1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleT4+fSBNYXAgb2ZcbiAqICAgICBsaXN0ZW5lcnMgYnkgZXZlbnQgdHlwZS5cbiAqL1xuZnVuY3Rpb24gZ2V0TGlzdGVuZXJNYXAodGFyZ2V0KSB7XG4gIGxldCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICBpZiAoIWxpc3RlbmVyTWFwKSB7XG4gICAgbGlzdGVuZXJNYXAgPSB0YXJnZXQuc2Fpal9sbSA9IHt9O1xuICB9XG4gIHJldHVybiBsaXN0ZW5lck1hcDtcbn1cblxuXG4vKipcbiAqIENsZWFuIHVwIGFsbCBsaXN0ZW5lciBvYmplY3RzIG9mIHRoZSBnaXZlbiB0eXBlLiAgQWxsIHByb3BlcnRpZXMgb24gdGhlXG4gKiBsaXN0ZW5lciBvYmplY3RzIHdpbGwgYmUgcmVtb3ZlZCwgYW5kIGlmIG5vIGxpc3RlbmVycyByZW1haW4gaW4gdGhlIGxpc3RlbmVyXG4gKiBtYXAsIGl0IHdpbGwgYmUgcmVtb3ZlZCBmcm9tIHRoZSB0YXJnZXQuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIFR5cGUuXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtc3RhdGVtZW50c1xuZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXJzKHRhcmdldCwgdHlwZSkge1xuICBjb25zdCBsaXN0ZW5lcnMgPSBnZXRMaXN0ZW5lcnModGFyZ2V0LCB0eXBlKTtcbiAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgaWYgKGxpc3RlbmVycykge1xuICAgIGZvciAobGV0IGkgPSAwLCBpaSA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBpaTsgaSArPSAxKSB7XG4gICAgICB0YXJnZXQucmVtb3ZlRXZlbnRMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnNbaV0uYm91bmRMaXN0ZW5lcik7XG4gICAgICBjbGVhcihsaXN0ZW5lcnNbaV0pO1xuICAgIH1cbiAgICBsaXN0ZW5lcnMubGVuZ3RoID0gMDtcbiAgICBjb25zdCBsaXN0ZW5lck1hcCA9IHRhcmdldC5zYWlqX2xtO1xuICAgIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gICAgaWYgKGxpc3RlbmVyTWFwKSB7XG4gICAgICBSZWZsZWN0LmRlbGV0ZVByb3BlcnR5KGxpc3RlbmVyTWFwLCB0eXBlKTtcbiAgICAgIGlmIChPYmplY3Qua2V5cyhsaXN0ZW5lck1hcCkubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuICAgICAgICBkZWxldGUgdGFyZ2V0LnNhaWpfbG07XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cblxuLyoqXG4gKiBSZWdpc3RlcnMgYW4gZXZlbnQgbGlzdGVuZXIgb24gYW4gZXZlbnQgdGFyZ2V0LiBJbnNwaXJlZCBieVxuICogaHR0cHM6Ly9nb29nbGUuZ2l0aHViLmlvL2Nsb3N1cmUtbGlicmFyeS9hcGkvc291cmNlL2Nsb3N1cmUvZ29vZy9ldmVudHMvZXZlbnRzLmpzLnNyYy5odG1sXG4gKlxuICogVGhpcyBmdW5jdGlvbiBlZmZpY2llbnRseSBiaW5kcyBhIGBsaXN0ZW5lcmAgdG8gYSBgdGhpc2Agb2JqZWN0LCBhbmQgcmV0dXJuc1xuICogYSBrZXkgZm9yIHVzZSB3aXRoIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fS5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IEV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIEV2ZW50IHR5cGUuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IGxpc3RlbmVyIExpc3RlbmVyLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBPYmplY3QgcmVmZXJlbmNlZCBieSB0aGUgYHRoaXNgIGtleXdvcmQgaW4gdGhlXG4gKiAgICAgbGlzdGVuZXIuIERlZmF1bHQgaXMgdGhlIGB0YXJnZXRgLlxuICogQHBhcmFtIHtib29sZWFuPX0gb3B0X29uY2UgSWYgdHJ1ZSwgYWRkIHRoZSBsaXN0ZW5lciBhcyBvbmUtb2ZmIGxpc3RlbmVyLlxuICogQHJldHVybiB7bW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+RXZlbnRzS2V5fSBVbmlxdWUga2V5IGZvciB0aGUgbGlzdGVuZXIuXG4gKi9cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtcGFyYW1zLCBtYXgtc3RhdGVtZW50c1xuZXhwb3J0IGZ1bmN0aW9uIGxpc3Rlbih0YXJnZXQsIHR5cGUsIGxpc3RlbmVyLCBvcHRfdGhpcywgb3B0X29uY2UpIHtcbiAgY29uc3QgbGlzdGVuZXJNYXAgPSBnZXRMaXN0ZW5lck1hcCh0YXJnZXQpO1xuICBsZXQgbGlzdGVuZXJzID0gbGlzdGVuZXJNYXBbdHlwZV07XG4gIGlmICghbGlzdGVuZXJzKSB7XG4gICAgbGlzdGVuZXJzID0gbGlzdGVuZXJNYXBbdHlwZV0gPSBbXTtcbiAgfVxuICBsZXQgbGlzdGVuZXJPYmogPSBmaW5kTGlzdGVuZXIobGlzdGVuZXJzLCBsaXN0ZW5lciwgb3B0X3RoaXMsIGZhbHNlKTtcbiAgaWYgKGxpc3RlbmVyT2JqKSB7XG4gICAgaWYgKCFvcHRfb25jZSkge1xuICAgICAgLy8gVHVybiBvbmUtb2ZmIGxpc3RlbmVyIGludG8gYSBwZXJtYW5lbnQgb25lLlxuICAgICAgbGlzdGVuZXJPYmouY2FsbE9uY2UgPSBmYWxzZTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgbGlzdGVuZXJPYmogPSAvKiogQHR5cGUge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gKi8gKHtcbiAgICAgIGJpbmRUbzogb3B0X3RoaXMsXG4gICAgICBjYWxsT25jZTogQm9vbGVhbihvcHRfb25jZSksXG4gICAgICBsaXN0ZW5lcixcbiAgICAgIHRhcmdldCxcbiAgICAgIHR5cGVcbiAgICB9KTtcbiAgICB0YXJnZXQuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBiaW5kTGlzdGVuZXIobGlzdGVuZXJPYmopKTtcbiAgICBsaXN0ZW5lcnMucHVzaChsaXN0ZW5lck9iaik7XG4gIH1cblxuICByZXR1cm4gbGlzdGVuZXJPYmo7XG59XG5cblxuLyoqXG4gKiBSZWdpc3RlcnMgYSBvbmUtb2ZmIGV2ZW50IGxpc3RlbmVyIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRoaXMgZnVuY3Rpb24gZWZmaWNpZW50bHkgYmluZHMgYSBgbGlzdGVuZXJgIGFzIHNlbGYtdW5yZWdpc3RlcmluZyBsaXN0ZW5lclxuICogdG8gYSBgdGhpc2Agb2JqZWN0LCBhbmQgcmV0dXJucyBhIGtleSBmb3IgdXNlIHdpdGhcbiAqIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c351bmxpc3RlbkJ5S2V5fSBpbiBjYXNlIHRoZSBsaXN0ZW5lciBuZWVkcyB0byBiZVxuICogdW5yZWdpc3RlcmVkIGJlZm9yZSBpdCBpcyBjYWxsZWQuXG4gKlxuICogV2hlbiB7QGxpbmsgbW9kdWxlOnNhaWovY29yZS91dGlscy9ldmVudHN+bGlzdGVufSBpcyBjYWxsZWQgd2l0aCB0aGUgc2FtZSBhcmd1bWVudHMgYWZ0ZXIgdGhpc1xuICogZnVuY3Rpb24sIHRoZSBzZWxmLXVucmVnaXN0ZXJpbmcgbGlzdGVuZXIgd2lsbCBiZSB0dXJuZWQgaW50byBhIHBlcm1hbmVudFxuICogbGlzdGVuZXIuXG4gKlxuICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL1RhcmdldH5FdmVudFRhcmdldExpa2V9IHRhcmdldCBFdmVudCB0YXJnZXQuXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSBFdmVudCB0eXBlLlxuICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35MaXN0ZW5lckZ1bmN0aW9ufSBsaXN0ZW5lciBMaXN0ZW5lci5cbiAqIEBwYXJhbSB7T2JqZWN0PX0gb3B0X3RoaXMgT2JqZWN0IHJlZmVyZW5jZWQgYnkgdGhlIGB0aGlzYCBrZXl3b3JkIGluIHRoZVxuICogICAgIGxpc3RlbmVyLiBEZWZhdWx0IGlzIHRoZSBgdGFyZ2V0YC5cbiAqIEByZXR1cm4ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0gS2V5IGZvciB1bmxpc3RlbkJ5S2V5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGlzdGVuT25jZSh0YXJnZXQsIHR5cGUsIGxpc3RlbmVyLCBvcHRfdGhpcykge1xuICByZXR1cm4gbGlzdGVuKHRhcmdldCwgdHlwZSwgbGlzdGVuZXIsIG9wdF90aGlzLCB0cnVlKTtcbn1cblxuXG4vKipcbiAqIFVucmVnaXN0ZXJzIGFuIGV2ZW50IGxpc3RlbmVyIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRvIHJldHVybiBhIGxpc3RlbmVyLCB0aGlzIGZ1bmN0aW9uIG5lZWRzIHRvIGJlIGNhbGxlZCB3aXRoIHRoZSBleGFjdCBzYW1lXG4gKiBhcmd1bWVudHMgdGhhdCB3ZXJlIHVzZWQgZm9yIGEgcHJldmlvdXMge0BsaW5rIG1vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfmxpc3Rlbn0gY2FsbC5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IEV2ZW50IHRhcmdldC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIEV2ZW50IHR5cGUuXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkxpc3RlbmVyRnVuY3Rpb259IGxpc3RlbmVyIExpc3RlbmVyLlxuICogQHBhcmFtIHtPYmplY3Q9fSBvcHRfdGhpcyBPYmplY3QgcmVmZXJlbmNlZCBieSB0aGUgYHRoaXNgIGtleXdvcmQgaW4gdGhlXG4gKiAgICAgbGlzdGVuZXIuIERlZmF1bHQgaXMgdGhlIGB0YXJnZXRgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdW5saXN0ZW4odGFyZ2V0LCB0eXBlLCBsaXN0ZW5lciwgb3B0X3RoaXMpIHtcbiAgY29uc3QgbGlzdGVuZXJzID0gZ2V0TGlzdGVuZXJzKHRhcmdldCwgdHlwZSk7XG4gIGlmIChsaXN0ZW5lcnMpIHtcbiAgICBjb25zdCBsaXN0ZW5lck9iaiA9IGZpbmRMaXN0ZW5lcihsaXN0ZW5lcnMsIGxpc3RlbmVyLCBvcHRfdGhpcywgdHJ1ZSk7XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICBpZiAobGlzdGVuZXJPYmopIHtcbiAgICAgIHVubGlzdGVuQnlLZXkobGlzdGVuZXJPYmopO1xuICAgIH1cbiAgfVxufVxuXG5cbi8qKlxuICogVW5yZWdpc3RlcnMgZXZlbnQgbGlzdGVuZXJzIG9uIGFuIGV2ZW50IHRhcmdldC4gSW5zcGlyZWQgYnlcbiAqIGh0dHBzOi8vZ29vZ2xlLmdpdGh1Yi5pby9jbG9zdXJlLWxpYnJhcnkvYXBpL3NvdXJjZS9jbG9zdXJlL2dvb2cvZXZlbnRzL2V2ZW50cy5qcy5zcmMuaHRtbFxuICpcbiAqIFRoZSBhcmd1bWVudCBwYXNzZWQgdG8gdGhpcyBmdW5jdGlvbiBpcyB0aGUga2V5IHJldHVybmVkIGZyb21cbiAqIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35saXN0ZW59IG9yIHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL3V0aWxzL2V2ZW50c35saXN0ZW5PbmNlfS5cbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvdXRpbHMvZXZlbnRzfkV2ZW50c0tleX0ga2V5IFRoZSBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmxpc3RlbkJ5S2V5KGtleSkge1xuICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICBpZiAoa2V5ICYmIGtleS50YXJnZXQpIHtcbiAgICBrZXkudGFyZ2V0LnJlbW92ZUV2ZW50TGlzdGVuZXIoa2V5LnR5cGUsIGtleS5ib3VuZExpc3RlbmVyKTtcbiAgICBjb25zdCBsaXN0ZW5lcnMgPSBnZXRMaXN0ZW5lcnMoa2V5LnRhcmdldCwga2V5LnR5cGUpO1xuICAgIGlmIChsaXN0ZW5lcnMpIHtcbiAgICAgIGNvbnN0IGkgPSAnZGVsZXRlSW5kZXgnIGluIGtleSA/IGtleS5kZWxldGVJbmRleCA6IGxpc3RlbmVycy5pbmRleE9mKGtleSk7XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgaWYgKGkgIT09IC0xKSB7XG4gICAgICAgIGxpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICB9XG4gICAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgICAgaWYgKGxpc3RlbmVycy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmVtb3ZlTGlzdGVuZXJzKGtleS50YXJnZXQsIGtleS50eXBlKTtcbiAgICAgIH1cbiAgICB9XG4gICAgY2xlYXIoa2V5KTtcbiAgfVxufVxuXG5cbi8qKlxuICogVW5yZWdpc3RlcnMgYWxsIGV2ZW50IGxpc3RlbmVycyBvbiBhbiBldmVudCB0YXJnZXQuIEluc3BpcmVkIGJ5XG4gKiBodHRwczovL2dvb2dsZS5naXRodWIuaW8vY2xvc3VyZS1saWJyYXJ5L2FwaS9zb3VyY2UvY2xvc3VyZS9nb29nL2V2ZW50cy9ldmVudHMuanMuc3JjLmh0bWxcbiAqXG4gKiBAcGFyYW0ge21vZHVsZTpzYWlqL2NvcmUvVGFyZ2V0fkV2ZW50VGFyZ2V0TGlrZX0gdGFyZ2V0IFRhcmdldC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVubGlzdGVuQWxsKHRhcmdldCkge1xuICBjb25zdCBsaXN0ZW5lck1hcCA9IGdldExpc3RlbmVyTWFwKHRhcmdldCk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBndWFyZC1mb3ItaW5cbiAgZm9yIChjb25zdCB0eXBlIGluIGxpc3RlbmVyTWFwKSB7XG4gICAgcmVtb3ZlTGlzdGVuZXJzKHRhcmdldCwgdHlwZSk7XG4gIH1cbn1cbiJdfQ==