UNPKG

@datorama/akita

Version:

State Management Tailored-Made for JS Applications

763 lines 62.7 kB
import * as tslib_1 from "tslib"; var _a; /** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { isEmpty } from './isEmpty'; import { setEntities } from './setEntities'; import { Store } from './store'; import { getActiveEntities } from './getActiveEntities'; import { addEntities } from './addEntities'; import { coerceArray } from './coerceArray'; import { removeEntities } from './removeEntities'; import { getInitialEntitiesState } from './getInitialEntitiesState'; import { isDefined } from './isDefined'; import { updateEntities } from './updateEntities'; import { transaction } from './transaction'; import { isNil } from './isNil'; import { isFunction } from './isFunction'; import { isUndefined } from './isUndefined'; import { logAction, setAction } from './actions'; import { isDev } from './env'; import { hasEntity } from './hasEntity'; import { Subject } from 'rxjs'; import { EntityActions } from './entityActions'; import { DEFAULT_ID_KEY } from './defaultIDKey'; /** * * Store for managing a collection of entities * * \@example * * export interface WidgetsState extends EntityState<Widget> { } * * \@StoreConfig({ name: 'widgets' }) * export class WidgetsStore extends EntityStore<WidgetsState> { * constructor() { * super(); * } * } * * * @template S, EntityType, IDType */ export class EntityStore extends Store { /** * @param {?=} initialState * @param {?=} options */ constructor(initialState = {}, options = {}) { super(Object.assign({}, getInitialEntitiesState(), initialState), options); this.options = options; this.entityActions = new Subject(); } // @internal /** * @return {?} */ get selectEntityAction$() { return this.entityActions.asObservable(); } // @internal /** * @return {?} */ get idKey() { return ((/** @type {?} */ (this.config))).idKey || this.options.idKey || DEFAULT_ID_KEY; } /** * * Replace current collection with provided collection * * \@example * * this.store.set([Entity, Entity]) * this.store.set({ids: [], entities: {}}) * this.store.set({ 1: {}, 2: {}}) * * @param {?} entities * @return {?} */ set(entities) { if (isNil(entities)) return; isDev() && setAction('Set Entity'); /** @type {?} */ const isNativePreAdd = this.akitaPreAddEntity === EntityStore.prototype.akitaPreAddEntity; this._setState((/** * @param {?} state * @return {?} */ state => setEntities({ state, entities, idKey: this.idKey, preAddEntity: this.akitaPreAddEntity, isNativePreAdd }))); this.setHasCache(true, { restartTTL: true }); if (this.hasInitialUIState()) { this.handleUICreation(); } this.entityActions.next({ type: EntityActions.Set, ids: this.ids }); } /** * Add entities * * \@example * * this.store.add([Entity, Entity]) * this.store.add(Entity) * this.store.add(Entity, { prepend: true }) * * this.store.add(Entity, { loading: false }) * @param {?} entities * @param {?=} options * @return {?} */ add(entities, options = { loading: false }) { /** @type {?} */ const collection = coerceArray(entities); if (isEmpty(collection)) return; /** @type {?} */ const data = addEntities({ state: this._value(), preAddEntity: this.akitaPreAddEntity, entities: collection, idKey: this.idKey, options }); if (data) { isDev() && setAction('Add Entity'); data.newState.loading = options.loading; this._setState((/** * @return {?} */ () => data.newState)); if (this.hasInitialUIState()) { this.handleUICreation(true); } this.entityActions.next({ type: EntityActions.Add, ids: data.newIds }); } } /** * @param {?} idsOrFnOrState * @param {?=} newStateOrFn * @return {?} */ update(idsOrFnOrState, newStateOrFn) { if (isUndefined(newStateOrFn)) { super.update((/** @type {?} */ (idsOrFnOrState))); return; } /** @type {?} */ let ids = []; if (isFunction(idsOrFnOrState)) { // We need to filter according the predicate function ids = this.ids.filter((/** * @param {?} id * @return {?} */ id => ((/** @type {?} */ (idsOrFnOrState)))(this.entities[id]))); } else { // If it's nil we want all of them ids = isNil(idsOrFnOrState) ? this.ids : coerceArray((/** @type {?} */ (idsOrFnOrState))); } if (isEmpty(ids)) return; isDev() && setAction('Update Entity', ids); this._setState((/** * @param {?} state * @return {?} */ state => updateEntities({ idKey: this.idKey, ids, preUpdateEntity: this.akitaPreUpdateEntity, state, newStateOrFn }))); this.entityActions.next({ type: EntityActions.Update, ids }); } /** * * Create or update * * \@example * * store.upsert(1, { active: true }) * store.upsert([2, 3], { active: true }) * store.upsert([2, 3], entity => ({ isOpen: !entity.isOpen})) * * @param {?} ids * @param {?} newState * @param {?=} options * @return {?} */ upsert(ids, newState, options = {}) { /** @type {?} */ const toArray = coerceArray(ids); /** @type {?} */ const predicate = (/** * @param {?} isUpdate * @return {?} */ isUpdate => (/** * @param {?} id * @return {?} */ id => hasEntity(this.entities, id) === isUpdate)); /** @type {?} */ const isClassBased = isFunction(options.baseClass); /** @type {?} */ const updateIds = toArray.filter(predicate(true)); /** @type {?} */ const newEntities = toArray.filter(predicate(false)).map((/** * @param {?} id * @return {?} */ id => { /** @type {?} */ let entity = isFunction(newState) ? newState((/** @type {?} */ ({}))) : newState; /** @type {?} */ const withId = Object.assign({}, ((/** @type {?} */ (entity))), { [this.idKey]: id }); if (isClassBased) { return new options.baseClass(withId); } return withId; })); // it can be any of the three types this.update((/** @type {?} */ (updateIds)), (/** @type {?} */ (newState))); this.add(newEntities); isDev() && logAction('Upsert Entity'); } /** * * Upsert entity collection (idKey must be present) * * \@example * * store.upsertMany([ { id: 1 }, { id: 2 }]); * * store.upsertMany([ { id: 1 }, { id: 2 }], { loading: true }); * store.upsertMany([ { id: 1 }, { id: 2 }], { baseClass: Todo }); * * @param {?} entities * @param {?=} options * @return {?} */ upsertMany(entities, options = {}) { /** @type {?} */ const addedIds = []; /** @type {?} */ const updatedIds = []; /** @type {?} */ const updatedEntities = {}; // Update the state directly to optimize performance for (const entity of entities) { /** @type {?} */ const withPreCheckHook = this.akitaPreCheckEntity(entity); /** @type {?} */ const id = withPreCheckHook[this.idKey]; if (hasEntity(this.entities, id)) { /** @type {?} */ const prev = this._value().entities[id]; /** @type {?} */ const merged = Object.assign({}, this._value().entities[id], withPreCheckHook); /** @type {?} */ const next = options.baseClass ? new options.baseClass(merged) : merged; /** @type {?} */ const withHook = this.akitaPreUpdateEntity(prev, next); /** @type {?} */ const nextId = withHook[this.idKey]; updatedEntities[nextId] = withHook; updatedIds.push(nextId); } else { /** @type {?} */ const newEntity = options.baseClass ? new options.baseClass(withPreCheckHook) : withPreCheckHook; /** @type {?} */ const withHook = this.akitaPreAddEntity(newEntity); /** @type {?} */ const nextId = withHook[this.idKey]; addedIds.push(nextId); updatedEntities[nextId] = withHook; } } isDev() && logAction('Upsert Many'); this._setState((/** * @param {?} state * @return {?} */ state => (Object.assign({}, state, { ids: addedIds.length ? [...state.ids, ...addedIds] : state.ids, entities: Object.assign({}, state.entities, updatedEntities), loading: !!options.loading })))); updatedIds.length && this.entityActions.next({ type: EntityActions.Update, ids: updatedIds }); addedIds.length && this.entityActions.next({ type: EntityActions.Add, ids: addedIds }); if (addedIds.length && this.hasUIStore()) { this.handleUICreation(true); } } /** * * Replace one or more entities (except the id property) * * * \@example * * this.store.replace(5, newEntity) * this.store.replace([1,2,3], newEntity) * @param {?} ids * @param {?} newState * @return {?} */ replace(ids, newState) { /** @type {?} */ const toArray = coerceArray(ids); if (isEmpty(toArray)) return; /** @type {?} */ let replaced = {}; for (const id of toArray) { newState[this.idKey] = id; replaced[id] = newState; } isDev() && setAction('Replace Entity', ids); this._setState((/** * @param {?} state * @return {?} */ state => (Object.assign({}, state, { entities: Object.assign({}, state.entities, replaced) })))); } /** * * Move entity inside the collection * * * \@example * * this.store.move(fromIndex, toIndex) * @param {?} from * @param {?} to * @return {?} */ move(from, to) { /** @type {?} */ const ids = this.ids.slice(); ids.splice(to < 0 ? ids.length + to : to, 0, ids.splice(from, 1)[0]); isDev() && setAction('Move Entity'); this._setState((/** * @param {?} state * @return {?} */ state => (Object.assign({}, state, { entities: Object.assign({}, state.entities), ids })))); } /** * @param {?=} idsOrFn * @return {?} */ remove(idsOrFn) { if (isEmpty(this.ids)) return; /** @type {?} */ const idPassed = isDefined(idsOrFn); // null means remove all /** @type {?} */ let ids = []; if (isFunction(idsOrFn)) { ids = this.ids.filter((/** * @param {?} entityId * @return {?} */ entityId => idsOrFn(this.entities[entityId]))); } else { ids = idPassed ? coerceArray(idsOrFn) : null; } if (isEmpty(ids)) return; isDev() && setAction('Remove Entity', ids); this._setState((/** * @param {?} state * @return {?} */ (state) => removeEntities({ state, ids }))); if (ids === null) { this.setHasCache(false); } this.handleUIRemove(ids); this.entityActions.next({ type: EntityActions.Remove, ids }); } /** * * Update the active entity * * \@example * * this.store.updateActive({ completed: true }) * this.store.updateActive(active => { * return { * config: { * ..active.config, * date * } * } * }) * @param {?} newStateOrCallback * @return {?} */ updateActive(newStateOrCallback) { /** @type {?} */ const ids = coerceArray(this.active); isDev() && setAction('Update Active', ids); this.update(ids, (/** @type {?} */ (newStateOrCallback))); } /** * @param {?} idOrOptions * @return {?} */ setActive(idOrOptions) { /** @type {?} */ const active = getActiveEntities(idOrOptions, this.ids, this.active); if (active === undefined) { return; } isDev() && setAction('Set Active', active); this._setActive(active); } /** * Add active entities * * \@example * * store.addActive(2); * store.addActive([3, 4, 5]); * @template T * @param {?} ids * @return {?} */ addActive(ids) { /** @type {?} */ const toArray = coerceArray(ids); if (isEmpty(toArray)) return; /** @type {?} */ const everyExist = toArray.every((/** * @param {?} id * @return {?} */ id => this.active.indexOf(id) > -1)); if (everyExist) return; isDev() && setAction('Add Active', ids); this._setState((/** * @param {?} state * @return {?} */ state => { /** * Protect against case that one of the items in the array exist * @type {?} */ const uniques = Array.from(new Set([...((/** @type {?} */ (state.active))), ...toArray])); return Object.assign({}, state, { active: uniques }); })); } /** * Remove active entities * * \@example * * store.removeActive(2) * store.removeActive([3, 4, 5]) * @template T * @param {?} ids * @return {?} */ removeActive(ids) { /** @type {?} */ const toArray = coerceArray(ids); if (isEmpty(toArray)) return; /** @type {?} */ const someExist = toArray.some((/** * @param {?} id * @return {?} */ id => this.active.indexOf(id) > -1)); if (!someExist) return; isDev() && setAction('Remove Active', ids); this._setState((/** * @param {?} state * @return {?} */ state => { return Object.assign({}, state, { active: Array.isArray(state.active) ? state.active.filter((/** * @param {?} currentId * @return {?} */ currentId => toArray.indexOf(currentId) === -1)) : null }); })); } /** * Toggle active entities * * \@example * * store.toggle(2) * store.toggle([3, 4, 5]) * @template T * @param {?} ids * @return {?} */ toggleActive(ids) { /** @type {?} */ const toArray = coerceArray(ids); /** @type {?} */ const filterExists = (/** * @param {?} remove * @return {?} */ remove => (/** * @param {?} id * @return {?} */ id => this.active.includes(id) === remove)); /** @type {?} */ const remove = toArray.filter(filterExists(true)); /** @type {?} */ const add = toArray.filter(filterExists(false)); this.removeActive(remove); this.addActive(add); isDev() && logAction('Toggle Active'); } /** * * Create sub UI store for managing Entity's UI state * * \@example * * export type ProductUI = { * isLoading: boolean; * isOpen: boolean * } * * interface ProductsUIState extends EntityState<ProductUI> {} * * export class ProductsStore EntityStore<ProductsState, Product> { * ui: EntityUIStore<ProductsUIState, ProductUI>; * * constructor() { * super(); * this.createUIStore(); * } * * } * @param {?=} initialState * @param {?=} storeConfig * @return {?} */ createUIStore(initialState = {}, storeConfig = {}) { /** @type {?} */ const defaults = { name: `UI/${this.storeName}`, idKey: this.idKey }; this.ui = new EntityUIStore(initialState, Object.assign({}, defaults, storeConfig)); return this.ui; } // @internal /** * @return {?} */ destroy() { super.destroy(); if (this.ui instanceof EntityStore) { this.ui.destroy(); } this.entityActions.complete(); } // @internal /** * @param {?} _ * @param {?} nextEntity * @return {?} */ akitaPreUpdateEntity(_, nextEntity) { return nextEntity; } // @internal /** * @param {?} newEntity * @return {?} */ akitaPreAddEntity(newEntity) { return newEntity; } // @internal /** * @param {?} newEntity * @return {?} */ akitaPreCheckEntity(newEntity) { return newEntity; } /** * @private * @return {?} */ get ids() { return this._value().ids; } /** * @private * @return {?} */ get entities() { return this._value().entities; } /** * @private * @return {?} */ get active() { return this._value().active; } /** * @private * @param {?} ids * @return {?} */ _setActive(ids) { this._setState((/** * @param {?} state * @return {?} */ state => { return Object.assign({}, state, { active: ids }); })); } /** * @private * @param {?=} add * @return {?} */ handleUICreation(add = false) { /** @type {?} */ const ids = this.ids; /** @type {?} */ const isFunc = isFunction(this.ui._akitaCreateEntityFn); /** @type {?} */ let uiEntities; /** @type {?} */ const createFn = (/** * @param {?} id * @return {?} */ id => { /** @type {?} */ const current = this.entities[id]; /** @type {?} */ const ui = isFunc ? this.ui._akitaCreateEntityFn(current) : this.ui._akitaCreateEntityFn; return Object.assign({ [this.idKey]: current[this.idKey] }, ui); }); if (add) { uiEntities = this.ids.filter((/** * @param {?} id * @return {?} */ id => isUndefined(this.ui.entities[id]))).map(createFn); } else { uiEntities = ids.map(createFn); } add ? this.ui.add(uiEntities) : this.ui.set(uiEntities); } /** * @private * @return {?} */ hasInitialUIState() { return this.hasUIStore() && isUndefined(this.ui._akitaCreateEntityFn) === false; } /** * @private * @param {?} ids * @return {?} */ handleUIRemove(ids) { if (this.hasUIStore()) { this.ui.remove(ids); } } /** * @private * @return {?} */ hasUIStore() { return this.ui instanceof EntityUIStore; } } tslib_1.__decorate([ transaction(), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [Object, Object, Object]), tslib_1.__metadata("design:returntype", void 0) ], EntityStore.prototype, "upsert", null); tslib_1.__decorate([ transaction(), tslib_1.__metadata("design:type", Function), tslib_1.__metadata("design:paramtypes", [typeof (_a = typeof T !== "undefined" && T) === "function" ? _a : Object]), tslib_1.__metadata("design:returntype", void 0) ], EntityStore.prototype, "toggleActive", null); if (false) { /** @type {?} */ EntityStore.prototype.ui; /** * @type {?} * @private */ EntityStore.prototype.entityActions; /** * @type {?} * @protected */ EntityStore.prototype.options; } // @internal /** * @template UIState, DEPRECATED */ export class EntityUIStore extends EntityStore { /** * @param {?=} initialState * @param {?=} storeConfig */ constructor(initialState = {}, storeConfig = {}) { super(initialState, storeConfig); } /** * * Set the initial UI entity state. This function will determine the entity's * initial state when we call `set()` or `add()`. * * \@example * * constructor() { * super(); * this.createUIStore().setInitialEntityState(entity => ({ isLoading: false, isOpen: true })); * this.createUIStore().setInitialEntityState({ isLoading: false, isOpen: true }); * } * * @template EntityUI, Entity * @param {?} createFn * @return {?} */ setInitialEntityState(createFn) { this._akitaCreateEntityFn = createFn; } } if (false) { /** @type {?} */ EntityUIStore.prototype._akitaCreateEntityFn; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5U3RvcmUuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9AZGF0b3JhbWEvYWtpdGEvIiwic291cmNlcyI6WyJzcmMvZW50aXR5U3RvcmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNwQyxPQUFPLEVBQWUsV0FBVyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pELE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFFaEMsT0FBTyxFQUFFLGlCQUFpQixFQUFvQixNQUFNLHFCQUFxQixDQUFDO0FBQzFFLE9BQU8sRUFBRSxXQUFXLEVBQXNCLE1BQU0sZUFBZSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3BFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDeEMsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBQ2xELE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDNUMsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUNoQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQzFDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFNUMsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDakQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLE9BQU8sQ0FBQztBQUM5QixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3hDLE9BQU8sRUFBYyxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFD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Ozs7OztJQWdCRCxxQkFBcUIsQ0FBK0IsUUFBNEM7UUFDOUYsSUFBSSxDQUFDLG9CQUFvQixHQUFHLFFBQVEsQ0FBQztJQUN2QyxDQUFDO0NBQ0Y7OztJQXZCQyw2Q0FBdUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpc0VtcHR5IH0gZnJvbSAnLi9pc0VtcHR5JztcbmltcG9ydCB7IFNldEVudGl0aWVzLCBzZXRFbnRpdGllcyB9IGZyb20gJy4vc2V0RW50aXRpZXMnO1xuaW1wb3J0IHsgU3RvcmUgfSBmcm9tICcuL3N0b3JlJztcbmltcG9ydCB7IENvbnN0cnVjdG9yLCBFbnRpdHlTdGF0ZSwgRW50aXR5VUlDcmVhdGVGbiwgSUQsIElEUywgT3JBcnJheSwgU3RhdGVXaXRoQWN0aXZlLCBVcGRhdGVFbnRpdHlQcmVkaWNhdGUsIFVwZGF0ZVN0YXRlQ2FsbGJhY2ssIGdldEVudGl0eVR5cGUsIGdldElEVHlwZSB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgZ2V0QWN0aXZlRW50aXRpZXMsIFNldEFjdGl2ZU9wdGlvbnMgfSBmcm9tICcuL2dldEFjdGl2ZUVudGl0aWVzJztcbmltcG9ydCB7IGFkZEVudGl0aWVzLCBBZGRFbnRpdGllc09wdGlvbnMgfSBmcm9tICcuL2FkZEVudGl0aWVzJztcbmltcG9ydCB7IGNvZXJjZUFycmF5IH0gZnJvbSAnLi9jb2VyY2VBcnJheSc7XG5pbXBvcnQgeyByZW1vdmVFbnRpdGllcyB9IGZyb20gJy4vcmVtb3ZlRW50aXRpZXMnO1xuaW1wb3J0IHsgZ2V0SW5pdGlhbEVudGl0aWVzU3RhdGUgfSBmcm9tICcuL2dldEluaXRpYWxFbnRpdGllc1N0YXRlJztcbmltcG9ydCB7IGlzRGVmaW5lZCB9IGZyb20gJy4vaXNEZWZpbmVkJztcbmltcG9ydCB7IHVwZGF0ZUVudGl0aWVzIH0gZnJvbSAnLi91cGRhdGVFbnRpdGllcyc7XG5pbXBvcnQgeyB0cmFuc2FjdGlvbiB9IGZyb20gJy4vdHJhbnNhY3Rpb24nO1xuaW1wb3J0IHsgaXNOaWwgfSBmcm9tICcuL2lzTmlsJztcbmltcG9ydCB7IGlzRnVuY3Rpb24gfSBmcm9tICcuL2lzRnVuY3Rpb24nO1xuaW1wb3J0IHsgaXNVbmRlZmluZWQgfSBmcm9tICcuL2lzVW5kZWZpbmVkJztcbmltcG9ydCB7IFN0b3JlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4vc3RvcmVDb25maWcnO1xuaW1wb3J0IHsgbG9nQWN0aW9uLCBzZXRBY3Rpb24gfSBmcm9tICcuL2FjdGlvbnMnO1xuaW1wb3J0IHsgaXNEZXYgfSBmcm9tICcuL2Vudic7XG5pbXBvcnQgeyBoYXNFbnRpdHkgfSBmcm9tICcuL2hhc0VudGl0eSc7XG5pbXBvcnQgeyBPYnNlcnZhYmxlLCBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBFbnRpdHlBY3Rpb24sIEVudGl0eUFjdGlvbnMgfSBmcm9tICcuL2VudGl0eUFjdGlvbnMnO1xuaW1wb3J0IHsgREVGQVVMVF9JRF9LRVkgfSBmcm9tICcuL2RlZmF1bHRJREtleSc7XG5cbi8qKlxuICpcbiAqIFN0b3JlIGZvciBtYW5hZ2luZyBhIGNvbGxlY3Rpb24gb2YgZW50aXRpZXNcbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGV4cG9ydCBpbnRlcmZhY2UgV2lkZ2V0c1N0YXRlIGV4dGVuZHMgRW50aXR5U3RhdGU8V2lkZ2V0PiB7IH1cbiAqXG4gKiBAU3RvcmVDb25maWcoeyBuYW1lOiAnd2lkZ2V0cycgfSlcbiAqICBleHBvcnQgY2xhc3MgV2lkZ2V0c1N0b3JlIGV4dGVuZHMgRW50aXR5U3RvcmU8V2lkZ2V0c1N0YXRlPiB7XG4gKiAgIGNvbnN0cnVjdG9yKCkge1xuICogICAgIHN1cGVyKCk7XG4gKiAgIH1cbiAqIH1cbiAqXG4gKlxuICovXG5leHBvcnQgY2xhc3MgRW50aXR5U3RvcmU8UyBleHRlbmRzIEVudGl0eVN0YXRlID0gYW55LCBFbnRpdHlUeXBlID0gZ2V0RW50aXR5VHlwZTxTPiwgSURUeXBlID0gZ2V0SURUeXBlPFM+PiBleHRlbmRzIFN0b3JlPFM+IHtcbiAgdWk6IEVudGl0eVVJU3RvcmU8YW55LCBFbnRpdHlUeXBlPjtcbiAgcHJpdmF0ZSBlbnRpdHlBY3Rpb25zID0gbmV3IFN1YmplY3Q8RW50aXR5QWN0aW9uPElEVHlwZT4+KCk7XG5cbiAgY29uc3RydWN0b3IoaW5pdGlhbFN0YXRlOiBQYXJ0aWFsPFM+ID0ge30sIHByb3RlY3RlZCBvcHRpb25zOiBQYXJ0aWFsPFN0b3JlQ29uZmlnT3B0aW9ucz4gPSB7fSkge1xuICAgIHN1cGVyKHsgLi4uZ2V0SW5pdGlhbEVudGl0aWVzU3RhdGUoKSwgLi4uaW5pdGlhbFN0YXRlIH0sIG9wdGlvbnMpO1xuICB9XG5cbiAgLy8gQGludGVybmFsXG4gIGdldCBzZWxlY3RFbnRpdHlBY3Rpb24kKCk6IE9ic2VydmFibGU8RW50aXR5QWN0aW9uPElEVHlwZT4+IHtcbiAgICByZXR1cm4gdGhpcy5lbnRpdHlBY3Rpb25zLmFzT2JzZXJ2YWJsZSgpO1xuICB9XG5cbiAgLy8gQGludGVybmFsXG4gIGdldCBpZEtleSgpIHtcbiAgICByZXR1cm4gKHRoaXMuY29uZmlnIGFzIFN0b3JlQ29uZmlnT3B0aW9ucykuaWRLZXkgfHwgdGhpcy5vcHRpb25zLmlkS2V5IHx8IERFRkFVTFRfSURfS0VZO1xuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIFJlcGxhY2UgY3VycmVudCBjb2xsZWN0aW9uIHdpdGggcHJvdmlkZWQgY29sbGVjdGlvblxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiB0aGlzLnN0b3JlLnNldChbRW50aXR5LCBFbnRpdHldKVxuICAgKiB0aGlzLnN0b3JlLnNldCh7aWRzOiBbXSwgZW50aXRpZXM6IHt9fSlcbiAgICogdGhpcy5zdG9yZS5zZXQoeyAxOiB7fSwgMjoge319KVxuICAgKlxuICAgKi9cbiAgc2V0KGVudGl0aWVzOiBTZXRFbnRpdGllczxFbnRpdHlUeXBlPikge1xuICAgIGlmIChpc05pbChlbnRpdGllcykpIHJldHVybjtcblxuICAgIGlzRGV2KCkgJiYgc2V0QWN0aW9uKCdTZXQgRW50aXR5Jyk7XG5cbiAgICBjb25zdCBpc05hdGl2ZVByZUFkZCA9IHRoaXMuYWtpdGFQcmVBZGRFbnRpdHkgPT09IEVudGl0eVN0b3JlLnByb3RvdHlwZS5ha2l0YVByZUFkZEVudGl0eTtcbiAgICB0aGlzLl9zZXRTdGF0ZShzdGF0ZSA9PlxuICAgICAgc2V0RW50aXRpZXMoe1xuICAgICAgICBzdGF0ZSxcbiAgICAgICAgZW50aXRpZXMsXG4gICAgICAgIGlkS2V5OiB0aGlzLmlkS2V5LFxuICAgICAgICBwcmVBZGRFbnRpdHk6IHRoaXMuYWtpdGFQcmVBZGRFbnRpdHksXG4gICAgICAgIGlzTmF0aXZlUHJlQWRkXG4gICAgICB9KVxuICAgICk7XG5cbiAgICB0aGlzLnNldEhhc0NhY2hlKHRydWUsIHsgcmVzdGFydFRUTDogdHJ1ZSB9KTtcblxuICAgIGlmICh0aGlzLmhhc0luaXRpYWxVSVN0YXRlKCkpIHtcbiAgICAgIHRoaXMuaGFuZGxlVUlDcmVhdGlvbigpO1xuICAgIH1cblxuICAgIHRoaXMuZW50aXR5QWN0aW9ucy5uZXh0KHsgdHlwZTogRW50aXR5QWN0aW9ucy5TZXQsIGlkczogdGhpcy5pZHMgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGVudGl0aWVzXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqXG4gICAqIHRoaXMuc3RvcmUuYWRkKFtFbnRpdHksIEVudGl0eV0pXG4gICAqIHRoaXMuc3RvcmUuYWRkKEVudGl0eSlcbiAgICogdGhpcy5zdG9yZS5hZGQoRW50aXR5LCB7IHByZXBlbmQ6IHRydWUgfSlcbiAgICpcbiAgICogdGhpcy5zdG9yZS5hZGQoRW50aXR5LCB7IGxvYWRpbmc6IGZhbHNlIH0pXG4gICAqL1xuICBhZGQoZW50aXRpZXM6IE9yQXJyYXk8RW50aXR5VHlwZT4sIG9wdGlvbnM6IEFkZEVudGl0aWVzT3B0aW9ucyA9IHsgbG9hZGluZzogZmFsc2UgfSkge1xuICAgIGNvbnN0IGNvbGxlY3Rpb24gPSBjb2VyY2VBcnJheShlbnRpdGllcyk7XG5cbiAgICBpZiAoaXNFbXB0eShjb2xsZWN0aW9uKSkgcmV0dXJuO1xuXG4gICAgY29uc3QgZGF0YSA9IGFkZEVudGl0aWVzKHtcbiAgICAgIHN0YXRlOiB0aGlzLl92YWx1ZSgpLFxuICAgICAgcHJlQWRkRW50aXR5OiB0aGlzLmFraXRhUHJlQWRkRW50aXR5LFxuICAgICAgZW50aXRpZXM6IGNvbGxlY3Rpb24sXG4gICAgICBpZEtleTogdGhpcy5pZEtleSxcbiAgICAgIG9wdGlvbnNcbiAgICB9KTtcblxuICAgIGlmIChkYXRhKSB7XG4gICAgICBpc0RldigpICYmIHNldEFjdGlvbignQWRkIEVudGl0eScpO1xuICAgICAgZGF0YS5uZXdTdGF0ZS5sb2FkaW5nID0gb3B0aW9ucy5sb2FkaW5nO1xuXG4gICAgICB0aGlzLl9zZXRTdGF0ZSgoKSA9PiBkYXRhLm5ld1N0YXRlKTtcblxuICAgICAgaWYgKHRoaXMuaGFzSW5pdGlhbFVJU3RhdGUoKSkge1xuICAgICAgICB0aGlzLmhhbmRsZVVJQ3JlYXRpb24odHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuZW50aXR5QWN0aW9ucy5uZXh0KHsgdHlwZTogRW50aXR5QWN0aW9ucy5BZGQsIGlkczogZGF0YS5uZXdJZHMgfSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqXG4gICAqIFVwZGF0ZSBlbnRpdGllc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBzdG9yZS51cGRhdGUoMSwgZW50aXR5ID0+IC4uLilcbiAgICogc3RvcmUudXBkYXRlKFsxLCAyLCAzXSwgZW50aXR5ID0+IC4uLilcbiAgICogc3RvcmUudXBkYXRlKG51bGwsIGVudGl0eSA9PiAuLi4pXG4gICAqL1xuICB1cGRhdGUoaWQ6IE9yQXJyYXk8SURUeXBlPiB8IG51bGwsIG5ld1N0YXRlRm46IFVwZGF0ZVN0YXRlQ2FsbGJhY2s8RW50aXR5VHlwZT4pO1xuICAvKipcbiAgICogc3RvcmUudXBkYXRlKDEsIHsgbmFtZTogbmV3TmFtZSB9KVxuICAgKi9cbiAgdXBkYXRlKGlkOiBPckFycmF5PElEVHlwZT4gfCBudWxsLCBuZXdTdGF0ZTogUGFydGlhbDxFbnRpdHlUeXBlPik7XG4gIC8qKlxuICAgKiBzdG9yZS51cGRhdGUoZW50aXR5ID0+IGVudGl0eS5wcmljZSA+IDMsIGVudGl0eSA9PiAoeyBuYW1lOiBuZXdOYW1lIH0pKVxuICAgKi9cbiAgdXBkYXRlKHByZWRpY2F0ZTogVXBkYXRlRW50aXR5UHJlZGljYXRlPEVudGl0eVR5cGU+LCBuZXdTdGF0ZUZuOiBVcGRhdGVTdGF0ZUNhbGxiYWNrPEVudGl0eVR5cGU+KTtcbiAgLyoqXG4gICAqIHN0b3JlLnVwZGF0ZShlbnRpdHkgPT4gZW50aXR5LnByaWNlID4gMywgeyBuYW1lOiBuZXdOYW1lIH0pXG4gICAqL1xuICB1cGRhdGUocHJlZGljYXRlOiBVcGRhdGVFbnRpdHlQcmVkaWNhdGU8RW50aXR5VHlwZT4sIG5ld1N0YXRlOiBQYXJ0aWFsPEVudGl0eVR5cGU+KTtcbiAgLyoqIFN1cHBvcnQgbm9uLWVudGl0eSB1cGRhdGVzICovXG4gIHVwZGF0ZShuZXdTdGF0ZTogVXBkYXRlU3RhdGVDYWxsYmFjazxTPik7XG4gIHVwZGF0ZShuZXdTdGF0ZTogUGFydGlhbDxTPik7XG4gIHVwZGF0ZShcbiAgICBpZHNPckZuT3JTdGF0ZTogT3JBcnJheTxJRFR5cGU+IHwgbnVsbCB8IFBhcnRpYWw8Uz4gfCBVcGRhdGVTdGF0ZUNhbGxiYWNrPFM+IHwgVXBkYXRlRW50aXR5UHJlZGljYXRlPEVudGl0eVR5cGU+LFxuICAgIG5ld1N0YXRlT3JGbj86IFVwZGF0ZVN0YXRlQ2FsbGJhY2s8RW50aXR5VHlwZT4gfCBQYXJ0aWFsPEVudGl0eVR5cGU+IHwgUGFydGlhbDxTPlxuICApIHtcbiAgICBpZiAoaXNVbmRlZmluZWQobmV3U3RhdGVPckZuKSkge1xuICAgICAgc3VwZXIudXBkYXRlKGlkc09yRm5PclN0YXRlIGFzIFBhcnRpYWw8Uz4pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBsZXQgaWRzOiBJRFR5cGVbXSA9IFtdO1xuXG4gICAgaWYgKGlzRnVuY3Rpb24oaWRzT3JGbk9yU3RhdGUpKSB7XG4gICAgICAvLyBXZSBuZWVkIHRvIGZpbHRlciBhY2NvcmRpbmcgdGhlIHByZWRpY2F0ZSBmdW5jdGlvblxuICAgICAgaWRzID0gdGhpcy5pZHMuZmlsdGVyKGlkID0+IChpZHNPckZuT3JTdGF0ZSBhcyBVcGRhdGVFbnRpdHlQcmVkaWNhdGU8RW50aXR5VHlwZT4pKHRoaXMuZW50aXRpZXNbaWRdKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElmIGl0J3MgbmlsIHdlIHdhbnQgYWxsIG9mIHRoZW1cbiAgICAgIGlkcyA9IGlzTmlsKGlkc09yRm5PclN0YXRlKSA/IHRoaXMuaWRzIDogY29lcmNlQXJyYXkoaWRzT3JGbk9yU3RhdGUgYXMgT3JBcnJheTxJRFR5cGU+KTtcbiAgICB9XG5cbiAgICBpZiAoaXNFbXB0eShpZHMpKSByZXR1cm47XG5cbiAgICBpc0RldigpICYmIHNldEFjdGlvbignVXBkYXRlIEVudGl0eScsIGlkcyk7XG4gICAgdGhpcy5fc2V0U3RhdGUoc3RhdGUgPT5cbiAgICAgIHVwZGF0ZUVudGl0aWVzKHtcbiAgICAgICAgaWRLZXk6IHRoaXMuaWRLZXksXG4gICAgICAgIGlkcyxcbiAgICAgICAgcHJlVXBkYXRlRW50aXR5OiB0aGlzLmFraXRhUHJlVXBkYXRlRW50aXR5LFxuICAgICAgICBzdGF0ZSxcbiAgICAgICAgbmV3U3RhdGVPckZuXG4gICAgICB9KVxuICAgICk7XG5cbiAgICB0aGlzLmVudGl0eUFjdGlvbnMubmV4dCh7IHR5cGU6IEVudGl0eUFjdGlvbnMuVXBkYXRlLCBpZHMgfSk7XG4gIH1cblxuICAvKipcbiAgICpcbiAgICogQ3JlYXRlIG9yIHVwZGF0ZVxuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKlxuICAgKiBzdG9yZS51cHNlcnQoMSwgeyBhY3RpdmU6IHRydWUgfSlcbiAgICogc3RvcmUudXBzZXJ0KFsyLCAzXSwgeyBhY3RpdmU6IHRydWUgfSlcbiAgICogc3RvcmUudXBzZXJ0KFsyLCAzXSwgZW50aXR5ID0+ICh7IGlzT3BlbjogIWVudGl0eS5pc09wZW59KSlcbiAgICpcbiAgICovXG4gIEB0cmFuc2FjdGlvbigpXG4gIHVwc2VydChpZHM6IE9yQXJyYXk8SURUeXBlPiwgbmV3U3RhdGU6IFBhcnRpYWw8RW50aXR5VHlwZT4gfCBFbnRpdHlUeXBlIHwgVXBkYXRlU3RhdGVDYWxsYmFjazxFbnRpdHlUeXBlPiB8IEVudGl0eVR5cGVbXSwgb3B0aW9uczogeyBiYXNlQ2xhc3M/OiBDb25zdHJ1Y3RvciB9ID0ge30pIHtcbiAgICBjb25zdCB0b0FycmF5ID0gY29lcmNlQXJyYXkoaWRzKTtcbiAgICBjb25zdCBwcmVkaWNhdGUgPSBpc1VwZGF0ZSA9PiBpZCA9PiBoYXNFbnRpdHkodGhpcy5lbnRpdGllcywgaWQpID09PSBpc1VwZGF0ZTtcbiAgICBjb25zdCBpc0NsYXNzQmFzZWQgPSBpc0Z1bmN0aW9uKG9wdGlvbnMuYmFzZUNsYXNzKTtcbiAgICBjb25zdCB1cGRhdGVJZHMgPSB0b0FycmF5LmZpbHRlcihwcmVkaWNhdGUodHJ1ZSkpO1xuICAgIGNvbnN0IG5ld0VudGl0aWVzID0gdG9BcnJheS5maWx0ZXIocHJlZGljYXRlKGZhbHNlKSkubWFwKGlkID0+IHtcbiAgICAgIGxldCBlbnRpdHkgPSBpc0Z1bmN0aW9uKG5ld1N0YXRlKSA/IG5ld1N0YXRlKHt9IGFzIEVudGl0eVR5cGUpIDogbmV3U3RhdGU7XG4gICAgICBjb25zdCB3aXRoSWQgPSB7IC4uLihlbnRpdHkgYXMgRW50aXR5VHlwZSksIFt0aGlzLmlkS2V5XTogaWQgfTtcbiAgICAgIGlmIChpc0NsYXNzQmFzZWQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBvcHRpb25zLmJhc2VDbGFzcyh3aXRoSWQpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHdpdGhJZDtcbiAgICB9KTtcblxuICAgIC8vIGl0IGNhbiBiZSBhbnkgb2YgdGhlIHRocmVlIHR5cGVzXG4gICAgdGhpcy51cGRhdGUodXBkYXRlSWRzIGFzIGFueSwgbmV3U3RhdGUgYXMgYW55KTtcbiAgICB0aGlzLmFkZChuZXdFbnRpdGllcyk7XG4gICAgaXNEZXYoKSAmJiBsb2dBY3Rpb24oJ1Vwc2VydCBFbnRpdHknKTtcbiAgfVxuXG4gIC8qKlxuICAgKlxuICAgKiBVcHNlcnQgZW50aXR5IGNvbGxlY3Rpb24gKGlkS2V5IG11c3QgYmUgcHJlc2VudClcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICpcbiAgICogc3RvcmUudXBzZXJ0TWFueShbIHsgaWQ6IDEgfSwgeyBpZDogMiB9XSk7XG4gICAqXG4gICAqIHN0b3JlLnVwc2VydE1hbnkoWyB7IGlkOiAxIH0sIHsgaWQ6IDIgfV0sIHsgbG9hZGluZzogdHJ1ZSAgfSk7XG4gICAqIHN0b3JlLnVwc2VydE1hbnkoWyB7IGlkOiAxIH0sIHsgaWQ6IDIgfV0sIHsgYmFzZUNsYXNzOiBUb2RvICB9KTtcbiAgICpcbiAgICovXG4gIHVwc2VydE1hbnkoZW50aXRpZXM6IEVudGl0eVR5cGVbXSwgb3B0aW9uczogeyBiYXNlQ2xhc3M/OiBDb25zdHJ1Y3RvcjsgbG9hZGluZz86IGJvb2xlYW4gfSA9IHt9KSB7XG4gICAgY29uc3QgYWRkZWRJZHMgPSBbXTtcbiAgICBjb25zdCB1cGRhdGVkSWRzID0gW107XG4gICAgY29uc3QgdXBkYXRlZEVudGl0aWVzID0ge307XG5cbiAgICAvLyBVcGRhdGUgdGhlIHN0YXRlIGRpcmVjdGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXG4gICAgZm9yIChjb25zdCBlbnRpdHkgb2YgZW50aXRpZXMpIHtcbiAgICAgIGNvbnN0IHdpdGhQcmVDaGVja0hvb2sgPSB0aGlzLmFraXRhUHJlQ2hlY2tFbnRpdHkoZW50aXR5KTtcbiAgICAgIGNvbnN0IGlkID0gd2l0aFByZUNoZWNrSG9va1t0aGlzLmlkS2V5XTtcbiAgICAgIGlmIChoYXNFbnRpdHkodGhpcy5lbnRpdGllcywgaWQpKSB7XG4gICAgICAgIGNvbnN0IHByZXYgPSB0aGlzLl92YWx1ZSgpLmVudGl0aWVzW2lkXTtcbiAgICAgICAgY29uc3QgbWVyZ2VkID0geyAuLi50aGlzLl92YWx1ZSgpLmVudGl0aWVzW2lkXSwgLi4ud2l0aFByZUNoZWNrSG9vayB9O1xuICAgICAgICBjb25zdCBuZXh0ID0gb3B0aW9ucy5iYXNlQ2xhc3MgPyBuZXcgb3B0aW9ucy5iYXNlQ2xhc3MobWVyZ2VkKSA6IG1lcmdlZDtcbiAgICAgICAgY29uc3Qgd2l0aEhvb2sgPSB0aGlzLmFraXRhUHJlVXBkYXRlRW50aXR5KHByZXYsIG5leHQpO1xuICAgICAgICBjb25zdCBuZXh0SWQgPSB3aXRoSG9va1t0aGlzLmlkS2V5XTtcbiAgICAgICAgdXBkYXRlZEVudGl0aWVzW25leHRJZF0gPSB3aXRoSG9vaztcbiAgICAgICAgdXBkYXRlZElkcy5wdXNoKG5leHRJZCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBuZXdFbnRpdHkgPSBvcHRpb25zLmJhc2VDbGFzcyA/IG5ldyBvcHRpb25zLmJhc2VDbGFzcyh3aXRoUHJlQ2hlY2tIb29rKSA6I