@data-client/normalizr
Version:
Normalizes and denormalizes JSON according to schema for Redux and Flux applications
148 lines (143 loc) • 19 kB
JavaScript
import WeakDependencyMap from './WeakDependencyMap.js';
export default class GlobalCache {
constructor(getEntity, entityCache, resultCache) {
this.dependencies = [];
this.cycleCache = new Map();
this.cycleIndex = -1;
this.localCache = new Map();
this._getEntity = getEntity;
this.getCache = getEntityCaches(entityCache);
this.resultCache = resultCache;
}
getEntity(pk, schema, entity, computeValue) {
const key = schema.key;
const {
localCacheKey,
cycleCacheKey
} = this.getCacheKey(key);
if (!localCacheKey.get(pk)) {
const globalCache = this.getCache(pk, schema);
const [cacheValue, cachePath] = globalCache.get(entity, this._getEntity);
// TODO: what if this just returned the deps - then we don't need to store them
if (cachePath) {
localCacheKey.set(pk, cacheValue.value);
// TODO: can we store the cache values instead of tracking *all* their sources?
// this is only used for setting endpoints cache correctly. if we got this far we will def need to set as we would have already tried getting it
this.dependencies.push(...cacheValue.dependencies);
return cacheValue.value;
}
// if we don't find in denormalize cache then do full denormalize
else {
const trackingIndex = this.dependencies.length;
cycleCacheKey.set(pk, trackingIndex);
this.dependencies.push({
entity,
path: {
key,
pk
}
});
/** NON-GLOBAL_CACHE CODE */
computeValue(localCacheKey);
/** /END NON-GLOBAL_CACHE CODE */
cycleCacheKey.delete(pk);
// if in cycle, use the start of the cycle to track all deps
// otherwise, we use our own trackingIndex
const localKey = this.dependencies.slice(this.cycleIndex === -1 ? trackingIndex : this.cycleIndex);
const cacheValue = {
dependencies: localKey,
value: localCacheKey.get(pk)
};
globalCache.set(localKey, cacheValue);
// start of cycle - reset cycle detection
if (this.cycleIndex === trackingIndex) {
this.cycleIndex = -1;
}
}
} else {
// cycle detected
if (cycleCacheKey.has(pk)) {
this.cycleIndex = cycleCacheKey.get(pk);
} else {
// with no cycle, globalCacheEntry will have already been set
this.dependencies.push({
entity,
path: {
key,
pk
}
});
}
}
return localCacheKey.get(pk);
}
getCacheKey(key) {
if (!this.localCache.has(key)) {
this.localCache.set(key, new Map());
}
if (!this.cycleCache.has(key)) {
this.cycleCache.set(key, new Map());
}
const localCacheKey = this.localCache.get(key);
const cycleCacheKey = this.cycleCache.get(key);
return {
localCacheKey,
cycleCacheKey
};
}
/** Cache varies based on input (=== aka reference) */
getResults(input, cachable, computeValue) {
if (!cachable) {
return {
data: computeValue(),
paths: this.paths()
};
}
let [data, paths] = this.resultCache.get(input, this._getEntity);
if (paths === undefined) {
data = computeValue();
// we want to do this before we add our 'input' entry
paths = this.paths();
// for the first entry, `path` is ignored so empty members is fine
this.dependencies.unshift({
entity: input,
path: {
key: '',
pk: ''
}
});
this.resultCache.set(this.dependencies, data);
} else {
paths.shift();
}
return {
data,
paths
};
}
paths() {
return this.dependencies.map(dep => dep.path);
}
}
const getEntityCaches = entityCache => {
return (pk, schema) => {
var _ref;
const key = schema.key;
// collections should use the entities they collect over
// TODO: this should be based on a public interface
const entityInstance = (_ref = schema.cacheWith) != null ? _ref : schema;
if (!entityCache.has(key)) {
entityCache.set(key, new Map());
}
const entityCacheKey = entityCache.get(key);
if (!entityCacheKey.get(pk)) entityCacheKey.set(pk, new WeakMap());
const entityCachePk = entityCacheKey.get(pk);
let wem = entityCachePk.get(entityInstance);
if (!wem) {
wem = new WeakDependencyMap();
entityCachePk.set(entityInstance, wem);
}
return wem;
};
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJXZWFrRGVwZW5kZW5jeU1hcCIsIkdsb2JhbENhY2hlIiwiY29uc3RydWN0b3IiLCJnZXRFbnRpdHkiLCJlbnRpdHlDYWNoZSIsInJlc3VsdENhY2hlIiwiZGVwZW5kZW5jaWVzIiwiY3ljbGVDYWNoZSIsIk1hcCIsImN5Y2xlSW5kZXgiLCJsb2NhbENhY2hlIiwiX2dldEVudGl0eSIsImdldENhY2hlIiwiZ2V0RW50aXR5Q2FjaGVzIiwicGsiLCJzY2hlbWEiLCJlbnRpdHkiLCJjb21wdXRlVmFsdWUiLCJrZXkiLCJsb2NhbENhY2hlS2V5IiwiY3ljbGVDYWNoZUtleSIsImdldENhY2hlS2V5IiwiZ2V0IiwiZ2xvYmFsQ2FjaGUiLCJjYWNoZVZhbHVlIiwiY2FjaGVQYXRoIiwic2V0IiwidmFsdWUiLCJwdXNoIiwidHJhY2tpbmdJbmRleCIsImxlbmd0aCIsInBhdGgiLCJkZWxldGUiLCJsb2NhbEtleSIsInNsaWNlIiwiaGFzIiwiZ2V0UmVzdWx0cyIsImlucHV0IiwiY2FjaGFibGUiLCJkYXRhIiwicGF0aHMiLCJ1bmRlZmluZWQiLCJ1bnNoaWZ0Iiwic2hpZnQiLCJtYXAiLCJkZXAiLCJfcmVmIiwiZW50aXR5SW5zdGFuY2UiLCJjYWNoZVdpdGgiLCJlbnRpdHlDYWNoZUtleSIsIldlYWtNYXAiLCJlbnRpdHlDYWNoZVBrIiwid2VtIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21lbW8vZ2xvYmFsQ2FjaGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRW5kcG9pbnRzQ2FjaGUsIEVudGl0eUNhY2hlIH0gZnJvbSAnLi90eXBlcy5qcyc7XG5pbXBvcnQgV2Vha0RlcGVuZGVuY3lNYXAsIHsgdHlwZSBEZXAgfSBmcm9tICcuL1dlYWtEZXBlbmRlbmN5TWFwLmpzJztcbmltcG9ydCB0eXBlIENhY2hlIGZyb20gJy4uL2Rlbm9ybWFsaXplL2NhY2hlLmpzJztcbmltcG9ydCB0eXBlIHsgR2V0RW50aXR5IH0gZnJvbSAnLi4vZGVub3JtYWxpemUvZ2V0RW50aXRpZXMuanMnO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHlJbnRlcmZhY2UgfSBmcm9tICcuLi9pbnRlcmZhY2UuanMnO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHlQYXRoIH0gZnJvbSAnLi4vdHlwZXMuanMnO1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBHbG9iYWxDYWNoZSBpbXBsZW1lbnRzIENhY2hlIHtcbiAgcHJpdmF0ZSBkZXBlbmRlbmNpZXM6IERlcDxFbnRpdHlQYXRoPltdID0gW107XG4gIHByaXZhdGUgY3ljbGVDYWNoZTogTWFwPHN0cmluZywgTWFwPHN0cmluZywgbnVtYmVyPj4gPSBuZXcgTWFwKCk7XG4gIHByaXZhdGUgY3ljbGVJbmRleCA9IC0xO1xuICBwcml2YXRlIGxvY2FsQ2FjaGU6IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIGFueT4+ID0gbmV3IE1hcCgpO1xuXG4gIGRlY2xhcmUgcHJpdmF0ZSBnZXRDYWNoZTogKFxuICAgIHBrOiBzdHJpbmcsXG4gICAgc2NoZW1hOiBFbnRpdHlJbnRlcmZhY2UsXG4gICkgPT4gV2Vha0RlcGVuZGVuY3lNYXA8RW50aXR5UGF0aCwgb2JqZWN0LCBhbnk+O1xuXG4gIGRlY2xhcmUgcHJpdmF0ZSBfZ2V0RW50aXR5OiBHZXRFbnRpdHk7XG4gIGRlY2xhcmUgcHJpdmF0ZSByZXN1bHRDYWNoZTogRW5kcG9pbnRzQ2FjaGU7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgZ2V0RW50aXR5OiBHZXRFbnRpdHksXG4gICAgZW50aXR5Q2FjaGU6IEVudGl0eUNhY2hlLFxuICAgIHJlc3VsdENhY2hlOiBFbmRwb2ludHNDYWNoZSxcbiAgKSB7XG4gICAgdGhpcy5fZ2V0RW50aXR5ID0gZ2V0RW50aXR5O1xuICAgIHRoaXMuZ2V0Q2FjaGUgPSBnZXRFbnRpdHlDYWNoZXMoZW50aXR5Q2FjaGUpO1xuICAgIHRoaXMucmVzdWx0Q2FjaGUgPSByZXN1bHRDYWNoZTtcbiAgfVxuXG4gIGdldEVudGl0eShcbiAgICBwazogc3RyaW5nLFxuICAgIHNjaGVtYTogRW50aXR5SW50ZXJmYWNlLFxuICAgIGVudGl0eTogYW55LFxuICAgIGNvbXB1dGVWYWx1ZTogKGxvY2FsQ2FjaGVLZXk6IE1hcDxzdHJpbmcsIGFueT4pID0+IHZvaWQsXG4gICk6IG9iamVjdCB8IHVuZGVmaW5lZCB8IHN5bWJvbCB7XG4gICAgY29uc3Qga2V5ID0gc2NoZW1hLmtleTtcbiAgICBjb25zdCB7IGxvY2FsQ2FjaGVLZXksIGN5Y2xlQ2FjaGVLZXkgfSA9IHRoaXMuZ2V0Q2FjaGVLZXkoa2V5KTtcblxuICAgIGlmICghbG9jYWxDYWNoZUtleS5nZXQocGspKSB7XG4gICAgICBjb25zdCBnbG9iYWxDYWNoZTogV2Vha0RlcGVuZGVuY3lNYXA8XG4gICAgICAgIEVudGl0eVBhdGgsXG4gICAgICAgIG9iamVjdCxcbiAgICAgICAgRW50aXR5Q2FjaGVWYWx1ZVxuICAgICAgPiA9IHRoaXMuZ2V0Q2FjaGUocGssIHNjaGVtYSk7XG4gICAgICBjb25zdCBbY2FjaGVWYWx1ZSwgY2FjaGVQYXRoXSA9IGdsb2JhbENhY2hlLmdldChlbnRpdHksIHRoaXMuX2dldEVudGl0eSk7XG4gICAgICAvLyBUT0RPOiB3aGF0IGlmIHRoaXMganVzdCByZXR1cm5lZCB0aGUgZGVwcyAtIHRoZW4gd2UgZG9uJ3QgbmVlZCB0byBzdG9yZSB0aGVtXG5cbiAgICAgIGlmIChjYWNoZVBhdGgpIHtcbiAgICAgICAgbG9jYWxDYWNoZUtleS5zZXQocGssIGNhY2hlVmFsdWUudmFsdWUpO1xuICAgICAgICAvLyBUT0RPOiBjYW4gd2Ugc3RvcmUgdGhlIGNhY2hlIHZhbHVlcyBpbnN0ZWFkIG9mIHRyYWNraW5nICphbGwqIHRoZWlyIHNvdXJjZXM/XG4gICAgICAgIC8vIHRoaXMgaXMgb25seSB1c2VkIGZvciBzZXR0aW5nIGVuZHBvaW50cyBjYWNoZSBjb3JyZWN0bHkuIGlmIHdlIGdvdCB0aGlzIGZhciB3ZSB3aWxsIGRlZiBuZWVkIHRvIHNldCBhcyB3ZSB3b3VsZCBoYXZlIGFscmVhZHkgdHJpZWQgZ2V0dGluZyBpdFxuICAgICAgICB0aGlzLmRlcGVuZGVuY2llcy5wdXNoKC4uLmNhY2hlVmFsdWUuZGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuIGNhY2hlVmFsdWUudmFsdWU7XG4gICAgICB9XG4gICAgICAvLyBpZiB3ZSBkb24ndCBmaW5kIGluIGRlbm9ybWFsaXplIGNhY2hlIHRoZW4gZG8gZnVsbCBkZW5vcm1hbGl6ZVxuICAgICAgZWxzZSB7XG4gICAgICAgIGNvbnN0IHRyYWNraW5nSW5kZXggPSB0aGlzLmRlcGVuZGVuY2llcy5sZW5ndGg7XG4gICAgICAgIGN5Y2xlQ2FjaGVLZXkuc2V0KHBrLCB0cmFja2luZ0luZGV4KTtcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXMucHVzaCh7IGVudGl0eSwgcGF0aDogeyBrZXksIHBrIH0gfSk7XG5cbiAgICAgICAgLyoqIE5PTi1HTE9CQUxfQ0FDSEUgQ09ERSAqL1xuICAgICAgICBjb21wdXRlVmFsdWUobG9jYWxDYWNoZUtleSk7XG4gICAgICAgIC8qKiAvRU5EIE5PTi1HTE9CQUxfQ0FDSEUgQ09ERSAqL1xuXG4gICAgICAgIGN5Y2xlQ2FjaGVLZXkuZGVsZXRlKHBrKTtcbiAgICAgICAgLy8gaWYgaW4gY3ljbGUsIHVzZSB0aGUgc3RhcnQgb2YgdGhlIGN5Y2xlIHRvIHRyYWNrIGFsbCBkZXBzXG4gICAgICAgIC8vIG90aGVyd2lzZSwgd2UgdXNlIG91ciBvd24gdHJhY2tpbmdJbmRleFxuICAgICAgICBjb25zdCBsb2NhbEtleSA9IHRoaXMuZGVwZW5kZW5jaWVzLnNsaWNlKFxuICAgICAgICAgIHRoaXMuY3ljbGVJbmRleCA9PT0gLTEgPyB0cmFja2luZ0luZGV4IDogdGhpcy5jeWNsZUluZGV4LFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBjYWNoZVZhbHVlOiBFbnRpdHlDYWNoZVZhbHVlID0ge1xuICAgICAgICAgIGRlcGVuZGVuY2llczogbG9jYWxLZXksXG4gICAgICAgICAgdmFsdWU6IGxvY2FsQ2FjaGVLZXkuZ2V0KHBrKSxcbiAgICAgICAgfTtcbiAgICAgICAgZ2xvYmFsQ2FjaGUuc2V0KGxvY2FsS2V5LCBjYWNoZVZhbHVlKTtcblxuICAgICAgICAvLyBzdGFydCBvZiBjeWNsZSAtIHJlc2V0IGN5Y2xlIGRldGVjdGlvblxuICAgICAgICBpZiAodGhpcy5jeWNsZUluZGV4ID09PSB0cmFja2luZ0luZGV4KSB7XG4gICAgICAgICAgdGhpcy5jeWNsZUluZGV4ID0gLTE7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLy8gY3ljbGUgZGV0ZWN0ZWRcbiAgICAgIGlmIChjeWNsZUNhY2hlS2V5LmhhcyhwaykpIHtcbiAgICAgICAgdGhpcy5jeWNsZUluZGV4ID0gY3ljbGVDYWNoZUtleS5nZXQocGspITtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHdpdGggbm8gY3ljbGUsIGdsb2JhbENhY2hlRW50cnkgd2lsbCBoYXZlIGFscmVhZHkgYmVlbiBzZXRcbiAgICAgICAgdGhpcy5kZXBlbmRlbmNpZXMucHVzaCh7IGVudGl0eSwgcGF0aDogeyBrZXksIHBrIH0gfSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBsb2NhbENhY2hlS2V5LmdldChwayk7XG4gIH1cblxuICBwcml2YXRlIGdldENhY2hlS2V5KGtleTogc3RyaW5nKSB7XG4gICAgaWYgKCF0aGlzLmxvY2FsQ2FjaGUuaGFzKGtleSkpIHtcbiAgICAgIHRoaXMubG9jYWxDYWNoZS5zZXQoa2V5LCBuZXcgTWFwKCkpO1xuICAgIH1cbiAgICBpZiAoIXRoaXMuY3ljbGVDYWNoZS5oYXMoa2V5KSkge1xuICAgICAgdGhpcy5jeWNsZUNhY2hlLnNldChrZXksIG5ldyBNYXAoKSk7XG4gICAgfVxuICAgIGNvbnN0IGxvY2FsQ2FjaGVLZXkgPSB0aGlzLmxvY2FsQ2FjaGUuZ2V0KGtleSkhO1xuICAgIGNvbnN0IGN5Y2xlQ2FjaGVLZXkgPSB0aGlzLmN5Y2xlQ2FjaGUuZ2V0KGtleSkhO1xuICAgIHJldHVybiB7IGxvY2FsQ2FjaGVLZXksIGN5Y2xlQ2FjaGVLZXkgfTtcbiAgfVxuXG4gIC8qKiBDYWNoZSB2YXJpZXMgYmFzZWQgb24gaW5wdXQgKD09PSBha2EgcmVmZXJlbmNlKSAqL1xuICBnZXRSZXN1bHRzKFxuICAgIGlucHV0OiBhbnksXG4gICAgY2FjaGFibGU6IGJvb2xlYW4sXG4gICAgY29tcHV0ZVZhbHVlOiAoKSA9PiBhbnksXG4gICk6IHtcbiAgICBkYXRhOiBhbnk7XG4gICAgcGF0aHM6IEVudGl0eVBhdGhbXTtcbiAgfSB7XG4gICAgaWYgKCFjYWNoYWJsZSkge1xuICAgICAgcmV0dXJuIHsgZGF0YTogY29tcHV0ZVZhbHVlKCksIHBhdGhzOiB0aGlzLnBhdGhzKCkgfTtcbiAgICB9XG5cbiAgICBsZXQgW2RhdGEsIHBhdGhzXSA9IHRoaXMucmVzdWx0Q2FjaGUuZ2V0KGlucHV0LCB0aGlzLl9nZXRFbnRpdHkpO1xuXG4gICAgaWYgKHBhdGhzID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGRhdGEgPSBjb21wdXRlVmFsdWUoKTtcbiAgICAgIC8vIHdlIHdhbnQgdG8gZG8gdGhpcyBiZWZvcmUgd2UgYWRkIG91ciAnaW5wdXQnIGVudHJ5XG4gICAgICBwYXRocyA9IHRoaXMucGF0aHMoKTtcbiAgICAgIC8vIGZvciB0aGUgZmlyc3QgZW50cnksIGBwYXRoYCBpcyBpZ25vcmVkIHNvIGVtcHR5IG1lbWJlcnMgaXMgZmluZVxuICAgICAgdGhpcy5kZXBlbmRlbmNpZXMudW5zaGlmdCh7IGVudGl0eTogaW5wdXQsIHBhdGg6IHsga2V5OiAnJywgcGs6ICcnIH0gfSk7XG4gICAgICB0aGlzLnJlc3VsdENhY2hlLnNldCh0aGlzLmRlcGVuZGVuY2llcywgZGF0YSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHBhdGhzLnNoaWZ0KCk7XG4gICAgfVxuICAgIHJldHVybiB7IGRhdGEsIHBhdGhzIH07XG4gIH1cblxuICBwcm90ZWN0ZWQgcGF0aHMoKSB7XG4gICAgcmV0dXJuIHRoaXMuZGVwZW5kZW5jaWVzLm1hcChkZXAgPT4gZGVwLnBhdGgpO1xuICB9XG59XG5cbmludGVyZmFjZSBFbnRpdHlDYWNoZVZhbHVlIHtcbiAgZGVwZW5kZW5jaWVzOiBEZXA8RW50aXR5UGF0aD5bXTtcbiAgdmFsdWU6IG9iamVjdCB8IHN5bWJvbCB8IHVuZGVmaW5lZDtcbn1cblxuY29uc3QgZ2V0RW50aXR5Q2FjaGVzID0gKGVudGl0eUNhY2hlOiBFbnRpdHlDYWNoZSkgPT4ge1xuICByZXR1cm4gKHBrOiBzdHJpbmcsIHNjaGVtYTogRW50aXR5SW50ZXJmYWNlKSA9PiB7XG4gICAgY29uc3Qga2V5ID0gc2NoZW1hLmtleTtcbiAgICAvLyBjb2xsZWN0aW9ucyBzaG91bGQgdXNlIHRoZSBlbnRpdGllcyB0aGV5IGNvbGxlY3Qgb3ZlclxuICAgIC8vIFRPRE86IHRoaXMgc2hvdWxkIGJlIGJhc2VkIG9uIGEgcHVibGljIGludGVyZmFjZVxuICAgIGNvbnN0IGVudGl0eUluc3RhbmNlOiBFbnRpdHlJbnRlcmZhY2UgPSAoc2NoZW1hLmNhY2hlV2l0aCBhcyBhbnkpID8/IHNjaGVtYTtcblxuICAgIGlmICghZW50aXR5Q2FjaGUuaGFzKGtleSkpIHtcbiAgICAgIGVudGl0eUNhY2hlLnNldChrZXksIG5ldyBNYXAoKSk7XG4gICAgfVxuICAgIGNvbnN0IGVudGl0eUNhY2hlS2V5ID0gZW50aXR5Q2FjaGUuZ2V0KGtleSkhO1xuICAgIGlmICghZW50aXR5Q2FjaGVLZXkuZ2V0KHBrKSlcbiAgICAgIGVudGl0eUNhY2hlS2V5LnNldChcbiAgICAgICAgcGssXG4gICAgICAgIG5ldyBXZWFrTWFwPFxuICAgICAgICAgIEVudGl0eUludGVyZmFjZSxcbiAgICAgICAgICBXZWFrRGVwZW5kZW5jeU1hcDxFbnRpdHlQYXRoLCBvYmplY3QsIGFueT5cbiAgICAgICAgPigpLFxuICAgICAgKTtcblxuICAgIGNvbnN0IGVudGl0eUNhY2hlUGsgPSBlbnRpdHlDYWNoZUtleS5nZXQocGspIGFzIFdlYWtNYXA8XG4gICAgICBFbnRpdHlJbnRlcmZhY2U8YW55PixcbiAgICAgIFdlYWtEZXBlbmRlbmN5TWFwPEVudGl0eVBhdGgsIG9iamVjdCwgYW55PlxuICAgID47XG4gICAgbGV0IHdlbSA9IGVudGl0eUNhY2hlUGsuZ2V0KGVudGl0eUluc3RhbmNlKSBhcyBXZWFrRGVwZW5kZW5jeU1hcDxcbiAgICAgIEVudGl0eVBhdGgsXG4gICAgICBvYmplY3QsXG4gICAgICBhbnlcbiAgICA+O1xuICAgIGlmICghd2VtKSB7XG4gICAgICB3ZW0gPSBuZXcgV2Vha0RlcGVuZGVuY3lNYXA8RW50aXR5UGF0aCwgb2JqZWN0LCBhbnk+KCk7XG4gICAgICBlbnRpdHlDYWNoZVBrLnNldChlbnRpdHlJbnN0YW5jZSwgd2VtKTtcbiAgICB9XG5cbiAgICByZXR1cm4gd2VtO1xuICB9O1xufTtcbiJdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBT0EsaUJBQWlCLE1BQW9CLHdCQUF3QjtBQU1wRSxlQUFlLE1BQU1DLFdBQVcsQ0FBa0I7RUFjaERDLFdBQVdBLENBQ1RDLFNBQW9CLEVBQ3BCQyxXQUF3QixFQUN4QkMsV0FBMkIsRUFDM0I7SUFBQSxLQWpCTUMsWUFBWSxHQUFzQixFQUFFO0lBQUEsS0FDcENDLFVBQVUsR0FBcUMsSUFBSUMsR0FBRyxDQUFDLENBQUM7SUFBQSxLQUN4REMsVUFBVSxHQUFHLENBQUMsQ0FBQztJQUFBLEtBQ2ZDLFVBQVUsR0FBa0MsSUFBSUYsR0FBRyxDQUFDLENBQUM7SUFlM0QsSUFBSSxDQUFDRyxVQUFVLEdBQUdSLFNBQVM7SUFDM0IsSUFBSSxDQUFDUyxRQUFRLEdBQUdDLGVBQWUsQ0FBQ1QsV0FBVyxDQUFDO0lBQzVDLElBQUksQ0FBQ0MsV0FBVyxHQUFHQSxXQUFXO0VBQ2hDO0VBRUFGLFNBQVNBLENBQ1BXLEVBQVUsRUFDVkMsTUFBdUIsRUFDdkJDLE1BQVcsRUFDWEMsWUFBdUQsRUFDMUI7SUFDN0IsTUFBTUMsR0FBRyxHQUFHSCxNQUFNLENBQUNHLEdBQUc7SUFDdEIsTUFBTTtNQUFFQyxhQUFhO01BQUVDO0lBQWMsQ0FBQyxHQUFHLElBQUksQ0FBQ0Ms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