UNPKG

@fireflysemantics/slice

Version:
668 lines (665 loc) 62.3 kB
import { AbstractStore } from './AbstractStore'; import { GUID } from './utilities'; import { ReplaySubject, of } from 'rxjs'; import { takeWhile, filter, switchMap } from 'rxjs/operators'; import { Slice } from './Slice'; /** * This `todoFactory` code will be used to illustrate the API examples. The following * utilities are used in the tests and the API Typedoc examples contained here. * @example Utilities for API Examples * ``` * export const enum TodoSliceEnum { * COMPLETE = "Complete", * INCOMPLETE = "Incomplete" * } * export class Todo { * constructor( * public complete: boolean, * public title: string, * public gid?:string, * public id?:string) {} * } * * export let todos = [new Todo(false, "You complete me!"), new Todo(true, "You completed me!")]; * * export function todosFactory():Todo[] { * return [new Todo(false, "You complete me!"), new Todo(true, "You completed me!")]; * } * ``` */ export class EStore extends AbstractStore { /** * Store constructor (Initialization with element is optional) * * perform initial notification to all observers, * such that functions like {@link combineLatest}{} * will execute at least once. * * @param entities The entities to initialize the store with. * @param config The optional configuration instance. * * @example EStore<Todo> Creation * ``` * // Initialize the Store * let store: EStore<Todo> = new EStore<Todo>(todosFactory()); * ``` */ constructor(entities = [], config) { super(config); /** * Notifies observers when the store is empty. */ this.notifyActive = new ReplaySubject(1); /** * `Map` of active entties. The instance is public and can be used * directly to add and remove active entities, however we recommend * using the {@link addActive} and {@link deleteActive} methods. */ this.active = new Map(); /** * Notifies observers when the store is loading. * * This is a common pattern found when implementing * `Observable` data sources. */ this.notifyLoading = new ReplaySubject(1); /** * The current loading state. Use loading when fetching new * data for the store. The default loading state is `true`. * * This is such that if data is fetched asynchronously * in a service, components can wait on loading notification * before attempting to retrieve data from the service. * * Loading could be based on a composite response. For example * when the stock and mutual funds have loaded, set loading to `false`. */ this._loading = true; /** * Notifies observers that a search is in progress. * * This is a common pattern found when implementing * `Observable` data sources. */ this.notifySearching = new ReplaySubject(1); /** * The current `searching` state. Use `searching` * for example to display a spinnner * when performing a search. * The default `searching` state is `false`. */ this._searching = false; /** * Store slices */ this.slices = new Map(); const delta = { type: "Initialize" /* ActionTypes.INTIALIZE */, entries: entities }; this.post(entities); this.notifyDelta.next(delta); } /** * Calls complete on all EStore {@link ReplaySubject} instances. * * Call destroy when disposing of the store. */ destroy() { super.destroy(); this.notifyLoading.complete(); this.notifyActive.complete(); this.slices.forEach((slice) => slice.destroy()); } /** * Toggles the entity: * * If the store contains the entity * it will be deleted. If the store * does not contains the entity, * it is added. * @param e The entity to toggle * @example Toggle the Todo instance * ``` * estore.post(todo); * // Remove todo * estore.toggle(todo); * // Add it back * estore.toggle(todo); * ``` */ toggle(e) { if (this.contains(e)) { this.delete(e); } else { this.post(e); } } /** * Add multiple entity entities to active. * * If the entity is not contained in the store it is added * to the store before it is added to `active`. * * Also we clone the map prior to broadcasting it with * `notifyActive` to make sure we will trigger Angular * change detection in the event that it maintains * a reference to the `active` state `Map` instance. * * @example Add todo1 and todo2 as active * ``` * addActive(todo1); * addActive(todo2); * ``` */ addActive(e) { if (this.contains(e)) { this.active.set(e.gid, e); this.notifyActive.next(new Map(this.active)); } else { this.post(e); this.active.set(e.gid, e); this.notifyActive.next(new Map(this.active)); } } /** * Delete an active entity. * * Also we clone the map prior to broadcasting it with * `notifyActive` to make sure we will trigger Angular * change detection in the event that it maintains * a reference to the `active` state `Map` instance. * * @example Remove todo1 and todo2 as active entities * ``` * deleteActive(todo1); * deleteActive(todo2); * ``` */ deleteActive(e) { this.active.delete(e.gid); this.notifyActive.next(new Map(this.active)); } /** * Clear / reset the active entity map. * * Also we clone the map prior to broadcasting it with * `notifyActive` to make sure we will trigger Angular * change detection in the event that it maintains * a reference to the `active` state `Map` instance. * * @example Clear active todo instances * ``` * store.clearActive(); * ``` */ clearActive() { this.active.clear(); this.notifyActive.next(new Map(this.active)); } /** * Observe the active entities. * * @example * ``` * let active$ = store.observeActive(); * ``` */ observeActive() { return this.notifyActive.asObservable(); } /** * Observe the active entity. * @example <pre> let active$ = source.activeSnapshot(); </pre> */ activeSnapshot() { return Array.from(this.active.values()); } /** * Sets the current loading state and notifies observers. */ set loading(loading) { this._loading = loading; this.notifyLoading.next(this._loading); } /** * @return A snapshot of the loading state. * @example Create a reference to the loading state * ``` * const loading:boolean = todoStore.loading; * ``` */ get loading() { return this._loading; } /** * Observe loading. * * Note that this obverable piped through * `takeWhile(v->v, true), such that it will * complete after each emission. * * See: * https://fireflysemantics.medium.com/waiting-on-estore-to-load-8dcbe161613c * * For more details. * Also note that v=>v is the same as v=>v!=false * * @example * ``` * const observeLoadingHandler: Observer<boolean> = { * complete: () => { * console.log(`Data Loaded and Observable Marked as Complete`); * }, // completeHandler * error: () => { * console.log(`Any Errors?`); * }, // errorHandler * next: (l) => { * console.log(`Data loaded and loading is ${l}`); * }, * }; * * const observeLoadingResubscribeHandler: Observer<boolean> = { * complete: () => { * console.log(`Data Loaded and Resubscribe Observable Marked as Complete`); * }, // completeHandler * error: () => { * console.log(`Any Resubscribe Errors?`); * }, // errorHandler * next: (l) => { * console.log(`Data loaded and resusbscribe loading value is ${l}`); * }, * }; * * const todoStore: EStore<Todo> = new EStore(); * //============================================ * // Loading is true by default * //============================================ * console.log(`The initial value of loading is ${todoStore.loading}`); * //============================================ * // Observe Loading * //============================================ * let loading$: Observable<boolean> = todoStore.observeLoading(); * loading$.subscribe((l) => console.log(`The value of loading is ${l}`)); * * todoStore.loading = false; * loading$.subscribe(observeLoadingHandler); * //============================================ * // The subscription no longer fires * //============================================ * todoStore.loading = true; * todoStore.loading = false; * * //============================================ * // The subscription no longer fires, * // so if we want to observe loading again * // resusbscribe. * //============================================ * todoStore.loading = true; * loading$ = todoStore.observeLoading(); * loading$.subscribe(observeLoadingResubscribeHandler); * todoStore.loading = false; * ``` */ observeLoading() { return this.notifyLoading.asObservable().pipe(takeWhile((v) => v, true)); } /** * Notfiies when loading has completed. */ observeLoadingComplete() { return this.observeLoading().pipe(filter((loading) => loading == false), switchMap(() => of(true))); } /** * Sets the current searching state and notifies observers. */ set searching(searching) { this._searching = searching; this.notifySearching.next(this._searching); } /** * @return A snapshot of the searching state. */ get searching() { return this._searching; } /** * Observe searching. * @example <pre> let searching$ = source.observeSearching(); </pre> Note that this obverable piped through `takeWhile(v->v, true), such that it will complete after each emission. See: https://medium.com/@ole.ersoy/waiting-on-estore-to-load-8dcbe161613c For more details. */ observeSearching() { return this.notifySearching.asObservable().pipe(takeWhile((v) => v, true)); } /** * Notfiies when searching has completed. */ observeSearchingComplete() { return this.observeSearching().pipe(filter((searching) => searching == false), switchMap(() => of(true))); } /** * Adds a slice to the store and keys it by the slices label. * * @param p * @param label * * @example Setup a Todo Slice for COMPLETE Todos ``` source.addSlice(todo => todo.complete, TodoSlices.COMPLETE); ``` */ addSlice(p, label) { const slice = new Slice(label, p, this); this.slices.set(slice.label, slice); } /** * Remove a slice * @param label The label identifying the slice * * @example Remove the TodoSlices.COMPLETE Slice ``` source.removeSlice(TodoSlices.COMPLETE); ``` */ removeSlice(label) { this.slices.delete(label); } /** * Get a slice * @param label The label identifying the slice * @return The Slice instance or undefined * * @example Get the TodoSlices.COMPLETE slice ``` source.getSlice(TodoSlices.COMPLETE); ``` */ getSlice(label) { return this.slices.get(label); } /** * Post (Add a new) element(s) to the store. * @param e An indiidual entity or an array of entities * @example Post a Todo instance. * *``` * store.post(todo); *``` */ post(e) { if (!Array.isArray(e)) { const guid = e[this.GUID_KEY] ? e[this.GUID_KEY] : GUID(); e[this.GUID_KEY] = guid; this.entries.set(guid, e); this.updateIDEntry(e); Array.from(this.slices.values()).forEach((s) => { s.post(e); }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; const delta = { type: "Post" /* ActionTypes.POST */, entries: [e] }; this.notifyAll(v, delta); } else { this.postA(e); } } /** * Post N entities to the store. * @param ...e * @example Post two Todo instances. * ``` * store.post(todo1, todo2); * ``` */ postN(...e) { e.forEach((e) => { const guid = e[this.GUID_KEY] ? e[this.GUID_KEY] : GUID(); e[this.GUID_KEY] = guid; this.entries.set(guid, e); this.updateIDEntry(e); }); Array.from(this.slices.values()).forEach((s) => { s.postA(e); }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; const delta = { type: "Post" /* ActionTypes.POST */, entries: e }; this.notifyAll(v, delta); } /** * Post (Add) an array of elements to the store. * @param e * @example Post a Todo array. * * ``` * store.post([todo1, todo2]); * ``` */ postA(e) { this.postN(...e); } /** * Put (Update) an entity. * @param e * @example Put a Todo instance. * ``` * store.put(todo1); * ``` */ put(e) { if (!Array.isArray(e)) { let id = e[this.GUID_KEY]; this.entries.set(id, e); this.updateIDEntry(e); let v = [...Array.from(this.entries.values())]; this.notify.next(v); const delta = { type: "Put" /* ActionTypes.PUT */, entries: [e] }; this.notifyDelta.next(delta); Array.from(this.slices.values()).forEach((s) => { s.put(e); }); } else { this.putA(e); } } /** * Put (Update) an element or add an element that was read from a persistence source * and thus already has an assigned global id`. * @param e The enetity instances to update. * @example Put N Todo instances. * * ``` * store.put(todo1, todo2); * ``` */ putN(...e) { this.putA(e); } /** * Put (Update) the array of enntities. * @param e The array of enntities to update * @example Put an array of Todo instances. * ``` * store.put([todo1, todo2]); * ``` */ putA(e) { e.forEach((e) => { let guid = e[this.GUID_KEY]; this.entries.set(guid, e); this.updateIDEntry(e); }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; this.notify.next(v); const delta = { type: "Put" /* ActionTypes.PUT */, entries: e }; this.notifyDelta.next(delta); Array.from(this.slices.values()).forEach((s) => { s.putA(e); }); } /** * Delete (Update) the array of elements. * @param e * @example Delete todo1. * ``` * store.delete(todo1]); * ``` */ delete(e) { if (!Array.isArray(e)) { this.deleteActive(e); const guid = e[this.GUID_KEY]; this.entries.delete(guid); this.deleteIDEntry(e); Array.from(this.slices.values()).forEach((s) => { s.entries.delete(guid); }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; const delta = { type: "Delete" /* ActionTypes.DELETE */, entries: [e] }; this.notifyAll(v, delta); Array.from(this.slices.values()).forEach((s) => { s.delete(e); }); } else { this.deleteA(e); } } /** * Delete N elements. * @param ...e * @example Delete N Todo instance argument. * ``` * store.deleteN(todo1, todo2); * ``` */ deleteN(...e) { this.deleteA(e); } /** * Delete an array of elements. * @param e The array of instances to be deleted * @example Delete the array of Todo instances. * ``` * store.deleteA([todo1, todo2]); * ``` */ deleteA(e) { e.forEach((e) => { this.deleteActive(e); const guid = e[this.GUID_KEY]; this.entries.delete(guid); this.deleteIDEntry(e); Array.from(this.slices.values()).forEach((s) => { s.entries.delete(guid); }); }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; const delta = { type: "Delete" /* ActionTypes.DELETE */, entries: e }; this.notifyAll(v, delta); Array.from(this.slices.values()).forEach((s) => { s.deleteA(e); }); } /** * Delete elements by {@link Predicate}. * @param p The predicate. * @example Delete the Todo instances. * ``` * store.delete(todo1, todo2); * ``` */ deleteP(p) { const d = []; Array.from(this.entries.values()).forEach((e) => { if (p(e)) { d.push(e); const id = e[this.GUID_KEY]; this.entries.delete(id); this.deleteActive(e); this.deleteIDEntry(e); } }); //Create a new array reference to trigger Angular change detection. let v = [...Array.from(this.entries.values())]; const delta = { type: "Delete" /* ActionTypes.DELETE */, entries: d }; this.notifyAll(v, delta); Array.from(this.slices.values()).forEach((s) => { s.deleteA(d); }); } /** * If the entity has the `id` key initialized with a value, * then also add the entity to the `idEntries`. * * @param e The element to be added to the `idEntries`. */ updateIDEntry(e) { if (e[this.ID_KEY]) { this.idEntries.set(e[this.ID_KEY], e); } } /** * If the entity has the `id` key initialized with a value, * then also delete the entity to the `idEntries`. * * @param e The element to be added to the `idEntries`. */ deleteIDEntry(e) { if (e[this.ID_KEY]) { this.idEntries.delete(e[this.ID_KEY]); } } /** * Resets the store and all contained slice instances to empty. * Also perform delta notification that sends all current store entries. * The ActionType.RESET code is sent with the delta notification. Slices * send their own delta notification. * * @example Reset the store. * ``` * store.reset(); * ``` */ reset() { const delta = { type: "Reset" /* ActionTypes.RESET */, entries: Array.from(this.entries.values()), }; this.notifyAll([], delta); this.entries = new Map(); Array.from(this.slices.values()).forEach((s) => { s.reset(); }); } /** * Call all the notifiers at once. * * @param v * @param delta */ notifyAll(v, delta) { super.notifyAll(v, delta); this.notifyLoading.next(this.loading); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRVN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvc2xpY2Uvc3JjL2xpYi9FU3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRWhELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFHbkMsT0FBTyxFQUFFLGFBQWEsRUFBRSxFQUFFLEVBQTZCLE1BQU0sTUFBTSxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzlELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFFaEM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJHO0FBQ0gsTUFBTSxPQUFPLE1BQVUsU0FBUSxhQUFnQjtJQUM3Qzs7Ozs7Ozs7Ozs7Ozs7O09BZUc7SUFDSCxZQUFZLFdBQWdCLEVBQUUsRUFBRSxNQUFvQjtRQUNsRCxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7UUEyQ2hCOztXQUVHO1FBQ0ssaUJBQVksR0FBRyxJQUFJLGFBQWEsQ0FBaUIsQ0FBQyxDQUFDLENBQUM7UUFFNUQ7Ozs7V0FJRztRQUNJLFdBQU0sR0FBbUIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQXNHMUM7Ozs7O1dBS0c7UUFDSyxrQkFBYSxHQUFHLElBQUksYUFBYSxDQUFVLENBQUMsQ0FBQyxDQUFDO1FBRXREOzs7Ozs7Ozs7O1dBVUc7UUFDSyxhQUFRLEdBQVksSUFBSSxDQUFDO1FBbUhqQzs7Ozs7V0FLRztRQUNLLG9CQUFlLEdBQUcsSUFBSSxhQUFhLENBQVUsQ0FBQyxDQUFDLENBQUM7UUFFeEQ7Ozs7O1dBS0c7UUFDSyxlQUFVLEdBQVksS0FBSyxDQUFDO1FBK0NwQzs7V0FFRztRQUNLLFdBQU0sR0FBMEIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQWhXaEQsTUFB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QUFLLEVBQUUsQ0FBQztRQUNaLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ2dCLFNBQVMsQ0FBQyxDQUFNLEVBQUUsS0FBZTtRQUNsRCxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMxQixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDeEMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQWJzdHJhY3RTdG9yZSB9IGZyb20gJy4vQWJzdHJhY3RTdG9yZSc7XG5pbXBvcnQgeyBTdG9yZUNvbmZpZyB9IGZyb20gJy4vbW9kZWxzL1N0b3JlQ29uZmlnJztcbmltcG9ydCB7IEdVSUQgfSBmcm9tICcuL3V0aWxpdGllcyc7XG5cbmltcG9ydCB7IEFjdGlvblR5cGVzLCBQcmVkaWNhdGUsIERlbHRhIH0gZnJvbSAnLi9tb2RlbHMvJztcbmltcG9ydCB7IFJlcGxheVN1YmplY3QsIG9mLCBPYnNlcnZhYmxlLCBjb21iaW5lTGF0ZXN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyB0YWtlV2hpbGUsIGZpbHRlciwgc3dpdGNoTWFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgU2xpY2UgfSBmcm9tICcuL1NsaWNlJztcblxuLyoqXG4gKiBUaGlzIGB0b2RvRmFjdG9yeWAgY29kZSB3aWxsIGJlIHVzZWQgdG8gaWxsdXN0cmF0ZSB0aGUgQVBJIGV4YW1wbGVzLiAgVGhlIGZvbGxvd2luZ1xuICogdXRpbGl0aWVzIGFyZSB1c2VkIGluIHRoZSB0ZXN0cyBhbmQgdGhlIEFQSSBUeXBlZG9jIGV4YW1wbGVzIGNvbnRhaW5lZCBoZXJlLlxuICogQGV4YW1wbGUgVXRpbGl0aWVzIGZvciBBUEkgRXhhbXBsZXNcbiAqIGBgYFxuICogZXhwb3J0IGNvbnN0IGVudW0gVG9kb1NsaWNlRW51bSB7XG4gKiAgICBDT01QTEVURSA9IFwiQ29tcGxldGVcIixcbiAqICAgIElOQ09NUExFVEUgPSBcIkluY29tcGxldGVcIlxuICogfVxuICogZXhwb3J0IGNsYXNzIFRvZG8ge1xuICogICAgY29uc3RydWN0b3IoXG4gKiAgICAgICAgIHB1YmxpYyBjb21wbGV0ZTogYm9vbGVhbixcbiAqICAgICAgICAgcHVibGljIHRpdGxlOiBzdHJpbmcsXG4gKiAgICAgICAgIHB1YmxpYyBnaWQ/OnN0cmluZyxcbiAqICAgICAgICAgcHVibGljIGlkPzpzdHJpbmcpIHt9XG4gKiB9XG4gKlxuICogZXhwb3J0IGxldCB0b2RvcyA9IFtuZXcgVG9kbyhmYWxzZSwgXCJZb3UgY29tcGxldGUgbWUhXCIpLCBuZXcgVG9kbyh0cnVlLCBcIllvdSBjb21wbGV0ZWQgbWUhXCIpXTtcbiAqXG4gKiBleHBvcnQgZnVuY3Rpb24gdG9kb3NGYWN0b3J5KCk6VG9kb1tdIHtcbiAqICAgcmV0dXJuIFtuZXcgVG9kbyhmYWxzZSwgXCJZb3UgY29tcGxldGUgbWUhXCIpLCBuZXcgVG9kbyh0cnVlLCBcIllvdSBjb21wbGV0ZWQgbWUhXCIpXTtcbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgY2xhc3MgRVN0b3JlPEU+IGV4dGVuZHMgQWJzdHJhY3RTdG9yZTxFPiB7XG4gIC8qKlxuICAgKiBTdG9yZSBjb25zdHJ1Y3RvciAoSW5pdGlhbGl6YXRpb24gd2l0aCBlbGVtZW50IGlzIG9wdGlvbmFsKVxuICAgKlxuICAgKiBwZXJmb3JtIGluaXRpYWwgbm90aWZpY2F0aW9uIHRvIGFsbCBvYnNlcnZlcnMsXG4gICAqIHN1Y2ggdGhhdCBmdW5jdGlvbnMgbGlrZSB7QGxpbmsgY29tYmluZUxhdGVzdH17fVxuICAgKiB3aWxsIGV4ZWN1dGUgYXQgbGVhc3Qgb25jZS5cbiAgICogXG4gICAqIEBwYXJhbSBlbnRpdGllcyBUaGUgZW50aXRpZXMgdG8gaW5pdGlhbGl6ZSB0aGUgc3RvcmUgd2l0aC5cbiAgICogQHBhcmFtIGNvbmZpZyBUaGUgb3B0aW9uYWwgY29uZmlndXJhdGlvbiBpbnN0YW5jZS5cbiAgICogXG4gICAqIEBleGFtcGxlIEVTdG9yZTxUb2RvPiBDcmVhdGlvblxuICAgKiBgYGBcbiAgICogLy8gSW5pdGlhbGl6ZSB0aGUgU3RvcmVcbiAgICogbGV0IHN0b3JlOiBFU3RvcmU8VG9kbz4gPSBuZXcgRVN0b3JlPFRvZG8+KHRvZG9zRmFjdG9yeSgpKTtcbiAgICogYGBgXG4gICAqL1xuICBjb25zdHJ1Y3RvcihlbnRpdGllczogRVtdID0gW10sIGNvbmZpZz86IFN0b3JlQ29uZmlnKSB7XG4gICAgc3VwZXIoY29uZmlnKTtcbiAgICBjb25zdCBkZWx0YTogRGVsdGE8RT4gPSB7IHR5cGU6IEFjdGlvblR5cGVzLklOVElBTElaRSwgZW50cmllczogZW50aXRpZXMgfTtcbiAgICB0aGlzLnBvc3QoZW50aXRpZXMpO1xuICAgIHRoaXMubm90aWZ5RGVsdGEubmV4dChkZWx0YSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FsbHMgY29tcGxldGUgb24gYWxsIEVTdG9yZSB7QGxpbmsgUmVwbGF5U3ViamVjdH0gaW5zdGFuY2VzLlxuICAgKlxuICAgKiBDYWxsIGRlc3Ryb3kgd2hlbiBkaXNwb3Npbmcgb2YgdGhlIHN0b3JlLlxuICAgKi9cbiAgb3ZlcnJpZGUgZGVzdHJveSgpIHtcbiAgICBzdXBlci5kZXN0cm95KCk7XG4gICAgdGhpcy5ub3RpZnlMb2FkaW5nLmNvbXBsZXRlKCk7XG4gICAgdGhpcy5ub3RpZnlBY3RpdmUuY29tcGxldGUoKTtcbiAgICB0aGlzLnNsaWNlcy5mb3JFYWNoKChzbGljZSkgPT4gc2xpY2UuZGVzdHJveSgpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUb2dnbGVzIHRoZSBlbnRpdHk6XG4gICAqXG4gICAqIElmIHRoZSBzdG9yZSBjb250YWlucyB0aGUgZW50aXR5XG4gICAqIGl0IHdpbGwgYmUgZGVsZXRlZC4gIElmIHRoZSBzdG9yZVxuICAgKiBkb2VzIG5vdCBjb250YWlucyB0aGUgZW50aXR5LFxuICAgKiBpdCBpcyBhZGRlZC5cbiAgICogQHBhcmFtIGUgVGhlIGVudGl0eSB0byB0b2dnbGVcbiAgICogQGV4YW1wbGUgVG9nZ2xlIHRoZSBUb2RvIGluc3RhbmNlXG4gICAqIGBgYFxuICAgKiBlc3RvcmUucG9zdCh0b2RvKTtcbiAgICogLy8gUmVtb3ZlIHRvZG9cbiAgICogZXN0b3JlLnRvZ2dsZSh0b2RvKTtcbiAgICogLy8gQWRkIGl0IGJhY2tcbiAgICogZXN0b3JlLnRvZ2dsZSh0b2RvKTtcbiAgICogYGBgXG4gICAqL1xuICBwdWJsaWMgdG9nZ2xlKGU6IEUpIHtcbiAgICBpZiAodGhpcy5jb250YWlucyhlKSkge1xuICAgICAgdGhpcy5kZWxldGUoZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucG9zdChlKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogTm90aWZpZXMgb2JzZXJ2ZXJzIHdoZW4gdGhlIHN0b3JlIGlzIGVtcHR5LlxuICAgKi9cbiAgcHJpdmF0ZSBub3RpZnlBY3RpdmUgPSBuZXcgUmVwbGF5U3ViamVjdDxNYXA8c3RyaW5nLCBFPj4oMSk7XG5cbiAgLyoqXG4gICAqIGBNYXBgIG9mIGFjdGl2ZSBlbnR0aWVzLiBUaGUgaW5zdGFuY2UgaXMgcHVibGljIGFuZCBjYW4gYmUgdXNlZFxuICAgKiBkaXJlY3RseSB0byBhZGQgYW5kIHJlbW92ZSBhY3RpdmUgZW50aXRpZXMsIGhvd2V2ZXIgd2UgcmVjb21tZW5kXG4gICAqIHVzaW5nIHRoZSB7QGxpbmsgYWRkQWN0aXZlfSBhbmQge0BsaW5rIGRlbGV0ZUFjdGl2ZX0gbWV0aG9kcy5cbiAgICovXG4gIHB1YmxpYyBhY3RpdmU6IE1hcDxzdHJpbmcsIEU+ID0gbmV3IE1hcCgpO1xuXG4gIC8qKlxuICAgKiBBZGQgbXVsdGlwbGUgZW50aXR5IGVudGl0aWVzIHRvIGFjdGl2ZS5cbiAgICpcbiAgICogSWYgdGhlIGVudGl0eSBpcyBub3QgY29udGFpbmVkIGluIHRoZSBzdG9yZSBpdCBpcyBhZGRlZFxuICAgKiB0byB0aGUgc3RvcmUgYmVmb3JlIGl0IGlzIGFkZGVkIHRvIGBhY3RpdmVgLlxuICAgKlxuICAgKiBBbHNvIHdlIGNsb25lIHRoZSBtYXAgcHJpb3IgdG8gYnJvYWRjYXN0aW5nIGl0IHdpdGhcbiAgICogYG5vdGlmeUFjdGl2ZWAgdG8gbWFrZSBzdXJlIHdlIHdpbGwgdHJpZ2dlciBBbmd1bGFyXG4gICAqIGNoYW5nZSBkZXRlY3Rpb24gaW4gdGhlIGV2ZW50IHRoYXQgaXQgbWFpbnRhaW5zXG4gICAqIGEgcmVmZXJlbmNlIHRvIHRoZSBgYWN0aXZlYCBzdGF0ZSBgTWFwYCBpbnN0YW5jZS5cbiAgICpcbiAgICogQGV4YW1wbGUgQWRkIHRvZG8xIGFuZCB0b2RvMiBhcyBhY3RpdmVcbiAgICogYGBgXG4gICAqIGFkZEFjdGl2ZSh0b2RvMSk7XG4gICAqIGFkZEFjdGl2ZSh0b2RvMik7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIGFkZEFjdGl2ZShlOiBFKSB7XG4gICAgaWYgKHRoaXMuY29udGFpbnMoZSkpIHtcbiAgICAgIHRoaXMuYWN0aXZlLnNldCgoPGFueT5lKS5naWQsIGUpO1xuICAgICAgdGhpcy5ub3RpZnlBY3RpdmUubmV4dChuZXcgTWFwKHRoaXMuYWN0aXZlKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucG9zdChlKTtcbiAgICAgIHRoaXMuYWN0aXZlLnNldCgoPGFueT5lKS5naWQsIGUpO1xuICAgICAgdGhpcy5ub3RpZnlBY3RpdmUubmV4dChuZXcgTWFwKHRoaXMuYWN0aXZlKSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIERlbGV0ZSBhbiBhY3RpdmUgZW50aXR5LlxuICAgKlxuICAgKiBBbHNvIHdlIGNsb25lIHRoZSBtYXAgcHJpb3IgdG8gYnJvYWRjYXN0aW5nIGl0IHdpdGhcbiAgICogYG5vdGlmeUFjdGl2ZWAgdG8gbWFrZSBzdXJlIHdlIHdpbGwgdHJpZ2dlciBBbmd1bGFyXG4gICAqIGNoYW5nZSBkZXRlY3Rpb24gaW4gdGhlIGV2ZW50IHRoYXQgaXQgbWFpbnRhaW5zXG4gICAqIGEgcmVmZXJlbmNlIHRvIHRoZSBgYWN0aXZlYCBzdGF0ZSBgTWFwYCBpbnN0YW5jZS5cbiAgICpcbiAgICogQGV4YW1wbGUgUmVtb3ZlIHRvZG8xIGFuZCB0b2RvMiBhcyBhY3RpdmUgZW50aXRpZXNcbiAgICogYGBgXG4gICAqIGRlbGV0ZUFjdGl2ZSh0b2RvMSk7XG4gICAqIGRlbGV0ZUFjdGl2ZSh0b2RvMik7XG4gICAqIGBgYFxuICAgKi9cbiAgcHVibGljIGRlbGV0ZUFjdGl2ZShlOiBFKSB7XG4gICAgdGhpcy5hY3RpdmUuZGVsZXRlKCg8YW55PmUpLmdpZCk7XG4gICAgdGhpcy5ub3RpZnlBY3RpdmUubmV4dChuZXcgTWFwKHRoaXMuYWN0aXZlKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgLyByZXNldCB0aGUgYWN0aXZlIGVudGl0eSBtYXAuXG4gICAqXG4gICAqIEFsc28gd2UgY2xvbmUgdGhlIG1hcCBwcmlvciB0byBicm9hZGNhc3RpbmcgaXQgd2l0aFxuICAgKiBgbm90aWZ5QWN0aXZlYCB0byBtYWtlIHN1cmUgd2Ugd2lsbCB0cmlnZ2VyIEFuZ3VsYXJcbiAgICogY2hhbmdlIGRldGVjdGlvbiBpbiB0aGUgZXZlbnQgdGhhdCBpdCBtYWludGFpbnNcbiAgICogYSByZWZlcmVuY2UgdG8gdGhlIGBhY3RpdmVgIHN0YXRlIGBNYXBgIGluc3RhbmNlLlxuICAgKlxuICAgKiBAZXhhbXBsZSBDbGVhciBhY3RpdmUgdG9kbyBpbnN0YW5jZXNcbiAgICogYGBgXG4gICAqIHN0b3JlLmNsZWFyQWN0aXZlKCk7XG4gICAqIGBgYFxuICAgKi9cbiAgY2xlYXJBY3RpdmUoKSB7XG4gICAgdGhpcy5hY3RpdmUuY2xlYXIoKTtcbiAgICB0aGlzLm5vdGlmeUFjdGl2ZS5uZXh0KG5ldyBNYXAodGhpcy5hY3RpdmUpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnNlcnZlIHRoZSBhY3RpdmUgZW50aXRpZXMuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYFxuICAgKiBsZXQgYWN0aXZlJCA9IHN0b3JlLm9ic2VydmVBY3RpdmUoKTtcbiAgICogYGBgXG4gICAqL1xuICBwdWJsaWMgb2JzZXJ2ZUFjdGl2ZSgpIHtcbiAgICByZXR1cm4gdGhpcy5ub3RpZnlBY3RpdmUuYXNPYnNlcnZhYmxlKCk7XG4gIH1cblxuICAvKipcbiAgICogT2JzZXJ2ZSB0aGUgYWN0aXZlIGVudGl0eS5cbiAgICogQGV4YW1wbGVcbiAgICAgPHByZT5cbiAgICBsZXQgYWN0aXZlJCA9IHNvdXJjZS5hY3RpdmVTbmFwc2hvdCgpO1xuICAgIDwvcHJlPlxuICAqL1xuICBwdWJsaWMgYWN0aXZlU25hcHNob3QoKSB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20odGhpcy5hY3RpdmUudmFsdWVzKCkpO1xuICB9XG5cbiAgLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gTE9BRElOR1xuICAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBPYnNlcnZhYmxlIG9mIGVycm9ycyBvY2N1cnJlZCBkdXJpbmcgYSBsb2FkIHJlcXVlc3QuXG4gICAqXG4gICAqIFRoZSBlcnJvciBPYnNlcnZhYmxlIHNob3VsZCBiZSBjcmVhdGVkIGJ5IHRoZVxuICAgKiBjbGllbnQuXG4gICAqL1xuICBwdWJsaWMgbG9hZGluZ0Vycm9yITogT2JzZXJ2YWJsZTxhbnk+O1xuXG4gIC8qKlxuICAgKiBOb3RpZmllcyBvYnNlcnZlcnMgd2hlbiB0aGUgc3RvcmUgaXMgbG9hZGluZy5cbiAgICpcbiAgICogVGhpcyBpcyBhIGNvbW1vbiBwYXR0ZXJuIGZvdW5kIHdoZW4gaW1wbGVtZW50aW5nXG4gICAqIGBPYnNlcnZhYmxlYCBkYXRhIHNvdXJjZXMuXG4gICAqL1xuICBwcml2YXRlIG5vdGlmeUxvYWRpbmcgPSBuZXcgUmVwbGF5U3ViamVjdDxib29sZWFuPigxKTtcblxuICAvKipcbiAgICogVGhlIGN1cnJlbnQgbG9hZGluZyBzdGF0ZS4gIFVzZSBsb2FkaW5nIHdoZW4gZmV0Y2hpbmcgbmV3XG4gICAqIGRhdGEgZm9yIHRoZSBzdG9yZS4gIFRoZSBkZWZhdWx0IGxvYWRpbmcgc3RhdGUgaXMgYHRydWVgLlxuICAgKlxuICAgKiBUaGlzIGlzIHN1Y2ggdGhhdCBpZiBkYXRhIGlzIGZldGNoZWQgYXN5bmNocm9ub3VzbHlcbiAgICogaW4gYSBzZXJ2aWNlLCBjb21wb25lbnRzIGNhbiB3YWl0IG9uIGxvYWRpbmcgbm90aWZpY2F0aW9uXG4gICAqIGJlZm9yZSBhdHRlbXB0aW5nIHRvIHJldHJpZXZlIGRhdGEgZnJvbSB0aGUgc2VydmljZS5cbiAgICpcbiAgICogTG9hZGluZyBjb3VsZCBiZSBiYXNlZCBvbiBhIGNvbXBvc2l0ZSByZXNwb25zZS4gIEZvciBleGFtcGxlXG4gICAqIHdoZW4gdGhlIHN0b2NrIGFuZCBtdXR1YWwgZnVuZHMgaGF2ZSBsb2FkZWQsIHNldCBsb2FkaW5nIHRvIGBmYWxzZWAuXG4gICAqL1xuICBwcml2YXRlIF9sb2FkaW5nOiBib29sZWFuID0gdHJ1ZTtcblxuICAvKipcbiAgICogU2V0cyB0aGUgY3VycmVudCBsb2FkaW5nIHN0YXRlIGFuZCBub3RpZmllcyBvYnNlcnZlcnMuXG4gICAqL1xuICBzZXQgbG9hZGluZyhsb2FkaW5nOiBib29sZWFuKSB7XG4gICAgdGhpcy5fbG9hZGluZyA9IGxvYWRpbmc7XG4gICAgdGhpcy5ub3RpZnlMb2FkaW5nLm5leHQodGhpcy5fbG9hZGluZyk7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiBBIHNuYXBzaG90IG9mIHRoZSBsb2FkaW5nIHN0YXRlLlxuICAgKiBAZXhhbXBsZSBDcmVhdGUgYSByZWZlcmVuY2UgdG8gdGhlIGxvYWRpbmcgc3RhdGVcbiAgICogYGBgXG4gICAqIGNvbnN0IGxvYWRpbmc6Ym9vbGVhbiA9IHRvZG9TdG9yZS5sb2FkaW5nO1xuICAgKiBgYGBcbiAgICovXG4gIGdldCBsb2FkaW5nKCkge1xuICAgIHJldHVybiB0aGlzLl9sb2FkaW5nO1xuICB9XG5cbiAgLyoqXG4gICAqIE9ic2VydmUgbG9hZGluZy5cbiAgICpcbiAgICogTm90ZSB0aGF0IHRoaXMgb2J2ZXJhYmxlIHBpcGVkIHRocm91Z2hcbiAgICogYHRha2VXaGlsZSh2LT52LCB0cnVlKSwgc3VjaCB0aGF0IGl0IHdpbGxcbiAgICogY29tcGxldGUgYWZ0ZXIgZWFjaCBlbWlzc2lvbi5cbiAgICpcbiAgICogU2VlOlxuICAgKiBodHRwczovL2ZpcmVmbHlzZW1hbnRpY3MubWVkaXVtLmNvbS93YWl0aW5nLW9uLWVzdG9yZS10by1sb2FkLThkY2JlMTYxNjEzY1xuICAgKlxuICAgKiBGb3IgbW9yZSBkZXRhaWxzLlxuICAgKiBBbHNvIG5vdGUgdGhhdCB2PT52IGlzIHRoZSBzYW1lIGFzIHY9PnYhPWZhbHNlXG4gICAqIFxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGBcbiAgICogY29uc3Qgb2JzZXJ2ZUxvYWRpbmdIYW5kbGVyOiBPYnNlcnZlcjxib29sZWFuPiA9IHtcbiAgICogICBjb21wbGV0ZTogKCkgPT4ge1xuICAgKiAgICAgY29uc29sZS5sb2coYERhdGEgTG9hZGVkIGFuZCBPYnNlcnZhYmxlIE1hcmtlZCBhcyBDb21wbGV0ZWApO1xuICAgKiAgIH0sIC8vIGNvbXBsZXRlSGFuZGxlclxuICAgKiAgIGVycm9yOiAoKSA9PiB7XG4gICAqICAgICBjb25zb2xlLmxvZyhgQW55IEVycm9ycz9gKTtcbiAgICogICB9LCAvLyBlcnJvckhhbmRsZXJcbiAgICogICBuZXh0OiAobCkgPT4ge1xuICAgKiAgICAgY29uc29sZS5sb2coYERhdGEgbG9hZGVkIGFuZCBsb2FkaW5nIGlzICR7bH1gKTtcbiAgICogICB9LFxuICAgKiB9O1xuICAgKlxuICAgKiBjb25zdCBvYnNlcnZlTG9hZGluZ1Jlc3Vic2NyaWJlSGFuZGxlcjogT2JzZXJ2ZXI8Ym9vbGVhbj4gPSB7XG4gICAqICAgY29tcGxldGU6ICgpID0+IHtcbiAgICogICAgIGNvbnNvbGUubG9nKGBEYXRhIExvYWRlZCBhbmQgUmVzdWJzY3JpYmUgT2JzZXJ2YWJsZSBNYXJrZWQgYXMgQ29tcGxldGVgKTtcbiAgICogICB9LCAvLyBjb21wbGV0ZUhhbmRsZXJcbiAgICogICBlcnJvcjogKCkgPT4ge1xuICAgKiAgICAgY29uc29sZS5sb2coYEFueSBSZXN1YnNjcmliZSBFcnJvcnM/YCk7XG4gICAqICAgfSwgLy8gZXJyb3JIYW5kbGVyXG4gICAqICAgbmV4dDogKGwpID0+IHtcbiAgICogICAgIGNvbnNvbGUubG9nKGBEYXRhIGxvYWRlZCBhbmQgcmVzdXNic2NyaWJlIGxvYWRpbmcgIHZhbHVlIGlzICR7bH1gKTtcbiAgICogICB9LFxuICAgKiB9O1xuICAgKlxuICAgKiBjb25zdCB0b2RvU3RvcmU6IEVTdG9yZTxUb2RvPiA9IG5ldyBFU3RvcmUoKTtcbiAgICogLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAgKiAvLyBMb2FkaW5nIGlzIHRydWUgYnkgZGVmYXVsdFxuICAgKiAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAqIGNvbnNvbGUubG9nKGBUaGUgaW5pdGlhbCB2YWx1ZSBvZiBsb2FkaW5nIGlzICR7dG9kb1N0b3JlLmxvYWRpbmd9YCk7XG4gICAqIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICogLy8gT2JzZXJ2ZSBMb2FkaW5nXG4gICAqIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICogbGV0IGxvYWRpbmckOiBPYnNlcnZhYmxlPGJvb2xlYW4+ID0gdG9kb1N0b3JlLm9ic2VydmVMb2FkaW5nKCk7XG4gICAqIGxvYWRpbmckLnN1YnNjcmliZSgobCkgPT4gY29uc29sZS5sb2coYFRoZSB2YWx1ZSBvZiBsb2FkaW5nIGlzICR7bH1gKSk7XG4gICAqXG4gICAqIHRvZG9TdG9yZS5sb2FkaW5nID0gZmFsc2U7XG4gICAqIGxvYWRpbmckLnN1YnNjcmliZShvYnNlcnZlTG9hZGluZ0hhbmRsZXIpO1xuICAgKiAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAqIC8vIFRoZSBzdWJzY3JpcHRpb24gbm8gbG9uZ2VyIGZpcmVzXG4gICAqIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICogdG9kb1N0b3JlLmxvYWRpbmcgPSB0cnVlO1xuICAgKiB0b2RvU3RvcmUubG9hZGluZyA9IGZhbHNlO1xuICAgKlxuICAgKiAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gICAqIC8vIFRoZSBzdWJzY3JpcHRpb24gbm8gbG9uZ2VyIGZpcmVzLFxuICAgKiAvLyBzbyBpZiB3ZSB3YW50IHRvIG9ic2VydmUgbG9hZGluZyBhZ2FpblxuICAgKiAvLyByZXN1c2JzY3JpYmUuXG4gICAqIC8vPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgICogdG9kb1N0b3JlLmxvYWRpbmcgPSB0cnVlO1xuICAgKiBsb2FkaW5nJCA9IHRvZG9TdG9yZS5vYnNlcnZlTG9hZGluZygpO1xuICAgKiBsb2FkaW5nJC5zdWJzY3JpYmUob2JzZXJ2ZUxvYWRpbmdSZXN1YnNjcmliZUhhbmRsZXIpO1xuICAgKiB0b2RvU3RvcmUubG9hZGluZyA9IGZhbHNlO1xuICAgKiBgYGBcbiAgICovXG4gIHB1YmxpYyBvYnNlcnZlTG9hZGluZygpIHtcbiAgICByZXR1cm4gdGhpcy5ub3RpZnlMb2FkaW5nLmFzT2JzZXJ2YWJsZSgpLnBpcGUodGFrZVdoaWxlKCh2KSA9PiB2LCB0cnVlKSk7XG4gIH1cblxuICAvKipcbiAgICogTm90ZmlpZXMgd2hlbiBsb2FkaW5nIGhhcyBjb21wbGV0ZWQuXG4gICAqL1xuICBwdWJsaWMgb2JzZXJ2ZUxvYWRpbmdDb21wbGV0ZSgpIHtcbiAgICByZXR1cm4gdGhpcy5vYnNlcnZlTG9hZGluZygpLnBpcGUoXG4gICAgICBmaWx0ZXIoKGxvYWRpbmcpID0+IGxvYWRpbmcgPT0gZmFsc2UpLFxuICAgICAgc3dpdGNoTWFwKCgpID0+IG9mKHRydWUpKVxuICAgICk7XG4gIH1cblxuICAvLz09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBTRUFSQ0hJTkdcbiAgLy89PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLyoqXG4gICAqIE9ic2VydmFibGUgb2YgZXJyb3JzIG9jY3VycmVkIGR1cmluZyBhIHNlYXJjaCByZXF1ZXN0LlxuICAgKlxuICAgKiBUaGUgZXJyb3IgT2JzZXJ2YWJsZSBzaG91bGQgYmUgY3JlYXRlZCBieSB0aGVcbiAgICogY2xpZW50LlxuICAgKi9cbiAgcHVibGljIHNlYXJjaEVycm9yITogT2JzZXJ2YWJsZTxhbnk+O1xuXG4gIC8qKlxuICAgKiBOb3RpZmllcyBvYnNlcnZlcnMgdGhhdCBhIHNlYXJjaCBpcyBpbiBwcm9ncmVzcy5cbiAgICpcbiAgICogVGhpcyBpcyBhIGNvbW1vbiBwYXR0ZXJuIGZvdW5kIHdoZW4gaW1wbGVtZW50aW5nXG4gICAqIGBPYnNlcnZhYmxlYCBkYXRhIHNvdXJjZXMuXG4gICAqL1xuICBwcml2YXRlIG5vdGlmeVNlYXJjaGluZyA9IG5ldyBSZXBsYXlTdWJqZWN0PGJvb2xlYW4+KDEpO1xuXG4gIC8qKlxuICAgKiBUaGUgY3VycmVudCBgc2VhcmNoaW5nYCBzdGF0ZS4gIFVzZSBgc2VhcmNoaW5nYFxuICAgKiBmb3IgZXhhbXBsZSB0byBkaXNwbGF5IGEgc3Bpbm5uZXJcbiAgICogd2hlbiBwZXJmb3JtaW5nIGEgc2VhcmNoLlxuICAgKiBUaGUgZGVmYXVsdCBgc2VhcmNoaW5nYCBzdGF0ZSBpcyBgZmFsc2VgLlxuICAgKi9cbiAgcHJpdmF0ZSBfc2VhcmNoaW5nOiBib29sZWFuID0gZmFsc2U7XG5cbiAgLyoqXG4gICAqIFNldHMgdGhlIGN1cnJlbnQgc2VhcmNoaW5nIHN0YXRlIGFuZCBub3RpZmllcyBvYnNlcnZlcnMuXG4gICAqL1xuICBzZXQgc2VhcmNoaW5nKHNlYXJjaGluZzogYm9vbGVhbikge1xuICAgIHRoaXMuX3NlYXJjaGluZyA9IHNlYXJjaGluZztcbiAgICB0aGlzLm5vdGlmeVNlYXJjaGluZy5uZXh0KHRoaXMuX3NlYXJjaGluZyk7XG4gIH1cblxuICAvKipcbiAgICogQHJldHVybiBBIHNuYXBzaG90IG9mIHRoZSBzZWFyY2hpbmcgc3RhdGUuXG4gICAqL1xuICBnZXQgc2VhcmNoaW5nKCkge1xuICAgIHJldHVybiB0aGlzLl9zZWFyY2hpbmc7XG4gIH1cblxuICAvKipcbiAgICogT2JzZXJ2ZSBzZWFyY2hpbmcuXG4gICAqIEBleGFtcGxlXG4gICAgIDxwcmU+XG4gICAgbGV0IHNlYXJjaGluZyQgPSBzb3VyY2Uub2JzZXJ2ZVNlYXJjaGluZygpO1xuICAgIDwvcHJlPlxuICBcbiAgICBOb3RlIHRoYXQgdGhpcyBvYnZlcmFibGUgcGlwZWQgdGhyb3VnaFxuICAgIGB0YWtlV2hpbGUodi0+diwgdHJ1ZSksIHN1Y2ggdGhhdCBpdCB3aWxsIFxuICAgIGNvbXBsZXRlIGFmdGVyIGVhY2ggZW1pc3Npb24uXG4gIFxuICAgIFNlZTpcbiAgICBodHRwczovL21lZGl1bS5jb20vQG9sZS5lcnNveS93YWl0aW5nLW9uLWVzdG9yZS10by1sb2FkLThkY2JlMTYxNjEzY1xuICBcbiAgICBGb3IgbW9yZSBkZXRhaWxzLlxuICAqL1xuICBwdWJsaWMgb2JzZXJ2ZVNlYXJjaGlu