saij
Version:
A learning engine.
323 lines (263 loc) • 22.8 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.CollectionEvent = void 0;
var _Object = _interopRequireDefault(require("./Object"));
var _Event = _interopRequireDefault(require("./Event"));
var _AssertionError = _interopRequireDefault(require("./AssertionError"));
var _CollectionEventType = _interopRequireDefault(require("./CollectionEventType"));
var _Errors = _interopRequireDefault(require("./Errors"));
/**
* @module saij/core/Collection
*/
/* eslint max-len: 0 */
/**
* @enum {string}
* @private
*/
const Property = {
LENGTH: 'length'
};
/**
* @classdesc
* Events emitted by {@link module:saij/core/Collection~Collection} instances are instances of this
* type.
*/
class CollectionEvent extends _Event.default {
/**
* @param {module:saij/core/CollectionEventType} type Type.
* @param {*=} opt_element Element.
*/
constructor(type, opt_element) {
super(type);
/**
* The element that is added to or removed from the collection.
* @type {*}
* @api
*/
this.element = opt_element;
}
}
/**
* @typedef {Object} Options
* @property {boolean} [unique=false] Disallow the same item from being added to
* the collection twice.
*/
/**
* @classdesc
* An expanded version of standard JS Array, adding convenience methods for
* manipulation. Add and remove changes to the Collection trigger a Collection
* event. Note that this does not cover changes to the objects _within_ the
* Collection; they trigger events on the appropriate object, not on the
* Collection as a whole.
*
* @template T
* @api
*/
exports.CollectionEvent = CollectionEvent;
class Collection extends _Object.default {
/**
* @param {Array<T>=} opt_array Array.
* @param {module:saij/core/Collection~Options=} opt_options Collection options.
*/
constructor(opt_array, opt_options) {
super();
const options = opt_options || {};
/**
* @private
* @type {boolean}
*/
this.unique_ = Boolean(options.unique);
/**
* @private
* @type {!Array<T>}
*/
this.array_ = opt_array ? opt_array : [];
if (this.unique_) {
for (let i = 0, ii = this.array_.length; i < ii; i += 1) {
this.assertUnique_(this.array_[i], i);
}
}
this.updateLength_();
}
/**
* Remove all elements from the collection.
* @api
*/
clear() {
while (this.getLength() > 0) {
this.pop();
}
}
/**
* Add elements to the collection. This pushes each item in the provided array
* to the end of the collection.
* @param {!Array<T>} arr Array.
* @return {module:saij/core/Collection<T>} This collection.
* @api
*/
extend(arr) {
for (let i = 0, ii = arr.length; i < ii; i += 1) {
this.push(arr[i]);
}
return this;
}
/**
* Iterate over each element, calling the provided callback.
* @param {function(T, number, Array<T>): *} func The function to call
* for every element. This function takes 3 arguments (the element, the
* index and the array). The return value is ignored.
* @api
*/
forEach(func) {
const array = this.array_;
for (let i = 0, ii = array.length; i < ii; i += 1) {
func(array[i], i, array);
}
}
/**
* Get a reference to the underlying Array object. Warning: if the array
* is mutated, no events will be dispatched by the collection, and the
* collection's "length" property won't be in sync with the actual length
* of the array.
* @return {!Array<T>} Array.
* @api
*/
getArray() {
return this.array_;
}
/**
* Get the element at the provided index.
* @param {number} index Index.
* @return {T} Element.
* @api
*/
item(index) {
return this.array_[index];
}
/**
* Get the length of this collection.
* @return {number} The length of the array.
* @observable
* @api
*/
getLength() {
return (
/** @type {number} */
this.get(Property.LENGTH)
);
}
/**
* Insert an element at the provided index.
* @param {number} index Index.
* @param {T} elem Element.
* @api
*/
insertAt(index, elem) {
if (this.unique_) {
this.assertUnique_(elem);
}
this.array_.splice(index, 0, elem);
this.updateLength_();
this.dispatchEvent(new CollectionEvent(_CollectionEventType.default.ADD, elem));
}
/**
* Remove the last element of the collection and return it.
* Return `undefined` if the collection is empty.
* @return {T|undefined} Element.
* @api
*/
pop() {
return this.removeAt(this.getLength() - 1);
}
/**
* Insert the provided element at the end of the collection.
* @param {T} elem Element.
* @return {number} New length of the collection.
* @api
*/
push(elem) {
if (this.unique_) {
this.assertUnique_(elem);
}
const len = this.getLength();
this.insertAt(len, elem);
return this.getLength();
}
/**
* Remove the first occurrence of an element from the collection.
* @param {T} elem Element.
* @return {T|undefined} The removed element or undefined if none found.
* @api
*/
remove(elem) {
const arr = this.array_;
for (let i = 0, ii = arr.length; i < ii; i += 1) {
if (arr[i] === elem) {
return this.removeAt(i);
}
}
return undefined;
}
/**
* Remove the element at the provided index and return it.
* Return `undefined` if the collection does not contain this index.
* @param {number} index Index.
* @return {T|undefined} Value.
* @api
*/
removeAt(index) {
const prev = this.array_[index];
this.array_.splice(index, 1);
this.updateLength_();
this.dispatchEvent(new CollectionEvent(_CollectionEventType.default.REMOVE, prev));
return prev;
}
/**
* Set the element at the provided index.
* @param {number} index Index.
* @param {T} elem Element.
* @api
*/
// eslint-disable-next-line max-statements
setAt(index, elem) {
const len = this.getLength();
if (index < len) {
if (this.unique_) {
this.assertUnique_(elem, index);
}
const prev = this.array_[index];
this.array_[index] = elem;
this.dispatchEvent(new CollectionEvent(_CollectionEventType.default.REMOVE, prev));
this.dispatchEvent(new CollectionEvent(_CollectionEventType.default.ADD, elem));
} else {
for (let j = len; j < index; j += 1) {
this.insertAt(j, undefined);
}
this.insertAt(index, elem);
}
}
/**
* @private
*/
updateLength_() {
this.set(Property.LENGTH, this.array_.length);
}
/**
* @private
* @param {T} elem Element.
* @param {number=} opt_except Optional index to ignore.
*/
assertUnique_(elem, opt_except) {
for (let i = 0, ii = this.array_.length; i < ii; i += 1) {
if (this.array_[i] === elem && i !== opt_except) {
throw new _AssertionError.default(_Errors.default.ASSERT_UNIQUE.code);
}
}
}
}
var _default = Collection;
exports.default = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9zYWlqL2NvcmUvQ29sbGVjdGlvbi5qcyJdLCJuYW1lcyI6WyJQcm9wZXJ0eSIsIkxFTkdUSCIsIkNvbGxlY3Rpb25FdmVudCIsIkV2ZW50IiwiY29uc3RydWN0b3IiLCJ0eXBlIiwib3B0X2VsZW1lbnQiLCJlbGVtZW50IiwiQ29sbGVjdGlvbiIsIkJhc2VPYmplY3QiLCJvcHRfYXJyYXkiLCJvcHRfb3B0aW9ucyIsIm9wdGlvbnMiLCJ1bmlxdWVfIiwiQm9vbGVhbiIsInVuaXF1ZSIsImFycmF5XyIsImkiLCJpaSIsImxlbmd0aCIsImFzc2VydFVuaXF1ZV8iLCJ1cGRhdGVMZW5ndGhfIiwiY2xlYXIiLCJnZXRMZW5ndGgiLCJwb3AiLCJleHRlbmQiLCJhcnIiLCJwdXNoIiwiZm9yRWFjaCIsImZ1bmMiLCJhcnJheSIsImdldEFycmF5IiwiaXRlbSIsImluZGV4IiwiZ2V0IiwiaW5zZXJ0QXQiLCJlbGVtIiwic3BsaWNlIiwiZGlzcGF0Y2hFdmVudCIsIkNvbGxlY3Rpb25FdmVudFR5cGUiLCJBREQiLCJyZW1vdmVBdCIsImxlbiIsInJlbW92ZSIsInVuZGVmaW5lZCIsInByZXYiLCJSRU1PVkUiLCJzZXRBdCIsImoiLCJzZXQiLCJvcHRfZXhjZXB0IiwiQXNzZXJ0aW9uRXJyb3IiLCJFcnJvcnMiLCJBU1NFUlRfVU5JUVVFIiwiY29kZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7O0FBR0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBUEE7Ozs7QUFTQTs7QUFHQTs7OztBQUlBLE1BQU1BLFFBQVEsR0FBRztBQUNmQyxFQUFBQSxNQUFNLEVBQUU7QUFETyxDQUFqQjtBQUtBOzs7Ozs7QUFLTyxNQUFNQyxlQUFOLFNBQThCQyxjQUE5QixDQUFvQztBQUV6Qzs7OztBQUlBQyxFQUFBQSxXQUFXLENBQUNDLElBQUQsRUFBT0MsV0FBUCxFQUFvQjtBQUM3QixVQUFNRCxJQUFOO0FBRUE7Ozs7OztBQUtBLFNBQUtFLE9BQUwsR0FBZUQs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QyxFQUFpRDtBQUMvQyxjQUFNLElBQUlDLHVCQUFKLENBQW1CQyxnQkFBT0MsYUFBUCxDQUFxQkMsSUFBeEMsQ0FBTjtBQUNEO0FBQ0Y7QUFDRjs7QUE3TmlDOztlQWlPckI5QyxVIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbW9kdWxlIHNhaWovY29yZS9Db2xsZWN0aW9uXG4gKi9cbmltcG9ydCBCYXNlT2JqZWN0IGZyb20gJy4vT2JqZWN0JztcbmltcG9ydCBFdmVudCBmcm9tICcuL0V2ZW50JztcbmltcG9ydCBBc3NlcnRpb25FcnJvciBmcm9tICcuL0Fzc2VydGlvbkVycm9yJztcbmltcG9ydCBDb2xsZWN0aW9uRXZlbnRUeXBlIGZyb20gJy4vQ29sbGVjdGlvbkV2ZW50VHlwZSc7XG5pbXBvcnQgRXJyb3JzIGZyb20gJy4vRXJyb3JzJztcblxuLyogZXNsaW50IG1heC1sZW46IDAgKi9cblxuXG4vKipcbiAqIEBlbnVtIHtzdHJpbmd9XG4gKiBAcHJpdmF0ZVxuICovXG5jb25zdCBQcm9wZXJ0eSA9IHtcbiAgTEVOR1RIOiAnbGVuZ3RoJ1xufTtcblxuXG4vKipcbiAqIEBjbGFzc2Rlc2NcbiAqIEV2ZW50cyBlbWl0dGVkIGJ5IHtAbGluayBtb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb25+Q29sbGVjdGlvbn0gaW5zdGFuY2VzIGFyZSBpbnN0YW5jZXMgb2YgdGhpc1xuICogdHlwZS5cbiAqL1xuZXhwb3J0IGNsYXNzIENvbGxlY3Rpb25FdmVudCBleHRlbmRzIEV2ZW50IHtcblxuICAvKipcbiAgICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb25FdmVudFR5cGV9IHR5cGUgVHlwZS5cbiAgICogQHBhcmFtIHsqPX0gb3B0X2VsZW1lbnQgRWxlbWVudC5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHR5cGUsIG9wdF9lbGVtZW50KSB7XG4gICAgc3VwZXIodHlwZSk7XG5cbiAgICAvKipcbiAgICAgKiBUaGUgZWxlbWVudCB0aGF0IGlzIGFkZGVkIHRvIG9yIHJlbW92ZWQgZnJvbSB0aGUgY29sbGVjdGlvbi5cbiAgICAgKiBAdHlwZSB7Kn1cbiAgICAgKiBAYXBpXG4gICAgICovXG4gICAgdGhpcy5lbGVtZW50ID0gb3B0X2VsZW1lbnQ7XG4gIH1cbn1cblxuXG4vKipcbiAqIEB0eXBlZGVmIHtPYmplY3R9IE9wdGlvbnNcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbn0gW3VuaXF1ZT1mYWxzZV0gRGlzYWxsb3cgdGhlIHNhbWUgaXRlbSBmcm9tIGJlaW5nIGFkZGVkIHRvXG4gKiB0aGUgY29sbGVjdGlvbiB0d2ljZS5cbiAqL1xuXG4vKipcbiAqIEBjbGFzc2Rlc2NcbiAqIEFuIGV4cGFuZGVkIHZlcnNpb24gb2Ygc3RhbmRhcmQgSlMgQXJyYXksIGFkZGluZyBjb252ZW5pZW5jZSBtZXRob2RzIGZvclxuICogbWFuaXB1bGF0aW9uLiBBZGQgYW5kIHJlbW92ZSBjaGFuZ2VzIHRvIHRoZSBDb2xsZWN0aW9uIHRyaWdnZXIgYSBDb2xsZWN0aW9uXG4gKiBldmVudC4gTm90ZSB0aGF0IHRoaXMgZG9lcyBub3QgY292ZXIgY2hhbmdlcyB0byB0aGUgb2JqZWN0cyBfd2l0aGluXyB0aGVcbiAqIENvbGxlY3Rpb247IHRoZXkgdHJpZ2dlciBldmVudHMgb24gdGhlIGFwcHJvcHJpYXRlIG9iamVjdCwgbm90IG9uIHRoZVxuICogQ29sbGVjdGlvbiBhcyBhIHdob2xlLlxuICpcbiAqIEB0ZW1wbGF0ZSBUXG4gKiBAYXBpXG4gKi9cbmNsYXNzIENvbGxlY3Rpb24gZXh0ZW5kcyBCYXNlT2JqZWN0IHtcblxuICAvKipcbiAgICogQHBhcmFtIHtBcnJheTxUPj19IG9wdF9hcnJheSBBcnJheS5cbiAgICogQHBhcmFtIHttb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb25+T3B0aW9ucz19IG9wdF9vcHRpb25zIENvbGxlY3Rpb24gb3B0aW9ucy5cbiAgICovXG4gIGNvbnN0cnVjdG9yKG9wdF9hcnJheSwgb3B0X29wdGlvbnMpIHtcblxuICAgIHN1cGVyKCk7XG5cbiAgICBjb25zdCBvcHRpb25zID0gb3B0X29wdGlvbnMgfHwge307XG5cbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAqL1xuICAgIHRoaXMudW5pcXVlXyA9IEJvb2xlYW4ob3B0aW9ucy51bmlxdWUpO1xuXG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKiBAdHlwZSB7IUFycmF5PFQ+fVxuICAgICAqL1xuICAgIHRoaXMuYXJyYXlfID0gb3B0X2FycmF5ID8gb3B0X2FycmF5IDogW107XG5cbiAgICBpZiAodGhpcy51bmlxdWVfKSB7XG4gICAgICBmb3IgKGxldCBpID0gMCwgaWkgPSB0aGlzLmFycmF5Xy5sZW5ndGg7IGkgPCBpaTsgaSArPSAxKSB7XG4gICAgICAgIHRoaXMuYXNzZXJ0VW5pcXVlXyh0aGlzLmFycmF5X1tpXSwgaSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdGhpcy51cGRhdGVMZW5ndGhfKCk7XG5cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYWxsIGVsZW1lbnRzIGZyb20gdGhlIGNvbGxlY3Rpb24uXG4gICAqIEBhcGlcbiAgICovXG4gIGNsZWFyKCkge1xuICAgIHdoaWxlICh0aGlzLmdldExlbmd0aCgpID4gMCkge1xuICAgICAgdGhpcy5wb3AoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGVsZW1lbnRzIHRvIHRoZSBjb2xsZWN0aW9uLiAgVGhpcyBwdXNoZXMgZWFjaCBpdGVtIGluIHRoZSBwcm92aWRlZCBhcnJheVxuICAgKiB0byB0aGUgZW5kIG9mIHRoZSBjb2xsZWN0aW9uLlxuICAgKiBAcGFyYW0geyFBcnJheTxUPn0gYXJyIEFycmF5LlxuICAgKiBAcmV0dXJuIHttb2R1bGU6c2Fpai9jb3JlL0NvbGxlY3Rpb248VD59IFRoaXMgY29sbGVjdGlvbi5cbiAgICogQGFwaVxuICAgKi9cbiAgZXh0ZW5kKGFycikge1xuICAgIGZvciAobGV0IGkgPSAwLCBpaSA9IGFyci5sZW5ndGg7IGkgPCBpaTsgaSArPSAxKSB7XG4gICAgICB0aGlzLnB1c2goYXJyW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvKipcbiAgICogSXRlcmF0ZSBvdmVyIGVhY2ggZWxlbWVudCwgY2FsbGluZyB0aGUgcHJvdmlkZWQgY2FsbGJhY2suXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oVCwgbnVtYmVyLCBBcnJheTxUPik6ICp9IGZ1bmMgVGhlIGZ1bmN0aW9uIHRvIGNhbGxcbiAgICogICAgIGZvciBldmVyeSBlbGVtZW50LiBUaGlzIGZ1bmN0aW9uIHRha2VzIDMgYXJndW1lbnRzICh0aGUgZWxlbWVudCwgdGhlXG4gICAqICAgICBpbmRleCBhbmQgdGhlIGFycmF5KS4gVGhlIHJldHVybiB2YWx1ZSBpcyBpZ25vcmVkLlxuICAgKiBAYXBpXG4gICAqL1xuICBmb3JFYWNoKGZ1bmMpIHtcbiAgICBjb25zdCBhcnJheSA9IHRoaXMuYXJyYXlfO1xuICAgIGZvciAobGV0IGkgPSAwLCBpaSA9IGFycmF5Lmxlbmd0aDsgaSA8IGlpOyBpICs9IDEpIHtcbiAgICAgIGZ1bmMoYXJyYXlbaV0sIGksIGFycmF5KTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IGEgcmVmZXJlbmNlIHRvIHRoZSB1bmRlcmx5aW5nIEFycmF5IG9iamVjdC4gV2FybmluZzogaWYgdGhlIGFycmF5XG4gICAqIGlzIG11dGF0ZWQsIG5vIGV2ZW50cyB3aWxsIGJlIGRpc3BhdGNoZWQgYnkgdGhlIGNvbGxlY3Rpb24sIGFuZCB0aGVcbiAgICogY29sbGVjdGlvbidzIFwibGVuZ3RoXCIgcHJvcGVydHkgd29uJ3QgYmUgaW4gc3luYyB3aXRoIHRoZSBhY3R1YWwgbGVuZ3RoXG4gICAqIG9mIHRoZSBhcnJheS5cbiAgICogQHJldHVybiB7IUFycmF5PFQ+fSBBcnJheS5cbiAgICogQGFwaVxuICAgKi9cbiAgZ2V0QXJyYXkoKSB7XG4gICAgcmV0dXJuIHRoaXMuYXJyYXlfO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgZWxlbWVudCBhdCB0aGUgcHJvdmlkZWQgaW5kZXguXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBJbmRleC5cbiAgICogQHJldHVybiB7VH0gRWxlbWVudC5cbiAgICogQGFwaVxuICAgKi9cbiAgaXRlbShpbmRleCkge1xuICAgIHJldHVybiB0aGlzLmFycmF5X1tpbmRleF07XG4gIH1cblxuICAvKipcbiAgICogR2V0IHRoZSBsZW5ndGggb2YgdGhpcyBjb2xsZWN0aW9uLlxuICAgKiBAcmV0dXJuIHtudW1iZXJ9IFRoZSBsZW5ndGggb2YgdGhlIGFycmF5LlxuICAgKiBAb2JzZXJ2YWJsZVxuICAgKiBAYXBpXG4gICAqL1xuICBnZXRMZW5ndGgoKSB7XG4gICAgcmV0dXJuIC8qKiBAdHlwZSB7bnVtYmVyfSAqLyAodGhpcy5nZXQoUHJvcGVydHkuTEVOR1RIKSk7XG4gIH1cblxuICAvKipcbiAgICogSW5zZXJ0IGFuIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIGluZGV4LlxuICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXguXG4gICAqIEBwYXJhbSB7VH0gZWxlbSBFbGVtZW50LlxuICAgKiBAYXBpXG4gICAqL1xuICBpbnNlcnRBdChpbmRleCwgZWxlbSkge1xuICAgIGlmICh0aGlzLnVuaXF1ZV8pIHtcbiAgICAgIHRoaXMuYXNzZXJ0VW5pcXVlXyhlbGVtKTtcbiAgICB9XG4gICAgdGhpcy5hcnJheV8uc3BsaWNlKGluZGV4LCAwLCBlbGVtKTtcbiAgICB0aGlzLnVwZGF0ZUxlbmd0aF8oKTtcbiAgICB0aGlzLmRpc3BhdGNoRXZlbnQoXG4gICAgICBuZXcgQ29sbGVjdGlvbkV2ZW50KENvbGxlY3Rpb25FdmVudFR5cGUuQURELCBlbGVtKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBsYXN0IGVsZW1lbnQgb2YgdGhlIGNvbGxlY3Rpb24gYW5kIHJldHVybiBpdC5cbiAgICogUmV0dXJuIGB1bmRlZmluZWRgIGlmIHRoZSBjb2xsZWN0aW9uIGlzIGVtcHR5LlxuICAgKiBAcmV0dXJuIHtUfHVuZGVmaW5lZH0gRWxlbWVudC5cbiAgICogQGFwaVxuICAgKi9cbiAgcG9wKCkge1xuICAgIHJldHVybiB0aGlzLnJlbW92ZUF0KHRoaXMuZ2V0TGVuZ3RoKCkgLSAxKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnQgdGhlIHByb3ZpZGVkIGVsZW1lbnQgYXQgdGhlIGVuZCBvZiB0aGUgY29sbGVjdGlvbi5cbiAgICogQHBhcmFtIHtUfSBlbGVtIEVsZW1lbnQuXG4gICAqIEByZXR1cm4ge251bWJlcn0gTmV3IGxlbmd0aCBvZiB0aGUgY29sbGVjdGlvbi5cbiAgICogQGFwaVxuICAgKi9cbiAgcHVzaChlbGVtKSB7XG4gICAgaWYgKHRoaXMudW5pcXVlXykge1xuICAgICAgdGhpcy5hc3NlcnRVbmlxdWVfKGVsZW0pO1xuICAgIH1cbiAgICBjb25zdCBsZW4gPSB0aGlzLmdldExlbmd0aCgpO1xuICAgIHRoaXMuaW5zZXJ0QXQobGVuLCBlbGVtKTtcbiAgICByZXR1cm4gdGhpcy5nZXRMZW5ndGgoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgdGhlIGZpcnN0IG9jY3VycmVuY2Ugb2YgYW4gZWxlbWVudCBmcm9tIHRoZSBjb2xsZWN0aW9uLlxuICAgKiBAcGFyYW0ge1R9IGVsZW0gRWxlbWVudC5cbiAgICogQHJldHVybiB7VHx1bmRlZmluZWR9IFRoZSByZW1vdmVkIGVsZW1lbnQgb3IgdW5kZWZpbmVkIGlmIG5vbmUgZm91bmQuXG4gICAqIEBhcGlcbiAgICovXG4gIHJlbW92ZShlbGVtKSB7XG4gICAgY29uc3QgYXJyID0gdGhpcy5hcnJheV87XG4gICAgZm9yIChsZXQgaSA9IDAsIGlpID0gYXJyLmxlbmd0aDsgaSA8IGlpOyBpICs9IDEpIHtcbiAgICAgIGlmIChhcnJbaV0gPT09IGVsZW0pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVtb3ZlQXQoaSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIHRoZSBlbGVtZW50IGF0IHRoZSBwcm92aWRlZCBpbmRleCBhbmQgcmV0dXJuIGl0LlxuICAgKiBSZXR1cm4gYHVuZGVmaW5lZGAgaWYgdGhlIGNvbGxlY3Rpb24gZG9lcyBub3QgY29udGFpbiB0aGlzIGluZGV4LlxuICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXguXG4gICAqIEByZXR1cm4ge1R8dW5kZWZpbmVkfSBWYWx1ZS5cbiAgICogQGFwaVxuICAgKi9cbiAgcmVtb3ZlQXQoaW5kZXgpIHtcbiAgICBjb25zdCBwcmV2ID0gdGhpcy5hcnJheV9baW5kZXhdO1xuICAgIHRoaXMuYXJyYXlfLnNwbGljZShpbmRleCwgMSk7XG4gICAgdGhpcy51cGRhdGVMZW5ndGhfKCk7XG4gICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBDb2xsZWN0aW9uRXZlbnQoQ29sbGVjdGlvbkV2ZW50VHlwZS5SRU1PVkUsIHByZXYpKTtcbiAgICByZXR1cm4gcHJldjtcbiAgfVxuXG4gIC8qKlxuICAgKiBTZXQgdGhlIGVsZW1lbnQgYXQgdGhlIHByb3ZpZGVkIGluZGV4LlxuICAgKiBAcGFyYW0ge251bWJlcn0gaW5kZXggSW5kZXguXG4gICAqIEBwYXJhbSB7VH0gZWxlbSBFbGVtZW50LlxuICAgKiBAYXBpXG4gICAqL1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LXN0YXRlbWVudHNcbiAgc2V0QXQoaW5kZXgsIGVsZW0pIHtcbiAgICBjb25zdCBsZW4gPSB0aGlzLmdldExlbmd0aCgpO1xuICAgIGlmIChpbmRleCA8IGxlbikge1xuICAgICAgaWYgKHRoaXMudW5pcXVlXykge1xuICAgICAgICB0aGlzLmFzc2VydFVuaXF1ZV8oZWxlbSwgaW5kZXgpO1xuICAgICAgfVxuICAgICAgY29uc3QgcHJldiA9IHRoaXMuYXJyYXlfW2luZGV4XTtcbiAgICAgIHRoaXMuYXJyYXlfW2luZGV4XSA9IGVsZW07XG4gICAgICB0aGlzLmRpc3BhdGNoRXZlbnQoXG4gICAgICAgIG5ldyBDb2xsZWN0aW9uRXZlbnQoQ29sbGVjdGlvbkV2ZW50VHlwZS5SRU1PVkUsIHByZXYpKTtcbiAgICAgIHRoaXMuZGlzcGF0Y2hFdmVudChcbiAgICAgICAgbmV3IENvbGxlY3Rpb25FdmVudChDb2xsZWN0aW9uRXZlbnRUeXBlLkFERCwgZWxlbSkpO1xuICAgIH0gZWxzZSB7XG4gICAgICBmb3IgKGxldCBqID0gbGVuOyBqIDwgaW5kZXg7IGogKz0gMSkge1xuICAgICAgICB0aGlzLmluc2VydEF0KGosIHVuZGVmaW5lZCk7XG4gICAgICB9XG4gICAgICB0aGlzLmluc2VydEF0KGluZGV4LCBlbGVtKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQHByaXZhdGVcbiAgICovXG4gIHVwZGF0ZUxlbmd0aF8oKSB7XG4gICAgdGhpcy5zZXQoUHJvcGVydHkuTEVOR1RILCB0aGlzLmFycmF5Xy5sZW5ndGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEBwcml2YXRlXG4gICAqIEBwYXJhbSB7VH0gZWxlbSBFbGVtZW50LlxuICAgKiBAcGFyYW0ge251bWJlcj19IG9wdF9leGNlcHQgT3B0aW9uYWwgaW5kZXggdG8gaWdub3JlLlxuICAgKi9cbiAgYXNzZXJ0VW5pcXVlXyhlbGVtLCBvcHRfZXhjZXB0KSB7XG4gICAgZm9yIChsZXQgaSA9IDAsIGlpID0gdGhpcy5hcnJheV8ubGVuZ3RoOyBpIDwgaWk7IGkgKz0gMSkge1xuICAgICAgaWYgKHRoaXMuYXJyYXlfW2ldID09PSBlbGVtICYmIGkgIT09IG9wdF9leGNlcHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKEVycm9ycy5BU1NFUlRfVU5JUVVFLmNvZGUpO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5cbmV4cG9ydCBkZWZhdWx0IENvbGxlY3Rpb247XG4iXX0=