ngx-store
Version:
Angular decorators to automagically keep variables in HTML5 LocalStorage, SessionStorage, cookies; injectable services for managing and listening to data changes and a bit more.
203 lines • 31.7 kB
JavaScript
import { Config, debug } from '../config/config';
const isEqual = require('lodash.isequal');
export class Cache {
static getCacheFor(cacheCandidate) {
let cacheItem = Cache.get(cacheCandidate.key);
if (!cacheItem) {
cacheItem = new CacheItem(cacheCandidate);
debug.log(`Created new CacheItem for ${cacheCandidate.name} for ${cacheItem.utilities[0].utility.getStorageName()}`);
Cache.set(cacheItem);
return cacheItem;
}
debug.log(`Loaded prior CacheItem of ${cacheItem.name}
for ${cacheCandidate.utilities[0].utility.getStorageName()}`);
cacheItem.addTargets(cacheCandidate.targets);
cacheItem.addServices(cacheCandidate.services);
cacheItem.addUtilities(cacheCandidate.utilities);
Cache.set(cacheItem);
return cacheItem;
}
static remove(cacheItem) {
return Cache.items.delete(cacheItem.key);
}
static get(key) {
return Cache.items.get(key);
}
static set(cacheItem) {
if (!Cache.get(cacheItem.key)) {
debug.log('CacheItem for ' + cacheItem.key, cacheItem);
}
Cache.items.set(cacheItem.key, cacheItem);
}
}
Cache.items = new Map();
// tslint:disable:only-arrow-functions
export class CacheItem {
constructor(cacheItem) {
this.name = '';
this.targets = [];
this.services = [];
this.utilities = [];
this.currentTarget = {};
this.proxy = null;
this._key = '';
this.initializedTargets = new Set();
this._key = cacheItem.key;
this.name = cacheItem.name;
this.addTargets(cacheItem.targets);
this.addServices(cacheItem.services);
this.addUtilities(cacheItem.utilities);
}
get key() {
return this._key;
}
saveValue(value, config = {}) {
debug.groupCollapsed('CacheItem#saveValue for ' + this.key + ' in ' + this.currentTarget.constructor.name);
debug.log('new value: ', value);
// if (value === false && this.readValue() === true) debugger;
debug.log('previous value: ', this.readValue());
debug.log('targets.length: ', this.targets.length);
debug.log('currentTarget:', this.currentTarget);
debug.groupEnd();
// prevent overwriting value by initializators
if (!this.initializedTargets.has(this.currentTarget)) {
this.initializedTargets.add(this.currentTarget);
let readValue = this.readValue();
if (config.migrateKey) {
this.migrate(config, this.utilities[0].utility);
readValue = this.readValue();
}
const savedValue = (readValue !== null && readValue !== undefined) ? readValue : value;
let proxy = this.getProxy(savedValue, config);
proxy = (proxy !== null) ? proxy : value;
debug.log('initial value for ' + this.key + ' in ' + this.currentTarget.constructor.name, proxy);
this.propagateChange(savedValue);
return proxy;
}
this.propagateChange(value);
return this.getProxy(value, config);
}
getProxy(value, config = {}) {
if (value === undefined && this.proxy) {
return this.proxy;
} // return cached proxy if value hasn't changed
value = (value === undefined) ? this.readValue() : value;
if (typeof value !== 'object' || value === null) {
this.proxy = value;
return value;
}
if ((!Config.mutateObjects && !config.mutate) || config.mutate === false) {
return value;
}
const _self = this; // alias to use in standard function expressions
const prototype = Object.assign(new value.constructor(), value.__proto__);
prototype.save = function () {
_self.saveValue(value, config);
};
// TODO set prototype for Array.prototype or something
if (Array.isArray(value)) { // handle methods that could change value of array
const methodsToOverwrite = [
'pop', 'push', 'reverse', 'shift', 'unshift', 'splice',
'filter', 'forEach', 'map', 'fill', 'sort', 'copyWithin',
];
for (const method of methodsToOverwrite) {
prototype[method] = function () {
const readValue = _self.readValue();
// @ts-ignore
const result = Array.prototype[method].apply(readValue, arguments);
debug.log('Saving value for ' + _self.key + ' by method '
+ prototype.constructor.name + '.' + method);
_self.saveValue(readValue, config);
return result;
};
}
}
Object.setPrototypeOf(value, prototype);
this.proxy = value;
return value;
}
readValue(config = {}) {
const entry = this.utilities[0];
const value = entry ? entry.utility.get(this.key, entry.config) : null;
return (typeof value !== 'object') ? value : JSON.parse(JSON.stringify(this.getProxy(value, entry.config)));
}
addTargets(targets) {
targets.forEach(target => {
if (this.targets.indexOf(target) === -1) {
if (typeof target === 'object') { // handle Angular Component destruction
const originalFunction = target.ngOnDestroy;
const _self = this;
target.ngOnDestroy = function () {
if (typeof originalFunction === 'function') {
originalFunction.apply(this, arguments);
}
target.ngOnDestroy = originalFunction || function () { };
_self.initializedTargets.delete(target);
_self.targets = _self.targets.filter(t => t !== target);
if (!_self.targets.length) {
_self.services.forEach(service => {
service.keys = service.keys.filter(key => key !== _self._key);
});
_self.resetProxy();
Cache.remove(_self);
}
debug.groupCollapsed(`${_self.key} OnDestroy handler:`);
debug.log('removed target:', target.constructor.name);
debug.log('remaining targets:', _self.targets);
debug.log('cacheItem:', Cache.get(_self.key));
debug.groupEnd();
};
this.targets.push(target);
}
}
});
}
addServices(services) {
services.forEach(service => {
if (this.services.indexOf(service) === -1) {
service.keys.push(this._key);
this.services.push(service);
}
});
}
addUtilities(utilityEntries) {
utilityEntries.forEach(entry => {
if (this.utilities.findIndex(e => e.utility === entry.utility) === -1) {
this.utilities.push(entry);
entry.utility.set(this.key, this.readValue());
}
});
}
resetProxy() {
this.proxy = null;
}
propagateChange(value, source) {
if (isEqual(value, this.readValue())) {
return;
}
this.utilities.forEach(entry => {
const utility = entry.utility;
// updating service which the change came from would affect in a cycle
if (utility === source) {
return;
}
debug.log(`propagating change on ${this.key} to:`, utility);
utility.set(this._key, value, entry.config);
});
}
migrate(config, utility) {
const prefix = (config.prefix || Config.prefix) || '';
const keyExists = (key) => key in utility.getStorage();
const migrateKey = keyExists(prefix + config.migrateKey)
? prefix + config.migrateKey
: config.migrateKey;
if (!keyExists(migrateKey)) {
return;
}
debug.log('Migrating', migrateKey, 'to', config.key, 'in', utility.getStorageName());
const value = utility.get(migrateKey, Object.assign(Object.assign({}, config), { prefix: '' }));
utility.set(this._key, value);
utility.remove(migrateKey, { prefix: '' });
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FjaGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtc3RvcmUvc3JjL2xpYi9kZWNvcmF0b3IvY2FjaGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLE1BQU0sRUFBRSxLQUFLLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQU1qRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztBQUUxQyxNQUFNLE9BQU8sS0FBSztJQUdULE1BQU0sQ0FBQyxXQUFXLENBQUMsY0FBa0M7UUFDMUQsSUFBSSxTQUFTLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDOUMsSUFBSSxDQUFDLFNBQVMsRUFBRTtZQUNkLFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUMxQyxLQUFLLENBQUMsR0FBRyxDQUFDLDZCQUE2QixjQUFjLENBQUMsSUFBSSxRQUFRLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNySCxLQUFLLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ3JCLE9BQU8sU0FBUyxDQUFDO1NBQ2xCO1FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsU0FBUyxDQUFDLElBQUk7V0FDOUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQy9ELFNBQVMsQ0FBQyxVQUFVLENBQUMsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQzdDLFNBQVMsQ0FBQyxXQUFXLENBQUMsY0FBYyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQy9DLFNBQVMsQ0FBQyxZQUFZLENBQUMsY0FBYyxDQUFDLFNBQVMsQ0FBQyxDQUFD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QU0sQ0FBQyxVQUFXO1lBQzdCLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLEVBQUU7WUFDMUIsT0FBTztTQUNSO1FBQ0QsS0FBSyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQztRQUNyRixNQUFNLEtBQUssR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLFVBQVUsa0NBQU0sTUFBTSxLQUFFLE1BQU0sRUFBRSxFQUFFLElBQUUsQ0FBQztRQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDOUIsT0FBTyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsRUFBQyxNQUFNLEVBQUUsRUFBRSxFQUFDLENBQUMsQ0FBQztJQUMzQyxDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb25maWcsIGRlYnVnIH0gZnJvbSAnLi4vY29uZmlnL2NvbmZpZyc7XG5pbXBvcnQgeyBDYWNoZUl0ZW1JbnRlcmZhY2UsIFV0aWxpdHlFbnRyeSB9IGZyb20gJy4vY2FjaGUuaW50ZXJmYWNlJztcbmltcG9ydCB7IFdlYlN0b3JhZ2VTZXJ2aWNlSW50ZXJmYWNlIH0gZnJvbSAnLi4vc2VydmljZS93ZWJzdG9yYWdlLmludGVyZmFjZSc7XG5pbXBvcnQgeyBEZWNvcmF0b3JDb25maWcgfSBmcm9tICcuLi9uZ3gtc3RvcmUudHlwZXMnO1xuaW1wb3J0IHsgV2ViU3RvcmFnZVV0aWxpdHkgfSBmcm9tICcuLi91dGlsaXR5L3dlYnN0b3JhZ2UudXRpbGl0eSc7XG5cbmNvbnN0IGlzRXF1YWwgPSByZXF1aXJlKCdsb2Rhc2guaXNlcXVhbCcpO1xuXG5leHBvcnQgY2xhc3MgQ2FjaGUge1xuICBwdWJsaWMgc3RhdGljIGl0ZW1zOiBNYXA8c3RyaW5nLCBDYWNoZUl0ZW0+ID0gbmV3IE1hcCgpO1xuXG4gIHB1YmxpYyBzdGF0aWMgZ2V0Q2FjaGVGb3IoY2FjaGVDYW5kaWRhdGU6IENhY2hlSXRlbUludGVyZmFjZSk6IENhY2hlSXRlbSB7XG4gICAgbGV0IGNhY2hlSXRlbSA9IENhY2hlLmdldChjYWNoZUNhbmRpZGF0ZS5rZXkpO1xuICAgIGlmICghY2FjaGVJdGVtKSB7XG4gICAgICBjYWNoZUl0ZW0gPSBuZXcgQ2FjaGVJdGVtKGNhY2hlQ2FuZGlkYXRlKTtcbiAgICAgIGRlYnVnLmxvZyhgQ3JlYXRlZCBuZXcgQ2FjaGVJdGVtIGZvciAke2NhY2hlQ2FuZGlkYXRlLm5hbWV9IGZvciAke2NhY2hlSXRlbS51dGlsaXRpZXNbMF0udXRpbGl0eS5nZXRTdG9yYWdlTmFtZSgpfWApO1xuICAgICAgQ2FjaGUuc2V0KGNhY2hlSXRlbSk7XG4gICAgICByZXR1cm4gY2FjaGVJdGVtO1xuICAgIH1cbiAgICBkZWJ1Zy5sb2coYExvYWRlZCBwcmlvciBDYWNoZUl0ZW0gb2YgJHtjYWNoZUl0ZW0ubmFtZX1cbiAgICAgZm9yICR7Y2FjaGVDYW5kaWRhdGUudXRpbGl0aWVzWzBdLnV0aWxpdHkuZ2V0U3RvcmFnZU5hbWUoKX1gKTtcbiAgICBjYWNoZUl0ZW0uYWRkVGFyZ2V0cyhjYWNoZUNhbmRpZGF0ZS50YXJnZXRzKTtcbiAgICBjYWNoZUl0ZW0uYWRkU2VydmljZXMoY2FjaGVDYW5kaWRhdGUuc2VydmljZXMpO1xuICAgIGNhY2hlSXRlbS5hZGRVdGlsaXRpZXMoY2FjaGVDYW5kaWRhdGUudXRpbGl0aWVzKTtcbiAgICBDYWNoZS5zZXQoY2FjaGVJdGVtKTtcbiAgICByZXR1cm4gY2FjaGVJdGVtO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyByZW1vdmUoY2FjaGVJdGVtOiBDYWNoZUl0ZW0pOiBib29sZWFuIHtcbiAgICByZXR1cm4gQ2FjaGUuaXRlbXMuZGVsZXRlKGNhY2hlSXRlbS5rZXkpO1xuICB9XG5cbiAgcHVibGljIHN0YXRpYyBnZXQoa2V5OiBzdHJpbmcpOiBDYWNoZUl0ZW0ge1xuICAgIHJldHVybiBDYWNoZS5pdGVtcy5nZXQoa2V5KSBhcyBDYWNoZUl0ZW07XG4gIH1cblxuICBwcm90ZWN0ZWQgc3RhdGljIHNldChjYWNoZUl0ZW06IENhY2hlSXRlbSk6IHZvaWQge1xuICAgIGlmICghQ2FjaGUuZ2V0KGNhY2hlSXRlbS5rZXkpKSB7XG4gICAgICBkZWJ1Zy5sb2coJ0NhY2hlSXRlbSBmb3IgJyArIGNhY2hlSXRlbS5rZXksIGNhY2hlSXRlbSk7XG4gICAgfVxuICAgIENhY2hlLml0ZW1zLnNldChjYWNoZUl0ZW0ua2V5LCBjYWNoZUl0ZW0pO1xuICB9XG59XG5cbi8vIHRzbGludDpkaXNhYmxlOm9ubHktYXJyb3ctZnVuY3Rpb25zXG5leHBvcnQgY2xhc3MgQ2FjaGVJdGVtIGltcGxlbWVudHMgQ2FjaGVJdGVtSW50ZXJmYWNlIHtcbiAgcHVibGljIG5hbWU6IHN0cmluZyA9ICcnO1xuICBwdWJsaWMgdGFyZ2V0czogQXJyYXk8b2JqZWN0PiA9IFtdO1xuICBwdWJsaWMgc2VydmljZXM6IEFycmF5PFdlYlN0b3JhZ2VTZXJ2aWNlSW50ZXJmYWNlPiA9IFtdO1xuICBwdWJsaWMgdXRpbGl0aWVzOiBBcnJheTxVdGlsaXR5RW50cnk+ID0gW107XG4gIHB1YmxpYyBjdXJyZW50VGFyZ2V0OiBvYmplY3QgPSB7fTtcbiAgcHJvdGVjdGVkIHByb3h5OiBhbnkgPSBudWxsO1xuICBwcm90ZWN0ZWQgX2tleTogc3RyaW5nID0gJyc7XG4gIHByb3RlY3RlZCBpbml0aWFsaXplZFRhcmdldHM6IFNldDxvYmplY3Q+ID0gbmV3IFNldCgpO1xuXG4gIGNvbnN0cnVjdG9yKGNhY2hlSXRlbTogQ2FjaGVJdGVtSW50ZXJmYWNlKSB7XG4gICAgdGhpcy5fa2V5ID0gY2FjaGVJdGVtLmtleTtcbiAgICB0aGlzLm5hbWUgPSBjYWNoZUl0ZW0ubmFtZTtcbiAgICB0aGlzLmFkZFRhcmdldHMoY2FjaGVJdGVtLnRhcmdldHMpO1xuICAgIHRoaXMuYWRkU2VydmljZXMoY2FjaGVJdGVtLnNlcnZpY2VzKTtcbiAgICB0aGlzLmFkZFV0aWxpdGllcyhjYWNoZUl0ZW0udXRpbGl0aWVzKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXQga2V5KCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIHRoaXMuX2tleTtcbiAgfVxuXG4gIHB1YmxpYyBzYXZlVmFsdWUodmFsdWU6IGFueSwgY29uZmlnOiBEZWNvcmF0b3JDb25maWcgPSB7fSk6IGFueSB7XG4gICAgZGVidWcuZ3JvdXBDb2xsYXBzZWQoJ0NhY2hlSXRlbSNzYXZlVmFsdWUgZm9yICcgKyB0aGlzLmtleSArICcgaW4gJyArIHRoaXMuY3VycmVudFRhcmdldC5jb25zdHJ1Y3Rvci5uYW1lKTtcbiAgICBkZWJ1Zy5sb2coJ25ldyB2YWx1ZTogJywgdmFsdWUpO1xuICAgIC8vIGlmICh2YWx1ZSA9PT0gZmFsc2UgJiYgdGhpcy5yZWFkVmFsdWUoKSA9PT0gdHJ1ZSkgZGVidWdnZXI7XG4gICAgZGVidWcubG9nKCdwcmV2aW91cyB2YWx1ZTogJywgdGhpcy5yZWFkVmFsdWUoKSk7XG4gICAgZGVidWcubG9nKCd0YXJnZXRzLmxlbmd0aDogJywgdGhpcy50YXJnZXRzLmxlbmd0aCk7XG4gICAgZGVidWcubG9nKCdjdXJyZW50VGFyZ2V0OicsIHRoaXMuY3VycmVudFRhcmdldCk7XG4gICAgZGVidWcuZ3JvdXBFbmQoKTtcblxuICAgIC8vIHByZXZlbnQgb3ZlcndyaXRpbmcgdmFsdWUgYnkgaW5pdGlhbGl6YXRvcnNcbiAgICBpZiAoIXRoaXMuaW5pdGlhbGl6ZWRUYXJnZXRzLmhhcyh0aGlzLmN1cnJlbnRUYXJnZXQpKSB7XG4gICAgICB0aGlzLmluaXRpYWxpemVkVGFyZ2V0cy5hZGQodGhpcy5jdXJyZW50VGFyZ2V0KTtcbiAgICAgIGxldCByZWFkVmFsdWUgPSB0aGlzLnJlYWRWYWx1ZSgpO1xuICAgICAgaWYgKGNvbmZpZy5taWdyYXRlS2V5KSB7XG4gICAgICAgIHRoaXMubWlncmF0ZShjb25maWcsIHRoaXMudXRpbGl0aWVzWzBdLnV0aWxpdHkpO1xuICAgICAgICByZWFkVmFsdWUgPSB0aGlzLnJlYWRWYWx1ZSgpO1xuICAgICAgfVxuICAgICAgY29uc3Qgc2F2ZWRWYWx1ZSA9IChyZWFkVmFsdWUgIT09IG51bGwgJiYgcmVhZFZhbHVlICE9PSB1bmRlZmluZWQpID8gcmVhZFZhbHVlIDogdmFsdWU7XG4gICAgICBsZXQgcHJveHkgPSB0aGlzLmdldFByb3h5KHNhdmVkVmFsdWUsIGNvbmZpZyk7XG4gICAgICBwcm94eSA9IChwcm94eSAhPT0gbnVsbCkgPyBwcm94eSA6IHZhbHVlO1xuICAgICAgZGVidWcubG9nKCdpbml0aWFsIHZhbHVlIGZvciAnICsgdGhpcy5rZXkgKyAnIGluICcgKyB0aGlzLmN1cnJlbnRUYXJnZXQuY29uc3RydWN0b3IubmFtZSwgcHJveHkpO1xuICAgICAgdGhpcy5wcm9wYWdhdGVDaGFuZ2Uoc2F2ZWRWYWx1ZSk7XG4gICAgICByZXR1cm4gcHJveHk7XG4gICAgfVxuICAgIHRoaXMucHJvcGFnYXRlQ2hhbmdlKHZhbHVlKTtcbiAgICByZXR1cm4gdGhpcy5nZXRQcm94eSh2YWx1ZSwgY29uZmlnKTtcbiAgfVxuXG4gIHB1YmxpYyBnZXRQcm94eSh2YWx1ZT86IGFueSwgY29uZmlnOiBEZWNvcmF0b3JDb25maWcgPSB7fSk6IGFueSB7XG4gICAgaWYgKHZhbHVlID09PSB1bmRlZmluZWQgJiYgdGhpcy5wcm94eSkge1xuICAgICAgcmV0dXJuIHRoaXMucHJveHk7XG4gICAgfSAvLyByZXR1cm4gY2FjaGVkIHByb3h5IGlmIHZhbHVlIGhhc24ndCBjaGFuZ2VkXG4gICAgdmFsdWUgPSAodmFsdWUgPT09IHVuZGVmaW5lZCkgPyB0aGlzLnJlYWRWYWx1ZSgpIDogdmFsdWU7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSAhPT0gJ29iamVjdCcgfHwgdmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHRoaXMucHJveHkgPSB2YWx1ZTtcbiAgICAgIHJldHVybiB2YWx1ZTtcbiAgICB9XG4gICAgaWYgKCghQ29uZmlnLm11dGF0ZU9iamVjdHMgJiYgIWNvbmZpZy5tdXRhdGUpIHx8IGNvbmZpZy5tdXRhdGUgPT09IGZhbHNlKSB7XG4gICAgICByZXR1cm4gdmFsdWU7XG4gICAgfVxuXG4gICAgY29uc3QgX3NlbGYgPSB0aGlzOyAvLyBhbGlhcyB0byB1c2UgaW4gc3RhbmRhcmQgZnVuY3Rpb24gZXhwcmVzc2lvbnNcbiAgICBjb25zdCBwcm90b3R5cGU6IGFueSA9IE9iamVjdC5hc3NpZ24obmV3IHZhbHVlLmNvbnN0cnVjdG9yKCksIHZhbHVlLl9fcHJvdG9fXyk7XG5cbiAgICBwcm90b3R5cGUuc2F2ZSA9IGZ1bmN0aW9uKCk6IHZvaWQgeyAvLyBhZGQgbWV0aG9kIGZvciB0cmlnZ2VyaW5nIGZvcmNlIHNhdmVcbiAgICAgIF9zZWxmLnNhdmVWYWx1ZSh2YWx1ZSwgY29uZmlnKTtcbiAgICB9O1xuXG4gICAgLy8gVE9ETyBzZXQgcHJvdG90eXBlIGZvciBBcnJheS5wcm90b3R5cGUgb3Igc29tZXRoaW5nXG4gICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7IC8vIGhhbmRsZSBtZXRob2RzIHRoYXQgY291bGQgY2hhbmdlIHZhbHVlIG9mIGFycmF5XG4gICAgICBjb25zdCBtZXRob2RzVG9PdmVyd3JpdGUgPSBbXG4gICAgICAgICdwb3AnLCAncHVzaCcsICdyZXZlcnNlJywgJ3NoaWZ0JywgJ3Vuc2hpZnQnLCAnc3BsaWNlJyxcbiAgICAgICAgJ2ZpbHRlcicsICdmb3JFYWNoJywgJ21hcCcsICdmaWxsJywgJ3NvcnQnLCAnY29weVdpdGhpbicsXG4gICAgICBdO1xuICAgICAgZm9yIChjb25zdCBtZXRob2Qgb2YgbWV0aG9kc1RvT3ZlcndyaXRlKSB7XG4gICAgICAgIHByb3RvdHlwZVttZXRob2RdID0gZnVuY3Rpb24oKTogdm9pZCB7XG4gICAgICAgICAgY29uc3QgcmVhZFZhbHVlID0gX3NlbGYucmVhZFZhbHVlKCk7XG4gICAgICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IEFycmF5LnByb3RvdHlwZVttZXRob2RdLmFwcGx5KHJlYWRWYWx1ZSwgYXJndW1lbnRzKTtcbiAgICAgICAgICBkZWJ1Zy5sb2coJ1NhdmluZyB2YWx1ZSBmb3IgJyArIF9zZWxmLmtleSArICcgYnkgbWV0aG9kICdcbiAgICAgICAgICAgICsgcHJvdG90eXBlLmNvbnN0cnVjdG9yLm5hbWUgKyAnLicgKyBtZXRob2QpO1xuICAgICAgICAgIF9zZWxmLnNhdmVWYWx1ZShyZWFkVmFsdWUsIGNvbmZpZyk7XG4gICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKHZhbHVlLCBwcm90b3R5cGUpO1xuICAgIHRoaXMucHJveHkgPSB2YWx1ZTtcbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBwdWJsaWMgcmVhZFZhbHVlKGNvbmZpZzogRGVjb3JhdG9yQ29uZmlnID0ge30pOiBhbnkge1xuICAgIGNvbnN0IGVudHJ5ID0gdGhpcy51dGlsaXRpZXNbMF07XG4gICAgY29uc3QgdmFsdWUgPSBlbnRyeSA/IGVudHJ5LnV0aWxpdHkuZ2V0KHRoaXMua2V5LCBlbnRyeS5jb25maWcpIDogbnVsbDtcbiAgICByZXR1cm4gKHR5cGVvZiB2YWx1ZSAhPT0gJ29iamVjdCcpID8gdmFsdWUgOiBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHRoaXMuZ2V0UHJveHkodmFsdWUsIGVudHJ5LmNvbmZpZykpKTtcbiAgfVxuXG4gIHB1YmxpYyBhZGRUYXJnZXRzKHRhcmdldHM6IEFycmF5PGFueT4pOiB2b2lkIHtcbiAgICB0YXJnZXRzLmZvckVhY2godGFyZ2V0ID0+IHtcbiAgICAgIGlmICh0aGlzLnRhcmdldHMuaW5kZXhPZih0YXJnZXQpID09PSAtMSkge1xuICAgICAgICBpZiAodHlwZW9mIHRhcmdldCA9PT0gJ29iamVjdCcpIHsgLy8gaGFuZGxlIEFuZ3VsYXIgQ29tcG9uZW50IGRlc3RydWN0aW9uXG4gICAgICAgICAgY29uc3Qgb3JpZ2luYWxGdW5jdGlvbiA9IHRhcmdldC5uZ09uRGVzdHJveTtcbiAgICAgICAgICBjb25zdCBfc2VsZiA9IHRoaXM7XG4gICAgICAgICAgdGFyZ2V0Lm5nT25EZXN0cm95ID0gZnVuY3Rpb24oKTogYW55IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygb3JpZ2luYWxGdW5jdGlvbiA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgICBvcmlnaW5hbEZ1bmN0aW9uLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0YXJnZXQubmdPbkRlc3Ryb3kgPSBvcmlnaW5hbEZ1bmN0aW9uIHx8IGZ1bmN0aW9uKCk6IGFueSB7fTtcblxuICAgICAgICAgICAgX3NlbGYuaW5pdGlhbGl6ZWRUYXJnZXRzLmRlbGV0ZSh0YXJnZXQpO1xuICAgICAgICAgICAgX3NlbGYudGFyZ2V0cyA9IF9zZWxmLnRhcmdldHMuZmlsdGVyKHQgPT4gdCAhPT0gdGFyZ2V0KTtcbiAgICAgICAgICAgIGlmICghX3NlbGYudGFyZ2V0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgX3NlbGYuc2VydmljZXMuZm9yRWFjaChzZXJ2aWNlID0+IHtcbiAgICAgICAgICAgICAgICBzZXJ2aWNlLmtleXMgPSBzZXJ2aWNlLmtleXMuZmlsdGVyKGtleSA9PiBrZXkgIT09IF9zZWxmLl9rZXkpO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgX3NlbGYucmVzZXRQcm94eSgpO1xuICAgICAgICAgICAgICBDYWNoZS5yZW1vdmUoX3NlbGYpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVidWcuZ3JvdXBDb2xsYXBzZWQoYCR7X3NlbGYua2V5fSBPbkRlc3Ryb3kgaGFuZGxlcjpgKTtcbiAgICAgICAgICAgIGRlYnVnLmxvZygncmVtb3ZlZCB0YXJnZXQ6JywgdGFyZ2V0LmNvbnN0cnVjdG9yLm5hbWUpO1xuICAgICAgICAgICAgZGVidWcubG9nKCdyZW1haW5pbmcgdGFyZ2V0czonLCBfc2VsZi50YXJnZXRzKTtcbiAgICAgICAgICAgIGRlYnVnLmxvZygnY2FjaGVJdGVtOicsIENhY2hlLmdldChfc2VsZi5rZXkpKTtcbiAgICAgICAgICAgIGRlYnVnLmdyb3VwRW5kKCk7XG4gICAgICAgICAgfTtcbiAgICAgICAgICB0aGlzLnRhcmdldHMucHVzaCh0YXJnZXQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYWRkU2VydmljZXMoc2VydmljZXM6IEFycmF5PFdlYlN0b3JhZ2VTZXJ2aWNlSW50ZXJmYWNlPik6IHZvaWQge1xuICAgIHNlcnZpY2VzLmZvckVhY2goc2VydmljZSA9PiB7XG4gICAgICBpZiAodGhpcy5zZXJ2aWNlcy5pbmRleE9mKHNlcnZpY2UpID09PSAtMSkge1xuICAgICAgICBzZXJ2aWNlLmtleXMucHVzaCh0aGlzLl9rZXkpO1xuICAgICAgICB0aGlzLnNlcnZpY2VzLnB1c2goc2VydmljZSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYWRkVXRpbGl0aWVzKHV0aWxpdHlFbnRyaWVzOiBBcnJheTxVdGlsaXR5RW50cnk+KTogdm9pZCB7XG4gICAgdXRpbGl0eUVudHJpZXMuZm9yRWFjaChlbnRyeSA9PiB7XG4gICAgICBpZiAodGhpcy51dGlsaXRpZXMuZmluZEluZGV4KGUgPT4gZS51dGlsaXR5ID09PSBlbnRyeS51dGlsaXR5KSA9PT0gLTEpIHtcbiAgICAgICAgdGhpcy51dGlsaXRpZXMucHVzaChlbnRyeSk7XG4gICAgICAgIGVudHJ5LnV0aWxpdHkuc2V0KHRoaXMua2V5LCB0aGlzLnJlYWRWYWx1ZSgpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyByZXNldFByb3h5KCk6IHZvaWQge1xuICAgIHRoaXMucHJveHkgPSBudWxsO1xuICB9XG5cbiAgcHVibGljIHByb3BhZ2F0ZUNoYW5nZSh2YWx1ZTogYW55LCBzb3VyY2U/OiBXZWJTdG9yYWdlVXRpbGl0eSk6IHZvaWQge1xuICAgIGlmIChpc0VxdWFsKHZhbHVlLCB0aGlzLnJlYWRWYWx1ZSgpKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLnV0aWxpdGllcy5mb3JFYWNoKGVudHJ5ID0+IHtcbiAgICAgIGNvbnN0IHV0aWxpdHkgPSBlbnRyeS51dGlsaXR5O1xuICAgICAgLy8gdXBkYXRpbmcgc2VydmljZSB3aGljaCB0aGUgY2hhbmdlIGNhbWUgZnJvbSB3b3VsZCBhZmZlY3QgaW4gYSBjeWNsZVxuICAgICAgaWYgKHV0aWxpdHkgPT09IHNvdXJjZSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBkZWJ1Zy5sb2coYHByb3BhZ2F0aW5nIGNoYW5nZSBvbiAke3RoaXMua2V5fSB0bzpgLCB1dGlsaXR5KTtcbiAgICAgIHV0aWxpdHkuc2V0KHRoaXMuX2tleSwgdmFsdWUsIGVudHJ5LmNvbmZpZyk7XG4gICAgfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgbWlncmF0ZShjb25maWc6IERlY29yYXRvckNvbmZpZywgdXRpbGl0eTogV2ViU3RvcmFnZVV0aWxpdHkpOiB2b2lkIHtcbiAgICBjb25zdCBwcmVmaXggPSAoY29uZmlnLnByZWZpeCB8fCBDb25maWcucHJlZml4KSB8fCAnJztcbiAgICBjb25zdCBrZXlFeGlzdHMgPSAoa2V5OiBzdHJpbmcpOiBib29sZWFuID0+IGtleSBpbiB1dGlsaXR5LmdldFN0b3JhZ2UoKTtcbiAgICBjb25zdCBtaWdyYXRlS2V5ID0ga2V5RXhpc3RzKHByZWZpeCArIGNvbmZpZy5taWdyYXRlS2V5ISlcbiAgICAgID8gcHJlZml4ICsgY29uZmlnLm1pZ3JhdGVLZXkhXG4gICAgICA6IGNvbmZpZy5taWdyYXRlS2V5ITtcbiAgICBpZiAoIWtleUV4aXN0cyhtaWdyYXRlS2V5KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkZWJ1Zy5sb2coJ01pZ3JhdGluZycsIG1pZ3JhdGVLZXksICd0bycsIGNvbmZpZy5rZXksICdpbicsIHV0aWxpdHkuZ2V0U3RvcmFnZU5hbWUoKSk7XG4gICAgY29uc3QgdmFsdWUgPSB1dGlsaXR5LmdldChtaWdyYXRlS2V5LCB7Li4uY29uZmlnLCBwcmVmaXg6ICcnfSk7XG4gICAgdXRpbGl0eS5zZXQodGhpcy5fa2V5LCB2YWx1ZSk7XG4gICAgdXRpbGl0eS5yZW1vdmUobWlncmF0ZUtleSwge3ByZWZpeDogJyd9KTtcbiAgfVxufVxuIl19