UNPKG

@ngx-toolkit/cache

Version:

Angular cache with Universal support

175 lines 26 kB
import 'reflect-metadata/Reflect'; import { getCacheManager } from './cache.instance'; export const METADATA_KEY_CACHE_DEFAULTS = '_cache_defaults'; export const METADATA_KEY_CACHE_KEYS = '_cache_keys'; export const METADATA_KEY_CACHE_VALUE = '_cache_value'; /** * Allows the configuration of defaults for `CacheResult`, `CachePut`, `CacheRemove`, and `CacheRemoveAll` at the class level. * Without the method level annotations this annotation has no effect. * * @param cacheName */ export function CacheDefaults(cacheName) { return (target) => { Reflect.defineMetadata(METADATA_KEY_CACHE_DEFAULTS, cacheName, target); }; } /** * When a method annotated with `CacheResult` is invoked a cache key will be generated * and *Cache.get(key)* is called before the annotated method actually executes. * If a value is found in the cache it is returned and the annotated method is never actually executed. * If no value is found the annotated method is invoked and the returned value is stored in the cache with the generated key. * * @param params (Optional) {cacheName?: string} */ export function CacheResult(params) { params = getDefaultParams(params); return (target, propertyKey, descriptor) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { const cache = getCache(target, params); const cacheKey = getCacheKey(target, propertyKey, args); // Find cache value let result = cache.get(cacheKey); // Call function & save function if no cache value if (result === undefined) { // Call function & save result result = originalMethod.apply(this, args); cache.put(cacheKey, result); } return result; }; return descriptor; }; } /** * Marks a method argument as part of the cache key. * If no arguments are marked all arguments are used. * The exception is for a method annotated with `CachePut` where the `CacheValue` parameter is never included in the key. */ export function CacheKey() { return (target, propertyKey, parameterIndex) => { const indices = Reflect.getMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, target, propertyKey) || []; indices.push(parameterIndex); Reflect.defineMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, indices, target, propertyKey); }; } /** * When a method annotated with `CachePut` is invoked a cache key will be generated * and *Cache.put(key, value)* will be invoked on the specified cache storing the value marked with `CacheValue`. * * @param params (Optional) {cacheName?: string, afterInvocation: boolean = true} */ export function CachePut(params) { params = getDefaultParams(params); return (target, propertyKey, descriptor) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { const cache = getCache(target, params); const indexValue = Reflect.getMetadata(`${METADATA_KEY_CACHE_VALUE}_${propertyKey.toString()}`, target, propertyKey); const cacheKey = getCacheKey(target, propertyKey, args, indexValue); if (!params.afterInvocation && indexValue && indexValue >= 0 && indexValue < args.length) { cache.put(cacheKey, args[indexValue]); } const result = originalMethod.apply(this, args); if (params.afterInvocation && indexValue && indexValue >= 0 && indexValue < args.length) { cache.put(cacheKey, args[indexValue]); } return result; }; return descriptor; }; } /** * Marks the parameter to be cached for a method annotated with `CachePut`. */ export function CacheValue() { return (target, propertyKey, parameterIndex) => { Reflect.defineMetadata(`${METADATA_KEY_CACHE_VALUE}_${propertyKey.toString()}`, parameterIndex, target, propertyKey); }; } /** * When a method annotated with `CacheRemove` is invoked a cache key will be generated * and *Cache.remove(key)* will be invoked on the specified cache. * The default behavior is to call *Cache.evict(key)* after the annotated method is invoked, * this behavior can be changed by setting *`afterInvocation`* to false in which case *Cache.evict(key)* * will be called before the annotated method is invoked. * * @param params (Optional) {cacheName?: string, afterInvocation: boolean = true} */ export function CacheRemove(params) { params = getDefaultParams(params); return (target, propertyKey, descriptor) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { const cache = getCache(target, params); const cacheKey = getCacheKey(target, propertyKey, args); if (!params.afterInvocation) { cache.evict(cacheKey); } const result = originalMethod.apply(this, args); if (params.afterInvocation) { cache.evict(cacheKey); } return result; }; return descriptor; }; } /** * When a method annotated with `CacheRemoveAll` is invoked all elements in the specified cache will be removed via the *Cache.clear()* method. * The default behavior is to call *Cache.clear()* after the annotated method is invoked, * this behavior can be changed by setting *`afterInvocation`* to false in which case *Cache.clear()* will be called before the annotated method is invoked. * * @param params (Optional) {cacheName?: string, afterInvocation: boolean = true} */ export function CacheRemoveAll(params) { params = getDefaultParams(params); return (target, propertyKey, descriptor) => { const originalMethod = descriptor.value; descriptor.value = function (...args) { const cache = getCache(target, params); if (!params.afterInvocation) { cache.clear(); } const result = originalMethod.apply(this, args); if (params.afterInvocation) { cache.clear(); } return result; }; return descriptor; }; } function getDefaultParams(cacheParams) { return Object.assign({ afterInvocation: true }, cacheParams || {}); } function getCache(target, params) { if (!params.cacheName) { params.cacheName = Reflect.getMetadata(METADATA_KEY_CACHE_DEFAULTS, target.constructor) || ''; } const cache = getCacheManager().getCache(params.cacheName); if (!cache) { throw new Error(`Cache '${params.cacheName}' not found for ${target.constructor.name}`); } return cache; } function getCacheKey(target, propertyKey, args, cacheValueIndex = -1) { if (!args) { args = []; } const indices = Reflect.getMetadata(`${METADATA_KEY_CACHE_KEYS}_${propertyKey.toString()}`, target, propertyKey); if (indices) { args = args.filter((value, index) => indices.indexOf(index) !== -1 && cacheValueIndex !== index); } else if (cacheValueIndex !== -1) { args = args.filter((value, index) => cacheValueIndex !== index); } if (args.length === 0) { throw new Error(`Couldn't generate key without params for '${propertyKey.toString()}' method of ${target.constructor.name}`); } return args.map(a => (JSON.stringify(a) || a.toString())).join('|'); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuZGVjb3JhdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvY2FjaGUvc3JjL2xpYi9jYWNoZS5kZWNvcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTywwQkFBMEIsQ0FBQztBQUNsQyxPQUFPLEVBQUMsZUFBZSxFQUFDLE1BQU0sa0JBQWtCLENBQUM7QUFHakQsTUFBTSxDQUFDLE1BQU0sMkJBQTJCLEdBQUcsaUJBQWlCLENBQUM7QUFDN0QsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsYUFBYSxDQUFDO0FBQ3JELE1BQU0sQ0FBQyxNQUFNLHdCQUF3QixHQUFHLGNBQWMsQ0FBQztBQVV2RDs7Ozs7R0FLRztBQUNILE1BQU0sVUFBVSxhQUFhLENBQUMsU0FBaUI7SUFDN0MsT0FBTyxDQUFDLE1BQWdCLEVBQVEsRUFBRTtRQUNoQyxPQUFPLENBQUMsY0FBYyxDQUFDLDJCQUEyQixFQUFFLFNBQVMsRUFBRSxNQUFNLENBQUMsQ0FBQztJQUN6RSxDQUFDLENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7R0FPRztBQUNILE1BQU0sVUFBVSxXQUFXLENBQUMsTUFBb0I7SUFDOUMsTUFBTSxHQUFHLGdCQUFnQixDQUFjLE1BQU0sQ0FBQyxDQUFDO0lBRS9DLE9BQU8sQ0FBQyxNQUFjLEVBQUUsV0FBNEIsRUFBRSxVQUF3QyxFQUFnQyxFQUFFO1FBQzlILE1BQU0sY0FBYyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFDeEMsVUFBVSxDQUFDLEtBQUssR0FBRyxVQUFTLEdBQUcsSUFBVztZQUN4QyxNQUFNLEtBQUssR0FBVSxRQUFRLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQzlDLE1BQU0sUUFBUSxHQUFXLFdBQVcsQ0FBQyxNQUFNLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxDQUFDO1lBRWhFLG1CQUFtQjtZQUNuQixJQUFJLE1BQU0sR0FBUSxLQUFLLENB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bmltcG9ydCB7Z2V0Q2FjaGVNYW5hZ2VyfSBmcm9tICcuL2NhY2hlLmluc3RhbmNlJztcbmltcG9ydCB7Q2FjaGV9IGZyb20gJy4vY2FjaGUubW9kZWwnO1xuXG5leHBvcnQgY29uc3QgTUVUQURBVEFfS0VZX0NBQ0hFX0RFRkFVTFRTID0gJ19jYWNoZV9kZWZhdWx0cyc7XG5leHBvcnQgY29uc3QgTUVUQURBVEFfS0VZX0NBQ0hFX0tFWVMgPSAnX2NhY2hlX2tleXMnO1xuZXhwb3J0IGNvbnN0IE1FVEFEQVRBX0tFWV9DQUNIRV9WQUxVRSA9ICdfY2FjaGVfdmFsdWUnO1xuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlUGFyYW1zIHtcbiAgY2FjaGVOYW1lPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlUGFyYW1zSW52b2MgZXh0ZW5kcyBDYWNoZVBhcmFtcyB7XG4gIGFmdGVySW52b2NhdGlvbj86IGJvb2xlYW47XG59XG5cbi8qKlxuICogQWxsb3dzIHRoZSBjb25maWd1cmF0aW9uIG9mIGRlZmF1bHRzIGZvciBgQ2FjaGVSZXN1bHRgLCBgQ2FjaGVQdXRgLCBgQ2FjaGVSZW1vdmVgLCBhbmQgYENhY2hlUmVtb3ZlQWxsYCBhdCB0aGUgY2xhc3MgbGV2ZWwuXG4gKiBXaXRob3V0IHRoZSBtZXRob2QgbGV2ZWwgYW5ub3RhdGlvbnMgdGhpcyBhbm5vdGF0aW9uIGhhcyBubyBlZmZlY3QuXG4gKlxuICogQHBhcmFtIGNhY2hlTmFtZVxuICovXG5leHBvcnQgZnVuY3Rpb24gQ2FjaGVEZWZhdWx0cyhjYWNoZU5hbWU6IHN0cmluZyk6IENsYXNzRGVjb3JhdG9yIHtcbiAgcmV0dXJuICh0YXJnZXQ6IEZ1bmN0aW9uKTogdm9pZCA9PiB7XG4gICAgUmVmbGVjdC5kZWZpbmVNZXRhZGF0YShNRVRBREFUQV9LRVlfQ0FDSEVfREVGQVVMVFMsIGNhY2hlTmFtZSwgdGFyZ2V0KTtcbiAgfTtcbn1cblxuLyoqXG4gKiBXaGVuIGEgbWV0aG9kIGFubm90YXRlZCB3aXRoIGBDYWNoZVJlc3VsdGAgaXMgaW52b2tlZCBhIGNhY2hlIGtleSB3aWxsIGJlIGdlbmVyYXRlZFxuICogYW5kICpDYWNoZS5nZXQoa2V5KSogaXMgY2FsbGVkIGJlZm9yZSB0aGUgYW5ub3RhdGVkIG1ldGhvZCBhY3R1YWxseSBleGVjdXRlcy5cbiAqIElmIGEgdmFsdWUgaXMgZm91bmQgaW4gdGhlIGNhY2hlIGl0IGlzIHJldHVybmVkIGFuZCB0aGUgYW5ub3RhdGVkIG1ldGhvZCBpcyBuZXZlciBhY3R1YWxseSBleGVjdXRlZC5cbiAqIElmIG5vIHZhbHVlIGlzIGZvdW5kIHRoZSBhbm5vdGF0ZWQgbWV0aG9kIGlzIGludm9rZWQgYW5kIHRoZSByZXR1cm5lZCB2YWx1ZSBpcyBzdG9yZWQgaW4gdGhlIGNhY2hlIHdpdGggdGhlIGdlbmVyYXRlZCBrZXkuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAoT3B0aW9uYWwpIHtjYWNoZU5hbWU/OiBzdHJpbmd9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDYWNoZVJlc3VsdChwYXJhbXM/OiBDYWNoZVBhcmFtcyk6IE1ldGhvZERlY29yYXRvciB7XG4gIHBhcmFtcyA9IGdldERlZmF1bHRQYXJhbXM8Q2FjaGVQYXJhbXM+KHBhcmFtcyk7XG5cbiAgcmV0dXJuICh0YXJnZXQ6IE9iamVjdCwgcHJvcGVydHlLZXk6IHN0cmluZyB8IHN5bWJvbCwgZGVzY3JpcHRvcjogVHlwZWRQcm9wZXJ0eURlc2NyaXB0b3I8YW55Pik6IFR5cGVkUHJvcGVydHlEZXNjcmlwdG9yPGFueT4gPT4ge1xuICAgIGNvbnN0IG9yaWdpbmFsTWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gZnVuY3Rpb24oLi4uYXJnczogYW55W10pIHtcbiAgICAgIGNvbnN0IGNhY2hlOiBDYWNoZSA9IGdldENhY2hlKHRhcmdldCwgcGFyYW1zKTtcbiAgICAgIGNvbnN0IGNhY2hlS2V5OiBzdHJpbmcgPSBnZXRDYWNoZUtleSh0YXJnZXQsIHByb3BlcnR5S2V5LCBhcmdzKTtcblxuICAgICAgLy8gRmluZCBjYWNoZSB2YWx1ZVxuICAgICAgbGV0IHJlc3VsdDogYW55ID0gY2FjaGUuZ2V0KGNhY2hlS2V5KTtcblxuICAgICAgLy8gQ2FsbCBmdW5jdGlvbiAmIHNhdmUgZnVuY3Rpb24gaWYgbm8gY2FjaGUgdmFsdWVcbiAgICAgIGlmIChyZXN1bHQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAvLyBDYWxsIGZ1bmN0aW9uICYgc2F2ZSByZXN1bHRcbiAgICAgICAgcmVzdWx0ID0gb3JpZ2luYWxNZXRob2QuYXBwbHkodGhpcywgYXJncyk7XG4gICAgICAgIGNhY2hlLnB1dChjYWNoZUtleSwgcmVzdWx0KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG4vKipcbiAqIE1hcmtzIGEgbWV0aG9kIGFyZ3VtZW50IGFzIHBhcnQgb2YgdGhlIGNhY2hlIGtleS5cbiAqIElmIG5vIGFyZ3VtZW50cyBhcmUgbWFya2VkIGFsbCBhcmd1bWVudHMgYXJlIHVzZWQuXG4gKiBUaGUgZXhjZXB0aW9uIGlzIGZvciBhIG1ldGhvZCBhbm5vdGF0ZWQgd2l0aCBgQ2FjaGVQdXRgIHdoZXJlIHRoZSBgQ2FjaGVWYWx1ZWAgcGFyYW1ldGVyIGlzIG5ldmVyIGluY2x1ZGVkIGluIHRoZSBrZXkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDYWNoZUtleSgpOiBQYXJhbWV0ZXJEZWNvcmF0b3Ige1xuICByZXR1cm4gKHRhcmdldDogT2JqZWN0LCBwcm9wZXJ0eUtleTogc3RyaW5nIHwgc3ltYm9sLCBwYXJhbWV0ZXJJbmRleDogbnVtYmVyKSA9PiB7XG4gICAgY29uc3QgaW5kaWNlcyA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoYCR7TUVUQURBVEFfS0VZX0NBQ0hFX0tFWVN9XyR7cHJvcGVydHlLZXkudG9TdHJpbmcoKX1gLCB0YXJnZXQsIHByb3BlcnR5S2V5KSB8fCBbXTtcbiAgICBpbmRpY2VzLnB1c2gocGFyYW1ldGVySW5kZXgpO1xuICAgIFJlZmxlY3QuZGVmaW5lTWV0YWRhdGEoYCR7TUVUQURBVEFfS0VZX0NBQ0hFX0tFWVN9XyR7cHJvcGVydHlLZXkudG9TdHJpbmcoKX1gLCBpbmRpY2VzLCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgfTtcbn1cblxuLyoqXG4gKiBXaGVuIGEgbWV0aG9kIGFubm90YXRlZCB3aXRoIGBDYWNoZVB1dGAgaXMgaW52b2tlZCBhIGNhY2hlIGtleSB3aWxsIGJlIGdlbmVyYXRlZFxuICogYW5kICpDYWNoZS5wdXQoa2V5LCB2YWx1ZSkqIHdpbGwgYmUgaW52b2tlZCBvbiB0aGUgc3BlY2lmaWVkIGNhY2hlIHN0b3JpbmcgdGhlIHZhbHVlIG1hcmtlZCB3aXRoIGBDYWNoZVZhbHVlYC5cbiAqXG4gKiBAcGFyYW0gcGFyYW1zIChPcHRpb25hbCkge2NhY2hlTmFtZT86IHN0cmluZywgYWZ0ZXJJbnZvY2F0aW9uOiBib29sZWFuID0gdHJ1ZX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIENhY2hlUHV0KHBhcmFtcz86IENhY2hlUGFyYW1zSW52b2MpOiBNZXRob2REZWNvcmF0b3Ige1xuICBwYXJhbXMgPSBnZXREZWZhdWx0UGFyYW1zPENhY2hlUGFyYW1zSW52b2M+KHBhcmFtcyk7XG5cbiAgcmV0dXJuICh0YXJnZXQ6IE9iamVjdCwgcHJvcGVydHlLZXk6IHN0cmluZyB8IHN5bWJvbCwgZGVzY3JpcHRvcjogVHlwZWRQcm9wZXJ0eURlc2NyaXB0b3I8YW55Pik6IFR5cGVkUHJvcGVydHlEZXNjcmlwdG9yPGFueT4gPT4ge1xuICAgIGNvbnN0IG9yaWdpbmFsTWV0aG9kID0gZGVzY3JpcHRvci52YWx1ZTtcbiAgICBkZXNjcmlwdG9yLnZhbHVlID0gZnVuY3Rpb24oLi4uYXJnczogYW55W10pIHtcbiAgICAgIGNvbnN0IGNhY2hlOiBDYWNoZSA9IGdldENhY2hlKHRhcmdldCwgcGFyYW1zKTtcbiAgICAgIGNvbnN0IGluZGV4VmFsdWU6IG51bWJlciA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoYCR7TUVUQURBVEFfS0VZX0NBQ0hFX1ZBTFVFfV8ke3Byb3BlcnR5S2V5LnRvU3RyaW5nKCl9YCwgdGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4gICAgICBjb25zdCBjYWNoZUtleTogc3RyaW5nID0gZ2V0Q2FjaGVLZXkodGFyZ2V0LCBwcm9wZXJ0eUtleSwgYXJncywgaW5kZXhWYWx1ZSk7XG5cbiAgICAgIGlmICghcGFyYW1zLmFmdGVySW52b2NhdGlvbiAmJiBpbmRleFZhbHVlICYmIGluZGV4VmFsdWUgPj0gMCAmJiBpbmRleFZhbHVlIDwgYXJncy5sZW5ndGgpIHtcbiAgICAgICAgY2FjaGUucHV0KGNhY2hlS2V5LCBhcmdzW2luZGV4VmFsdWVdKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0ID0gb3JpZ2luYWxNZXRob2QuYXBwbHkodGhpcywgYXJncyk7XG5cbiAgICAgIGlmIChwYXJhbXMuYWZ0ZXJJbnZvY2F0aW9uICYmIGluZGV4VmFsdWUgJiYgaW5kZXhWYWx1ZSA+PSAwICYmIGluZGV4VmFsdWUgPCBhcmdzLmxlbmd0aCkge1xuICAgICAgICBjYWNoZS5wdXQoY2FjaGVLZXksIGFyZ3NbaW5kZXhWYWx1ZV0pO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gIH07XG59XG5cbi8qKlxuICogTWFya3MgdGhlIHBhcmFtZXRlciB0byBiZSBjYWNoZWQgZm9yIGEgbWV0aG9kIGFubm90YXRlZCB3aXRoIGBDYWNoZVB1dGAuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDYWNoZVZhbHVlKCk6IFBhcmFtZXRlckRlY29yYXRvciB7XG4gIHJldHVybiAodGFyZ2V0OiBPYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcgfCBzeW1ib2wsIHBhcmFtZXRlckluZGV4OiBudW1iZXIpID0+IHtcbiAgICBSZWZsZWN0LmRlZmluZU1ldGFkYXRhKGAke01FVEFEQVRBX0tFWV9DQUNIRV9WQUxVRX1fJHtwcm9wZXJ0eUtleS50b1N0cmluZygpfWAsIHBhcmFtZXRlckluZGV4LCB0YXJnZXQsIHByb3BlcnR5S2V5KTtcbiAgfTtcbn1cblxuLyoqXG4gKiBXaGVuIGEgbWV0aG9kIGFubm90YXRlZCB3aXRoIGBDYWNoZVJlbW92ZWAgaXMgaW52b2tlZCBhIGNhY2hlIGtleSB3aWxsIGJlIGdlbmVyYXRlZFxuICogYW5kICpDYWNoZS5yZW1vdmUoa2V5KSogd2lsbCBiZSBpbnZva2VkIG9uIHRoZSBzcGVjaWZpZWQgY2FjaGUuXG4gKiBUaGUgZGVmYXVsdCBiZWhhdmlvciBpcyB0byBjYWxsICpDYWNoZS5ldmljdChrZXkpKiBhZnRlciB0aGUgYW5ub3RhdGVkIG1ldGhvZCBpcyBpbnZva2VkLFxuICogdGhpcyBiZWhhdmlvciBjYW4gYmUgY2hhbmdlZCBieSBzZXR0aW5nICpgYWZ0ZXJJbnZvY2F0aW9uYCogdG8gZmFsc2UgaW4gd2hpY2ggY2FzZSAqQ2FjaGUuZXZpY3Qoa2V5KSpcbiAqIHdpbGwgYmUgY2FsbGVkIGJlZm9yZSB0aGUgYW5ub3RhdGVkIG1ldGhvZCBpcyBpbnZva2VkLlxuICpcbiAqIEBwYXJhbSBwYXJhbXMgKE9wdGlvbmFsKSB7Y2FjaGVOYW1lPzogc3RyaW5nLCBhZnRlckludm9jYXRpb246IGJvb2xlYW4gPSB0cnVlfVxuICovXG5leHBvcnQgZnVuY3Rpb24gQ2FjaGVSZW1vdmUocGFyYW1zPzogQ2FjaGVQYXJhbXNJbnZvYyk6IE1ldGhvZERlY29yYXRvciB7XG4gIHBhcmFtcyA9IGdldERlZmF1bHRQYXJhbXM8Q2FjaGVQYXJhbXNJbnZvYz4ocGFyYW1zKTtcblxuICByZXR1cm4gKHRhcmdldDogT2JqZWN0LCBwcm9wZXJ0eUtleTogc3RyaW5nIHwgc3ltYm9sLCBkZXNjcmlwdG9yOiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+KTogVHlwZWRQcm9wZXJ0eURlc2NyaXB0b3I8YW55PiA9PiB7XG4gICAgY29uc3Qgb3JpZ2luYWxNZXRob2QgPSBkZXNjcmlwdG9yLnZhbHVlO1xuICAgIGRlc2NyaXB0b3IudmFsdWUgPSBmdW5jdGlvbiguLi5hcmdzOiBhbnlbXSkge1xuICAgICAgY29uc3QgY2FjaGU6IENhY2hlID0gZ2V0Q2FjaGUodGFyZ2V0LCBwYXJhbXMpO1xuICAgICAgY29uc3QgY2FjaGVLZXk6IHN0cmluZyA9IGdldENhY2hlS2V5KHRhcmdldCwgcHJvcGVydHlLZXksIGFyZ3MpO1xuXG4gICAgICBpZiAoIXBhcmFtcy5hZnRlckludm9jYXRpb24pIHtcbiAgICAgICAgY2FjaGUuZXZpY3QoY2FjaGVLZXkpO1xuICAgICAgfVxuXG4gICAgICBjb25zdCByZXN1bHQ6IGFueSA9IG9yaWdpbmFsTWV0aG9kLmFwcGx5KHRoaXMsIGFyZ3MpO1xuXG5cbiAgICAgIGlmIChwYXJhbXMuYWZ0ZXJJbnZvY2F0aW9uKSB7XG4gICAgICAgIGNhY2hlLmV2aWN0KGNhY2hlS2V5KTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG4vKipcbiAqIFdoZW4gYSBtZXRob2QgYW5ub3RhdGVkIHdpdGggYENhY2hlUmVtb3ZlQWxsYCBpcyBpbnZva2VkIGFsbCBlbGVtZW50cyBpbiB0aGUgc3BlY2lmaWVkIGNhY2hlIHdpbGwgYmUgcmVtb3ZlZCB2aWEgdGhlICpDYWNoZS5jbGVhcigpKiBtZXRob2QuXG4gKiBUaGUgZGVmYXVsdCBiZWhhdmlvciBpcyB0byBjYWxsICpDYWNoZS5jbGVhcigpKiBhZnRlciB0aGUgYW5ub3RhdGVkIG1ldGhvZCBpcyBpbnZva2VkLFxuICogdGhpcyBiZWhhdmlvciBjYW4gYmUgY2hhbmdlZCBieSBzZXR0aW5nICpgYWZ0ZXJJbnZvY2F0aW9uYCogdG8gZmFsc2UgaW4gd2hpY2ggY2FzZSAqQ2FjaGUuY2xlYXIoKSogd2lsbCBiZSBjYWxsZWQgYmVmb3JlIHRoZSBhbm5vdGF0ZWQgbWV0aG9kIGlzIGludm9rZWQuXG4gKlxuICogQHBhcmFtIHBhcmFtcyAoT3B0aW9uYWwpIHtjYWNoZU5hbWU/OiBzdHJpbmcsIGFmdGVySW52b2NhdGlvbjogYm9vbGVhbiA9IHRydWV9XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBDYWNoZVJlbW92ZUFsbChwYXJhbXM/OiBDYWNoZVBhcmFtc0ludm9jKTogTWV0aG9kRGVjb3JhdG9yIHtcbiAgcGFyYW1zID0gZ2V0RGVmYXVsdFBhcmFtczxDYWNoZVBhcmFtc0ludm9jPihwYXJhbXMpO1xuXG4gIHJldHVybiAodGFyZ2V0OiBPYmplY3QsIHByb3BlcnR5S2V5OiBzdHJpbmcgfCBzeW1ib2wsIGRlc2NyaXB0b3I6IFR5cGVkUHJvcGVydHlEZXNjcmlwdG9yPGFueT4pOiBUeXBlZFByb3BlcnR5RGVzY3JpcHRvcjxhbnk+ID0+IHtcbiAgICBjb25zdCBvcmlnaW5hbE1ldGhvZCA9IGRlc2NyaXB0b3IudmFsdWU7XG4gICAgZGVzY3JpcHRvci52YWx1ZSA9IGZ1bmN0aW9uKC4uLmFyZ3M6IGFueVtdKSB7XG4gICAgICBjb25zdCBjYWNoZTogQ2FjaGUgPSBnZXRDYWNoZSh0YXJnZXQsIHBhcmFtcyk7XG4gICAgICBpZiAoIXBhcmFtcy5hZnRlckludm9jYXRpb24pIHtcbiAgICAgICAgY2FjaGUuY2xlYXIoKTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgcmVzdWx0OiBhbnkgPSBvcmlnaW5hbE1ldGhvZC5hcHBseSh0aGlzLCBhcmdzKTtcblxuICAgICAgaWYgKHBhcmFtcy5hZnRlckludm9jYXRpb24pIHtcbiAgICAgICAgY2FjaGUuY2xlYXIoKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9O1xuICAgIHJldHVybiBkZXNjcmlwdG9yO1xuICB9O1xufVxuXG5mdW5jdGlvbiBnZXREZWZhdWx0UGFyYW1zPFQ+KGNhY2hlUGFyYW1zOiBDYWNoZVBhcmFtcyk6IHsgYWZ0ZXJJbnZvY2F0aW9uOiBib29sZWFuIH0gJiBDYWNoZVBhcmFtcyB7XG4gIHJldHVybiBPYmplY3QuYXNzaWduKHtcbiAgICBhZnRlckludm9jYXRpb246IHRydWVcbiAgfSwgY2FjaGVQYXJhbXMgfHwge30pO1xufVxuXG5mdW5jdGlvbiBnZXRDYWNoZSh0YXJnZXQ6IE9iamVjdCwgcGFyYW1zOiBDYWNoZVBhcmFtcyk6IENhY2hlIHtcbiAgaWYgKCFwYXJhbXMuY2FjaGVOYW1lKSB7XG4gICAgcGFyYW1zLmNhY2hlTmFtZSA9IFJlZmxlY3QuZ2V0TWV0YWRhdGEoTUVUQURBVEFfS0VZX0NBQ0hFX0RFRkFVTFRTLCB0YXJnZXQuY29uc3RydWN0b3IpIHx8ICcnO1xuICB9XG5cbiAgY29uc3QgY2FjaGU6IENhY2hlID0gZ2V0Q2FjaGVNYW5hZ2VyKCkuZ2V0Q2FjaGUocGFyYW1zLmNhY2hlTmFtZSk7XG4gIGlmICghY2FjaGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYENhY2hlICcke3BhcmFtcy5jYWNoZU5hbWV9JyBub3QgZm91bmQgZm9yICR7dGFyZ2V0LmNvbnN0cnVjdG9yLm5hbWV9YCk7XG4gIH1cbiAgcmV0dXJuIGNhY2hlO1xufVxuXG5mdW5jdGlvbiBnZXRDYWNoZUtleSh0YXJnZXQ6IE9iamVjdCwgcHJvcGVydHlLZXk6IHN0cmluZyB8IHN5bWJvbCwgYXJnczogYW55W10sIGNhY2hlVmFsdWVJbmRleCA9IC0xKTogc3RyaW5nIHtcbiAgaWYgKCFhcmdzKSB7XG4gICAgYXJncyA9IFtdO1xuICB9XG5cbiAgY29uc3QgaW5kaWNlczogbnVtYmVyW10gPSBSZWZsZWN0LmdldE1ldGFkYXRhKGAke01FVEFEQVRBX0tFWV9DQUNIRV9LRVlTfV8ke3Byb3BlcnR5S2V5LnRvU3RyaW5nKCl9YCwgdGFyZ2V0LCBwcm9wZXJ0eUtleSk7XG4gIGlmIChpbmRpY2VzKSB7XG4gICAgYXJncyA9IGFyZ3MuZmlsdGVyKCh2YWx1ZTogYW55LCBpbmRleDogbnVtYmVyKSA9PiBpbmRpY2VzLmluZGV4T2YoaW5kZXgpICE9PSAtMSAmJiBjYWNoZVZhbHVlSW5kZXggIT09IGluZGV4KTtcbiAgfSBlbHNlIGlmIChjYWNoZVZhbHVlSW5kZXggIT09IC0xKSB7XG4gICAgYXJncyA9IGFyZ3MuZmlsdGVyKCh2YWx1ZTogYW55LCBpbmRleDogbnVtYmVyKSA9PiBjYWNoZVZhbHVlSW5kZXggIT09IGluZGV4KTtcbiAgfVxuXG4gIGlmIChhcmdzLmxlbmd0aCA9PT0gMCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgQ291bGRuJ3QgZ2VuZXJhdGUga2V5IHdpdGhvdXQgcGFyYW1zIGZvciAnJHtwcm9wZXJ0eUtleS50b1N0cmluZygpfScgbWV0aG9kIG9mICR7dGFyZ2V0LmNvbnN0cnVjdG9yLm5hbWV9YCk7XG4gIH1cblxuICByZXR1cm4gYXJncy5tYXAoYSA9PiAoSlNPTi5zdHJpbmdpZnkoYSkgfHwgYS50b1N0cmluZygpKSkuam9pbignfCcpO1xufVxuIl19