@data-client/normalizr
Version:
Normalizes and denormalizes JSON according to schema for Redux and Flux applications
132 lines (127 loc) • 20.2 kB
JavaScript
import GlobalCache from './globalCache.js';
import WeakDependencyMap from './WeakDependencyMap.js';
import buildQueryKey from '../buildQueryKey.js';
import { getEntities } from '../denormalize/getEntities.js';
import getUnvisit from '../denormalize/unvisit.js';
import { isImmutable } from '../schemas/ImmutableUtils.js';
//TODO: make immutable distinction occur when initilizing MemoCache
/** Singleton to store the memoization cache for denormalization methods */
export default class MemoCache {
constructor() {
/** Cache for every entity based on its dependencies and its own input */
this.entities = new Map();
/** Caches the final denormalized form based on input, entities */
this.endpoints = new WeakDependencyMap();
/** Caches the queryKey based on schema, args, and any used entities or indexes */
this.queryKeys = new Map();
}
/** Compute denormalized form maintaining referential equality for same inputs */
denormalize(schema, input, entities, args = []) {
// we already vary based on input, so we don't need endpointKey? TODO: verify
// if (!this.endpoints[endpointKey])
// this.endpoints[endpointKey] = new WeakDependencyMap<EntityPath>();
// undefined means don't do anything
if (schema === undefined) {
return {
data: input,
paths: []
};
}
if (input === undefined) {
return {
data: undefined,
paths: []
};
}
const getEntity = getEntities(entities);
return getUnvisit(getEntity, new GlobalCache(getEntity, this.entities, this.endpoints), args)(schema, input);
}
/** Compute denormalized form maintaining referential equality for same inputs */
query(schema, args, entities, indexes,
// NOTE: different orders can result in cache busting here; but since it's just a perf penalty we will allow for now
argsKey = JSON.stringify(args)) {
const input = this.buildQueryKey(schema, args, entities, indexes, argsKey);
if (!input) {
return;
}
const {
data
} = this.denormalize(schema, input, entities, args);
return typeof data === 'symbol' ? undefined : data;
}
buildQueryKey(schema, args, entities, indexes,
// NOTE: different orders can result in cache busting here; but since it's just a perf penalty we will allow for now
argsKey = JSON.stringify(args)) {
// This is redundant for buildQueryKey checks, but that was is used for recursion so we still need the checks there
// TODO: If we make each recursive call include cache lookups, we combine these checks together
// null is object so we need double check
if (typeof schema !== 'object' && typeof schema.queryKey !== 'function' || !schema) return schema;
// cache lookup: argsKey -> schema -> ...touched indexes or entities
if (!this.queryKeys.get(argsKey)) {
this.queryKeys.set(argsKey, new WeakDependencyMap());
}
const queryCache = this.queryKeys.get(argsKey);
const getEntity = createGetEntity(entities);
const getIndex = createGetIndex(indexes);
// eslint-disable-next-line prefer-const
let [value, paths] = queryCache.get(schema, createDepLookup(getEntity, getIndex));
// paths undefined is the only way to truly tell nothing was found (the value could have actually been undefined)
if (!paths) {
// first dep path is ignored
// we start with schema object, then lookup any 'touched' members and their paths
const dependencies = [{
path: [''],
entity: schema
}];
value = buildQueryKey(schema, args, trackLookup(getEntity, dependencies), trackLookup(getIndex, dependencies));
queryCache.set(dependencies, value);
}
return value;
}
}
function createDepLookup(getEntity, getIndex) {
return args => {
return args.length === 3 ? getIndex(...args) : getEntity(...args);
};
}
function trackLookup(lookup, dependencies) {
return (...args) => {
const entity = lookup(...args);
dependencies.push({
path: args,
entity
});
return entity;
};
}
export function createGetEntity(entities) {
const entityIsImmutable = isImmutable(entities);
if (entityIsImmutable) {
return (...args) => {
var _entities$getIn;
return (_entities$getIn = entities.getIn(args)) == null || _entities$getIn.toJS == null ? void 0 : _entities$getIn.toJS();
};
} else {
return (entityKey, pk) => {
var _entities$entityKey;
return pk ? (_entities$entityKey = entities[entityKey]) == null ? void 0 : _entities$entityKey[pk] : entities[entityKey];
};
}
}
export function createGetIndex(indexes) {
const entityIsImmutable = isImmutable(indexes);
if (entityIsImmutable) {
return (key, field, value) => {
var _indexes$getIn;
return (_indexes$getIn = indexes.getIn([key, field])) == null || _indexes$getIn.toJS == null ? void 0 : _indexes$getIn.toJS();
};
} else {
return (key, field, value) => {
if (indexes[key]) {
return indexes[key][field];
}
return {};
};
}
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJHbG9iYWxDYWNoZSIsIldlYWtEZXBlbmRlbmN5TWFwIiwiYnVpbGRRdWVyeUtleSIsImdldEVudGl0aWVzIiwiZ2V0VW52aXNpdCIsImlzSW1tdXRhYmxlIiwiTWVtb0NhY2hlIiwiY29uc3RydWN0b3IiLCJlbnRpdGllcyIsIk1hcCIsImVuZHBvaW50cyIsInF1ZXJ5S2V5cyIsImRlbm9ybWFsaXplIiwic2NoZW1hIiwiaW5wdXQiLCJhcmdzIiwidW5kZWZpbmVkIiwiZGF0YSIsInBhdGhzIiwiZ2V0RW50aXR5IiwicXVlcnkiLCJpbmRleGVzIiwiYXJnc0tleSIsIkpTT04iLCJzdHJpbmdpZnkiLCJxdWVyeUtleSIsImdldCIsInNldCIsInF1ZXJ5Q2FjaGUiLCJjcmVhdGVHZXRFbnRpdHkiLCJnZXRJbmRleCIsImNyZWF0ZUdldEluZGV4IiwidmFsdWUiLCJjcmVhdGVEZXBMb29rdXAiLCJkZXBlbmRlbmNpZXMiLCJwYXRoIiwiZW50aXR5IiwidHJhY2tMb29rdXAiLCJsZW5ndGgiLCJsb29rdXAiLCJwdXNoIiwiZW50aXR5SXNJbW11dGFibGUiLCJfZW50aXRpZXMkZ2V0SW4iLCJnZXRJbiIsInRvSlMiLCJlbnRpdHlLZXkiLCJwayIsIl9lbnRpdGllcyRlbnRpdHlLZXkiLCJrZXkiLCJmaWVsZCIsIl9pbmRleGVzJGdldEluIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL21lbW8vTWVtb0NhY2hlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBHbG9iYWxDYWNoZSBmcm9tICcuL2dsb2JhbENhY2hlLmpzJztcbmltcG9ydCB7IEVuZHBvaW50c0NhY2hlLCBFbnRpdHlDYWNoZSB9IGZyb20gJy4vdHlwZXMuanMnO1xuaW1wb3J0IFdlYWtEZXBlbmRlbmN5TWFwLCB7IERlcCwgR2V0RGVwZW5kZW5jeSB9IGZyb20gJy4vV2Vha0RlcGVuZGVuY3lNYXAuanMnO1xuaW1wb3J0IGJ1aWxkUXVlcnlLZXkgZnJvbSAnLi4vYnVpbGRRdWVyeUtleS5qcyc7XG5pbXBvcnQgeyBnZXRFbnRpdGllcyB9IGZyb20gJy4uL2Rlbm9ybWFsaXplL2dldEVudGl0aWVzLmpzJztcbmltcG9ydCBnZXRVbnZpc2l0IGZyb20gJy4uL2Rlbm9ybWFsaXplL3VudmlzaXQuanMnO1xuaW1wb3J0IHR5cGUgeyBFbnRpdHlUYWJsZSwgTm9ybWFsaXplZEluZGV4LCBTY2hlbWEgfSBmcm9tICcuLi9pbnRlcmZhY2UuanMnO1xuaW1wb3J0IHsgaXNJbW11dGFibGUgfSBmcm9tICcuLi9zY2hlbWFzL0ltbXV0YWJsZVV0aWxzLmpzJztcbmltcG9ydCB0eXBlIHtcbiAgRGVub3JtYWxpemVOdWxsYWJsZSxcbiAgRW50aXR5UGF0aCxcbiAgTm9ybWFsaXplTnVsbGFibGUsXG59IGZyb20gJy4uL3R5cGVzLmpzJztcblxuLy9UT0RPOiBtYWtlIGltbXV0YWJsZSBkaXN0aW5jdGlvbiBvY2N1ciB3aGVuIGluaXRpbGl6aW5nIE1lbW9DYWNoZVxuXG4vKiogU2luZ2xldG9uIHRvIHN0b3JlIHRoZSBtZW1vaXphdGlvbiBjYWNoZSBmb3IgZGVub3JtYWxpemF0aW9uIG1ldGhvZHMgKi9cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIE1lbW9DYWNoZSB7XG4gIC8qKiBDYWNoZSBmb3IgZXZlcnkgZW50aXR5IGJhc2VkIG9uIGl0cyBkZXBlbmRlbmNpZXMgYW5kIGl0cyBvd24gaW5wdXQgKi9cbiAgcHJvdGVjdGVkIGVudGl0aWVzOiBFbnRpdHlDYWNoZSA9IG5ldyBNYXAoKTtcbiAgLyoqIENhY2hlcyB0aGUgZmluYWwgZGVub3JtYWxpemVkIGZvcm0gYmFzZWQgb24gaW5wdXQsIGVudGl0aWVzICovXG4gIHByb3RlY3RlZCBlbmRwb2ludHM6IEVuZHBvaW50c0NhY2hlID0gbmV3IFdlYWtEZXBlbmRlbmN5TWFwPEVudGl0eVBhdGg+KCk7XG4gIC8qKiBDYWNoZXMgdGhlIHF1ZXJ5S2V5IGJhc2VkIG9uIHNjaGVtYSwgYXJncywgYW5kIGFueSB1c2VkIGVudGl0aWVzIG9yIGluZGV4ZXMgKi9cbiAgcHJvdGVjdGVkIHF1ZXJ5S2V5czogTWFwPHN0cmluZywgV2Vha0RlcGVuZGVuY3lNYXA8UXVlcnlQYXRoPj4gPSBuZXcgTWFwKCk7XG5cbiAgLyoqIENvbXB1dGUgZGVub3JtYWxpemVkIGZvcm0gbWFpbnRhaW5pbmcgcmVmZXJlbnRpYWwgZXF1YWxpdHkgZm9yIHNhbWUgaW5wdXRzICovXG4gIGRlbm9ybWFsaXplPFMgZXh0ZW5kcyBTY2hlbWE+KFxuICAgIHNjaGVtYTogUyB8IHVuZGVmaW5lZCxcbiAgICBpbnB1dDogdW5rbm93bixcbiAgICBlbnRpdGllczogYW55LFxuICAgIGFyZ3M6IHJlYWRvbmx5IGFueVtdID0gW10sXG4gICk6IHtcbiAgICBkYXRhOiBEZW5vcm1hbGl6ZU51bGxhYmxlPFM+IHwgc3ltYm9sO1xuICAgIHBhdGhzOiBFbnRpdHlQYXRoW107XG4gIH0ge1xuICAgIC8vIHdlIGFscmVhZHkgdmFyeSBiYXNlZCBvbiBpbnB1dCwgc28gd2UgZG9uJ3QgbmVlZCBlbmRwb2ludEtleT8gVE9ETzogdmVyaWZ5XG4gICAgLy8gaWYgKCF0aGlzLmVuZHBvaW50c1tlbmRwb2ludEtleV0pXG4gICAgLy8gICB0aGlzLmVuZHBvaW50c1tlbmRwb2ludEtleV0gPSBuZXcgV2Vha0RlcGVuZGVuY3lNYXA8RW50aXR5UGF0aD4oKTtcblxuICAgIC8vIHVuZGVmaW5lZCBtZWFucyBkb24ndCBkbyBhbnl0aGluZ1xuICAgIGlmIChzY2hlbWEgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIHsgZGF0YTogaW5wdXQgYXMgYW55LCBwYXRoczogW10gfTtcbiAgICB9XG4gICAgaWYgKGlucHV0ID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHJldHVybiB7IGRhdGE6IHVuZGVmaW5lZCBhcyBhbnksIHBhdGhzOiBbXSB9O1xuICAgIH1cbiAgICBjb25zdCBnZXRFbnRpdHkgPSBnZXRFbnRpdGllcyhlbnRpdGllcyk7XG5cbiAgICByZXR1cm4gZ2V0VW52aXNpdChcbiAgICAgIGdldEVudGl0eSxcbiAgICAgIG5ldyBHbG9iYWxDYWNoZShnZXRFbnRpdHksIHRoaXMuZW50aXRpZXMsIHRoaXMuZW5kcG9pbnRzKSxcbiAgICAgIGFyZ3MsXG4gICAgKShzY2hlbWEsIGlucHV0KTtcbiAgfVxuXG4gIC8qKiBDb21wdXRlIGRlbm9ybWFsaXplZCBmb3JtIG1haW50YWluaW5nIHJlZmVyZW50aWFsIGVxdWFsaXR5IGZvciBzYW1lIGlucHV0cyAqL1xuICBxdWVyeTxTIGV4dGVuZHMgU2NoZW1hPihcbiAgICBzY2hlbWE6IFMsXG4gICAgYXJnczogcmVhZG9ubHkgYW55W10sXG4gICAgZW50aXRpZXM6XG4gICAgICB8IFJlY29yZDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIGFueT4gfCB1bmRlZmluZWQ+XG4gICAgICB8IHtcbiAgICAgICAgICBnZXRJbihrOiBzdHJpbmdbXSk6IGFueTtcbiAgICAgICAgfSxcbiAgICBpbmRleGVzOlxuICAgICAgfCBOb3JtYWxpemVkSW5kZXhcbiAgICAgIHwge1xuICAgICAgICAgIGdldEluKGs6IHN0cmluZ1tdKTogYW55O1xuICAgICAgICB9LFxuICAgIC8vIE5PVEU6IGRpZmZlcmVudCBvcmRlcnMgY2FuIHJlc3VsdCBpbiBjYWNoZSBidXN0aW5nIGhlcmU7IGJ1dCBzaW5jZSBpdCdzIGp1c3QgYSBwZXJmIHBlbmFsdHkgd2Ugd2lsbCBhbGxvdyBmb3Igbm93XG4gICAgYXJnc0tleTogc3RyaW5nID0gSlNPTi5zdHJpbmdpZnkoYXJncyksXG4gICk6IERlbm9ybWFsaXplTnVsbGFibGU8Uz4gfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IGlucHV0ID0gdGhpcy5idWlsZFF1ZXJ5S2V5KHNjaGVtYSwgYXJncywgZW50aXRpZXMsIGluZGV4ZXMsIGFyZ3NLZXkpO1xuXG4gICAgaWYgKCFpbnB1dCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHsgZGF0YSB9ID0gdGhpcy5kZW5vcm1hbGl6ZShzY2hlbWEsIGlucHV0LCBlbnRpdGllcywgYXJncyk7XG4gICAgcmV0dXJuIHR5cGVvZiBkYXRhID09PSAnc3ltYm9sJyA/IHVuZGVmaW5lZCA6IChkYXRhIGFzIGFueSk7XG4gIH1cblxuICBidWlsZFF1ZXJ5S2V5PFMgZXh0ZW5kcyBTY2hlbWE+KFxuICAgIHNjaGVtYTogUyxcbiAgICBhcmdzOiByZWFkb25seSBhbnlbXSxcbiAgICBlbnRpdGllczpcbiAgICAgIHwgUmVjb3JkPHN0cmluZywgUmVjb3JkPHN0cmluZywgYW55PiB8IHVuZGVmaW5lZD5cbiAgICAgIHwge1xuICAgICAgICAgIGdldEluKGs6IHN0cmluZ1tdKTogYW55O1xuICAgICAgICB9LFxuICAgIGluZGV4ZXM6XG4gICAgICB8IE5vcm1hbGl6ZWRJbmRleFxuICAgICAgfCB7XG4gICAgICAgICAgZ2V0SW4oazogc3RyaW5nW10pOiBhbnk7XG4gICAgICAgIH0sXG4gICAgLy8gTk9URTogZGlmZmVyZW50IG9yZGVycyBjYW4gcmVzdWx0IGluIGNhY2hlIGJ1c3RpbmcgaGVyZTsgYnV0IHNpbmNlIGl0J3MganVzdCBhIHBlcmYgcGVuYWx0eSB3ZSB3aWxsIGFsbG93IGZvciBub3dcbiAgICBhcmdzS2V5OiBzdHJpbmcgPSBKU09OLnN0cmluZ2lmeShhcmdzKSxcbiAgKTogTm9ybWFsaXplTnVsbGFibGU8Uz4ge1xuICAgIC8vIFRoaXMgaXMgcmVkdW5kYW50IGZvciBidWlsZFF1ZXJ5S2V5IGNoZWNrcywgYnV0IHRoYXQgd2FzIGlzIHVzZWQgZm9yIHJlY3Vyc2lvbiBzbyB3ZSBzdGlsbCBuZWVkIHRoZSBjaGVja3MgdGhlcmVcbiAgICAvLyBUT0RPOiBJZiB3ZSBtYWtlIGVhY2ggcmVjdXJzaXZlIGNhbGwgaW5jbHVkZSBjYWNoZSBsb29rdXBzLCB3ZSBjb21iaW5lIHRoZXNlIGNoZWNrcyB0b2dldGhlclxuICAgIC8vIG51bGwgaXMgb2JqZWN0IHNvIHdlIG5lZWQgZG91YmxlIGNoZWNrXG4gICAgaWYgKFxuICAgICAgKHR5cGVvZiBzY2hlbWEgIT09ICdvYmplY3QnICYmXG4gICAgICAgIHR5cGVvZiAoc2NoZW1hIGFzIGFueSkucXVlcnlLZXkgIT09ICdmdW5jdGlvbicpIHx8XG4gICAgICAhc2NoZW1hXG4gICAgKVxuICAgICAgcmV0dXJuIHNjaGVtYSBhcyBhbnk7XG5cbiAgICAvLyBjYWNoZSBsb29rdXA6IGFyZ3NLZXkgLT4gc2NoZW1hIC0+IC4uLnRvdWNoZWQgaW5kZXhlcyBvciBlbnRpdGllc1xuICAgIGlmICghdGhpcy5xdWVyeUtleXMuZ2V0KGFyZ3NLZXkpKSB7XG4gICAgICB0aGlzLnF1ZXJ5S2V5cy5zZXQoYXJnc0tleSwgbmV3IFdlYWtEZXBlbmRlbmN5TWFwPFF1ZXJ5UGF0aD4oKSk7XG4gICAgfVxuICAgIGNvbnN0IHF1ZXJ5Q2FjaGUgPSB0aGlzLnF1ZXJ5S2V5cy5nZXQoYXJnc0tleSkgYXMgV2Vha0RlcGVuZGVuY3lNYXA8XG4gICAgICBRdWVyeVBhdGgsXG4gICAgICBvYmplY3QsXG4gICAgICBhbnlcbiAgICA+O1xuICAgIGNvbnN0IGdldEVudGl0eSA9IGNyZWF0ZUdldEVudGl0eShlbnRpdGllcyk7XG4gICAgY29uc3QgZ2V0SW5kZXggPSBjcmVhdGVHZXRJbmRleChpbmRleGVzKTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcHJlZmVyLWNvbnN0XG4gICAgbGV0IFt2YWx1ZSwgcGF0aHNdID0gcXVlcnlDYWNoZS5nZXQoXG4gICAgICBzY2hlbWEgYXMgYW55LFxuICAgICAgY3JlYXRlRGVwTG9va3VwKGdldEVudGl0eSwgZ2V0SW5kZXgpLFxuICAgICk7XG5cbiAgICAvLyBwYXRocyB1bmRlZmluZWQgaXMgdGhlIG9ubHkgd2F5IHRvIHRydWx5IHRlbGwgbm90aGluZyB3YXMgZm91bmQgKHRoZSB2YWx1ZSBjb3VsZCBoYXZlIGFjdHVhbGx5IGJlZW4gdW5kZWZpbmVkKVxuICAgIGlmICghcGF0aHMpIHtcbiAgICAgIC8vIGZpcnN0IGRlcCBwYXRoIGlzIGlnbm9yZWRcbiAgICAgIC8vIHdlIHN0YXJ0IHdpdGggc2NoZW1hIG9iamVjdCwgdGhlbiBsb29rdXAgYW55ICd0b3VjaGVkJyBtZW1iZXJzIGFuZCB0aGVpciBwYXRoc1xuICAgICAgY29uc3QgZGVwZW5kZW5jaWVzOiBEZXA8UXVlcnlQYXRoPltdID0gW1xuICAgICAgICB7IHBhdGg6IFsnJ10sIGVudGl0eTogc2NoZW1hIGFzIGFueSB9LFxuICAgICAgXTtcblxuICAgICAgdmFsdWUgPSBidWlsZFF1ZXJ5S2V5KFxuICAgICAgICBzY2hlbWEsXG4gICAgICAgIGFyZ3MsXG4gICAgICAgIHRyYWNrTG9va3VwKGdldEVudGl0eSwgZGVwZW5kZW5jaWVzKSxcbiAgICAgICAgdHJhY2tMb29rdXAoZ2V0SW5kZXgsIGRlcGVuZGVuY2llcyksXG4gICAgICApO1xuICAgICAgcXVlcnlDYWNoZS5zZXQoZGVwZW5kZW5jaWVzLCB2YWx1ZSk7XG4gICAgfVxuICAgIHJldHVybiB2YWx1ZTtcbiAgfVxufVxuXG50eXBlIEluZGV4UGF0aCA9IFtrZXk6IHN0cmluZywgZmllbGQ6IHN0cmluZywgdmFsdWU6IHN0cmluZ107XG50eXBlIEVudGl0eVNjaGVtYVBhdGggPSBba2V5OiBzdHJpbmddIHwgW2tleTogc3RyaW5nLCBwazogc3RyaW5nXTtcbnR5cGUgUXVlcnlQYXRoID0gSW5kZXhQYXRoIHwgRW50aXR5U2NoZW1hUGF0aDtcblxuZnVuY3Rpb24gY3JlYXRlRGVwTG9va3VwKGdldEVudGl0eSwgZ2V0SW5kZXgpOiBHZXREZXBlbmRlbmN5PFF1ZXJ5UGF0aD4ge1xuICByZXR1cm4gKGFyZ3M6IFF1ZXJ5UGF0aCkgPT4ge1xuICAgIHJldHVybiBhcmdzLmxlbmd0aCA9PT0gMyA/IGdldEluZGV4KC4uLmFyZ3MpIDogZ2V0RW50aXR5KC4uLmFyZ3MpO1xuICB9O1xufVxuXG5mdW5jdGlvbiB0cmFja0xvb2t1cDxEIGV4dGVuZHMgYW55W10sIEZEIGV4dGVuZHMgRD4oXG4gIGxvb2t1cDogKC4uLmFyZ3M6IEZEKSA9PiBhbnksXG4gIGRlcGVuZGVuY2llczogRGVwPEQ+W10sXG4pIHtcbiAgcmV0dXJuICgoLi4uYXJnczogUGFyYW1ldGVyczx0eXBlb2YgbG9va3VwPikgPT4ge1xuICAgIGNvbnN0IGVudGl0eSA9IGxvb2t1cCguLi5hcmdzKTtcbiAgICBkZXBlbmRlbmNpZXMucHVzaCh7IHBhdGg6IGFyZ3MsIGVudGl0eSB9KTtcbiAgICByZXR1cm4gZW50aXR5O1xuICB9KSBhcyBhbnk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVHZXRFbnRpdHkoXG4gIGVudGl0aWVzOlxuICAgIHwgRW50aXR5VGFibGVcbiAgICB8IHtcbiAgICAgICAgZ2V0SW4oazogc3RyaW5nW10pOiB7IHRvSlMoKTogYW55IH0gfCB1bmRlZmluZWQ7XG4gICAgICB9LFxuKSB7XG4gIGNvbnN0IGVudGl0eUlzSW1tdXRhYmxlID0gaXNJbW11dGFibGUoZW50aXRpZXMpO1xuICBpZiAoZW50aXR5SXNJbW11dGFibGUpIHtcbiAgICByZXR1cm4gKC4uLmFyZ3MpID0+IGVudGl0aWVzLmdldEluKGFyZ3MpPy50b0pTPy4oKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gKGVudGl0eUtleTogc3RyaW5nIHwgc3ltYm9sLCBwaz86IHN0cmluZyk6IGFueSA9PlxuICAgICAgcGsgPyBlbnRpdGllc1tlbnRpdHlLZXldPy5bcGtdIDogZW50aXRpZXNbZW50aXR5S2V5XTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlR2V0SW5kZXgoXG4gIGluZGV4ZXM6XG4gICAgfCBOb3JtYWxpemVkSW5kZXhcbiAgICB8IHtcbiAgICAgICAgZ2V0SW4oazogc3RyaW5nW10pOiBhbnk7XG4gICAgICB9LFxuKSB7XG4gIGNvbnN0IGVudGl0eUlzSW1tdXRhYmxlID0gaXNJbW11dGFibGUoaW5kZXhlcyk7XG4gIGlmIChlbnRpdHlJc0ltbXV0YWJsZSkge1xuICAgIHJldHVybiAoXG4gICAgICBrZXk6IHN0cmluZyxcbiAgICAgIGZpZWxkOiBzdHJpbmcsXG4gICAgICB2YWx1ZTogc3RyaW5nLFxuICAgICk6IHsgcmVhZG9ubHkgW2luZGV4S2V5OiBzdHJpbmddOiBzdHJpbmcgfCB1bmRlZmluZWQgfSA9PlxuICAgICAgaW5kZXhlcy5nZXRJbihba2V5LCBmaWVsZF0pPy50b0pTPy4oKTtcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gKFxuICAgICAga2V5OiBzdHJpbmcsXG4gICAgICBmaWVsZDogc3RyaW5nLFxuICAgICAgdmFsdWU6IHN0cmluZyxcbiAgICApOiB7IHJlYWRvbmx5IFtpbmRleEtleTogc3RyaW5nXTogc3RyaW5nIHwgdW5kZWZpbmVkIH0gPT4ge1xuICAgICAgaWYgKGluZGV4ZXNba2V5XSkge1xuICAgICAgICByZXR1cm4gaW5kZXhlc1trZXldW2ZpZWxkXTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7fTtcbiAgICB9O1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiJBQUFBLE9BQU9BLFdBQVcsTUFBTSxrQkFBa0I7QUFFMUMsT0FBT0MsaUJBQWlCLE1BQThCLHdCQUF3QjtBQUM5RSxPQUFPQyxhQUFhLE1BQU0scUJBQXFCO0FBQy9DLFNBQVNDLFdBQVcsUUFBUSwrQkFBK0I7QUFDM0QsT0FBT0MsVUFBVSxNQUFNLDJCQUEyQjtBQUVsRCxTQUFTQyxXQUFXLFFBQVEsOEJBQThCO0FBTzFEOztBQUVBO0FBQ0EsZUFBZSxNQUFNQyxTQUFTLENBQUM7RUFBQUMsWUFBQTtJQUM3QjtJQUFBLEtBQ1VDLFFBQVEsR0FBZ0IsSUFBSUMsR0FBRyxDQUFDLENBQUM7SUFDM0M7SUFBQSxLQUNVQyxTQUFTLEdBQW1CLElBQUlULGlCQUFpQixDQUFhLENBQUM7SUFDekU7SUFBQSxLQUNVVSxTQUFTLEdBQThDLElBQUlGLEdBQUcsQ0FBQyxDQUFDO0VBQUE7RUFFMUU7RUFDQUcsV0FBV0EsQ0FDVEMsTUFBcUIsRUFDckJDLEtBQWMsRUFDZE4sUUFBYSxFQUNiTyxJQUFvQixHQUFHLEVBQUUsRUFJekI7SUFDQTtJQUNBO0lBQ0E7O0lBRUE7SUFDQSxJQUFJRixNQUFNLEtBQUtHLFNBQVMsRUFBRTtNQUN4QixPQUFPO1FB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