UNPKG

@data-client/normalizr

Version:

Normalizes and denormalizes JSON according to schema for Redux and Flux applications

132 lines (127 loc) 20.2 kB
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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