UNPKG

@fireflysemantics/slice

Version:
368 lines 31.1 kB
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQWJzdHJhY3RTdG9yZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL3NsaWNlL3NyYy9saWIvQWJzdHJhY3RTdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsYUFBYSxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ2pELE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUlyQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsTUFBTSxDQUFDO0FBRTFCLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDO0FBQ25DLE1BQU0sc0JBQXNCLEdBQUcsS0FBSyxDQUFDO0FBRXJDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFnQixNQUFNLENBQUM7SUFDdkQsS0FBSyxFQUFFLHFCQUFxQjtJQUM1QixPQUFPLEVBQUUsc0JBQXNCO0NBQ2hDLENBQUMsQ0FBQztBQUVILE1BQU0sT0FBZ0IsYUFBYTtJQU1qQyxZQUFZLE1BQW9CO1FBTWhDOztXQUVHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLGFBQWEsQ0FBUyxDQUFDLENBQUMsQ0FBQztRQUVyRDs7V0FFRztRQUNPLFdBQU0sR0FBVyxFQUFFLENBQUM7UUEyQzlCOztXQUVHO1FBQ0ksWUFBTyxHQUFtQixJQUFJLEdBQUcsRUFBRSxDQUFDO1FBRTNDOzs7V0FHRztRQUNJLGNBQVMsR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUU3Qzs7O1dBR0c7UUFDTyxXQUFNLEdBQUcsSUFBSSxhQUFhLENBQU0sQ0FBQyxDQUFDLENBQUM7UUFFN0M7OztXQUdHO1FBQ08sZ0JBQVcsR0FBRyxJQUFJLGFBQWEsQ0FBVyxDQUFDLENBQUMsQ0FBQztRQStCdkQ7Ozs7V0FJRztRQUNJLFFBQUcsR0FBb0IsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBakgzQyxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU07WUFDbEIsQ0FBQyxDQUFDLE1BQU0sQ0FB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QixJQUFJLENBQUMsRUFBRTtZQUNMLE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQztTQUMzRDtRQUNELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsTUFBTSxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsV0FBVztRQUNULE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVEOzs7Ozs7Ozs7OztPQVdHO0lBQ0gsUUFBUSxDQUFDLE1BQWtCO1FBQ3pCLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFO1lBQzlCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1NBQ2hEO1FBQ0QsTUFBTSxJQUFJLEdBQWlCLE1BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3hELE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsWUFBWSxDQUFDLE1BQWtCO1FBQzdCLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFO1lBQzlCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO1NBQ2xEO1FBQ0QsTUFBTSxFQUFFLEdBQWlCLE1BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3BELE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7T0FjRztJQUNILE9BQU8sQ0FBQyxJQUFZO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDaEMsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0gsV0FBVyxDQUFDLEVBQVU7UUFDcEIsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNoQyxDQUFDO0lBRUQ7Ozs7Ozs7Ozs7T0FVRztJQUNILE1BQU0sQ0FBQyxDQUFlO1FBQ3BCLE1BQU0sUUFBUSxHQUFRLEVBQUUsQ0FBQztRQUN6QixLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRTtZQUM5QyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRTtnQkFDUixRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO2FBQ2xCO1FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDSCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQ7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxZQUFZLENBQUMsRUFBTyxFQUFFLEVBQU87UUFDM0IsT0FBTyxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILFVBQVUsQ0FBQyxFQUFPLEVBQUUsRUFBTztRQUN6QixPQUFPLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSCxPQUFPO1FBQ0wsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN2QixJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzVCLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxFQUFFLENBQUM7SUFDOUIsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUmVwbGF5U3ViamVjdCwgT2JzZXJ2YWJsZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgbWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRGVsdGEsIFByZWRpY2F0ZSB9IGZyb20gJy4vbW9kZWxzJztcbmltcG9ydCB7IFN0b3JlQ29uZmlnIH0gZnJvbSAnLi9tb2RlbHMvU3RvcmVDb25maWcnO1xuXG5jb25zdCB7IGZyZWV6ZSB9ID0gT2JqZWN0O1xuXG5jb25zdCBFU1RPUkVfREVGQVVMVF9JRF9LRVkgPSAnaWQnO1xuY29uc3QgRVNUT1JFX0RFRkFVTFRfR0lEX0tFWSA9ICdnaWQnO1xuXG5leHBvcnQgY29uc3QgRVNUT1JFX0NPTkZJR19ERUZBVUxUOiBTdG9yZUNvbmZpZyA9IGZyZWV6ZSh7XG4gIGlkS2V5OiBFU1RPUkVfREVGQVVMVF9JRF9LRVksXG4gIGd1aWRLZXk6IEVTVE9SRV9ERUZBVUxUX0dJRF9LRVksXG59KTtcblxuZXhwb3J0IGFic3RyYWN0IGNsYXNzIEFic3RyYWN0U3RvcmU8RT4ge1xuICAvKipcbiAgICogVGhlIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBzdG9yZS5cbiAgICovXG4gIHB1YmxpYyBjb25maWc6IFN0b3JlQ29uZmlnO1xuXG4gIGNvbnN0cnVjdG9yKGNvbmZpZz86IFN0b3JlQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSBjb25maWdcbiAgICAgID8gZnJlZXplKHsgLi4uRVNUT1JFX0NPTkZJR19ERUZBVUxULCAuLi5jb25maWcgfSlcbiAgICAgIDogRVNUT1JFX0NPTkZJR19ERUZBVUxUO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vdGlmaWVzIG9ic2VydmVycyBvZiB0aGUgc3RvcmUgcXVlcnkuXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5UXVlcnkgPSBuZXcgUmVwbGF5U3ViamVjdDxzdHJpbmc+KDEpO1xuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCBxdWVyeSBzdGF0ZS5cbiAgICovXG4gIHByb3RlY3RlZCBfcXVlcnk6IHN0cmluZyA9ICcnO1xuXG4gIC8qKlxuICAgKiBTZXRzIHRoZSBjdXJyZW50IHF1ZXJ5IHN0YXRlIGFuZCBub3RpZmllcyBvYnNlcnZlcnMuXG4gICAqL1xuICBzZXQgcXVlcnkocXVlcnk6IHN0cmluZykge1xuICAgIHRoaXMuX3F1ZXJ5ID0gcXVlcnk7XG4gICAgdGhpcy5ub3RpZnlRdWVyeS5uZXh0KHRoaXMuX3F1ZXJ5KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBAcmV0dXJuIEEgc25hcHNob3Qgb2YgdGhlIHF1ZXJ5IHN0YXRlLlxuICAgKi9cbiAgZ2V0IHF1ZXJ5KCkge1xuICAgIHJldHVybiB0aGlzLl9xdWVyeTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZlIHRoZSBxdWVyeS5cbiAgICogQGV4YW1wbGVcbiAgICAgPHByZT5cbiAgICBsZXQgcXVlcnkkID0gc291cmNlLm9ic2VydmVRdWVyeSgpO1xuICAgIDwvcHJlPlxuICAqL1xuICBwdWJsaWMgb2JzZXJ2ZVF1ZXJ5KCkge1xuICAgIHJldHVybiB0aGlzLm5vdGlmeVF1ZXJ5LmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGlkIGtleSBmb3IgdGhlIEVTdG9yZSBpbnN0YW5jZS5cbiAgICogQHJldHVybiB0aGlzLmNvbmZpZy5pZEtleTtcbiAgICovXG4gIGdldCBJRF9LRVkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuaWRLZXk7XG4gIH1cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IGd1aWQga2V5IGZvciB0aGUgRVN0b3JlIGluc3RhbmNlLlxuICAgKiBAcmV0dXJuIHRoaXMuY29uZmlnLmd1aWRLZXk7XG4gICAqL1xuICBnZXQgR1VJRF9LRVkoKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5jb25maWcuZ3VpZEtleTtcbiAgfVxuXG4gIC8qKlxuICAgKiBQcmltYXJ5IGluZGV4IGZvciB0aGUgc3RvcmVzIGVsZW1lbnRzLlxuICAgKi9cbiAgcHVibGljIGVudHJpZXM6IE1hcDxzdHJpbmcsIEU+ID0gbmV3IE1hcCgpO1xuXG4gIC8qKlxuICAgKiBUaGUgZWxlbWVudCBlbnRyaWVzIHRoYXQgYXJlIGtleWVkIGJ5XG4gICAqIGFuIGlkIGdlbmVyYXRlZCBvbiB0aGUgc2VydmVyLlxuICAgKi9cbiAgcHVibGljIGlkRW50cmllczogTWFwPHN0cmluZywgRT4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIENyZWF0ZSBub3RpZmljYXRpb25zIHRoYXQgYnJvYWNhc3RcbiAgICogdGhlIGVudGlyZSBzZXQgb2YgZW50cmllcy5cbiAgICovXG4gIHByb3RlY3RlZCBub3RpZnkgPSBuZXcgUmVwbGF5U3ViamVjdDxFW10+KDEpO1xuXG4gIC8qKlxuICAgKiBDcmVhdGUgbm90aWZpY2F0aW9ucyB0aGF0IGJyb2FjYXN0XG4gICAqIHN0b3JlIG9yIHNsaWNlIGRlbHRhIHN0YXRlIGNoYW5nZXMuXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5RGVsdGEgPSBuZXcgUmVwbGF5U3ViamVjdDxEZWx0YTxFPj4oMSk7XG5cbiAgLyoqXG4gICAqIENhbGwgYWxsIHRoZSBub3RpZmllcnMgYXQgb25jZS5cbiAgICpcbiAgICogQHBhcmFtIHZcbiAgICogQHBhcmFtIGRlbHRhXG4gICAqL1xuICBwcm90ZWN0ZWQgbm90aWZ5QWxsKHY6IEVbXSwgZGVsdGE6IERlbHRhPEU+KSB7XG4gICAgdGhpcy5ub3RpZnkubmV4dCh2KTtcbiAgICB0aGlzLm5vdGlmeURlbHRhLm5leHQoZGVsdGEpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ic2VydmUgc3RvcmUgc3RhdGUgY2hhbmdlcy5cbiAgICpcbiAgICogQHBhcmFtIHNvcnQgT3B0aW9uYWwgc29ydGluZyBmdW5jdGlvbiB5aWVsZGluZyBhIHNvcnRlZCBvYnNlcnZhYmxlLlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IHRvZG9zJCA9IHNvdXJjZS5vYnNlcnZlKCk7XG4gICAqIC8vb3Igd2l0aCBhIHNvcnQgYnkgdGl0bGUgZnVuY3Rpb25cbiAgICogbGV0IHRvZG9zJCA9IHNvdXJjZS5vYnNlcnZlKChhLCBiKT0+KGEudGl0bGUgPiBiLnRpdGxlID8gLTEgOiAxKSk7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIG9ic2VydmUoc29ydD86IChhOiBhbnksIGI6IGFueSkgPT4gbnVtYmVyKTogT2JzZXJ2YWJsZTxFW10+IHtcbiAgICBpZiAoc29ydCkge1xuICAgICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlOiBFW10pID0+IGUuc29ydChzb3J0KSkpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5ub3RpZnkuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogQW4gT2JzZXJ2YWJsZTxFW10+IHJlZmVyZW5jZVxuICAgKiB0byB0aGUgZW50aXRpZXMgaW4gdGhlIHN0b3JlIG9yXG4gICAqIFNsaWNlIGluc3RhbmNlLlxuICAgKi9cbiAgcHVibGljIG9iczogT2JzZXJ2YWJsZTxFW10+ID0gdGhpcy5vYnNlcnZlKCk7XG5cbiAgLyoqXG4gICAqIE9ic2VydmUgZGVsdGEgdXBkYXRlcy5cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgXG4gICAqIGxldCB0b2RvcyQgPSBzb3VyY2Uub2JzZXJ2ZURlbHRhKCk7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIG9ic2VydmVEZWx0YSgpOiBPYnNlcnZhYmxlPERlbHRhPEU+PiB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5RGVsdGEuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogQ2hlY2sgd2hldGhlciB0aGUgc3RvcmUgaXMgZW1wdHkuXG4gICAqXG4gICAqIEByZXR1cm4gQSBob3Qge0BsaW5rIE9ic2VydmFibGV9IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZW1wdHkkOk9ic2VydmFibGU8Ym9vbGVhbj4gPSBzb3VyY2UuaXNFbXB0eSgpO1xuICAgKiBgYGBcbiAgICovXG4gIGlzRW1wdHkoKTogT2JzZXJ2YWJsZTxib29sZWFuPiB7XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlbnRyaWVzOiBFW10pID0+IGVudHJpZXMubGVuZ3RoID09IDApKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVjayB3aGV0aGVyIHRoZSBzdG9yZSBpcyBlbXB0eS5cbiAgICpcbiAgICogQHJldHVybiBBIHNuYXBzaG90IHRoYXQgaW5kaWNhdGVzIHdoZXRoZXIgdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZW1wdHk6Ym9vbGVhbiA9IHNvdXJjZS5pc0VtcHR5U25hcHNob3QoKTtcbiAgICogYGBgXG4gICAqL1xuICBpc0VtcHR5U25hcHNob3QoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKS5sZW5ndGggPT0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRoZSBudW1iZXIgb2YgZW50cmllcyBjb250YWluZWQuXG4gICAqIEBwYXJhbSBwIFRoZSBwcmVkaWNhdGUgdG8gYXBwbHkgaW4gb3JkZXIgdG8gZmlsdGVyIHRoZSBjb3VudFxuICAgKiBcbiAgICogQGV4YW1wbGVcbiAgICogYGBgXG4gICAqIGNvbnN0IGNvbXBsZXRlUHJlZGljYXRlOiBQcmVkaWNhdGU8VG9kbz4gPSBmdW5jdGlvbiBwcmVkKHQ6IFRvZG8pIHtcbiAgICogICByZXR1cm4gdC5jb21wbGV0ZTtcbiAgICogfTtcbiAgICogXG4gICAqIGNvbnN0IGluY29tcGxldGVQcmVkaWNhdGU6IFByZWRpY2F0ZTxUb2RvPiA9IGZ1bmN0aW9uIHByZWQodDogVG9kbykge1xuICAgKiAgIHJldHVybiAhdC5jb21wbGV0ZTtcbiAgICogfTtcbiAgICogXG4gICAqIHN0b3JlLmNvdW50KCkuc3Vic2NyaWJlKChjKSA9PiB7XG4gICAqICAgY29uc29sZS5sb2coYFRoZSBvYnNlcnZlZCBjb3VudCBvZiBUb2RvIGVudGl0aWVzIGlzICR7Y31gKTtcbiAgICogfSk7XG4gICAqIHN0b3JlLmNvdW50KGluY29tcGxldGVQcmVkaWNhdGUpLnN1YnNjcmliZSgoYykgPT4ge1xuICAgKiAgIGNvbnNvbGUubG9nKGBUaGUgb2JzZXJ2ZWQgY291bnQgb2YgaW5jb21wbGV0ZSBUb2RvIGVudHRpaWVzIGlzICR7Y31gKTtcbiAgICogfSk7XG4gICAqIHN0b3JlLmNvdW50KGNvbXBsZXRlUHJlZGljYXRlKS5zdWJzY3JpYmUoKGMpID0+IHtcbiAgICogICBjb25zb2xlLmxvZyhgVGhlIG9ic2VydmVkIGNvdW50IG9mIGNvbXBsZXRlIFRvZG8gZW50dGlpZXMgaXMgJHtjfWApO1xuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBjb3VudChwPzogUHJlZGljYXRlPEU+KTogT2JzZXJ2YWJsZTxudW1iZXI+IHtcbiAgICBpZiAocCkge1xuICAgICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUoXG4gICAgICAgIG1hcCgoZTogRVtdKSA9PiBlLnJlZHVjZSgodG90YWwsIGUpID0+IHRvdGFsICsgKHAoZSkgPyAxIDogMCksIDApKVxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMubm90aWZ5LnBpcGUobWFwKChlbnRyaWVzOiBFW10pID0+IGVudHJpZXMubGVuZ3RoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJucyBhIHNuYXBzaG90IG9mIHRoZSBudW1iZXIgb2YgZW50cmllcyBjb250YWluZWQgaW4gdGhlIHN0b3JlLlxuICAgKiBAcGFyYW0gcCBUaGUgcHJlZGljYXRlIHRvIGFwcGx5IGluIG9yZGVyIHRvIGZpbHRlciB0aGUgY291bnRcbiAgICogXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYFxuICAgKiBjb25zdCBjb21wbGV0ZVByZWRpY2F0ZTogUHJlZGljYXRlPFRvZG8+ID0gZnVuY3Rpb24gcHJlZCh0OiBUb2RvKSB7XG4gICAqICAgcmV0dXJuIHQuY29tcGxldGU7XG4gICAqIH07XG4gICAqIFxuICAgKiBjb25zdCBpbmNvbXBsZXRlUHJlZGljYXRlOiBQcmVkaWNhdGU8VG9kbz4gPSBmdW5jdGlvbiBwcmVkKHQ6IFRvZG8pIHtcbiAgICogICByZXR1cm4gIXQuY29tcGxldGU7XG4gICAqIH07XG4gICAqIFxuICAgKiBjb25zdCBzbmFwc2hvdENvdW50ID0gc3RvcmUuY291bnRTbmFwc2hvdChjb21wbGV0ZVByZWRpY2F0ZSk7XG4gICAqIGNvbnNvbGUubG9nKGBUaGUgY291bnQgaXMgJHtzbmFwc2hvdENvdW50fWApO1xuICAgKiBcbiAgICogY29uc3QgY29tcGxldGVTbmFwc2hvdENvdW50ID0gc3RvcmUuY291bnRTbmFwc2hvdChjb21wbGV0ZVByZWRpY2F0ZSk7XG4gICAqIGNvbnNvbGUubG9nKFxuICAgKiAgIGBUaGUgY29tcGxldGUgVG9kbyBFbnRpdHkgU25hcHNob3QgY291bnQgaXMgJHtjb21wbGV0ZVNuYXBzaG90Q291bnR9YFxuICAgKiApO1xuICAgKiBcbiAgICogY29uc3QgaW5jb21wbGV0ZVNuYXBzaG90Q291bnQgPSBzdG9yZS5jb3VudFNuYXBzaG90KGluY29tcGxldGVQcmVkaWNhdGUpO1xuICAgKiBjb25zb2xlLmxvZyhcbiAgICogICBgVGhlIGluY29tcGxldGUgVG9kbyBFbnRpdHkgU25hcHNob3QgY291bnQgaXMgJHtpbmNvbXBsZXRlU25hcHNob3RDb3VudH1gXG4gICAqICk7XG4gICAqIGBgYFxuICAgKi9cbiAgY291bnRTbmFwc2hvdChwPzogUHJlZGljYXRlPEU+KTogbnVtYmVyIHtcbiAgICBpZiAocCkge1xuICAgICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKS5maWx0ZXIocCkubGVuZ3RoO1xuICAgIH1cbiAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpLmxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbmFwc2hvdCBvZiBhbGwgZW50cmllcy5cbiAgICogXG4gICAqIEByZXR1cm4gU25hcHNob3QgYXJyYXkgb2YgYWxsIHRoZSBlbGVtZW50cyB0aGUgZW50aXRpZXMgdGhlIHN0b3JlIGNvbnRhaW5zLlxuICAgKiBcbiAgICogQGV4YW1wbGUgT2JzZXJ2ZSBhIHNuYXBzaG90IG9mIGFsbCB0aGUgZW50aXRpZXMgaW4gdGhlIHN0b3JlLlxuICAgKiBcbiAgICogYGBgXG4gICAqIGxldCBzZWxlY3RlZFRvZG9zOlRvZG9bXSA9IHNvdXJjZS5hbGxTbmFwc2hvdCgpO1xuICAgKiBgYGBcbiAgICovXG4gIGFsbFNuYXBzaG90KCk6IEVbXSB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5lbnRyaWVzLnZhbHVlcygpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIGVudHJpZXMgY29udGFpbiB0aGUgaWRlbnRpZmllZCBpbnN0YW5jZS5cbiAgICogXG4gICAqIEBwYXJhbSB0YXJnZXQgRWl0aGVyIGFuIGluc3RhbmNlIG9mIHR5cGUgYEVgIG9yIGEgYGd1aWRgIGlkZW50aWZ5aW5nIHRoZSBpbnN0YW5jZS4gXG4gICAqIEBwYXJhbSBieUlkIFdoZXRoZXIgdGhlIGxvb2t1cCBzaG91bGQgYmUgcGVyZm9ybWVkIHdpdGggdGhlIGBpZGAga2V5IHJhdGhlciB0aGFuIHRoZSBgZ3VpZGAuXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGluc3RhbmNlIGlkZW50aWZpZWQgYnkgdGhlIGd1aWQgZXhpc3RzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IGNvbnRhaW5zOmJvb2xlYW4gPSBzb3VyY2UuY29udGFpbnMoZ3VpZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgY29udGFpbnModGFyZ2V0OiBFIHwgc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgaWYgKHR5cGVvZiB0YXJnZXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm4gdGhpcy5lbnRyaWVzLmdldCh0YXJnZXQpID8gdHJ1ZSA6IGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBndWlkOiBzdHJpbmcgPSAoPGFueT50YXJnZXQpW3RoaXMuY29uZmlnLmd1aWRLZXldO1xuICAgIHJldHVybiB0aGlzLmVudHJpZXMuZ2V0KGd1aWQpID8gdHJ1ZSA6IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdHJ1ZSBpZiB0aGUgZW50cmllcyBjb250YWluIHRoZSBpZGVudGlmaWVkIGluc3RhbmNlLlxuICAgKiBcbiAgICogQHBhcmFtIHRhcmdldCBFaXRoZXIgYW4gaW5zdGFuY2Ugb2YgdHlwZSBgRWAgb3IgYSBgaWRgIGlkZW50aWZ5aW5nIHRoZSBpbnN0YW5jZS4gXG4gICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGluc3RhbmNlIGlkZW50aWZpZWQgYnkgdGhlIGBpZGAgZXhpc3RzLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogbGV0IGNvbnRhaW5zOmJvb2xlYW4gPSBzb3VyY2UuY29udGFpbnMoZ3VpZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgY29udGFpbnNCeUlkKHRhcmdldDogRSB8IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIGlmICh0eXBlb2YgdGFyZ2V0ID09PSAnc3RyaW5nJykge1xuICAgICAgcmV0dXJuIHRoaXMuaWRFbnRyaWVzLmdldCh0YXJnZXQpID8gdHJ1ZSA6IGZhbHNlO1xuICAgIH1cbiAgICBjb25zdCBpZDogc3RyaW5nID0gKDxhbnk+dGFyZ2V0KVt0aGlzLmNvbmZpZy5pZEtleV07XG4gICAgcmV0dXJuIHRoaXMuaWRFbnRyaWVzLmdldChpZCkgPyB0cnVlIDogZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhbmQgcmV0dXJuIHRoZSBlbnRpdHkgaWRlbnRpZmllZCBieSB0aGUgR1VJRCBwYXJhbWV0ZXJcbiAgICogaWYgaXQgZXhpc3RzIGFuZCByZXR1cm4gaXQuXG4gICAqXG4gICAqIEBwYXJhbSBndWlkXG4gICAqIEByZXR1cm4gVGhlIGVudGl0eSBpbnN0YW5jZSBpZiBpdCBleGlzdHMsIG51bGwgb3RoZXJ3aXNlXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3QgZ2xvYmFsSUQ6IHN0cmluZyA9ICcxJztcbiAgICogbGV0IGZpbmRUaGlzVG9kbyA9IG5ldyBUb2RvKGZhbHNlLCAnRmluZCB0aGlzIFRvZG8nLCBnbG9iYWxJRCk7XG4gICAqIHN0b3JlLnBvc3QoZmluZFRoaXNUb2RvKTtcbiAgICogY29uc3QgdG9kbyA9IHN0b3JlLmZpbmRPbmUoZ2xvYmFsSUQpO1xuICAgKiBgYGBcbiAgICovXG4gIGZpbmRPbmUoZ3VpZDogc3RyaW5nKTogRSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuZW50cmllcy5nZXQoZ3VpZCk7XG4gIH1cblxuICAvKipcbiAgICogRmluZCBhbmQgcmV0dXJuIHRoZSBlbnRpdHkgaWRlbnRpZmllZCBieSB0aGUgSUQgcGFyYW1ldGVyXG4gICAqIGlmIGl0IGV4aXN0cyBhbmQgcmV0dXJuIGl0LlxuICAgKlxuICAgKiBAcGFyYW0gaWRcbiAgICogQHJldHVybiBUaGUgZW50aXR5IGluc3RhbmNlIGlmIGl0IGV4aXN0cywgbnVsbCBvdGhlcndpc2VcbiAgICogXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYFxuICAgKiBjb25zdCB0b2RvTGF0ZXI6IFRvZG8gPSBuZXcgVG9kbyhmYWxzZSwgJ0RvIG1lIGxhdGVyLicpO1xuICAgKiB0b2RvTGF0ZXIuaWQgPSAnZmluZE1lJztcbiAgICogc3RvcmUucG9zdCh0b2RvTGF0ZXIpO1xuICAgKiBjb25zdCBwb3N0ZWRUb2RvID0gc3RvcmUuZmluZE9uZUJ5SUQoJ2ZpbmRNZScpO1xuICAgKiBgYGBcbiAgICovXG4gIGZpbmRPbmVCeUlEKGlkOiBzdHJpbmcpOiBFIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5pZEVudHJpZXMuZ2V0KGlkKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTbmFwc2hvdCBvZiB0aGUgZW50cmllcyB0aGF0IG1hdGNoIHRoZSBwcmVkaWNhdGUuXG4gICAqXG4gICAqIEBwYXJhbSBwIFRoZSBwcmVkaWNhdGUgdXNlZCB0byBxdWVyeSBmb3IgdGhlIHNlbGVjdGlvbi5cbiAgICogQHJldHVybiBBIHNuYXBzaG90IGFycmF5IGNvbnRhaW5pbmcgdGhlIGVudGl0aWVzIHRoYXQgbWF0Y2ggdGhlIHByZWRpY2F0ZS5cbiAgICpcbiAgICogQGV4YW1wbGUgU2VsZWN0IGFsbCB0aGUgVG9kbyBpbnN0YW5jZXMgd2hlcmUgdGhlIHRpdGxlIGxlbmd0aCBpcyBncmVhdGVyIHRoYW4gMTAwLlxuICAgKiBgYGBcbiAgICogbGV0IHRvZG9zOlRvZG9bXT1zdG9yZS5zZWxlY3QodG9kbz0+dG9kby50aXRsZS5sZW5ndGg+MTAwKTtcbiAgICogYGBgXG4gICAqL1xuICBzZWxlY3QocDogUHJlZGljYXRlPEU+KTogRVtdIHtcbiAgICBjb25zdCBzZWxlY3RlZDogRVtdID0gW107XG4gICAgQXJyYXkuZnJvbSh0aGlzLmVudHJpZXMudmFsdWVzKCkpLmZvckVhY2goKGUpID0+IHtcbiAgICAgIGlmIChwKGUpKSB7XG4gICAgICAgIHNlbGVjdGVkLnB1c2goZSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHNlbGVjdGVkO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbXBhcmUgZW50aXRpZXMgYnkgR1VJRFxuICAgKiBcbiAgICogQHBhcmFtIGUxIFRoZSBmaXJzdCBlbnRpdHlcbiAgICogQHBhcmFtIGUyIFRoZSBzZWNvbmQgZW50aXR5XG4gICAqIEByZXR1cm4gdHJ1ZSBpZiB0aGUgdHdvIGVudGl0aWVzIGhhdmUgZXF1YWwgR1VJRCBpZHNcbiAgICpcbiAgICogQGV4YW1wbGUgQ29tcGFyZSB0b2RvMSB3aXRoIHRvZG8yIGJ5IGdpZC5cbiAgICogYGBgXG4gICAqIGlmIChlcXVhbHNCeUdVSUQodG9kbzEsIHRvZG8yKSl7Li4ufTtcbiAgICogYGBgXG4gICAqL1xuICBlcXVhbHNCeUdVSUQoZTE6IGFueSwgZTI6IGFueSkge1xuICAgIHJldHVybiBlMVt0aGlzLkdVSURfS0VZXSA9PSBlMlt0aGlzLkdVSURfS0VZXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21wYXJlIGVudGl0aWVzIGJ5IElEXG4gICAqIFxuICAgKiBAcGFyYW0gZTEgVGhlIGZpcnN0IGVudGl0eVxuICAgKiBAcGFyYW0gZTIgVGhlIHNlY29uZCBlbnRpdHlcbiAgICogQHJldHVybiB0cnVlIGlmIHRoZSB0d28gZW50aXRpZXMgaGF2ZSBlcXVhbCBJRCBpZHNcbiAgICpcbiAgICogQGV4YW1wbGUgQ29tcGFyZSB0b2RvMSB3aXRoIHRvZG8yIGJ5IGlkLlxuICAgKlxuICAgKiBgYGBcbiAgICogaWYgKGVxdWFsc0J5SUQodG9kbzEsIHRvZG8yKSl7Li4ufTtcbiAgICogYGBgXG4gICAqL1xuICBlcXVhbHNCeUlEKGUxOiBhbnksIGUyOiBhbnkpIHtcbiAgICByZXR1cm4gZTFbdGhpcy5JRF9LRVldID09IGUyW3RoaXMuSURfS0VZXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDYWxsIGRlc3Ryb3kgd2hlbiBkaXNwb3Npbmcgb2YgdGhlIHN0b3JlLCBhcyBpdFxuICAgKiBjb21wbGV0ZXMgYWxsIHtAbGluayBSZXBsYXlTdWJqZWN0fSBpbnN0YW5jZXMuXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogc3RvcmUuZGVzdHJveSgpO1xuICAgKiBgYGBcbiAgICovXG4gIGRlc3Ryb3koKSB7XG4gICAgdGhpcy5ub3RpZnkuY29tcGxldGUoKTtcbiAgICB0aGlzLm5vdGlmeURlbHRhLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5ub3RpZnlRdWVyeS5jb21wbGV0ZSgpO1xuICB9XG59XG4iXX0=