@datorama/akita
Version:
State Management Tailored-Made for JS Applications
763 lines • 62.7 kB
JavaScript
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