@activejs/core
Version:
Pragmatic, Reactive State Management for JavaScript Apps
659 lines • 80.3 kB
JavaScript
import { Observable } from 'rxjs';
import { Configuration } from './configuration';
import { Base } from './abstract-base';
import { UnitBase } from './abstract-unit-base';
import { NonPrimitiveUnitBase } from './abstract-non-primitive-unit-base';
import { EventListUnitCopyWithin, EventListUnitDelete, EventListUnitFill, EventListUnitPop, EventListUnitPush, EventListUnitRemove, EventListUnitReverse, EventListUnitSet, EventListUnitShift, EventListUnitSort, EventListUnitSplice, EventListUnitUnshift, } from '../models';
import { isFunction, isObject, isValidIndex, IteratorSymbol, makeNonEnumerable, normalizeIndex, sanitizeIndices, } from '../utils/funcs';
/**
* ListUnit is a reactive storage Unit that emulates `array`.
*
* ListUnit only accepts `array` data type as its value.
* It ensures that at any point of time the value would always be an `array`.
*
* ListUnit is based on `array`, it implements all the `Array.prototype` methods that are available
* in the environment/browser its running, including polyfills.
* e.g.: `find`, `filter`, `includes`, etc.
*
* Learn more about Units [here](https://docs.activejs.dev/fundamentals/units). \
* Learn more about ListUnit [here](https://docs.activejs.dev/fundamentals/units/listunit).
*
* Just like every other Non-Primitive ActiveJS Unit:
* - ListUnit extends {@link NonPrimitiveUnitBase}
* - Which further extends {@link UnitBase}, {@link Base} and `Observable`
*
* @category 1. Units
*/
export class ListUnit extends NonPrimitiveUnitBase {
constructor(config) {
super(Object.assign(Object.assign({}, Configuration.LIST_UNIT), config));
makeNonEnumerable(this);
}
/**
* The length of the list-{@link value}.
*/
get length() {
return this.rawValue().length;
}
/**
* Indicates whether the length of the list-{@link value} is `0` or not.
*/
get isEmpty() {
return this.length === 0;
}
/**
* @internal please do not use.
*/
defaultValue() {
return [];
}
/**
* Extends {@link UnitBase.wouldDispatch} and adds additional check for type `array` {@see {@link Array.isArray}}, \
* which cannot be bypassed even by using {@link force}.
*
* @param value The value to be dispatched.
* @param force Whether dispatch-checks should be bypassed or not.
* @returns A boolean indicating whether the param `value` would pass the dispatch-checks if dispatched.
*
* @category Common Units
*/
wouldDispatch(value, force) {
return this.isValidValue(value) && super.wouldDispatch(value, force);
}
/**
* Sets the item on the given index in the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the index is valid-numeric.
*
* @param index The index of the item. \
* A negative index is normalized as following: \
* - If the index is less than negative of list-{@link length} it's treated as 0.
* - Otherwise, it's subtracted from the list-{@link length}.
* eg: If list length is `5`, negative index `-5` will be normalized to `0`, \
* negative index `-6` will be normalized to `0`, and so on.
* @param item The item.
*
* @triggers {@link EventListUnitSet}
* @category Custom ListUnit
*/
set(index, item) {
var _a;
if (this.isFrozen || !isValidIndex(index)) {
return;
}
this.checkSerializabilityMaybe(item);
const listShallowCopy = [...this.rawValue()];
listShallowCopy[normalizeIndex(index, this.length)] = this.deepCopyMaybe(item);
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitSet(index, item));
}
}
/**
* Inserts items to the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen and there's at least 1 item to be inserted.
*
* @param start The zero-based index in the list from which to start adding items. \
* A negative index is normalized as following: \
* - If the index is less than negative of list-{@link length} it's treated as 0.
* - Otherwise, it's subtracted from the list-{@link length}.
* eg: If list length is `5`, negative index `-5` will be normalized to `0`, \
* negative index `-6` will be normalized to `0`, and so on.
* @param items The items to be insert.
* @returns The new length of the list.
*
* @triggers {@link EventListUnitSplice}
* @category Custom ListUnit
*/
insert(start, ...items) {
if (this.isFrozen || !items.length) {
return this.length;
}
this.checkSerializabilityMaybe(items);
this.splice(start, 0, ...items); // splice also takes care of empty spaces
return this.length;
}
/**
* Removes items at given indices from the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value. \
* It modifies the length of the list as these indices are not deleted,
* rather removed using `Array.prototype.splice`.
*
* It only works if the Unit is not frozen, and
* the list is not empty, and at least 1 valid-numeric index is provided.
*
* Notes:
* - The indices are removed in descending order.
* - The indices are deduplicated.
* - Negative indices are normalized before starting the removal. \
* A negative index is normalized as following: \
* - If the index is less than negative of list-{@link length}, it's treated as 0.
* - Otherwise, it's subtracted from the list-{@link length}.
* eg: If list length is `5`, negative index `-5` will be normalized to `0`, \
* negative index `-6` will be normalized to `0`, and so on.
*
* @param indices The indices of the items to be removed.
* @returns The removed items or an empty `array`.
*
* @triggers {@link EventListUnitRemove}
* @category Custom ListUnit
*/
remove(...indices) {
var _a;
const listLength = this.length;
indices = sanitizeIndices(indices, listLength).filter(i => this.hasOwnProperty(i));
if (this.isFrozen || !indices.length || this.isEmpty) {
return [];
}
indices.sort().reverse();
const removedItems = [];
const listShallowCopy = [...this.rawValue()];
indices.forEach(index => {
removedItems.push(...this.deepCopyMaybe(listShallowCopy.splice(index, 1)));
});
this.updateValueAndCache(listShallowCopy);
removedItems.reverse();
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitRemove(indices, removedItems));
}
return removedItems;
}
/**
* Removes items from the list-{@link value} where the predicate returns `truthy` value. \
* Dispatches a new copy of the value, without mutating the current-value. \
* It modifies the length of the list as these indices are not deleted,
* rather removed using `Array.prototype.splice`.
*
* It only works if the Unit is not frozen, and
* the predicate is a function, and the list is not empty. \
* It uses {@link remove} internally, for actual removal.
*
* @param predicate A callback function that gets called for every item in the list with the item and index as arguments.
* @returns The removed items or an empty `array`.
*
* @triggers {@link EventListUnitRemove}
* @category Custom ListUnit
*/
removeIf(predicate) {
if (this.isFrozen || typeof predicate !== 'function' || this.isEmpty) {
return [];
}
const indicesToBeRemoved = [];
this.value().forEach((item, index) => {
if (predicate(item, index)) {
indicesToBeRemoved.push(index);
}
});
return this.remove(...indicesToBeRemoved);
}
/**
* Deletes items at given indices in the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value. \
* It doesn't modify the length of the list as these indices are only deleted, not removed.
*
* It only works if the Unit is not frozen, and
* the list is not empty, and at least 1 valid-numeric index is provided.
*
* @param indices The indices of the items to be deleted. \
* A negative index is normalized as following: \
* - If the index is less than negative of list-{@link length} it's treated as 0.
* - Otherwise, it's subtracted from the list-{@link length}.
* eg: If list length is `5`, negative index `-5` will be normalized to `0`, \
* negative index `-6` will be normalized to `0`, and so on.
* @returns The removed items or an empty `array`.
*
* @triggers {@link EventListUnitDelete}
* @category Custom ListUnit
*/
delete(...indices) {
var _a;
indices = sanitizeIndices(indices, this.length).filter(i => this.hasOwnProperty(i));
if (this.isFrozen || indices.length === 0 || this.isEmpty) {
return [];
}
const deletedItems = [];
const listShallowCopy = [...this.rawValue()];
indices.forEach(index => {
deletedItems.push(this.deepCopyMaybe(listShallowCopy[index]));
delete listShallowCopy[index];
});
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitDelete(indices, deletedItems));
}
return deletedItems;
}
/**
* Deletes items from the list-{@link value} where the predicate returns `true`. \
* Dispatches a new copy of the value, without mutating the current-value. \
* It doesn't modify the length of the list as these indices are only deleted, not removed.
*
* It only works if the Unit is not frozen, and
* the predicate is a function, and the list is not empty.
*
* @param predicate A callback function that gets called for every item in the list with the item and index as arguments.
* @returns The removed items or an empty `array`.
*
* @triggers {@link EventListUnitDelete}
* @category Custom ListUnit
*/
deleteIf(predicate) {
if (this.isFrozen || typeof predicate !== 'function' || this.isEmpty) {
return [];
}
const indicesToBeDeleted = [];
this.value().forEach((item, index) => {
if (predicate(item, index)) {
indicesToBeDeleted.push(index);
}
});
return this.delete(...indicesToBeDeleted);
}
/**
* Finds items of the list that have a direct child property
* that matches with `key` and `value` passed as params.
*
* @example
* ```ts
* const initialValue = [{b: 1}, {b: 1, b2: 2}, {c: 1}, {b: null}];
* const list = new ListUnit({initialValue});
* const itemsFound = list.findByProp('b', 1);
* console.log(itemsFound); // logs [[0, {b: 1}], [1, {b: 1, b2: 2}]]
* ```
*
* @param key The key of the property whose value needs to be matched against param `value`.
* @param value A value that will be matched against every item's prop-value using equality operator.
* @param strictEquality A flag governing whether the value be matched using `===` or `==` operator.
* Default is `true`, ie: strict equality `===`. Pass `false` to use `==` instead.
* @returns An `array` of key/values of the matched properties, an empty `array` otherwise.
*
* @category Custom ListUnit
*/
findByProp(key, value, strictEquality = true) {
if (this.isEmpty) {
return [];
}
return this.rawValue().reduce((res, item, index) => {
const aMatch = isObject(item) &&
(strictEquality === false
? // tslint:disable-next-line:triple-equals
item[key] == value
: item[key] === value);
if (aMatch) {
res.push([index, this.deepCopyMaybe(item)]);
}
return res;
}, []);
}
/**
* Returns the item at the given index in the list-{@link value}. \
* Negative index returns items from the end of the list.
*
* @param index The index of the item. \
* A negative index is normalized as following: \
* - If the index is less than negative of list-{@link length} it's treated as 0.
* - Otherwise, it's subtracted from the list-{@link length}.
* eg: If list length is `5`, negative index `-5` will be normalized to `0`, \
* negative index `-6` will be normalized to `0`, and so on.
* @returns The item at the given index.
*
* @category Custom ListUnit
*/
get(index) {
index = normalizeIndex(index, this.length);
return this.hasOwnProperty(index) ? this.deepCopyMaybe(this.rawValue()[index]) : undefined;
}
/**
* Returns the first item in the list-{@link value}.
*
* @returns The first item in the list.
*
* @category Custom ListUnit
*/
first() {
return this.get(0);
}
/**
* Returns the last item in the list-{@link value}.
*
* @returns The last item in the list.
*
* @category Custom ListUnit
*/
last() {
return this.get(-1);
}
/**
* Adds all the items of the list separated by the specified separator string, and
* all the items are converted into string first using JSON.stringify
*
* @param separator A string used to separate one item of the list from the next in the resulting String.
* If omitted, the list items are separated with a comma.
* @returns Concatenated `JSON.stringify`d list items.
*
* @category Custom ListUnit
*/
jsonJoin(separator) {
return this.rawValue()
.map(item => JSON.stringify(item))
.join(separator);
}
/**
* Appends new items to the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and at least 1 item is provided.
*
* @param items The items to be appended to the list.
* @returns The new length of the list.
*
* @triggers {@link EventListUnitPush}
* @category Customised Array.prototype
*/
push(...items) {
var _a;
if (this.isFrozen || !items.length) {
return this.length;
}
this.checkSerializabilityMaybe(items);
const listShallowCopy = [...this.rawValue()];
const newLength = listShallowCopy.push(...this.deepCopyMaybe(items));
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitPush(items));
}
return newLength;
}
/**
* Removes the last item from the list-{@link value} and returns it. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @returns The popped item.
*
* @triggers {@link EventListUnitPop}
* @category Customised Array.prototype
*/
pop() {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
const listShallowCopy = [...this.rawValue()];
const poppedItem = this.deepCopyMaybe(listShallowCopy.pop());
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitPop(poppedItem));
}
return poppedItem;
}
/**
* Removes the first item from the list-{@link value} and returns it. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @returns The shifted item.
*
* @triggers {@link EventListUnitShift}
* @category Customised Array.prototype
*/
shift() {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
const listShallowCopy = [...this.rawValue()];
const shiftedItem = this.deepCopyMaybe(listShallowCopy.shift());
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitShift(shiftedItem));
}
return shiftedItem;
}
/**
* Inserts new items at the start of the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and at least 1 item is provided.
*
* @param items The items to be insert at the start of the list
* @returns The new length of the list.
*
* @triggers {@link EventListUnitUnshift}
* @category Customised Array.prototype
*/
unshift(...items) {
var _a;
if (this.isFrozen || !items.length) {
return this.length;
}
this.checkSerializabilityMaybe(items);
const listShallowCopy = [...this.rawValue()];
const newLength = listShallowCopy.unshift(...this.deepCopyMaybe(items));
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitUnshift(items));
}
return newLength;
}
/**
* Removes items from the list-{@link value} and, if necessary,
* inserts new items in their place, returning the deleted items. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and \
* either deleteCount is not 0 (loose comparison) and the list is not empty {@link isEmpty}, or \
* there's at least 1 item to be added.
*
* @param start The zero-based location in the list from which to start removing items.
* @param deleteCount The number of items to remove.
* @param items Items to insert into the list in place of the deleted items.
* @returns The deleted Items or an empty `array`.
*
* @triggers {@link EventListUnitSplice}
* @category Customised Array.prototype
*/
splice(start, deleteCount, ...items) {
var _a;
// tslint:disable-next-line:triple-equals
if (this.isFrozen || ((deleteCount == 0 || this.isEmpty) && !items.length)) {
return [];
}
this.checkSerializabilityMaybe(items);
const listShallowCopy = [...this.rawValue()];
const removedItems = this.deepCopyMaybe(listShallowCopy.splice(start, deleteCount, ...items.map(item => this.deepCopyMaybe(item))));
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitSplice(start, deleteCount, removedItems, items));
}
return removedItems;
}
/**
* Fills a section of the list-{@link value} with provided param `item`. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @param item The item to fill the section of ListUnit's value with.
* @param start The index to start filling the list at. If start is negative, it is treated as
* length+start where length is the length of the list.
* @param end The index to stop filling the list at. If end is negative, it is treated as
* length+end.
* @returns Nothing, unlike `Array.prototype.fill`
*
* @triggers {@link EventListUnitFill}
* @category Customised Array.prototype
*/
fill(item, start, end) {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
this.checkSerializabilityMaybe(item);
const listShallowCopy = [...this.rawValue()];
listShallowCopy.fill(this.deepCopyMaybe(item), start, end);
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitFill(item, start, end));
}
}
/**
* Copies a section of the current-value identified by param `start` and param `end`
* to the ListUnit's value starting at position {@link target}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @param target If target is negative, it is treated as length+target where length is the
* length of the list.
* @param start If start is negative, it is treated as length+start. If end is negative, it
* is treated as length+end.
* @param end If end is not specified, length of the list is used as its default value.
* @returns Nothing, unlike `Array.prototype.copyWithin`
*
* @triggers {@link EventListUnitCopyWithin}
* @category Customised Array.prototype
*/
copyWithin(target, start, end) {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
const listShallowCopy = [...this.rawValue()];
listShallowCopy.copyWithin(target, start, end);
this.updateValueAndCache(listShallowCopy);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitCopyWithin(target, start, end));
}
}
/**
* Reverses the items in the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @returns Nothing, unlike `Array.prototype.reverse`
*
* @triggers {@link EventListUnitReverse}
* @category Customised Array.prototype
*/
reverse() {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
const listShallowCopyReversed = [...this.rawValue()].reverse();
this.updateValueAndCache(listShallowCopyReversed);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitReverse());
}
}
/**
* Sorts the list-{@link value}. \
* Dispatches a new copy of the value, without mutating the current-value.
*
* It only works if the Unit is not frozen, and the list is not empty {@link isEmpty}.
*
* @param compareFn The name of the function used to determine the order of the items.
* If omitted, the items are sorted in ascending, ASCII character order.
* @returns Nothing, unlike `Array.prototype.sort`
*
* @triggers {@link EventListUnitSort}
* @category Customised Array.prototype
*/
sort(compareFn) {
var _a;
if (this.isFrozen || this.isEmpty) {
return;
}
const listShallowCopySorted = typeof compareFn === 'function'
? [...this.value()].sort(compareFn)
: [...this.rawValue()].sort();
this.updateValueAndCache(listShallowCopySorted);
if (((_a = this.eventsSubject) === null || _a === void 0 ? void 0 : _a.observers.length) && !this.isMuted) {
this.eventsSubject.next(new EventListUnitSort());
}
}
/**
* Returns a section of the list-{@link value}.
*
* @param start The beginning of the specified portion of the list.
* @param end The end of the specified portion of the list.
* @returns A section of the list.
*
* @category Customised Array.prototype
*/
slice(start, end) {
return this.deepCopyMaybe(this.rawValue().slice(start, end));
}
/**
* Performs the specified action for each item in the list-{@link value}. \
* It's a drop-in replacement for the `Array.prototype.forEach` method.
*
* @param callbackFn A function that accepts up to three arguments.
* forEvery calls the callbackFn function one time for each element in the list.
* @param thisArg An object to which this keyword can refer in the callbackFn function.
* If thisArg is omitted, undefined is used as this value.
*
* @category Customised Array.prototype
*/
forEvery(callbackFn, thisArg) {
Array.prototype.forEach.apply(this.value(), [callbackFn, thisArg]);
}
/**
* @internal please do not use.
*/
[IteratorSymbol]() {
return Array.prototype[IteratorSymbol].call(this.value());
}
/**
* @internal please do not use.
*/
isValidValue(value) {
return Array.isArray(value);
}
}
/**
* @internal please do not use.
*/
const MethodsWithNoRiskOfMutation = [
'includes',
'indexOf',
'lastIndexOf',
'join',
'keys',
'toLocaleString',
];
MethodsWithNoRiskOfMutation.forEach(methodName => {
Object.defineProperty(ListUnit.prototype, methodName, {
value(...args) {
return Array.prototype[methodName].apply(this.rawValue(), args);
},
});
});
/**
* @internal please do not use.
*/
const MethodsNotToImplement = [
...Object.getOwnPropertyNames(Observable.prototype),
...Object.getOwnPropertyNames(Base.prototype),
...Object.getOwnPropertyNames(UnitBase.prototype),
...Object.getOwnPropertyNames(ListUnit.prototype),
...MethodsWithNoRiskOfMutation,
];
Object.getOwnPropertyNames(Array.prototype).forEach(method => {
if (!isFunction(Array.prototype[method]) || MethodsNotToImplement.includes(method)) {
return;
}
Object.defineProperty(ListUnit.prototype, method, {
value(...args) {
return Array.prototype[method].apply(this.value(), args);
},
});
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC11bml0LmpzIiwic291cmNlUm9vdCI6Ii9ob21lL3J1bm5lci93b3JrL2FjdGl2ZWpzL2FjdGl2ZWpzL3BhY2thZ2VzL2NvcmUvc3JjLyIsInNvdXJjZXMiOlsibGliL2xpc3QtdW5pdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUMsVUFBVSxFQUFVLE1BQU0sTUFBTSxDQUFDO0FBQ3pDLE9BQU8sRUFBQyxhQUFhLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUMsSUFBSSxFQUFDLE1BQU0saUJBQWlCLENBQUM7QUFDckMsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLHNCQUFzQixDQUFDO0FBQzlDLE9BQU8sRUFBQyxvQkFBb0IsRUFBQyxNQUFNLG9DQUFvQyxDQUFDO0FBQ3hFLE9BQU8sRUFDTCx1QkFBdUIsRUFDdkIsbUJBQW1CLEVBQ25CLGlCQUFpQixFQUNqQixnQkFBZ0IsRUFDaEIsaUJBQWlCLEVBQ2pCLG1CQUFtQixFQUNuQixvQkFBb0IsRUFDcEIsZ0JBQWdCLEVBQ2hCLGtCQUFrQixFQUNsQixpQkFBaUIsRUFDakIsbUJBQW1CLEVBQ25CLG9CQUFvQixHQUlyQixNQUFNLFdBQVcsQ0FBQztBQUNuQixPQUFPLEVBQ0wsVUFBVSxFQUNWLFFBQVEsRUFDUixZQUFZLEVBQ1osY0FBYyxFQUNkLGlCQUFpQixFQUNqQixjQUFjLEVBQ2QsZUFBZSxHQUNoQixNQUFNLGdCQUFnQixDQUFDO0FBS3hCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FrQkc7QUFDSCxNQUFNLE9BQU8sUUFBZSxTQUFRLG9CQUE0QjtJQStCOUQsWUFBWSxNQUEyQjtRQUNyQyxLQUFLLGlDQUNBLGFBQWEsQ0FBQyxTQUFTLEdBQ3ZCLE1BQU0sRUFDVCxDQUFDO1FBRUgsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDMUIsQ0FBQztJQTVCRDs7T0FFRztJQUNILElBQUksTUFBTTtRQUNSLE9BQU8sSUFBSSxDQUFDLFFBQVEsRUFBRSxD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akQsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztJQUNqRCxHQUFHLDJCQUEyQjtDQUMvQixDQUFDO0FBQ0YsTUFBTSxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUU7SUFDM0QsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUkscUJBQXFCLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFO1FBQ2xGLE9BQU87S0FDUjtJQUVELE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLFNBQVMsRUFBRSxNQUFNLEVBQUU7UUFDaEQsS0FBSyxDQUFDLEdBQUcsSUFBSTtZQUNYLE9BQU8sS0FBSyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzNELENBQUM7S0FDRixDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7T2JzZXJ2YWJsZSwgU3ViamVjdH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge0NvbmZpZ3VyYXRpb259IGZyb20gJy4vY29uZmlndXJhdGlvbic7XG5pbXBvcnQge0Jhc2V9IGZyb20gJy4vYWJzdHJhY3QtYmFzZSc7XG5pbXBvcnQge1VuaXRCYXNlfSBmcm9tICcuL2Fic3RyYWN0LXVuaXQtYmFzZSc7XG5pbXBvcnQge05vblByaW1pdGl2ZVVuaXRCYXNlfSBmcm9tICcuL2Fic3RyYWN0LW5vbi1wcmltaXRpdmUtdW5pdC1iYXNlJztcbmltcG9ydCB7XG4gIEV2ZW50TGlzdFVuaXRDb3B5V2l0aGluLFxuICBFdmVudExpc3RVbml0RGVsZXRlLFxuICBFdmVudExpc3RVbml0RmlsbCxcbiAgRXZlbnRMaXN0VW5pdFBvcCxcbiAgRXZlbnRMaXN0VW5pdFB1c2gsXG4gIEV2ZW50TGlzdFVuaXRSZW1vdmUsXG4gIEV2ZW50TGlzdFVuaXRSZXZlcnNlLFxuICBFdmVudExpc3RVbml0U2V0LFxuICBFdmVudExpc3RVbml0U2hpZnQsXG4gIEV2ZW50TGlzdFVuaXRTb3J0LFxuICBFdmVudExpc3RVbml0U3BsaWNlLFxuICBFdmVudExpc3RVbml0VW5zaGlmdCxcbiAgS09mLFxuICBMaXN0VW5pdEV2ZW50cyxcbiAgVW5pdENvbmZpZyxcbn0gZnJvbSAnLi4vbW9kZWxzJztcbmltcG9ydCB7XG4gIGlzRnVuY3Rpb24sXG4gIGlzT2JqZWN0LFxuICBpc1ZhbGlkSW5kZXgsXG4gIEl0ZXJhdG9yU3ltYm9sLFxuICBtYWtlTm9uRW51bWVyYWJsZSxcbiAgbm9ybWFsaXplSW5kZXgsXG4gIHNhbml0aXplSW5kaWNlcyxcbn0gZnJvbSAnLi4vdXRpbHMvZnVuY3MnO1xuXG4vLyB0c2xpbnQ6ZGlzYWJsZS1uZXh0LWxpbmU6bm8tZW1wdHktaW50ZXJmYWNlXG5leHBvcnQgaW50ZXJmYWNlIExpc3RVbml0PEl0ZW0+IGV4dGVuZHMgQXJyYXk8SXRlbT4ge31cblxuLyoqXG4gKiBMaXN0VW5pdCBpcyBhIHJlYWN0aXZlIHN0b3JhZ2UgVW5pdCB0aGF0IGVtdWxhdGVzIGBhcnJheWAuXG4gKlxuICogTGlzdFVuaXQgb25seSBhY2NlcHRzIGBhcnJheWAgZGF0YSB0eXBlIGFzIGl0cyB2YWx1ZS5cbiAqIEl0IGVuc3VyZXMgdGhhdCBhdCBhbnkgcG9pbnQgb2YgdGltZSB0aGUgdmFsdWUgd291bGQgYWx3YXlzIGJlIGFuIGBhcnJheWAuXG4gKlxuICogTGlzdFVuaXQgaXMgYmFzZWQgb24gYGFycmF5YCwgaXQgaW1wbGVtZW50cyBhbGwgdGhlIGBBcnJheS5wcm90b3R5cGVgIG1ldGhvZHMgdGhhdCBhcmUgYXZhaWxhYmxlXG4gKiBpbiB0aGUgZW52aXJvbm1lbnQvYnJvd3NlciBpdHMgcnVubmluZywgaW5jbHVkaW5nIHBvbHlmaWxscy5cbiAqIGUuZy46IGBmaW5kYCwgYGZpbHRlcmAsIGBpbmNsdWRlc2AsIGV0Yy5cbiAqXG4gKiBMZWFybiBtb3JlIGFib3V0IFVuaXRzIFtoZXJlXShodHRwczovL2RvY3MuYWN0aXZlanMuZGV2L2Z1bmRhbWVudGFscy91bml0cykuIFxcXG4gKiBMZWFybiBtb3JlIGFib3V0IExpc3RVbml0IFtoZXJlXShodHRwczovL2RvY3MuYWN0aXZlanMuZGV2L2Z1bmRhbWVudGFscy91bml0cy9saXN0dW5pdCkuXG4gKlxuICogSnVzdCBsaWtlIGV2ZXJ5IG90aGVyIE5vbi1QcmltaXRpdmUgQWN0aXZlSlMgVW5pdDpcbiAqIC0gTGlzdFVuaXQgZXh0ZW5kcyB7QGxpbmsgTm9uUHJpbWl0aXZlVW5pdEJhc2V9XG4gKiAtIFdoaWNoIGZ1cnRoZXIgZXh0ZW5kcyB7QGxpbmsgVW5pdEJhc2V9LCB7QGxpbmsgQmFzZX0gYW5kIGBPYnNlcnZhYmxlYFxuICpcbiAqIEBjYXRlZ29yeSAxLiBVbml0c1xuICovXG5leHBvcnQgY2xhc3MgTGlzdFVuaXQ8SXRlbT4gZXh0ZW5kcyBOb25QcmltaXRpdmVVbml0QmFzZTxJdGVtW10+IHtcbiAgLyoqXG4gICAqIEBpbnRlcm5hbCBwbGVhc2UgZG8gbm90IHVzZS5cbiAgICovXG4gIHByb3RlY3RlZCByZWFkb25seSBldmVudHNTdWJqZWN0OiBTdWJqZWN0PExpc3RVbml0RXZlbnRzPEl0ZW0+PjtcbiAgLyoqXG4gICAqIE9uLWRlbWFuZCBvYnNlcnZhYmxlIGV2ZW50cy5cbiAgICovXG4gIHJlYWRvbmx5IGV2ZW50cyQ6IE9ic2VydmFibGU8TGlzdFVuaXRFdmVudHM8SXRlbT4+O1xuXG4gIC8qKlxuICAgKiBUaGUgbGVuZ3RoIG9mIHRoZSBsaXN0LXtAbGluayB2YWx1ZX0uXG4gICAqL1xuICBnZXQgbGVuZ3RoKCk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMucmF3VmFsdWUoKS5sZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGxlbmd0aCBvZiB0aGUgbGlzdC17QGxpbmsgdmFsdWV9IGlzIGAwYCBvciBub3QuXG4gICAqL1xuICBnZXQgaXNFbXB0eSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5sZW5ndGggPT09IDA7XG4gIH1cblxuICAvKipcbiAgICogQGludGVybmFsIHBsZWFzZSBkbyBub3QgdXNlLlxuICAgKi9cbiAgcHJvdGVjdGVkIGRlZmF1bHRWYWx1ZSgpOiBJdGVtW10ge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFVuaXRDb25maWc8SXRlbVtdPikge1xuICAgIHN1cGVyKHtcbiAgICAgIC4uLkNvbmZpZ3VyYXRpb24uTElTVF9VTklULFxuICAgICAgLi4uY29uZmlnLFxuICAgIH0pO1xuXG4gICAgbWFrZU5vbkVudW1lcmFibGUodGhpcyk7XG4gIH1cblxuICAvKipcbiAgICogRXh0ZW5kcyB7QGxpbmsgVW5pdEJhc2Uud291bGREaXNwYXRjaH0gYW5kIGFkZHMgYWRkaXRpb25hbCBjaGVjayBmb3IgdHlwZSBgYXJyYXlgIHtAc2VlIHtAbGluayBBcnJheS5pc0FycmF5fX0sIFxcXG4gICAqIHdoaWNoIGNhbm5vdCBiZSBieXBhc3NlZCBldmVuIGJ5IHVzaW5nIHtAbGluayBmb3JjZX0uXG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gYmUgZGlzcGF0Y2hlZC5cbiAgICogQHBhcmFtIGZvcmNlIFdoZXRoZXIgZGlzcGF0Y2gtY2hlY2tzIHNob3VsZCBiZSBieXBhc3NlZCBvciBub3QuXG4gICAqIEByZXR1cm5zIEEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIHBhcmFtIGB2YWx1ZWAgd291bGQgcGFzcyB0aGUgZGlzcGF0Y2gtY2hlY2tzIGlmIGRpc3BhdGNoZWQuXG4gICAqXG4gICAqIEBjYXRlZ29yeSBDb21tb24gVW5pdHNcbiAgICovXG4gIHdvdWxkRGlzcGF0Y2godmFsdWU6IEl0ZW1bXSwgZm9yY2U/OiBib29sZWFuKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuaXNWYWxpZFZhbHVlKHZhbHVlKSAmJiBzdXBlci53b3VsZERpc3BhdGNoKHZhbHVlLCBmb3JjZSk7XG4gIH1cblxuICAvKipcbiAgICogU2V0cyB0aGUgaXRlbSBvbiB0aGUgZ2l2ZW4gaW5kZXggaW4gdGhlIGxpc3Qte0BsaW5rIHZhbHVlfS4gXFxcbiAgICogRGlzcGF0Y2hlcyBhIG5ldyBjb3B5IG9mIHRoZSB2YWx1ZSwgd2l0aG91dCBtdXRhdGluZyB0aGUgY3VycmVudC12YWx1ZS5cbiAgICpcbiAgICogSXQgb25seSB3b3JrcyBpZiB0aGUgVW5pdCBpcyBub3QgZnJvemVuLCBhbmQgdGhlIGluZGV4IGlzIHZhbGlkLW51bWVyaWMuXG4gICAqXG4gICAqIEBwYXJhbSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIGl0ZW0uIFxcXG4gICAqIEEgbmVnYXRpdmUgaW5kZXggaXMgbm9ybWFsaXplZCBhcyBmb2xsb3dpbmc6IFxcXG4gICAqIC0gSWYgdGhlIGluZGV4IGlzIGxlc3MgdGhhbiBuZWdhdGl2ZSBvZiBsaXN0LXtAbGluayBsZW5ndGh9IGl0J3MgdHJlYXRlZCBhcyAwLlxuICAgKiAtIE90aGVyd2lzZSwgaXQncyBzdWJ0cmFjdGVkIGZyb20gdGhlIGxpc3Qte0BsaW5rIGxlbmd0aH0uXG4gICAqIGVnOiBJZiBsaXN0IGxlbmd0aCBpcyBgNWAsIG5lZ2F0aXZlIGluZGV4IGAtNWAgd2lsbCBiZSBub3JtYWxpemVkIHRvIGAwYCwgXFxcbiAgICogbmVnYXRpdmUgaW5kZXggYC02YCB3aWxsIGJlIG5vcm1hbGl6ZWQgdG8gYDBgLCBhbmQgc28gb24uXG4gICAqIEBwYXJhbSBpdGVtIFRoZSBpdGVtLlxuICAgKlxuICAgKiBAdHJpZ2dlcnMge0BsaW5rIEV2ZW50TGlzdFVuaXRTZXR9XG4gICAqIEBjYXRlZ29yeSBDdXN0b20gTGlzdFVuaXRcbiAgICovXG4gIHNldChpbmRleDogbnVtYmVyLCBpdGVtOiBJdGVtKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuaXNGcm96ZW4gfHwgIWlzVmFsaWRJbmRleChpbmRleCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5jaGVja1NlcmlhbGl6YWJpbGl0eU1heWJlKGl0ZW0pO1xuXG4gICAgY29uc3QgbGlzdFNoYWxsb3dDb3B5ID0gWy4uLnRoaXMucmF3VmFsdWUoKV07XG4gICAgbGlzdFNoYWxsb3dDb3B5W25vcm1hbGl6ZUluZGV4KGluZGV4LCB0aGlzLmxlbmd0aCldID0gdGhpcy5kZWVwQ29weU1heWJlKGl0ZW0pO1xuICAgIHRoaXMudXBkYXRlVmFsdWVBbmRDYWNoZShsaXN0U2hhbGxvd0NvcHkpO1xuXG4gICAgaWYgKHRoaXMuZXZlbnRzU3ViamVjdD8ub2JzZXJ2ZXJzLmxlbmd0aCAmJiAhdGhpcy5pc011dGVkKSB7XG4gICAgICB0aGlzLmV2ZW50c1N1YmplY3QubmV4dChuZXcgRXZlbnRMaXN0VW5pdFNldChpbmRleCwgaXRlbSkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnRzIGl0ZW1zIHRvIHRoZSBsaXN0LXtAbGluayB2YWx1ZX0uIFxcXG4gICAqIERpc3BhdGNoZXMgYSBuZXcgY29weSBvZiB0aGUgdmFsdWUsIHdpdGhvdXQgbXV0YXRpbmcgdGhlIGN1cnJlbnQtdmFsdWUuXG4gICAqXG4gICAqIEl0IG9ubHkgd29ya3MgaWYgdGhlIFVuaXQgaXMgbm90IGZyb3plbiBhbmQgdGhlcmUncyBhdCBsZWFzdCAxIGl0ZW0gdG8gYmUgaW5zZXJ0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSBzdGFydCBUaGUgemVyby1iYXNlZCBpbmRleCBpbiB0aGUgbGlzdCBmcm9tIHdoaWNoIHRvIHN0YXJ0IGFkZGluZyBpdGVtcy4gXFxcbiAgICogQSBuZWdhdGl2ZSBpbmRleCBpcyBub3JtYWxpemVkIGFzIGZvbGxvd2luZzogXFxcbiAgICogLSBJZiB0aGUgaW5kZXggaXMgbGVzcyB0aGFuIG5lZ2F0aXZlIG9mIGxpc3Qte0BsaW5rIGxlbmd0aH0gaXQncyB0cmVhdGVkIGFzIDAuXG4gICAqIC0gT3RoZXJ3aXNlLCBpdCdzIHN1YnRyYWN0ZWQgZnJvbSB0aGUgbGlzdC17QGxpbmsgbGVuZ3Rof