@ortoo/angular-resource
Version:
Magical CRUD resource management for angular
282 lines • 39.7 kB
JavaScript
// 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