@fireflysemantics/slice
Version:

368 lines • 31.1 kB
JavaScript
import { ReplaySubject } from 'rxjs';
import { map } from 'rxjs/operators';
const { freeze } = Object;
const ESTORE_DEFAULT_ID_KEY = 'id';
const ESTORE_DEFAULT_GID_KEY = 'gid';
export const ESTORE_CONFIG_DEFAULT = freeze({
idKey: ESTORE_DEFAULT_ID_KEY,
guidKey: ESTORE_DEFAULT_GID_KEY,
});
export class AbstractStore {
constructor(config) {
/**
* Notifies observers of the store query.
*/
this.notifyQuery = new ReplaySubject(1);
/**
* The current query state.
*/
this._query = '';
/**
* Primary index for the stores elements.
*/
this.entries = new Map();
/**
* The element entries that are keyed by
* an id generated on the server.
*/
this.idEntries = new Map();
/**
* Create notifications that broacast
* the entire set of entries.
*/
this.notify = new ReplaySubject(1);
/**
* Create notifications that broacast
* store or slice delta state changes.
*/
this.notifyDelta = new ReplaySubject(1);
/**
* An Observable<E[]> reference
* to the entities in the store or
* Slice instance.
*/
this.obs = this.observe();
this.config = config
? freeze({ ...ESTORE_CONFIG_DEFAULT, ...config })
: ESTORE_CONFIG_DEFAULT;
}
/**
* Sets the current query state and notifies observers.
*/
set query(query) {
this._query = query;
this.notifyQuery.next(this._query);
}
/**
* @return A snapshot of the query state.
*/
get query() {
return this._query;
}
/**
* Observe the query.
* @example
<pre>
let query$ = source.observeQuery();
</pre>
*/
observeQuery() {
return this.notifyQuery.asObservable();
}
/**
* The current id key for the EStore instance.
* @return this.config.idKey;
*/
get ID_KEY() {
return this.config.idKey;
}
/**
* The current guid key for the EStore instance.
* @return this.config.guidKey;
*/
get GUID_KEY() {
return this.config.guidKey;
}
/**
* Call all the notifiers at once.
*
* @param v
* @param delta
*/
notifyAll(v, delta) {
this.notify.next(v);
this.notifyDelta.next(delta);
}
/**
* Observe store state changes.
*
* @param sort Optional sorting function yielding a sorted observable.
* @example
* ```
* let todos$ = source.observe();
* //or with a sort by title function
* let todos$ = source.observe((a, b)=>(a.title > b.title ? -1 : 1));
* ```
*/
observe(sort) {
if (sort) {
return this.notify.pipe(map((e) => e.sort(sort)));
}
return this.notify.asObservable();
}
/**
* Observe delta updates.
*
* @example
* ```
* let todos$ = source.observeDelta();
* ```
*/
observeDelta() {
return this.notifyDelta.asObservable();
}
/**
* Check whether the store is empty.
*
* @return A hot {@link Observable} that indicates whether the store is empty.
*
* @example
* ```
* const empty$:Observable<boolean> = source.isEmpty();
* ```
*/
isEmpty() {
return this.notify.pipe(map((entries) => entries.length == 0));
}
/**
* Check whether the store is empty.
*
* @return A snapshot that indicates whether the store is empty.
*
* @example
* ```
* const empty:boolean = source.isEmptySnapshot();
* ```
*/
isEmptySnapshot() {
return Array.from(this.entries.values()).length == 0;
}
/**
* Returns the number of entries contained.
* @param p The predicate to apply in order to filter the count
*
* @example
* ```
* const completePredicate: Predicate<Todo> = function pred(t: Todo) {
* return t.complete;
* };
*
* const incompletePredicate: Predicate<Todo> = function pred(t: Todo) {
* return !t.complete;
* };
*
* store.count().subscribe((c) => {
* console.log(`The observed count of Todo entities is ${c}`);
* });
* store.count(incompletePredicate).subscribe((c) => {
* console.log(`The observed count of incomplete Todo enttiies is ${c}`);
* });
* store.count(completePredicate).subscribe((c) => {
* console.log(`The observed count of complete Todo enttiies is ${c}`);
* });
* ```
*/
count(p) {
if (p) {
return this.notify.pipe(map((e) => e.reduce((total, e) => total + (p(e) ? 1 : 0), 0)));
}
return this.notify.pipe(map((entries) => entries.length));
}
/**
* Returns a snapshot of the number of entries contained in the store.
* @param p The predicate to apply in order to filter the count
*
* @example
* ```
* const completePredicate: Predicate<Todo> = function pred(t: Todo) {
* return t.complete;
* };
*
* const incompletePredicate: Predicate<Todo> = function pred(t: Todo) {
* return !t.complete;
* };
*
* const snapshotCount = store.countSnapshot(completePredicate);
* console.log(`The count is ${snapshotCount}`);
*
* const completeSnapshotCount = store.countSnapshot(completePredicate);
* console.log(
* `The complete Todo Entity Snapshot count is ${completeSnapshotCount}`
* );
*
* const incompleteSnapshotCount = store.countSnapshot(incompletePredicate);
* console.log(
* `The incomplete Todo Entity Snapshot count is ${incompleteSnapshotCount}`
* );
* ```
*/
countSnapshot(p) {
if (p) {
return Array.from(this.entries.values()).filter(p).length;
}
return Array.from(this.entries.values()).length;
}
/**
* Snapshot of all entries.
*
* @return Snapshot array of all the elements the entities the store contains.
*
* @example Observe a snapshot of all the entities in the store.
*
* ```
* let selectedTodos:Todo[] = source.allSnapshot();
* ```
*/
allSnapshot() {
return Array.from(this.entries.values());
}
/**
* Returns true if the entries contain the identified instance.
*
* @param target Either an instance of type `E` or a `guid` identifying the instance.
* @param byId Whether the lookup should be performed with the `id` key rather than the `guid`.
* @returns true if the instance identified by the guid exists, false otherwise.
*
* @example
* ```
* let contains:boolean = source.contains(guid);
* ```
*/
contains(target) {
if (typeof target === 'string') {
return this.entries.get(target) ? true : false;
}
const guid = target[this.config.guidKey];
return this.entries.get(guid) ? true : false;
}
/**
* Returns true if the entries contain the identified instance.
*
* @param target Either an instance of type `E` or a `id` identifying the instance.
* @returns true if the instance identified by the `id` exists, false otherwise.
*
* @example
* ```
* let contains:boolean = source.contains(guid);
* ```
*/
containsById(target) {
if (typeof target === 'string') {
return this.idEntries.get(target) ? true : false;
}
const id = target[this.config.idKey];
return this.idEntries.get(id) ? true : false;
}
/**
* Find and return the entity identified by the GUID parameter
* if it exists and return it.
*
* @param guid
* @return The entity instance if it exists, null otherwise
*
* @example
* ```
* const globalID: string = '1';
* let findThisTodo = new Todo(false, 'Find this Todo', globalID);
* store.post(findThisTodo);
* const todo = store.findOne(globalID);
* ```
*/
findOne(guid) {
return this.entries.get(guid);
}
/**
* Find and return the entity identified by the ID parameter
* if it exists and return it.
*
* @param id
* @return The entity instance if it exists, null otherwise
*
* @example
* ```
* const todoLater: Todo = new Todo(false, 'Do me later.');
* todoLater.id = 'findMe';
* store.post(todoLater);
* const postedTodo = store.findOneByID('findMe');
* ```
*/
findOneByID(id) {
return this.idEntries.get(id);
}
/**
* Snapshot of the entries that match the predicate.
*
* @param p The predicate used to query for the selection.
* @return A snapshot array containing the entities that match the predicate.
*
* @example Select all the Todo instances where the title length is greater than 100.
* ```
* let todos:Todo[]=store.select(todo=>todo.title.length>100);
* ```
*/
select(p) {
const selected = [];
Array.from(this.entries.values()).forEach((e) => {
if (p(e)) {
selected.push(e);
}
});
return selected;
}
/**
* Compare entities by GUID
*
* @param e1 The first entity
* @param e2 The second entity
* @return true if the two entities have equal GUID ids
*
* @example Compare todo1 with todo2 by gid.
* ```
* if (equalsByGUID(todo1, todo2)){...};
* ```
*/
equalsByGUID(e1, e2) {
return e1[this.GUID_KEY] == e2[this.GUID_KEY];
}
/**
* Compare entities by ID
*
* @param e1 The first entity
* @param e2 The second entity
* @return true if the two entities have equal ID ids
*
* @example Compare todo1 with todo2 by id.
*
* ```
* if (equalsByID(todo1, todo2)){...};
* ```
*/
equalsByID(e1, e2) {
return e1[this.ID_KEY] == e2[this.ID_KEY];
}
/**
* Call destroy when disposing of the store, as it
* completes all {@link ReplaySubject} instances.
*
* @example
* ```
* store.destroy();
* ```
*/
destroy() {
this.notify.complete();
this.notifyDelta.complete();
this.notifyQuery.complete();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RTdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3NsaWNlL3NyYy9saWIvQWJzdHJhY3RTdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUlyQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDO0FBRTFCLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBQ25DLE1BQU0sc0JBQXNCLEdBQUcsS0FBSyxDQUFDO0FBRXJDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFnQixNQUFNLENBQUM7SUFDdkQsS0FBSyxFQUFFLHFCQUFxQjtJQUM1QixPQUFPLEVBQUUsc0JBQXNCO0NBQ2hDLENBQUMsQ0FBQztBQUVILE1BQU0sT0FBZ0IsYUFBYTtJQU1qQyxZQUFZLE1BQW9CO1FBTWhDOztXQUVHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLGFBQWEsQ0FBUyxDQUFDLENBQUMsQ0FBQztRQUVyRDs7V0FFRztRQUNPLFdBQU0sR0FBVyxFQUFFLENBQUM7UUEyQzlCOztXQUVHO1FBQ0ksWUFBTyxHQUFtQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRTNDOzs7V0FHRztRQUNJLGNBQVMsR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUU3Qzs7O1dBR0c7UUFDTyxXQUFNLEdBQUcsSUFBSSxhQUFhLENBQU0sQ0FBQyxDQUFDLENBQUM7UUFFN0M7OztXQUdHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLGFBQWEsQ0FBVyxDQUFDLENBQUMsQ0FBQztRQStCdkQ7Ozs7V0FJRztRQUNJLFFBQUcsR0FBb0IsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBakgzQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU07WUFDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxFQUFFLEdBQUcscUJBQXFCLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQztZQUNqRCxDQUFDLENBQUMscUJBQXFCLENBQUM7SUFDNUIsQ0FBQztJQVlEOztPQUVHO0lBQ0gsSUFBSSxLQUFLLENBQUMsS0FBYTtRQUNyQixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztRQUNwQixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsSUFBSSxLQUFLO1FBQ1AsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDO0lBQ3JCLENBQUM7SUFFRDs7Ozs7O01BTUU7SUFDSyxZQUFZO1FBQ2pCLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQztJQUMzQixDQUFDO0lBQ0Q7OztPQUdHO0lBQ0gsSUFBSSxRQUFRO1FBQ1YsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQztJQUM3QixDQUFDO0lBeUJEOzs7OztPQUtHO0lBQ08sU0FBUyxDQUFDLENBQU0sRUFBRSxLQUFlO1FBQ3pDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3BCLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQy9CLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0ksT0FBTyxDQUFDLElBQWlDO1FBQzlDLElBQUksSUFBSSxFQUFFO1lBQ1IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1NBQ3hEO1FBQ0QsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO0lBQ3BDLENBQUM7SUFTRDs7Ozs7OztPQU9HO0lBQ0ksWUFBWTtRQUNqQixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDekMsQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNILE9BQU87UUFDTCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQVksRUFBRSxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRDs7Ozs7Ozs7O09BU0c7SUFDSCxlQUFlO1FBQ2IsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxNQUFNLElBQUksQ0FBQyxDQUFDO0lBQ3ZELENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O09Bd0JHO0lBQ0gsS0FBSyxDQUFDLENBQWdCO1FBQ3BCLElBQUksQ0FBQyxFQUFFO1lBQ0wsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDckIsR0FBRyxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsS0FBSyxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQ25FLENBQUM7U0FDSDtRQUNELE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsT0FBWSxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUNqRSxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTJCRztJQUNILGFBQWEsQ0FBQyxDQUFnQjtRQUM1QixJQUFJLENBQUMsRUFBRTtZQUNMLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztTQUMzRDtRQUNELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsV0FBVztRQUNULE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsUUFBUSxDQUFDLE1BQWtCO1FBQ3pCLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFO1lBQzlCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1NBQ2hEO1FBQ0QsTUFBTSxJQUFJLEdBQWlCLE1BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsWUFBWSxDQUFDLE1BQWtCO1FBQzdCLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFO1lBQzlCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1NBQ2xEO1FBQ0QsTUFBTSxFQUFFLEdBQWlCLE1BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3BELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILE9BQU8sQ0FBQyxJQUFZO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0gsV0FBVyxDQUFDLEVBQVU7UUFDcEIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNILE1BQU0sQ0FBQyxDQUFlO1FBQ3BCLE1BQU0sUUFBUSxHQUFRLEVBQUUsQ0FBQztRQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUM5QyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDUixRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ2xCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxZQUFZLENBQUMsRUFBTyxFQUFFLEVBQU87UUFDM0IsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILFVBQVUsQ0FBQyxFQUFPLEVBQUUsRUFBTztRQUN6QixPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxPQUFPO1FBQ0wsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDOUIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVwbGF5U3ViamVjdCwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRGVsdGEsIFByZWRpY2F0ZSB9IGZyb20gJy4vbW9kZWxzJztcbmltcG9ydCB7IFN0b3JlQ29uZmlnIH0gZnJvbSAnLi9tb2RlbHMvU3RvcmVDb25maWcnO1xuXG5jb25zdCB7IGZyZWV6ZSB9ID0gT2JqZWN0O1xuXG5jb25zdCBFU1RPUkVfREVGQVVMVF9JRF9LRVkgPSAnaWQnO1xuY29uc3QgRVNUT1JFX0RFRkFVTFRfR0lEX0tFWSA9ICdnaWQnO1xuXG5leHBvcnQgY29uc3QgRVNUT1JFX0NPTkZJR19ERUZBVUxUOiBTdG9yZUNvbmZpZyA9IGZyZWV6ZSh7XG4gIGlkS2V5OiBFU1RPUkVfREVGQVVMVF9JRF9LRVksXG4gIGd1aWRLZXk6IEVTVE9SRV9ERUZBVUxUX0dJRF9LRVksXG59KTtcblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEFic3RyYWN0U3RvcmU8RT4ge1xuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBzdG9yZS5cbiAgICovXG4gIHB1YmxpYyBjb25maWc6IFN0b3JlQ29uZmlnO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFN0b3JlQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWdcbiAgICAgID8gZnJlZXplKHsgLi4uRVNUT1JFX0NPTkZJR19ERUZBVUxULCAuLi5jb25maWcgfSlcbiAgICAgIDogRVNUT1JFX0NPTkZJR19ERUZBVUxUO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdGlmaWVzIG9ic2VydmVycyBvZiB0aGUgc3RvcmUgcXVlcnkuXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5UXVlcnkgPSBuZXcgUmVwbGF5U3ViamVjdDxzdHJpbmc+KDEpO1xuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCBxdWVyeSBzdGF0ZS5cbiAgICovXG4gIHByb3RlY3RlZCBfcXVlcnk6IHN0cmluZyA9ICcnO1xuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBjdXJyZW50IHF1ZXJ5IHN0YXRlIGFuZCBub3RpZmllcyBvYnNlcnZlcnMuXG4gICAqL1xuICBzZXQgcXVlcnkocXVlcnk6IHN0cmluZykge1xuICAgIHRoaXMuX3F1ZXJ5ID0gcXVlcnk7XG4gICAgdGhpcy5ub3RpZnlRdWVyeS5uZXh0KHRoaXMuX3F1ZXJ5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIEEgc25hcHNob3Qgb2YgdGhlIHF1ZXJ5IHN0YXRlLlxuICAgKi9cbiAgZ2V0IHF1ZXJ5KCkge1xuICAgIHJldHVybiB0aGlzLl9xdWVyeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZlIHRoZSBxdWVyeS5cbiAgICogQGV4YW1wbGVcbiAgICAgPHByZT5cbiAgICBsZXQgcXVlcnkkID0gc291cmNlLm9ic2VydmVRdWVyeSgpO1xuICAgIDwvcHJlPlxuICAqL1xuICBwdWJsaWMgb2JzZXJ2ZVF1ZXJ5KCkge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeVF1ZXJ5LmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGlkIGtleSBmb3IgdGhlIEVTdG9yZSBpbnN0YW5jZS5cbiAgICogQHJldHVybiB0aGlzLmNvbmZpZy5pZEtleTtcbiAgICovXG4gIGdldCBJRF9LRVkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuaWRLZXk7XG4gIH1cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGd1aWQga2V5IGZvciB0aGUgRVN0b3JlIGluc3RhbmNlLlxuICAgKiBAcmV0dXJuIHRoaXMuY29uZmlnLmd1aWRLZXk7XG4gICAqL1xuICBnZXQgR1VJRF9LRVkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuZ3VpZEtleTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmltYXJ5IGluZGV4IGZvciB0aGUgc3RvcmVzIGVsZW1lbnRzLlxuICAgKi9cbiAgcHVibGljIGVudHJpZXM6IE1hcDxzdHJpbmcsIEU+ID0gbmV3IE1hcCgpO1xuXG4gIC8qKlxuICAgKiBUaGUgZWxlbWVudCBlbnRyaWVzIHRoYXQgYXJlIGtleWVkIGJ5XG4gICAqIGFuIGlkIGdlbmVyYXRlZCBvbiB0aGUgc2VydmVyLlxuICAgKi9cbiAgcHVibGljIGlkRW50cmllczogTWFwPHN0cmluZywgRT4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBub3RpZmljYXRpb25zIHRoYXQgYnJvYWNhc3RcbiAgICogdGhlIGVudGlyZSBzZXQgb2YgZW50cmllcy5cbiAgICovXG4gIHByb3RlY3RlZCBub3RpZnkgPSBuZXcgUmVwbGF5U3ViamVjdDxFW10+KDEpO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgbm90aWZpY2F0aW9ucyB0aGF0IGJyb2FjYXN0XG4gICAqIHN0b3JlIG9yIHNsaWNlIGRlbHRhIHN0YXRlIGNoYW5nZXMuXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5RGVsdGEgPSBuZXcgUmVwbGF5U3ViamVjdDxEZWx0YTxFPj4oMSk7XG5cbiAgLyoqXG4gICAqIENhbGwgYWxsIHRoZSBub3RpZmllcnMgYXQgb25jZS5cbiAgICpcbiAgICogQHBhcmFtIHZcbiAgICogQHBhcmFtIGRlbHRhXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5QWxsKHY6IEVbXSwgZGVsdGE6IERlbHRhPEU+KSB7XG4gICAgdGhpcy5ub3RpZnkubmV4dCh2KTtcbiAgICB0aGlzLm5vdGlmeURlbHRhLm5leHQoZGVsdGEpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ic2VydmUgc3RvcmUgc3RhdGUgY2hhbmdlcy5cbiAgICpcbiAgICogQHBhcmFtIHNvcnQgT3B0aW9uYWwgc29ydGluZyBmdW5jdGlvbiB5aWVsZGluZyBhIHNvcnRlZCBvYnNlcnZhYmxlLlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IHRvZG9zJCA9IHNvdXJjZS5vYnNlcnZlKCk7XG4gICAqIC8vb3Igd2l0aCBhIHNvcnQgYnkgdGl0bGUgZnVuY3Rpb25cbiAgICogbGV0IHRvZG9zJCA9IHNvdXJjZS5vYnNlcnZlKChhLCBiKT0+KGEudGl0bGUgPiBiLnRpdGxlID8gLTEgOiAxKSk7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIG9ic2VydmUoc29ydD86IChhOiBhbnksIGI6IGFueSkgPT4gbnVtYmVyKTogT2JzZXJ2YWJsZTxFW10+IHtcbiAgICBpZiAoc29ydCkge1xuICAgICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlOiBFW10pID0+IGUuc29ydChzb3J0KSkpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5ub3RpZnkuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogQW4gT2JzZXJ2YWJsZTxFW10+IHJlZmVyZW5jZVxuICAgKiB0byB0aGUgZW50aXRpZXMgaW4gdGhlIHN0b3JlIG9yXG4gICAqIFNsaWNlIGluc3RhbmNlLlxuICAgKi9cbiAgcHVibGljIG9iczogT2JzZXJ2YWJsZTxFW10+ID0gdGhpcy5vYnNlcnZlKCk7XG5cbiAgLyoqXG4gICAqIE9ic2VydmUgZGVsdGEgdXBkYXRlcy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgXG4gICAqIGxldCB0b2RvcyQgPSBzb3VyY2Uub2JzZXJ2ZURlbHRhKCk7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIG9ic2VydmVEZWx0YSgpOiBPYnNlcnZhYmxlPERlbHRhPEU+PiB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5RGVsdGEuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciB0aGUgc3RvcmUgaXMgZW1wdHkuXG4gICAqXG4gICAqIEByZXR1cm4gQSBob3Qge0BsaW5rIE9ic2VydmFibGV9IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZW1wdHkkOk9ic2VydmFibGU8Ym9vbGVhbj4gPSBzb3VyY2UuaXNFbXB0eSgpO1xuICAgKiBgYGBcbiAgICovXG4gIGlzRW1wdHkoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlbnRyaWVzOiBFW10pID0+IGVudHJpZXMubGVuZ3RoID09IDApKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB3aGV0aGVyIHRoZSBzdG9yZSBpcyBlbXB0eS5cbiAgICpcbiAgICogQHJldHVybiBBIHNuYXBzaG90IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZW1wdHk6Ym9vbGVhbiA9IHNvdXJjZS5pc0VtcHR5U25hcHNob3QoKTtcbiAgICogYGBgXG4gICAqL1xuICBpc0VtcHR5U25hcHNob3QoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKS5sZW5ndGggPT0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgZW50cmllcyBjb250YWluZWQuXG4gICAqIEBwYXJhbSBwIFRoZSBwcmVkaWNhdGUgdG8gYXBwbHkgaW4gb3JkZXIgdG8gZmlsdGVyIHRoZSBjb3VudFxuICAgKiBcbiAgICogQGV4YW1wbGVcbiAgICogYGBgXG4gICAqIGNvbnN0IGNvbXBsZXRlUHJlZGljYXRlOiBQcmVkaWNhdGU8VG9kbz4gPSBmdW5jdGlvbiBwcmVkKHQ6IFRvZG8pIHtcbiAgICogICByZXR1cm4gdC5jb21wbGV0ZTtcbiAgICogfTtcbiAgICogXG4gICAqIGNvbnN0IGluY29tcGxldGVQcmVkaWNhdGU6IFByZWRpY2F0ZTxUb2RvPiA9IGZ1bmN0aW9uIHByZWQodDogVG9kbykge1xuICAgKiAgIHJldHVybiAhdC5jb21wbGV0ZTtcbiAgICogfTtcbiAgICogXG4gICAqIHN0b3JlLmNvdW50KCkuc3Vic2NyaWJlKChjKSA9PiB7XG4gICAqICAgY29uc29sZS5sb2coYFRoZSBvYnNlcnZlZCBjb3VudCBvZiBUb2RvIGVudGl0aWVzIGlzICR7Y31gKTtcbiAgICogfSk7XG4gICAqIHN0b3JlLmNvdW50KGluY29tcGxldGVQcmVkaWNhdGUpLnN1YnNjcmliZSgoYykgPT4ge1xuICAgKiAgIGNvbnNvbGUubG9nKGBUaGUgb2JzZXJ2ZWQgY291bnQgb2YgaW5jb21wbGV0ZSBUb2RvIGVudHRpaWVzIGlzICR7Y31gKTtcbiAgICogfSk7XG4gICAqIHN0b3JlLmNvdW50KGNvbXBsZXRlUHJlZGljYXRlKS5zdWJzY3JpYmUoKGMpID0+IHtcbiAgICogICBjb25zb2xlLmxvZyhgVGhlIG9ic2VydmVkIGNvdW50IG9mIGNvbXBsZXRlIFRvZG8gZW50dGlpZXMgaXMgJHtjfWApO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBjb3VudChwPzogUHJlZGljYXRlPEU+KTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcbiAgICBpZiAocCkge1xuICAgICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUoXG4gICAgICAgIG1hcCgoZTogRVtdKSA9PiBlLnJlZHVjZSgodG90YWwsIGUpID0+IHRvdGFsICsgKHAoZSkgPyAxIDogMCksIDApKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlbnRyaWVzOiBFW10pID0+IGVudHJpZXMubGVuZ3RoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIHNuYXBzaG90IG9mIHRoZSBudW1iZXIgb2YgZW50cmllcyBjb250YWluZWQgaW4gdGhlIHN0b3JlLlxuICAgKiBAcGFyYW0gcCBUaGUgcHJlZGljYXRlIHRvIGFwcGx5IGluIG9yZGVyIHRvIGZpbHRlciB0aGUgY291bnRcbiAgICogXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYFxuICAgKiBjb25zdCBjb21wbGV0ZVByZWRpY2F0ZTogUHJlZGljYXRlPFRvZG8+ID0gZnVuY3Rpb24gcHJlZCh0OiBUb2RvKSB7XG4gICAqICAgcmV0dXJuIHQuY29tcGxldGU7XG4gICAqIH07XG4gICAqIFxuICAgKiBjb25zdCBpbmNvbXBsZXRlUHJlZGljYXRlOiBQcmVkaWNhdGU8VG9kbz4gPSBmdW5jdGlvbiBwcmVkKHQ6IFRvZG8pIHtcbiAgICogICByZXR1cm4gIXQuY29tcGxldGU7XG4gICAqIH07XG4gICAqIFxuICAgKiBjb25zdCBzbmFwc2hvdENvdW50ID0gc3RvcmUuY291bnRTbmFwc2hvdChjb21wbGV0ZVByZWRpY2F0ZSk7XG4gICAqIGNvbnNvbGUubG9nKGBUaGUgY291bnQgaXMgJHtzbmFwc2hvdENvdW50fWApO1xuICAgKiBcbiAgICogY29uc3QgY29tcGxldGVTbmFwc2hvdENvdW50ID0gc3RvcmUuY291bnRTbmFwc2hvdChjb21wbGV0ZVByZWRpY2F0ZSk7XG4gICAqIGNvbnNvbGUubG9nKFxuICAgKiAgIGBUaGUgY29tcGxldGUgVG9kbyBFbnRpdHkgU25hcHNob3QgY291bnQgaXMgJHtjb21wbGV0ZVNuYXBzaG90Q291bnR9YFxuICAgKiApO1xuICAgKiBcbiAgICogY29uc3QgaW5jb21wbGV0ZVNuYXBzaG90Q291bnQgPSBzdG9yZS5jb3VudFNuYXBzaG90KGluY29tcGxldGVQcmVkaWNhdGUpO1xuICAgKiBjb25zb2xlLmxvZyhcbiAgICogICBgVGhlIGluY29tcGxldGUgVG9kbyBFbnRpdHkgU25hcHNob3QgY291bnQgaXMgJHtpbmNvbXBsZXRlU25hcHNob3RDb3VudH1gXG4gICAqICk7XG4gICAqIGBgYFxuICAgKi9cbiAgY291bnRTbmFwc2hvdChwPzogUHJlZGljYXRlPEU+KTogbnVtYmVyIHtcbiAgICBpZiAocCkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKS5maWx0ZXIocCkubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpLmxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbmFwc2hvdCBvZiBhbGwgZW50cmllcy5cbiAgICogXG4gICAqIEByZXR1cm4gU25hcHNob3QgYXJyYXkgb2YgYWxsIHRoZSBlbGVtZW50cyB0aGUgZW50aXRpZXMgdGhlIHN0b3JlIGNvbnRhaW5zLlxuICAgKiBcbiAgICogQGV4YW1wbGUgT2JzZXJ2ZSBhIHNuYXBzaG90IG9mIGFsbCB0aGUgZW50aXRpZXMgaW4gdGhlIHN0b3JlLlxuICAgKiBcbiAgICogYGBgXG4gICAqIGxldCBzZWxlY3RlZFRvZG9zOlRvZG9bXSA9IHNvdXJjZS5hbGxTbmFwc2hvdCgpO1xuICAgKiBgYGBcbiAgICovXG4gIGFsbFNuYXBzaG90KCk6IEVbXSB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIGVudHJpZXMgY29udGFpbiB0aGUgaWRlbnRpZmllZCBpbnN0YW5jZS5cbiAgICogXG4gICAqIEBwYXJhbSB0YXJnZXQgRWl0aGVyIGFuIGluc3RhbmNlIG9mIHR5cGUgYEVgIG9yIGEgYGd1aWRgIGlkZW50aWZ5aW5nIHRoZSBpbnN0YW5jZS4gXG4gICAqIEBwYXJhbSBieUlkIFdoZXRoZXIgdGhlIGxvb2t1cCBzaG91bGQgYmUgcGVyZm9ybWVkIHdpdGggdGhlIGBpZGAga2V5IHJhdGhlciB0aGFuIHRoZSBgZ3VpZGAuXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGluc3RhbmNlIGlkZW50aWZpZWQgYnkgdGhlIGd1aWQgZXhpc3RzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IGNvbnRhaW5zOmJvb2xlYW4gPSBzb3VyY2UuY29udGFpbnMoZ3VpZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgY29udGFpbnModGFyZ2V0OiBFIHwgc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKHR5cGVvZiB0YXJnZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gdGhpcy5lbnRyaWVzLmdldCh0YXJnZXQpID8gdHJ1ZSA6IGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBndWlkOiBzdHJpbmcgPSAoPGFueT50YXJnZXQpW3RoaXMuY29uZmlnLmd1aWRLZXldO1xuICAgIHJldHVybiB0aGlzLmVudHJpZXMuZ2V0KGd1aWQpID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZW50cmllcyBjb250YWluIHRoZSBpZGVudGlmaWVkIGluc3RhbmNlLlxuICAgKiBcbiAgICogQHBhcmFtIHRhcmdldCBFaXRoZXIgYW4gaW5zdGFuY2Ugb2YgdHlwZSBgRWAgb3IgYSBgaWRgIGlkZW50aWZ5aW5nIHRoZSBpbnN0YW5jZS4gXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGluc3RhbmNlIGlkZW50aWZpZWQgYnkgdGhlIGBpZGAgZXhpc3RzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IGNvbnRhaW5zOmJvb2xlYW4gPSBzb3VyY2UuY29udGFpbnMoZ3VpZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgY29udGFpbnNCeUlkKHRhcmdldDogRSB8IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmICh0eXBlb2YgdGFyZ2V0ID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHRoaXMuaWRFbnRyaWVzLmdldCh0YXJnZXQpID8gdHJ1ZSA6IGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBpZDogc3RyaW5nID0gKDxhbnk+dGFyZ2V0KVt0aGlzLmNvbmZpZy5pZEtleV07XG4gICAgcmV0dXJuIHRoaXMuaWRFbnRyaWVzLmdldChpZCkgPyB0cnVlIDogZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhbmQgcmV0dXJuIHRoZSBlbnRpdHkgaWRlbnRpZmllZCBieSB0aGUgR1VJRCBwYXJhbWV0ZXJcbiAgICogaWYgaXQgZXhpc3RzIGFuZCByZXR1cm4gaXQuXG4gICAqXG4gICAqIEBwYXJhbSBndWlkXG4gICAqIEByZXR1cm4gVGhlIGVudGl0eSBpbnN0YW5jZSBpZiBpdCBleGlzdHMsIG51bGwgb3RoZXJ3aXNlXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZ2xvYmFsSUQ6IHN0cmluZyA9ICcxJztcbiAgICogbGV0IGZpbmRUaGlzVG9kbyA9IG5ldyBUb2RvKGZhbHNlLCAnRmluZCB0aGlzIFRvZG8nLCBnbG9iYWxJRCk7XG4gICAqIHN0b3JlLnBvc3QoZmluZFRoaXNUb2RvKTtcbiAgICogY29uc3QgdG9kbyA9IHN0b3JlLmZpbmRPbmUoZ2xvYmFsSUQpO1xuICAgKiBgYGBcbiAgICovXG4gIGZpbmRPbmUoZ3VpZDogc3RyaW5nKTogRSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuZW50cmllcy5nZXQoZ3VpZCk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhbmQgcmV0dXJuIHRoZSBlbnRpdHkgaWRlbnRpZmllZCBieSB0aGUgSUQgcGFyYW1ldGVyXG4gICAqIGlmIGl0IGV4aXN0cyBhbmQgcmV0dXJuIGl0LlxuICAgKlxuICAgKiBAcGFyYW0gaWRcbiAgICogQHJldHVybiBUaGUgZW50aXR5IGluc3RhbmNlIGlmIGl0IGV4aXN0cywgbnVsbCBvdGhlcndpc2VcbiAgICogXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYFxuICAgKiBjb25zdCB0b2RvTGF0ZXI6IFRvZG8gPSBuZXcgVG9kbyhmYWxzZSwgJ0RvIG1lIGxhdGVyLicpO1xuICAgKiB0b2RvTGF0ZXIuaWQgPSAnZmluZE1lJztcbiAgICogc3RvcmUucG9zdCh0b2RvTGF0ZXIpO1xuICAgKiBjb25zdCBwb3N0ZWRUb2RvID0gc3RvcmUuZmluZE9uZUJ5SUQoJ2ZpbmRNZScpO1xuICAgKiBgYGBcbiAgICovXG4gIGZpbmRPbmVCeUlEKGlkOiBzdHJpbmcpOiBFIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5pZEVudHJpZXMuZ2V0KGlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbmFwc2hvdCBvZiB0aGUgZW50cmllcyB0aGF0IG1hdGNoIHRoZSBwcmVkaWNhdGUuXG4gICAqXG4gICAqIEBwYXJhbSBwIFRoZSBwcmVkaWNhdGUgdXNlZCB0byBxdWVyeSBmb3IgdGhlIHNlbGVjdGlvbi5cbiAgICogQHJldHVybiBBIHNuYXBzaG90IGFycmF5IGNvbnRhaW5pbmcgdGhlIGVudGl0aWVzIHRoYXQgbWF0Y2ggdGhlIHByZWRpY2F0ZS5cbiAgICpcbiAgICogQGV4YW1wbGUgU2VsZWN0IGFsbCB0aGUgVG9kbyBpbnN0YW5jZXMgd2hlcmUgdGhlIHRpdGxlIGxlbmd0aCBpcyBncmVhdGVyIHRoYW4gMTAwLlxuICAgKiBgYGBcbiAgICogbGV0IHRvZG9zOlRvZG9bXT1zdG9yZS5zZWxlY3QodG9kbz0+dG9kby50aXRsZS5sZW5ndGg+MTAwKTtcbiAgICogYGBgXG4gICAqL1xuICBzZWxlY3QocDogUHJlZGljYXRlPEU+KTogRVtdIHtcbiAgICBjb25zdCBzZWxlY3RlZDogRVtdID0gW107XG4gICAgQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpLmZvckVhY2goKGUpID0+IHtcbiAgICAgIGlmIChwKGUpKSB7XG4gICAgICAgIHNlbGVjdGVkLnB1c2goZSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHNlbGVjdGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXBhcmUgZW50aXRpZXMgYnkgR1VJRFxuICAgKiBcbiAgICogQHBhcmFtIGUxIFRoZSBmaXJzdCBlbnRpdHlcbiAgICogQHBhcmFtIGUyIFRoZSBzZWNvbmQgZW50aXR5XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgdHdvIGVudGl0aWVzIGhhdmUgZXF1YWwgR1VJRCBpZHNcbiAgICpcbiAgICogQGV4YW1wbGUgQ29tcGFyZSB0b2RvMSB3aXRoIHRvZG8yIGJ5IGdpZC5cbiAgICogYGBgXG4gICAqIGlmIChlcXVhbHNCeUdVSUQodG9kbzEsIHRvZG8yKSl7Li4ufTtcbiAgICogYGBgXG4gICAqL1xuICBlcXVhbHNCeUdVSUQoZTE6IGFueSwgZTI6IGFueSkge1xuICAgIHJldHVybiBlMVt0aGlzLkdVSURfS0VZXSA9PSBlMlt0aGlzLkdVSURfS0VZXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wYXJlIGVudGl0aWVzIGJ5IElEXG4gICAqIFxuICAgKiBAcGFyYW0gZTEgVGhlIGZpcnN0IGVudGl0eVxuICAgKiBAcGFyYW0gZTIgVGhlIHNlY29uZCBlbnRpdHlcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSB0d28gZW50aXRpZXMgaGF2ZSBlcXVhbCBJRCBpZHNcbiAgICpcbiAgICogQGV4YW1wbGUgQ29tcGFyZSB0b2RvMSB3aXRoIHRvZG8yIGJ5IGlkLlxuICAgKlxuICAgKiBgYGBcbiAgICogaWYgKGVxdWFsc0J5SUQodG9kbzEsIHRvZG8yKSl7Li4ufTtcbiAgICogYGBgXG4gICAqL1xuICBlcXVhbHNCeUlEKGUxOiBhbnksIGUyOiBhbnkpIHtcbiAgICByZXR1cm4gZTFbdGhpcy5JRF9LRVldID09IGUyW3RoaXMuSURfS0VZXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsIGRlc3Ryb3kgd2hlbiBkaXNwb3Npbmcgb2YgdGhlIHN0b3JlLCBhcyBpdFxuICAgKiBjb21wbGV0ZXMgYWxsIHtAbGluayBSZXBsYXlTdWJqZWN0fSBpbnN0YW5jZXMuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogc3RvcmUuZGVzdHJveSgpO1xuICAgKiBgYGBcbiAgICovXG4gIGRlc3Ryb3koKSB7XG4gICAgdGhpcy5ub3RpZnkuY29tcGxldGUoKTtcbiAgICB0aGlzLm5vdGlmeURlbHRhLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5ub3RpZnlRdWVyeS5jb21wbGV0ZSgpO1xuICB9XG59XG4iXX0=