UNPKG

@ortoo/angular-resource

Version:

Magical CRUD resource management for angular

282 lines 39.7 kB
// tslint:disable only-arrow-functions import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { EventEmitter } from './emitter'; import * as utils from './utils'; import { Chain } from './chain'; // The length of time since an object has been requested that we keep in persistent storage. // In milliseconds - default to 7 days export const defaultPStorageMaxLen = 7 * 24 * 60 * 60 * 1000; export function createResourceFactory(LocalResourceFactory, localforage, plugins, pStorageMaxLen = defaultPStorageMaxLen) { const ResourceFactory = (url, rootKey, rootKeyPlural) => { rootKeyPlural = rootKeyPlural || (rootKey + 's'); // Create the local resource let LocalResource = LocalResourceFactory(url, rootKey, rootKeyPlural); // In memory resource store let _resources = {}; let _resFromLocal = {}; // Create an event emitter let emitter = new EventEmitter(); // Load from persistent storage (if we have something more exciting than localstorage) if (utils.advancedStorage(localforage)) { let pStorageKey = utils.persistentStorageKey(url); localforage.getItem(pStorageKey).then(function (data) { if (!(data && Array.isArray(data))) { return; } let now = new Date().getTime(); data.forEach(function (datum) { let obj = datum.obj; let lastRequested = datum.lastreq; // Only create if the time between now and the last request is less than // pStorageMaxLen if ((now - lastRequested) <= pStorageMaxLen) { createFromStorage(obj, lastRequested); } }); }); } function localToRes(loc, id) { let res = _resFromLocal[loc.$id]; // If we don't have a resource then create it if (!res) { res = new Resource(loc, true); } if (id) { addedResource(id, res); } return res; } function toObject() { return utils.toObject(this); } function reset() { // If we aren't saved at all then just remove if (!this.$created) { this.$remove(true); return; } let newValues = this.$loc.$toObject(); utils.removeResValues(this); utils.setResValues(this, newValues); } // The promise resolves once the save has been committed function save() { let res = this; res.$created = true; return this.$loc.$save(this.$toObject()).then(function () { emitter.emit('updated', res); res.$subject.next(res); if (!res.$resolved) { res.$deferred.resolve(res); res.$resolved = true; } return res; }); } function remove(noPrompt, skipLocal) { if (!noPrompt) { // Add confirmation alert if (!window.confirm('Do you really want to delete this item?')) { return; } } this.$deleted = true; if (this._id) { removedResource(this._id, this); } let prom; if (skipLocal) { prom = Promise.resolve(true); } else { prom = this.$loc.$remove(); } emitter.emit('remove', this); return prom; } function type() { return rootKey[0].toUpperCase() + rootKey.slice(1); } function collection(seeds, relation) { return LocalResource.collect(Resource, seeds, relation); } function chain(origQry, modelOrQryFn, qryFn) { return Chain(origQry, modelOrQryFn, qryFn); } function query(qry, limit) { let result = LocalResource.query(qry, limit, Resource); emitter.emit('query', result, qry, limit); return result; } function get(ids, force) { let results = LocalResource.get(ids, force, localToRes); emitter.emit('get', ids, results, force); return results; } function addedResource(id, res) { let existing = _resources[id]; _resources[id] = res; if (!existing) { emitter.emit('created', id, res); } } function removedResource(id, res) { let existing = _resources[id]; delete _resources[id]; if (existing) { emitter.emit('deleted', id, res); res.$subject.next(null); } } function updatedLocal(res, newVal, oldVal) { // We could have been deleted (existing oldVal, null newval) if (oldVal && !newVal) { // We have been deleted. Cleanup ourselves res.$remove(true, true); } else { res.$created = true; if (oldVal._id && (newVal._id !== oldVal._id)) { throw new Error('Not allowed to change id'); } // Merge the objects together using the oldVal as a base, and using *our* version // to resolve any conflicts. We may need to put in some conflict resolution logic // somewhere on a case by case basis let merge = utils.mergeObjects(res.$toObject(), oldVal, newVal); // Now put back in the merge values utils.removeResValues(res); utils.setResValues(res, merge); // Make sure we are stored addedResource(res._id, res); } // Notify on the subject that we've updated res.$subject.next(res); } function updateServer(val) { this.$loc.$updateServer(val); } // updates or creates a model depending on whether we know about it already. This // is usually used when we recieve a response with model data from the server using // a non-standard method function updateOrCreate(val) { let res = _resources[val._id]; if (!res) { res = new Resource(val, false, new Date().getTime()); } else { res.$updateServer(val); } return res; } function createFromStorage(val, lastRequested) { let res = _resources[val._id]; // If we do have already know about a resource then lets assume it is more up to date // than the storage version. If we haven't resolved yet though (or we don't yet have // an ID on the object) lets update our values if (!res) { res = new Resource(val, false, lastRequested); } else if (!res._id || !res.$resolved) { res.$updateServer(val); } return res; } function refresh() { this.$loc.$refresh(); } class Resource { constructor(val, fromLoc, lastRequested) { this.$save = save; this.$remove = remove; this.$delete = remove; this.$type = type; this.$reset = reset; this.$refresh = refresh; this.$toObject = toObject; this.$updateServer = updateServer; let res = this; this.$deleted = false; this.$deferred = new utils.Deferred(); this.$promise = this.$deferred.promise; // An initial promise for our initial // fetch or create of data this.$resolved = false; // Have we had an initial resolution of the promise this.$created = false; // Goes true on an initial save this.$subject = new BehaviorSubject(this); this.$resolvedSubject = utils.convertToResolvedSubject(this.$subject, this.$promise); // If we've been given values put them on if (val) { let props = fromLoc ? val.$toObject() : val; for (let key of Object.keys(props)) { res[key] = props[key]; } } // Create the local resource if (fromLoc) { this.$loc = val; this.$loc.$mod = this; // Resolve the promise once the local copy has resolved this.$loc.$promise.then(function () { if (!res.$resolved) { res.$deferred.resolve(res); res.$resolved = true; } }); } else if (this._id) { // We have an id - so we persist down this.$loc = new LocalResource(val, false, this, lastRequested); // We immediately resolve our promise since we have data this.$deferred.resolve(this); this.$resolved = true; } else { // Don't add in the values until we save this.$loc = new LocalResource(null, false, this); } this.$id = this.$loc.$id; _resFromLocal[this.$id] = this; // If we have an id then add us to the store if (this._id) { addedResource(this._id, this); } // Listen for changes on the local resource this.$loc.$emitter.on('update', function (newVal, oldVal) { updatedLocal(res, newVal, oldVal); }); } } Resource.get = get; Resource.query = query; Resource.chain = chain; Resource.type = type; Resource.updateOrCreate = updateOrCreate; Resource.collect = collection; // Trigger any plugins for (let plugin of plugins) { plugin(Resource, rootKey); } inheritEventEmitter(Resource, emitter); return Resource; }; ResourceFactory.Chain = Chain; return ResourceFactory; } function inheritEventEmitter(obj, emitter) { let props = [ 'dispose', 'addListener', 'emit', 'listen', 'off', 'on', 'once', 'removeListener', ]; // Event emitter 'inheritance' for (let prop of props) { obj[prop] = function () { return emitter[prop].apply(emitter, arguments); }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kZWwuanMiLCJzb3VyY2VSb290IjoiL0BvcnRvby9hbmd1bGFyLXJlc291cmNlLyIsInNvdXJjZXMiOlsibW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsc0NBQXNDO0FBQ3RDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUd2RCxPQUFPLEVBQUUsWUFBWSxFQUF5QixNQUFNLFdBQVcsQ0FBQztBQUNoRSxPQUFPLEtBQUssS0FBSyxNQUFNLFNBQVMsQ0FBQztBQUVqQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBZ0JoQyw0RkFBNEY7QUFDNUYsc0NBQXNDO0FBQ3RDLE1BQU0sQ0FBQyxNQUFNLHFCQUFxQixHQUFHLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxJQUFJLENBQUM7QUFFN0QsTUFBTSxnQ0FBZ0Msb0JBQTBDLEVBQzFDLFdBQXdCLEVBQ3hCLE9BQTZCLEVBQzdCLGlCQUF5QixxQkFBcUI7SUFFbEYsTUFBTSxlQUFlLEdBQTRCLENBQUMsR0FBVyxFQUFFLE9BQWUsRUFBRSxhQUFzQjtRQUNwRyxhQUFhLEdBQUcsYUFBYSxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBRWpELDRCQUE0QjtRQUM1QixJQUFJLGFBQWEsR0FBRyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRXRFLDJCQUEyQjtRQUMzQixJQUFJLFVBQVUsR0FBMEIsRUFBRSxDQUFDO1FBQzNDLElBQUksYUFBYSxHQUEyQixFQUFFLENBQUM7UUFFL0MsMEJBQTBCO1FBQzFCLElBQUksT0FBTyxHQUFHLElBQUksWUFBWSxFQUFFLENBQUM7UUFFakMsc0ZBQXNGO1FBQ3RGLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxlQUFlLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQ3ZDLElBQUksV0FBVyxHQUFHLEtBQUssQ0FB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UztRQUNULGFBQWE7UUFDYixNQUFNO1FBQ04sUUFBUTtRQUNSLEtBQUs7UUFDTCxJQUFJO1FBQ0osTUFBTTtRQUNOLGdCQUFnQjtLQUNqQixDQUFDO0lBRUYsOEJBQThCO0lBQzlCLEdBQUcsQ0FBQyxDQUFDLElBQUksSUFBSSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDdkIsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHO1lBQ1YsTUFBTSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQ2pELENBQUMsQ0FBQztJQUNKLENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gdHNsaW50OmRpc2FibGUgb25seS1hcnJvdy1mdW5jdGlvbnNcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCB9IGZyb20gJ3J4anMvQmVoYXZpb3JTdWJqZWN0JztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzL1N1YmplY3QnO1xuXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIsIEhhbmRsZXIsIFN1YnNjcmlwdGlvbiB9IGZyb20gJy4vZW1pdHRlcic7XG5pbXBvcnQgKiBhcyB1dGlscyBmcm9tICcuL3V0aWxzJztcblxuaW1wb3J0IHsgQ2hhaW4gfSBmcm9tICcuL2NoYWluJztcbmltcG9ydCB7IENoYWluYWJsZVF1ZXJ5LFxuICAgICAgICAgQ29sbGVjdGlvbixcbiAgICAgICAgIENvbGxlY3Rpb25TZWFyY2hlcixcbiAgICAgICAgIExvY2FsRm9yYWdlLFxuICAgICAgICAgTG9jYWxNb2RlbCxcbiAgICAgICAgIExvY2FsUmVzb3VyY2VGYWN0b3J5LFxuICAgICAgICAgTW9kZWwsXG4gICAgICAgICBNb2RlbEFycmF5LFxuICAgICAgICAgUGx1Z2luLFxuICAgICAgICAgUXVlcnksXG4gICAgICAgICBRdWVyeUZ1bmN0aW9uLFxuICAgICAgICAgUmVzb3VyY2VGYWN0b3J5IGFzIElSZXNvdXJjZUZhY3Rvcnl9IGZyb20gJy4vdHlwZXMnO1xuXG50eXBlIExhc3RSZXF1ZXN0ID0gKERhdGUgfCBudW1iZXIpO1xuXG4vLyBUaGUgbGVuZ3RoIG9mIHRpbWUgc2luY2UgYW4gb2JqZWN0IGhhcyBiZWVuIHJlcXVlc3RlZCB0aGF0IHdlIGtlZXAgaW4gcGVyc2lzdGVudCBzdG9yYWdlLlxuLy8gSW4gbWlsbGlzZWNvbmRzIC0gZGVmYXVsdCB0byA3IGRheXNcbmV4cG9ydCBjb25zdCBkZWZhdWx0UFN0b3JhZ2VNYXhMZW4gPSA3ICogMjQgKiA2MCAqIDYwICogMTAwMDtcblxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZVJlc291cmNlRmFjdG9yeShMb2NhbFJlc291cmNlRmFjdG9yeTogTG9jYWxSZXNvdXJjZUZhY3RvcnksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsZm9yYWdlOiBMb2NhbEZvcmFnZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGx1Z2luczogQXJyYXk8UGx1Z2luPE1vZGVsPj4sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBTdG9yYWdlTWF4TGVuOiBudW1iZXIgPSBkZWZhdWx0UFN0b3JhZ2VNYXhMZW4pOiBJUmVzb3VyY2VGYWN0b3J5PE1vZGVsPiB7XG5cbiAgY29uc3QgUmVzb3VyY2VGYWN0b3J5OiBJUmVzb3VyY2VGYWN0b3J5PE1vZGVsPiA9ICh1cmw6IHN0cmluZywgcm9vdEtleTogc3RyaW5nLCByb290S2V5UGx1cmFsPzogc3RyaW5nKSA9PiB7XG4gICAgcm9vdEtleVBsdXJhbCA9IHJvb3RLZXlQbHVyYWwgfHwgKHJvb3RLZXkgKyAncycpO1xuXG4gICAgLy8gQ3JlYXRlIHRoZSBsb2NhbCByZXNvdXJjZVxuICAgIGxldCBMb2NhbFJlc291cmNlID0gTG9jYWxSZXNvdXJjZUZhY3RvcnkodXJsLCByb290S2V5LCByb290S2V5UGx1cmFsKTtcblxuICAgIC8vIEluIG1lbW9yeSByZXNvdXJjZSBzdG9yZVxuICAgIGxldCBfcmVzb3VyY2VzOiB7W2lkOiBzdHJpbmddOiBNb2RlbH0gPSB7fTtcbiAgICBsZXQgX3Jlc0Zyb21Mb2NhbDoge1skaWQ6IHN0cmluZ106IE1vZGVsfSA9IHt9O1xuXG4gICAgLy8gQ3JlYXRlIGFuIGV2ZW50IGVtaXR0ZXJcbiAgICBsZXQgZW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcblxuICAgIC8vIExvYWQgZnJvbSBwZXJzaXN0ZW50IHN0b3JhZ2UgKGlmIHdlIGhhdmUgc29tZXRoaW5nIG1vcmUgZXhjaXRpbmcgdGhhbiBsb2NhbHN0b3JhZ2UpXG4gICAgaWYgKHV0aWxzLmFkdmFuY2VkU3RvcmFnZShsb2NhbGZvcmFnZSkpIHtcbiAgICAgIGxldCBwU3RvcmFnZUtleSA9IHV0aWxzLnBlcnNpc3RlbnRTdG9yYWdlS2V5KHVybCk7XG4gICAgICBsb2NhbGZvcmFnZS5nZXRJdGVtKHBTdG9yYWdlS2V5KS50aGVuKGZ1bmN0aW9uKGRhdGEpIHtcbiAgICAgICAgaWYgKCEoZGF0YSAmJiBBcnJheS5pc0FycmF5KGRhdGEpKSkge1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGxldCBub3cgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgICAgICBkYXRhLmZvckVhY2goZnVuY3Rpb24oZGF0dW0pIHtcbiAgICAgICAgICBsZXQgb2JqID0gZGF0dW0ub2JqO1xuICAgICAgICAgIGxldCBsYXN0UmVxdWVzdGVkID0gZGF0dW0ubGFzdHJlcTtcblxuICAgICAgICAgIC8vIE9ubHkgY3JlYXRlIGlmIHRoZSB0aW1lIGJldHdlZW4gbm93IGFuZCB0aGUgbGFzdCByZXF1ZXN0IGlzIGxlc3MgdGhhblxuICAgICAgICAgIC8vIHBTdG9yYWdlTWF4TGVuXG4gICAgICAgICAgaWYgKChub3cgLSBsYXN0UmVxdWVzdGVkKSA8PSBwU3RvcmFnZU1heExlbikge1xuICAgICAgICAgICAgY3JlYXRlRnJvbVN0b3JhZ2Uob2JqLCBsYXN0UmVxdWVzdGVkKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9jYWxUb1Jlcyhsb2M6IExvY2FsTW9kZWwsIGlkOiBzdHJpbmcpIHtcbiAgICAgIGxldCByZXMgPSBfcmVzRnJvbUxvY2FsW2xvYy4kaWRdO1xuXG4gICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgcmVzb3VyY2UgdGhlbiBjcmVhdGUgaXRcbiAgICAgIGlmICghcmVzKSB7XG4gICAgICAgIHJlcyA9IG5ldyAoPGFueT4gUmVzb3VyY2UpKGxvYywgdHJ1ZSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChpZCkge1xuICAgICAgICBhZGRlZFJlc291cmNlKGlkLCByZXMpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRvT2JqZWN0KHRoaXM6IE1vZGVsKSB7XG4gICAgICByZXR1cm4gdXRpbHMudG9PYmplY3QodGhpcyk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVzZXQodGhpczogTW9kZWwpIHtcblxuICAgICAgLy8gSWYgd2UgYXJlbid0IHNhdmVkIGF0IGFsbCB0aGVuIGp1c3QgcmVtb3ZlXG4gICAgICBpZiAoIXRoaXMuJGNyZWF0ZWQpIHtcbiAgICAgICAgdGhpcy4kcmVtb3ZlKHRydWUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGxldCBuZXdWYWx1ZXMgPSB0aGlzLiRsb2MuJHRvT2JqZWN0KCk7XG4gICAgICB1dGlscy5yZW1vdmVSZXNWYWx1ZXModGhpcyk7XG4gICAgICB1dGlscy5zZXRSZXNWYWx1ZXModGhpcywgbmV3VmFsdWVzKTtcbiAgICB9XG5cbiAgICAvLyBUaGUgcHJvbWlzZSByZXNvbHZlcyBvbmNlIHRoZSBzYXZlIGhhcyBiZWVuIGNvbW1pdHRlZFxuICAgIGZ1bmN0aW9uIHNhdmUodGhpczogTW9kZWwpIHtcbiAgICAgIGxldCByZXMgPSB0aGlzO1xuICAgICAgcmVzLiRjcmVhdGVkID0gdHJ1ZTtcbiAgICAgIHJldHVybiB0aGlzLiRsb2MuJHNhdmUodGhpcy4kdG9PYmplY3QoKSkudGhlbihmdW5jdGlvbigpIHtcbiAgICAgICAgZW1pdHRlci5lbWl0KCd1cGRhdGVkJywgcmVzKTtcbiAgICAgICAgcmVzLiRzdWJqZWN0Lm5leHQocmVzKTtcbiAgICAgICAgaWYgKCFyZXMuJHJlc29sdmVkKSB7XG4gICAgICAgICAgcmVzLiRkZWZlcnJlZC5yZXNvbHZlKHJlcyk7XG4gICAgICAgICAgcmVzLiRyZXNvbHZlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlcztcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlbW92ZSh0aGlzOiBNb2RlbCwgbm9Qcm9tcHQ/OiBib29sZWFuLCBza2lwTG9jYWw/OiBib29sZWFuKSB7XG4gICAgICBpZiAoIW5vUHJvbXB0KSB7XG4gICAgICAgIC8vIEFkZCBjb25maXJtYXRpb24gYWxlcnRcbiAgICAgICAgaWYgKCF3aW5kb3cuY29uZmlybSgnRG8geW91IHJlYWxseSB3YW50IHRvIGRlbGV0ZSB0aGlzIGl0ZW0/JykpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHRoaXMuJGRlbGV0ZWQgPSB0cnVlO1xuICAgICAgaWYgKHRoaXMuX2lkKSB7XG4gICAgICAgIHJlbW92ZWRSZXNvdXJjZSh0aGlzLl9pZCwgdGhpcyk7XG4gICAgICB9XG5cbiAgICAgIGxldCBwcm9tO1xuICAgICAgaWYgKHNraXBMb2NhbCkge1xuICAgICAgICBwcm9tID0gUHJvbWlzZS5yZXNvbHZlKHRydWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcHJvbSA9IHRoaXMuJGxvYy4kcmVtb3ZlKCk7XG4gICAgICB9XG5cbiAgICAgIGVtaXR0ZXIuZW1pdCgncmVtb3ZlJywgdGhpcyk7XG5cbiAgICAgIHJldHVybiBwcm9tO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHR5cGUoKSB7XG4gICAgICByZXR1cm4gcm9vdEtleVswXS50b1VwcGVyQ2FzZSgpICsgcm9vdEtleS5zbGljZSgxKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb2xsZWN0aW9uKHNlZWRzOiBNb2RlbCB8IE1vZGVsQXJyYXk8TW9kZWw+LCByZWxhdGlvbjogQ29sbGVjdGlvblNlYXJjaGVyKTogQ29sbGVjdGlvbjxNb2RlbD4ge1xuICAgICAgcmV0dXJuIExvY2FsUmVzb3VyY2UuY29sbGVjdChSZXNvdXJjZSwgc2VlZHMsIHJlbGF0aW9uKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjaGFpbihvcmlnUXJ5OiBDaGFpbmFibGVRdWVyeTxNb2RlbD4sXG4gICAgICAgICAgICAgICAgICAgbW9kZWxPclFyeUZuOiAodHlwZW9mIFJlc291cmNlIHwgUXVlcnlGdW5jdGlvbiksXG4gICAgICAgICAgICAgICAgICAgcXJ5Rm4/OiBRdWVyeUZ1bmN0aW9uKTogUXVlcnk8TW9kZWw+IHtcbiAgICAgIHJldHVybiBDaGFpbihvcmlnUXJ5LCBtb2RlbE9yUXJ5Rm4sIHFyeUZuKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBxdWVyeShxcnk6IGFueSwgbGltaXQ/OiBudW1iZXIpIHtcbiAgICAgIGxldCByZXN1bHQgPSBMb2NhbFJlc291cmNlLnF1ZXJ5KHFyeSwgbGltaXQsIFJlc291cmNlKTtcbiAgICAgIGVtaXR0ZXIuZW1pdCgncXVlcnknLCByZXN1bHQsIHFyeSwgbGltaXQpO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXQoaWQ6IHN0cmluZywgZm9yY2U/OiBib29sZWFuKTogTW9kZWw7XG4gICAgZnVuY3Rpb24gZ2V0KGlkczogc3RyaW5nW10sIGZvcmNlPzogYm9vbGVhbik6IE1vZGVsQXJyYXk8TW9kZWw+O1xuICAgIGZ1bmN0aW9uIGdldChpZHM6IChzdHJpbmcgfCBzdHJpbmdbXSksIGZvcmNlPzogYm9vbGVhbikge1xuICAgICAgbGV0IHJlc3VsdHMgPSBMb2NhbFJlc291cmNlLmdldChpZHMsIGZvcmNlLCBsb2NhbFRvUmVzKTtcbiAgICAgIGVtaXR0ZXIuZW1pdCgnZ2V0JywgaWRzLCByZXN1bHRzLCBmb3JjZSk7XG4gICAgICByZXR1cm4gcmVzdWx0cztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhZGRlZFJlc291cmNlKGlkOiBzdHJpbmcsIHJlczogTW9kZWwpIHtcbiAgICAgIGxldCBleGlzdGluZyA9IF9yZXNvdXJjZXNbaWRdO1xuICAgICAgX3Jlc291cmNlc1tpZF0gPSByZXM7XG4gICAgICBpZiAoIWV4aXN0aW5nKSB7XG4gICAgICAgIGVtaXR0ZXIuZW1pdCgnY3JlYXRlZCcsIGlkLCByZXMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlbW92ZWRSZXNvdXJjZShpZDogc3RyaW5nLCByZXM6IE1vZGVsKSB7XG4gICAgICBsZXQgZXhpc3RpbmcgPSBfcmVzb3VyY2VzW2lkXTtcbiAgICAgIGRlbGV0ZSBfcmVzb3VyY2VzW2lkXTtcbiAgICAgIGlmIChleGlzdGluZykge1xuICAgICAgICBlbWl0dGVyLmVtaXQoJ2RlbGV0ZWQnLCBpZCwgcmVzKTtcbiAgICAgICAgcmVzLiRzdWJqZWN0Lm5leHQobnVsbCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdXBkYXRlZExvY2FsKHJlczogTW9kZWwsIG5ld1ZhbDogYW55LCBvbGRWYWw6IGFueSkge1xuXG4gICAgICAvLyBXZSBjb3VsZCBoYXZlIGJlZW4gZGVsZXRlZCAoZXhpc3Rpbmcgb2xkVmFsLCBudWxsIG5ld3ZhbClcbiAgICAgIGlmIChvbGRWYWwgJiYgIW5ld1ZhbCkge1xuICAgICAgICAvLyBXZSBoYXZlIGJlZW4gZGVsZXRlZC4gQ2xlYW51cCBvdXJzZWx2ZXNcbiAgICAgICAgcmVzLiRyZW1vdmUodHJ1ZSwgdHJ1ZSk7XG4gICAgICB9IGVsc2Uge1xuXG4gICAgICAgIHJlcy4kY3JlYXRlZCA9IHRydWU7XG5cbiAgICAgICAgaWYgKG9sZFZhbC5faWQgJiYgKG5ld1ZhbC5faWQgIT09IG9sZFZhbC5faWQpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdOb3QgYWxsb3dlZCB0byBjaGFuZ2UgaWQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE1lcmdlIHRoZSBvYmplY3RzIHRvZ2V0aGVyIHVzaW5nIHRoZSBvbGRWYWwgYXMgYSBiYXNlLCBhbmQgdXNpbmcgKm91ciogdmVyc2lvblxuICAgICAgICAvLyB0byByZXNvbHZlIGFueSBjb25mbGljdHMuIFdlIG1heSBuZWVkIHRvIHB1dCBpbiBzb21lIGNvbmZsaWN0IHJlc29sdXRpb24gbG9naWNcbiAgICAgICAgLy8gc29tZXdoZXJlIG9uIGEgY2FzZSBieSBjYXNlIGJhc2lzXG4gICAgICAgIGxldCBtZXJnZSA9IHV0aWxzLm1lcmdlT2JqZWN0cyhyZXMuJHRvT2JqZWN0KCksIG9sZFZhbCwgbmV3VmFsKTtcblxuICAgICAgICAvLyBOb3cgcHV0IGJhY2sgaW4gdGhlIG1lcmdlIHZhbHVlc1xuICAgICAgICB1dGlscy5yZW1vdmVSZXNWYWx1ZXMocmVzKTtcbiAgICAgICAgdXRpbHMuc2V0UmVzVmFsdWVzKHJlcywgbWVyZ2UpO1xuXG4gICAgICAgIC8vIE1ha2Ugc3VyZSB3ZSBhcmUgc3RvcmVkXG4gICAgICAgIGFkZGVkUmVzb3VyY2UocmVzLl9pZCwgcmVzKTtcbiAgICAgIH1cblxuICAgICAgLy8gTm90aWZ5IG9uIHRoZSBzdWJqZWN0IHRoYXQgd2UndmUgdXBkYXRlZFxuICAgICAgcmVzLiRzdWJqZWN0Lm5leHQocmVzKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB1cGRhdGVTZXJ2ZXIodGhpczogTW9kZWwsIHZhbDogYW55KSB7XG4gICAgICB0aGlzLiRsb2MuJHVwZGF0ZVNlcnZlcih2YWwpO1xuICAgIH1cblxuICAgIC8vIHVwZGF0ZXMgb3IgY3JlYXRlcyBhIG1vZGVsIGRlcGVuZGluZyBvbiB3aGV0aGVyIHdlIGtub3cgYWJvdXQgaXQgYWxyZWFkeS4gVGhpc1xuICAgIC8vIGlzIHVzdWFsbHkgdXNlZCB3aGVuIHdlIHJlY2lldmUgYSByZXNwb25zZSB3aXRoIG1vZGVsIGRhdGEgZnJvbSB0aGUgc2VydmVyIHVzaW5nXG4gICAgLy8gYSBub24tc3RhbmRhcmQgbWV0aG9kXG4gICAgZnVuY3Rpb24gdXBkYXRlT3JDcmVhdGUodmFsOiBhbnkpIHtcbiAgICAgIGxldCByZXMgPSBfcmVzb3VyY2VzW3ZhbC5faWRdO1xuICAgICAgaWYgKCFyZXMpIHtcbiAgICAgICAgcmVzID0gbmV3ICg8YW55PiBSZXNvdXJjZSkodmFsLCBmYWxzZSwgbmV3IERhdGUoKS5nZXRUaW1lKCkpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVzLiR1cGRhdGVTZXJ2ZXIodmFsKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHJlcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjcmVhdGVGcm9tU3RvcmFnZSh2YWw6IGFueSwgbGFzdFJlcXVlc3RlZDogTGFzdFJlcXVlc3QpIHtcbiAgICAgIGxldCByZXMgPSBfcmVzb3VyY2VzW3ZhbC5faWRdO1xuXG4gICAgICAvLyBJZiB3ZSBkbyBoYXZlIGFscmVhZHkga25vdyBhYm91dCBhIHJlc291cmNlIHRoZW4gbGV0cyBhc3N1bWUgaXQgaXMgbW9yZSB1cCB0byBkYXRlXG4gICAgICAvLyB0aGFuIHRoZSBzdG9yYWdlIHZlcnNpb24uIElmIHdlIGhhdmVuJ3QgcmVzb2x2ZWQgeWV0IHRob3VnaCAob3Igd2UgZG9uJ3QgeWV0IGhhdmVcbiAgICAgIC8vIGFuIElEIG9uIHRoZSBvYmplY3QpIGxldHMgdXBkYXRlIG91ciB2YWx1ZXNcbiAgICAgIGlmICghcmVzKSB7XG4gICAgICAgIHJlcyA9IG5ldyAoPGFueT4gUmVzb3VyY2UpKHZhbCwgZmFsc2UsIGxhc3RSZXF1ZXN0ZWQpO1xuICAgICAgfSBlbHNlIGlmICghcmVzLl9pZCB8fCAhcmVzLiRyZXNvbHZlZCkge1xuICAgICAgICByZXMuJHVwZGF0ZVNlcnZlcih2YWwpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gcmVzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlZnJlc2goKSB7XG4gICAgICB0aGlzLiRsb2MuJHJlZnJlc2goKTtcbiAgICB9XG5cbiAgICBjbGFzcyBSZXNvdXJjZSBpbXBsZW1lbnRzIE1vZGVsIHtcbiAgICAgIHB1YmxpYyBzdGF0aWMgZ2V0ID0gZ2V0O1xuICAgICAgcHVibGljIHN0YXRpYyBxdWVyeSA9IHF1ZXJ5O1xuICAgICAgcHVibGljIHN0YXRpYyBjaGFpbiA9IGNoYWluO1xuICAgICAgcHVibGljIHN0YXRpYyB0eXBlID0gdHlwZTtcbiAgICAgIHB1YmxpYyBzdGF0aWMgdXBkYXRlT3JDcmVhdGUgPSB1cGRhdGVPckNyZWF0ZTtcbiAgICAgIHB1YmxpYyBzdGF0aWMgY29sbGVjdCA9IGNvbGxlY3Rpb247XG5cbiAgICAgIHB1YmxpYyBzdGF0aWMgZGlzcG9zZTogeygpOiB2b2lkfTtcbiAgICAgIHB1YmxpYyBzdGF0aWMgYWRkTGlzdGVuZXI6IHsobmFtZTogc3RyaW5nLCBoYW5kbGVyOiBIYW5kbGVyKTogdm9pZH07XG4gICAgICBwdWJsaWMgc3RhdGljIGVtaXQ6IHsoZm5OYW1lOiBzdHJpbmcsIC4uLmRhdGE6IGFueVtdKTogdm9pZH07XG4gICAgICBwdWJsaWMgc3RhdGljIGxpc3RlbjogeyhuYW1lOiBzdHJpbmcsIGhhbmRsZXI6IEhhbmRsZXIpOiBTdWJzY3JpcHRpb259O1xuICAgICAgcHVibGljIHN0YXRpYyBvZmY6IHsobmFtZTogc3RyaW5nLCBoYW5kbGVyOiBIYW5kbGVyKTogdm9pZH07XG4gICAgICBwdWJsaWMgc3RhdGljIG9uOiB7KG5hbWU6IHN0cmluZywgaGFuZGxlcjogSGFuZGxlcik6IHZvaWR9O1xuICAgICAgcHVibGljIHN0YXRpYyBvbmNlOiB7KG5hbWU6IHN0cmluZywgaGFuZGxlcjogSGFuZGxlcik6IHZvaWR9O1xuICAgICAgcHVibGljIHN0YXRpYyByZW1vdmVMaXN0ZW5lcjogeyhuYW1lOiBzdHJpbmcsIGhhbmRsZXI6IEhhbmRsZXIpOiB2b2lkfTtcblxuICAgICAgcHVibGljIF9pZD86IHN0cmluZztcblxuICAgICAgcHVibGljICRjcmVhdGVkOiBib29sZWFuO1xuICAgICAgcHVibGljICRkZWxldGVkOiBib29sZWFuO1xuICAgICAgcHVibGljICRwcm9taXNlOiBQcm9taXNlPFJlc291cmNlPjtcbiAgICAgIHB1YmxpYyAkc3ViamVjdDogQmVoYXZpb3JTdWJqZWN0PFJlc291cmNlPjtcbiAgICAgIHB1YmxpYyAkcmVzb2x2ZWRTdWJqZWN0OiBTdWJqZWN0PFJlc291cmNlPjtcbiAgICAgIHB1YmxpYyAkZGVmZXJyZWQ6IHV0aWxzLkRlZmVycmVkPFJlc291cmNlPjtcbiAgICAgIHB1YmxpYyAkcmVzb2x2ZWQ6IGJvb2xlYW47XG4gICAgICBwdWJsaWMgJGxvYzogTG9jYWxNb2RlbDtcbiAgICAgIHB1YmxpYyAkaWQ6IHN0cmluZztcblxuICAgICAgcHVibGljICRzYXZlID0gc2F2ZTtcbiAgICAgIHB1YmxpYyAkcmVtb3ZlID0gcmVtb3ZlO1xuICAgICAgcHVibGljICRkZWxldGUgPSByZW1vdmU7XG4gICAgICBwdWJsaWMgJHR5cGUgPSB0eXBlO1xuICAgICAgcHVibGljICRyZXNldCA9IHJlc2V0O1xuICAgICAgcHVibGljICRyZWZyZXNoID0gcmVmcmVzaDtcbiAgICAgIHB1YmxpYyAkdG9PYmplY3QgPSB0b09iamVjdDtcbiAgICAgIHB1YmxpYyAkdXBkYXRlU2VydmVyID0gdXBkYXRlU2VydmVyO1xuXG4gICAgICBjb25zdHJ1Y3Rvcih2YWw/OiBhbnksIGZyb21Mb2M/OiBib29sZWFuLCBsYXN0UmVxdWVzdGVkPzogTGFzdFJlcXVlc3QpIHtcbiAgICAgICAgbGV0IHJlcyA9IHRoaXM7XG4gICAgICAgIHRoaXMuJGRlbGV0ZWQgPSBmYWxzZTtcbiAgICAgICAgdGhpcy4kZGVmZXJyZWQgPSBuZXcgdXRpbHMuRGVmZXJyZWQoKTtcbiAgICAgICAgdGhpcy4kcHJvbWlzZSA9IHRoaXMuJGRlZmVycmVkLnByb21pc2U7IC8vIEFuIGluaXRpYWwgcHJvbWlzZSBmb3Igb3VyIGluaXRpYWxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZldGNoIG9yIGNyZWF0ZSBvZiBkYXRhXG4gICAgICAgIHRoaXMuJHJlc29sdmVkID0gZmFsc2U7IC8vIEhhdmUgd2UgaGFkIGFuIGluaXRpYWwgcmVzb2x1dGlvbiBvZiB0aGUgcHJvbWlzZVxuICAgICAgICB0aGlzLiRjcmVhdGVkID0gZmFsc2U7IC8vIEdvZXMgdHJ1ZSBvbiBhbiBpbml0aWFsIHNhdmVcbiAgICAgICAgdGhpcy4kc3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3QodGhpcyk7XG4gICAgICAgIHRoaXMuJHJlc29sdmVkU3ViamVjdCA9IHV0aWxzLmNvbnZlcnRUb1Jlc29sdmVkU3ViamVjdCh0aGlzLiRzdWJqZWN0LCB0aGlzLiRwcm9taXNlKTtcblxuICAgICAgICAvLyBJZiB3ZSd2ZSBiZWVuIGdpdmVuIHZhbHVlcyBwdXQgdGhlbSBvblxuICAgICAgICBpZiAodmFsKSB7XG4gICAgICAgICAgbGV0IHByb3BzID0gZnJvbUxvYyA/IHZhbC4kdG9PYmplY3QoKSA6IHZhbDtcbiAgICAgICAgICBmb3IgKGxldCBrZXkgb2YgT2JqZWN0LmtleXMocHJvcHMpKSB7XG4gICAgICAgICAgICByZXNba2V5XSA9IHByb3BzW2tleV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBsb2NhbCByZXNvdXJjZVxuICAgICAgICBpZiAoZnJvbUxvYykge1xuICAgICAgICAgIHRoaXMuJGxvYyA9IHZhbDtcbiAgICAgICAgICB0aGlzLiRsb2MuJG1vZCA9IHRoaXM7XG5cbiAgICAgICAgICAvLyBSZXNvbHZlIHRoZSBwcm9taXNlIG9uY2UgdGhlIGxvY2FsIGNvcHkgaGFzIHJlc29sdmVkXG4gICAgICAgICAgdGhpcy4kbG9jLiRwcm9taXNlLnRoZW4oZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZiAoIXJlcy4kcmVzb2x2ZWQpIHtcbiAgICAgICAgICAgICAgcmVzLiRkZWZlcnJlZC5yZXNvbHZlKHJlcyk7XG4gICAgICAgICAgICAgIHJlcy4kcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX2lkKSB7XG4gICAgICAgICAgLy8gV2UgaGF2ZSBhbiBpZCAtIHNvIHdlIHBlcnNpc3QgZG93blxuICAgICAgICAgIHRoaXMuJGxvYyA9IG5ldyAoPGFueT4gTG9jYWxSZXNvdXJjZSkodmFsLCBmYWxzZSwgdGhpcywgbGFzdFJlcXVlc3RlZCk7XG5cbiAgICAgICAgICAvLyBXZSBpbW1lZGlhdGVseSByZXNvbHZlIG91ciBwcm9taXNlIHNpbmNlIHdlIGhhdmUgZGF0YVxuICAgICAgICAgIHRoaXMuJGRlZmVycmVkLnJlc29sdmUodGhpcyk7XG4gICAgICAgICAgdGhpcy4kcmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIC8vIERvbid0IGFkZCBpbiB0aGUgdmFsdWVzIHVudGlsIHdlIHNhdmVcbiAgICAgICAgICB0aGlzLiRsb2MgPSBuZXcgKDxhbnk+IExvY2FsUmVzb3VyY2UpKG51bGwsIGZhbHNlLCB0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuJGlkID0gdGhpcy4kbG9jLiRpZDtcbiAgICAgICAgX3Jlc0Zyb21Mb2NhbFt0aGlzLiRpZF0gPSB0aGlzO1xuXG4gICAgICAgIC8vIElmIHdlIGhhdmUgYW4gaWQgdGhlbiBhZGQgdXMgdG8gdGhlIHN0b3JlXG4gICAgICAgIGlmICh0aGlzLl9pZCkge1xuICAgICAgICAgIGFkZGVkUmVzb3VyY2UodGhpcy5faWQsIHRoaXMpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTGlzdGVuIGZvciBjaGFuZ2VzIG9uIHRoZSBsb2NhbCByZXNvdXJjZVxuICAgICAgICB0aGlzLiRsb2MuJGVtaXR0ZXIub24oJ3VwZGF0ZScsIGZ1bmN0aW9uKG5ld1ZhbCwgb2xkVmFsKSB7XG4gICAgICAgICAgdXBkYXRlZExvY2FsKHJlcywgbmV3VmFsLCBvbGRWYWwpO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBUcmlnZ2VyIGFueSBwbHVnaW5zXG4gICAgZm9yIChsZXQgcGx1Z2luIG9mIHBsdWdpbnMpIHtcbiAgICAgIHBsdWdpbihSZXNvdXJjZSwgcm9vdEtleSk7XG4gICAgfVxuXG4gICAgaW5oZXJpdEV2ZW50RW1pdHRlcihSZXNvdXJjZSwgZW1pdHRlcik7XG5cbiAgICByZXR1cm4gUmVzb3VyY2U7XG4gIH07XG5cbiAgUmVzb3VyY2VGYWN0b3J5LkNoYWluID0gQ2hhaW47XG4gIHJldHVybiBSZXNvdXJjZUZhY3Rvcnk7XG59XG5cbmZ1bmN0aW9uIGluaGVyaXRFdmVudEVtaXR0ZXIob2JqOiBhbnksIGVtaXR0ZXI6IEV2ZW50RW1pdHRlcikge1xuICBsZXQgcHJvcHMgPSBbXG4gICAgJ2Rpc3Bvc2UnLFxuICAgICdhZGRMaXN0ZW5lcicsXG4gICAgJ2VtaXQnLFxuICAgICdsaXN0ZW4nLFxuICAgICdvZmYnLFxuICAgICdvbicsXG4gICAgJ29uY2UnLFxuICAgICdyZW1vdmVMaXN0ZW5lcicsXG4gIF07XG5cbiAgLy8gRXZlbnQgZW1pdHRlciAnaW5oZXJpdGFuY2UnXG4gIGZvciAobGV0IHByb3Agb2YgcHJvcHMpIHtcbiAgICBvYmpbcHJvcF0gPSBmdW5jdGlvbigpIHtcbiAgICAgIHJldHVybiBlbWl0dGVyW3Byb3BdLmFwcGx5KGVtaXR0ZXIsIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfVxufVxuIl19