168 lines
24 KiB
JavaScript
168 lines
24 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.Database = void 0;
|
|
const entity_1 = require("./entity");
|
|
const relationship_1 = require("./relationship");
|
|
class Database {
|
|
static entitiesOnly(entities) {
|
|
return new Database(entities, relationship_1.NO_RELATIONSHIPS);
|
|
}
|
|
constructor(entities, relationships) {
|
|
this.idCtr = 0;
|
|
this.schema = {
|
|
...entities,
|
|
...relationships({
|
|
relationship: (fromKey, toKey) => (0, relationship_1.relationshipCollection)((id) => this.get(fromKey, id), (id) => this.get(toKey, id)),
|
|
}),
|
|
};
|
|
}
|
|
id() {
|
|
return `${this.idCtr++}`;
|
|
}
|
|
/**
|
|
* Allocate an ID and store
|
|
*/
|
|
allocate(key, entity) {
|
|
return this.store(key, this.e(entity));
|
|
}
|
|
/**
|
|
* Store with a preallocated ID
|
|
*/
|
|
store(key, entity) {
|
|
const coll = this.schema[key];
|
|
coll.add(entity);
|
|
return entity;
|
|
}
|
|
/**
|
|
* Get an entity by key
|
|
*/
|
|
get(key, id) {
|
|
const coll = this.schema[key];
|
|
const ret = coll.entities.get(typeof id === 'string' ? id : id.$ref);
|
|
if (!ret) {
|
|
throw new Error(`No such ${String(key)}: ${id}`);
|
|
}
|
|
return ret;
|
|
}
|
|
/**
|
|
* All entities of a given type
|
|
*/
|
|
all(key) {
|
|
const coll = this.schema[key];
|
|
return Array.from(coll.entities.values());
|
|
}
|
|
/**
|
|
* Lookup an entity by index
|
|
*/
|
|
lookup(key, index, lookup, value) {
|
|
const coll = this.schema[key];
|
|
const ids = coll.indexes[index].lookups[lookup](value);
|
|
return addOnlyMethod(ids.map((id) => coll.entities.get(id)), `${String(key)} with ${String(index)} ${String(lookup)} ${JSON.stringify(value)}`);
|
|
}
|
|
/**
|
|
* Allocate an ID and store if the entity does not yet exist
|
|
*/
|
|
findOrAllocate(key, index, lookup, entity) {
|
|
const res = this.lookup(key, index, lookup, entity[index]);
|
|
if (res.length) {
|
|
return res.only();
|
|
}
|
|
return this.allocate(key, entity);
|
|
}
|
|
link(key, from, to, attributes) {
|
|
const col = this.schema[key];
|
|
col.add(from, to, attributes);
|
|
}
|
|
/**
|
|
* Follow a link
|
|
*/
|
|
follow(key, from) {
|
|
const col = this.schema[key];
|
|
const toLinks = col.forward.get(from.$id) ?? [];
|
|
const ret = toLinks.map((i) => ({ entity: col.toColl(i.$id), ...removeId(i) }));
|
|
return addOnlyMethod(ret, `${String(key)} from ${from}`);
|
|
}
|
|
/**
|
|
* Follow incoming links backwards
|
|
*/
|
|
incoming(key, to) {
|
|
const col = this.schema[key];
|
|
const fromIds = col.backward.get(to.$id) ?? [];
|
|
const ret = fromIds.map((i) => ({ entity: col.fromColl(i.$id), ...removeId(i) }));
|
|
return addOnlyMethod(ret, `${String(key)} to ${to}`);
|
|
}
|
|
e(entity) {
|
|
return {
|
|
$id: this.id(),
|
|
...entity,
|
|
};
|
|
}
|
|
/**
|
|
* Turn the current database collection into something that can be stored.
|
|
*/
|
|
save() {
|
|
return {
|
|
idCtr: this.idCtr,
|
|
schema: dehydrate(this.schema),
|
|
};
|
|
function dehydrate(x) {
|
|
if ((0, entity_1.isEntityCollection)(x)) {
|
|
return x.dehydrate();
|
|
}
|
|
if ((0, relationship_1.isRelationshipCollection)(x)) {
|
|
return x.dehydrate();
|
|
}
|
|
if (Array.isArray(x)) {
|
|
return x.map(dehydrate);
|
|
}
|
|
if (!!x && typeof x === 'object') {
|
|
return Object.fromEntries(Object.entries(x).map(([k, v]) => [k, dehydrate(v)]));
|
|
}
|
|
return x;
|
|
}
|
|
}
|
|
load(db) {
|
|
this.idCtr = db.idCtr;
|
|
hydrate(this.schema, db.schema);
|
|
function hydrate(proto, x) {
|
|
if ((0, entity_1.isEntityCollection)(proto)) {
|
|
proto.hydrateFrom(x);
|
|
}
|
|
if ((0, relationship_1.isRelationshipCollection)(proto)) {
|
|
proto.hydrateFrom(x);
|
|
}
|
|
if (Array.isArray(x)) {
|
|
x.forEach(hydrate);
|
|
}
|
|
if (!!proto && typeof proto === 'object' && !!x && typeof x === 'object') {
|
|
for (const [k, v] of Object.entries(proto)) {
|
|
const dehydratedData = x[k];
|
|
if (dehydratedData !== undefined) {
|
|
// May be missing if this is from a database created from an old version of the schema
|
|
hydrate(v, dehydratedData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
exports.Database = Database;
|
|
function removeId(x) {
|
|
const ret = { ...x };
|
|
delete ret.$id;
|
|
return ret;
|
|
}
|
|
function addOnlyMethod(xs, description) {
|
|
return Object.defineProperties(xs, {
|
|
only: {
|
|
enumerable: false,
|
|
value: () => {
|
|
if (xs.length !== 1) {
|
|
throw new Error(`Expected exactly 1 ${description}, found ${xs.length}`);
|
|
}
|
|
return xs[0];
|
|
},
|
|
},
|
|
});
|
|
}
|
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YWJhc2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZGF0YWJhc2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEscUNBQXVHO0FBQ3ZHLGlEQU13QjtBQVN4QixNQUFhLFFBQVE7SUFDWixNQUFNLENBQUMsWUFBWSxDQUFvQixRQUFZO1FBQ3hELE9BQU8sSUFBSSxRQUFRLENBQUMsUUFBUSxFQUFFLCtCQUFnQixDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUtELFlBQVksUUFBWSxFQUFFLGFBQWtEO1FBRnBFLFVBQUssR0FBRyxDQUFDLENBQUM7UUFHaEIsSUFBSSxDQUFDLE1BQU0sR0FBRztZQUNaLEdBQUcsUUFBUTtZQUNYLEdBQUcsYUFBYSxDQUFDO2dCQUNmLFlBQVksRUFBRSxDQUFDLE9BQU8sRUFBRSxLQUFLLEVBQUUsRUFBRSxDQUMvQixJQUFBLHFDQUFzQixFQUNwQixDQUFDLEVBQUUsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLEVBQzdCLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FDNUI7YUFDSixDQUFDO1NBQ0gsQ0FBQztJQUNKLENBQUM7SUFFTSxFQUFFO1FBQ1AsT0FBTyxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDO0lBQzNCLENBQUM7SUFFRDs7T0FFRztJQUNJLFFBQVEsQ0FBcUIsR0FBTSxFQUFFLE1BQWdDO1FBQzFFLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNJLEtBQUssQ0FBcUIsR0FBTSxFQUFFLE1BQXlCO1FBQ2hFLE1BQU0sSUFBSSxHQUEwQixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBUSxDQUFD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LENBQUMsQ0FBQyxDQUFDO1lBQ2YsQ0FBQztTQUNGO0tBQ0YsQ0FBUSxDQUFDO0FBQ1osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEVudGl0eSwgRW50aXR5Q29sbGVjdGlvbiwgRW50aXR5SW5kZXgsIGlzRW50aXR5Q29sbGVjdGlvbiwgUGxhaW4sIFJlZmVyZW5jZSB9IGZyb20gJy4vZW50aXR5JztcbmltcG9ydCB7XG4gIGlzUmVsYXRpb25zaGlwQ29sbGVjdGlvbixcbiAgTk9fUkVMQVRJT05TSElQUyxcbiAgUmVsYXRpb25zaGlwLFxuICByZWxhdGlvbnNoaXBDb2xsZWN0aW9uLFxuICBSZWxhdGlvbnNoaXBDb2xsZWN0aW9uLFxufSBmcm9tICcuL3JlbGF0aW9uc2hpcCc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmVsYXRpb25zaGlwc0J1aWxkZXI8RVMgZXh0ZW5kcyBvYmplY3Q+IHtcbiAgcmVsYXRpb25zaGlwPFIgZXh0ZW5kcyBSZWxhdGlvbnNoaXA8YW55LCBhbnksIGFueT4+KFxuICAgIGZyb21LZXk6IEtleXNGb3I8RVMsIEVudGl0eUNvbGxlY3Rpb248UlsnZnJvbSddLCBhbnk+PixcbiAgICB0b0tleTogS2V5c0ZvcjxFUywgRW50aXR5Q29sbGVjdGlvbjxSWyd0byddLCBhbnk+PixcbiAgKTogUmVsYXRpb25zaGlwQ29sbGVjdGlvbjxSPjtcbn1cblxuZXhwb3J0IGNsYXNzIERhdGFiYXNlPEVTIGV4dGVuZHMgb2JqZWN0LCBSUyBleHRlbmRzIG9iamVjdD4ge1xuICBwdWJsaWMgc3RhdGljIGVudGl0aWVzT25seTxFUyBleHRlbmRzIG9iamVjdD4oZW50aXRpZXM6IEVTKTogRGF0YWJhc2U8RVMsIHt9PiB7XG4gICAgcmV0dXJuIG5ldyBEYXRhYmFzZShlbnRpdGllcywgTk9fUkVMQVRJT05TSElQUyk7XG4gIH1cblxuICBwcml2YXRlIHJlYWRvbmx5IHNjaGVtYTogRVMgJiBSUztcbiAgcHJpdmF0ZSBpZEN0ciA9IDA7XG5cbiAgY29uc3RydWN0b3IoZW50aXRpZXM6IEVTLCByZWxhdGlvbnNoaXBzOiAoeDogUmVsYXRpb25zaGlwc0J1aWxkZXI8RVM+KSA9PiBSUykge1xuICAgIHRoaXMuc2NoZW1hID0ge1xuICAgICAgLi4uZW50aXRpZXMsXG4gICAgICAuLi5yZWxhdGlvbnNoaXBzKHtcbiAgICAgICAgcmVsYXRpb25zaGlwOiAoZnJvbUtleSwgdG9LZXkpID0+XG4gICAgICAgICAgcmVsYXRpb25zaGlwQ29sbGVjdGlvbihcbiAgICAgICAgICAgIChpZCkgPT4gdGhpcy5nZXQoZnJvbUtleSwgaWQpLFxuICAgICAgICAgICAgKGlkKSA9PiB0aGlzLmdldCh0b0tleSwgaWQpLFxuICAgICAgICAgICksXG4gICAgICB9KSxcbiAgICB9O1xuICB9XG5cbiAgcHVibGljIGlkKCkge1xuICAgIHJldHVybiBgJHt0aGlzLmlkQ3RyKyt9YDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvY2F0ZSBhbiBJRCBhbmQgc3RvcmVcbiAgICovXG4gIHB1YmxpYyBhbGxvY2F0ZTxLIGV4dGVuZHMga2V5b2YgRVM+KGtleTogSywgZW50aXR5OiBQbGFpbjxFbnRpdHlUeXBlPEVTW0tdPj4pOiBFbnRpdHlUeXBlPEVTW0tdPiB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUoa2V5LCB0aGlzLmUoZW50aXR5KSk7XG4gIH1cblxuICAvKipcbiAgICogU3RvcmUgd2l0aCBhIHByZWFsbG9jYXRlZCBJRFxuICAgKi9cbiAgcHVibGljIHN0b3JlPEsgZXh0ZW5kcyBrZXlvZiBFUz4oa2V5OiBLLCBlbnRpdHk6IEVudGl0eVR5cGU8RVNbS10+KTogRW50aXR5VHlwZTxFU1tLXT4ge1xuICAgIGNvbnN0IGNvbGw6IEVudGl0eUNvbGxlY3Rpb248YW55PiA9IHRoaXMuc2NoZW1hW2tleV0gYXMgYW55O1xuICAgIGNvbGwuYWRkKGVudGl0eSk7XG4gICAgcmV0dXJuIGVudGl0eSBhcyBhbnk7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGFuIGVudGl0eSBieSBrZXlcbiAgICovXG4gIHB1YmxpYyBnZXQ8SyBleHRlbmRzIGtleW9mIEVTPihrZXk6IEssIGlkOiBzdHJpbmcgfCBSZWZlcmVuY2U8RW50aXR5VHlwZTxFU1tLXT4+KTogRW50aXR5VHlwZTxFU1tLXT4ge1xuICAgIGNvbnN0IGNvbGw6IEVudGl0eUNvbGxlY3Rpb248YW55PiA9IHRoaXMuc2NoZW1hW2tleV0gYXMgYW55O1xuICAgIGNvbnN0IHJldCA9IGNvbGwuZW50aXRpZXMuZ2V0KHR5cGVvZiBpZCA9PT0gJ3N0cmluZycgPyBpZCA6IGlkLiRyZWYpO1xuICAgIGlmICghcmV0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHN1Y2ggJHtTdHJpbmcoa2V5KX06ICR7aWR9YCk7XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICAvKipcbiAgICogQWxsIGVudGl0aWVzIG9mIGEgZ2l2ZW4gdHlwZVxuICAgKi9cbiAgcHVibGljIGFsbDxLIGV4dGVuZHMga2V5b2YgRVM+KGtleTogSyk6IEFycmF5PEVudGl0eVR5cGU8RVNbS10+PiB7XG4gICAgY29uc3QgY29sbDogRW50aXR5Q29sbGVjdGlvbjxhbnk+ID0gdGhpcy5zY2hlbWFba2V5XSBhcyBhbnk7XG4gICAgcmV0dXJuIEFycmF5LmZyb20oY29sbC5lbnRpdGllcy52YWx1ZXMoKSk7XG4gIH1cblxuICAvKipcbiAgICogTG9va3VwIGFuIGVudGl0eSBieSBpbmRleFxuICAgKi9cbiAgcHVibGljIGxvb2t1cDxLIGV4dGVuZHMga2V5b2YgRVMsIEkgZXh0ZW5kcyBJbmRleE5hbWVzT2Y8RVNbS10+PihcbiAgICBrZXk6IEssXG4gICAgaW5kZXg6IEksXG4gICAgbG9va3VwOiBJbmRleE9mPEVTW0tdLCBJPlsnbG9va3VwcyddLFxuICAgIHZhbHVlOiBJbmRleE9mPEVTW0tdLCBJPlsndmFsdWVUeXBlJ10sXG4gICk6IFJpY2hSZWFkb25seUFycmF5PEVudGl0eVR5cGU8RVNbS10+PiB7XG4gICAgY29uc3QgY29sbDogRW50aXR5Q29sbGVjdGlvbjxhbnk+ID0gdGhpcy5zY2hlbWFba2V5XSBhcyBhbnk7XG4gICAgY29uc3QgaWRzID0gKGNvbGwuaW5kZXhlcyBhcyBhbnkpW2luZGV4XS5sb29rdXBzW2xvb2t1cF0odmFsdWUpO1xuICAgIHJldHVybiBhZGRPbmx5TWV0aG9kKFxuICAgICAgaWRzLm1hcCgoaWQ6IHN0cmluZykgPT4gY29sbC5lbnRpdGllcy5nZXQoaWQpKSxcbiAgICAgIGAke1N0cmluZyhrZXkpfSB3aXRoICR7U3RyaW5nKGluZGV4KX0gJHtTdHJpbmcobG9va3VwKX0gJHtKU09OLnN0cmluZ2lmeSh2YWx1ZSl9YCxcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEFsbG9jYXRlIGFuIElEIGFuZCBzdG9yZSBpZiB0aGUgZW50aXR5IGRvZXMgbm90IHlldCBleGlzdFxuICAgKi9cbiAgcHVibGljIGZpbmRPckFsbG9jYXRlPEsgZXh0ZW5kcyBrZXlvZiBFUywgSSBleHRlbmRzIGtleW9mIFBsYWluPEVudGl0eVR5cGU8RVNbS10+PiAmIEluZGV4TmFtZXNPZjxFU1tLXT4+KFxuICAgIGtleTogSyxcbiAgICBpbmRleDogSSxcbiAgICBsb29rdXA6IEluZGV4T2Y8RVNbS10sIEk+Wydsb29rdXBzJ10sXG4gICAgZW50aXR5OiBQbGFpbjxFbnRpdHlUeXBlPEVTW0tdPj4sXG4gICk6IEVudGl0eVR5cGU8RVNbS10+IHtcbiAgICBjb25zdCByZXMgPSB0aGlzLmxvb2t1cChrZXksIGluZGV4LCBsb29rdXAsIGVudGl0eVtpbmRleF0pO1xuICAgIGlmIChyZXMubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gcmVzLm9ubHkoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuYWxsb2NhdGUoa2V5LCBlbnRpdHkpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlY29yZCBhIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHR3byBlbnRpdGllc1xuICAgKlxuICAgKiBPdmVybG9hZCB0byBhY2NvdW50IGZvciB3aGV0aGVyIHdlIGhhdmUgYXR0cmlidXRlcyBvciBub3QuXG4gICAqL1xuICBwdWJsaWMgbGluazxLIGV4dGVuZHMgUmVsV0F0dHJzPFJTPj4oXG4gICAga2V5OiBLLFxuICAgIGZyb206IFJlbFR5cGU8UlNbS10+Wydmcm9tJ10sXG4gICAgdG86IFJlbFR5cGU8UlNbS10+Wyd0byddLFxuICAgIGF0dHJpYnV0ZXM6IFJlbFR5cGU8UlNbS10+WydhdHRyJ10sXG4gICk6IHZvaWQ7XG4gIHB1YmxpYyBsaW5rPEsgZXh0ZW5kcyBSZWxXb0F0dHJzPFJTPj4oa2V5OiBLLCBmcm9tOiBSZWxUeXBlPFJTW0tdPlsnZnJvbSddLCB0bzogUmVsVHlwZTxSU1tLXT5bJ3RvJ10pOiB2b2lkO1xuICBwdWJsaWMgbGluazxLIGV4dGVuZHMga2V5b2YgUlM+KFxuICAgIGtleTogSyxcbiAgICBmcm9tOiBSZWxUeXBlPFJTW0tdPlsnZnJvbSddLFxuICAgIHRvOiBSZWxUeXBlPFJTW0tdPlsndG8nXSxcbiAgICBhdHRyaWJ1dGVzPzogUmVsVHlwZTxSU1tLXT5bJ2F0dHInXSxcbiAgKSB7XG4gICAgY29uc3QgY29sOiBSZWxhdGlvbnNoaXBDb2xsZWN0aW9uPGFueT4gPSB0aGlzLnNjaGVtYVtrZXldIGFzIGFueTtcbiAgICBjb2wuYWRkKGZyb20sIHRvLCBhdHRyaWJ1dGVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGb2xsb3cgYSBsaW5rXG4gICAqL1xuICBwdWJsaWMgZm9sbG93PEsgZXh0ZW5kcyBrZXlvZiBSUz4oXG4gICAga2V5OiBLLFxuICAgIGZyb206IFJlbFR5cGU8UlNbS10+Wydmcm9tJ10sXG4gICk6IFJpY2hSZWFkb25seUFycmF5PExpbms8UmVsVHlwZTxSU1tLXT5bJ3RvJ10sIFJlbFR5cGU8UlNbS10+WydhdHRyJ10+PiB7XG4gICAgY29uc3QgY29sOiBSZWxhdGlvbnNoaXBDb2xsZWN0aW9uPGFueT4gPSB0aGlzLnNjaGVtYVtrZXldIGFzIGFueTtcbiAgICBjb25zdCB0b0xpbmtzID0gY29sLmZvcndhcmQuZ2V0KGZyb20uJGlkKSA/PyBbXTtcbiAgICBjb25zdCByZXQgPSB0b0xpbmtzLm1hcCgoaSkgPT4gKHsgZW50aXR5OiBjb2wudG9Db2xsKGkuJGlkKSwgLi4ucmVtb3ZlSWQoaSkgfSBhcyBhbnkpKTtcblxuICAgIHJldHVybiBhZGRPbmx5TWV0aG9kKHJldCwgYCR7U3RyaW5nKGtleSl9IGZyb20gJHtmcm9tfWApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvbGxvdyBpbmNvbWluZyBsaW5rcyBiYWNrd2FyZHNcbiAgICovXG4gIHB1YmxpYyBpbmNvbWluZzxLIGV4dGVuZHMga2V5b2YgUlM+KFxuICAgIGtleTogSyxcbiAgICB0bzogUmVsVHlwZTxSU1tLXT5bJ3RvJ10sXG4gICk6IFJpY2hSZWFkb25seUFycmF5PExpbms8UmVsVHlwZTxSU1tLXT5bJ2Zyb20nXSwgUmVsVHlwZTxSU1tLXT5bJ2F0dHInXT4+IHtcbiAgICBjb25zdCBjb2w6IFJlbGF0aW9uc2hpcENvbGxlY3Rpb248YW55PiA9IHRoaXMuc2NoZW1hW2tleV0gYXMgYW55O1xuICAgIGNvbnN0IGZyb21JZHMgPSBjb2wuYmFja3dhcmQuZ2V0KHRvLiRpZCkgPz8gW107XG4gICAgY29uc3QgcmV0ID0gZnJvbUlkcy5tYXAoKGkpID0+ICh7IGVudGl0eTogY29sLmZyb21Db2xsKGkuJGlkKSwgLi4ucmVtb3ZlSWQoaSkgfSBhcyBhbnkpKTtcblxuICAgIHJldHVybiBhZGRPbmx5TWV0aG9kKHJldCwgYCR7U3RyaW5nKGtleSl9IHRvICR7dG99YCk7XG4gIH1cblxuICBwdWJsaWMgZTxFIGV4dGVuZHMgRW50aXR5PihlbnRpdHk6IFBsYWluPEU+KTogRSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICRpZDogdGhpcy5pZCgpLFxuICAgICAgLi4uZW50aXR5LFxuICAgIH0gYXMgYW55O1xuICB9XG5cbiAgLyoqXG4gICAqIFR1cm4gdGhlIGN1cnJlbnQgZGF0YWJhc2UgY29sbGVjdGlvbiBpbnRvIHNvbWV0aGluZyB0aGF0IGNhbiBiZSBzdG9yZWQuXG4gICAqL1xuICBwdWJsaWMgc2F2ZSgpOiBEZWh5ZHJhdGVkRGF0YWJhc2Uge1xuICAgIHJldHVybiB7XG4gICAgICBpZEN0cjogdGhpcy5pZEN0cixcbiAgICAgIHNjaGVtYTogZGVoeWRyYXRlKHRoaXMuc2NoZW1hKSxcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gZGVoeWRyYXRlKHg6IHVua25vd24pOiBhbnkge1xuICAgICAgaWYgKGlzRW50aXR5Q29sbGVjdGlvbih4KSkge1xuICAgICAgICByZXR1cm4geC5kZWh5ZHJhdGUoKTtcbiAgICAgIH1cbiAgICAgIGlmIChpc1JlbGF0aW9uc2hpcENvbGxlY3Rpb24oeCkpIHtcbiAgICAgICAgcmV0dXJuIHguZGVoeWRyYXRlKCk7XG4gICAgICB9XG4gICAgICBpZiAoQXJyYXkuaXNBcnJheSh4KSkge1xuICAgICAgICByZXR1cm4geC5tYXAoZGVoeWRyYXRlKTtcbiAgICAgIH1cbiAgICAgIGlmICghIXggJiYgdHlwZW9mIHggPT09ICdvYmplY3QnKSB7XG4gICAgICAgIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoeCkubWFwKChbaywgdl0pID0+IFtrLCBkZWh5ZHJhdGUodildKSk7XG4gICAgICB9XG4gICAgICByZXR1cm4geDtcbiAgICB9XG4gIH1cblxuICBwdWJsaWMgbG9hZChkYjogRGVoeWRyYXRlZERhdGFiYXNlKSB7XG4gICAgdGhpcy5pZEN0ciA9IGRiLmlkQ3RyO1xuICAgIGh5ZHJhdGUodGhpcy5zY2hlbWEsIGRiLnNjaGVtYSk7XG5cbiAgICBmdW5jdGlvbiBoeWRyYXRlKHByb3RvOiB1bmtub3duLCB4OiB1bmtub3duKTogdm9pZCB7XG4gICAgICBpZiAoaXNFbnRpdHlDb2xsZWN0aW9uKHByb3RvKSkge1xuICAgICAgICBwcm90by5oeWRyYXRlRnJvbSh4KTtcbiAgICAgIH1cbiAgICAgIGlmIChpc1JlbGF0aW9uc2hpcENvbGxlY3Rpb24ocHJvdG8pKSB7XG4gICAgICAgIHByb3RvLmh5ZHJhdGVGcm9tKHgpO1xuICAgICAgfVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoeCkpIHtcbiAgICAgICAgeC5mb3JFYWNoKGh5ZHJhdGUpO1xuICAgICAgfVxuICAgICAgaWYgKCEhcHJvdG8gJiYgdHlwZW9mIHByb3RvID09PSAnb2JqZWN0JyAmJiAhIXggJiYgdHlwZW9mIHggPT09ICdvYmplY3QnKSB7XG4gICAgICAgIGZvciAoY29uc3QgW2ssIHZdIG9mIE9iamVjdC5lbnRyaWVzKHByb3RvKSkge1xuICAgICAgICAgIGNvbnN0IGRlaHlkcmF0ZWREYXRhID0gKHggYXMgYW55KVtrXTtcbiAgICAgICAgICBpZiAoZGVoeWRyYXRlZERhdGEgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gTWF5IGJlIG1pc3NpbmcgaWYgdGhpcyBpcyBmcm9tIGEgZGF0YWJhc2UgY3JlYXRlZCBmcm9tIGFuIG9sZCB2ZXJzaW9uIG9mIHRoZSBzY2hlbWFcbiAgICAgICAgICAgIGh5ZHJhdGUodiwgZGVoeWRyYXRlZERhdGEpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5pbnRlcmZhY2UgRGVoeWRyYXRlZERhdGFiYXNlIHtcbiAgcmVhZG9ubHkgaWRDdHI6IG51bWJlcjtcbiAgcmVhZG9ubHkgc2NoZW1hOiBhbnk7XG59XG5cbmZ1bmN0aW9uIHJlbW92ZUlkPEEgZXh0ZW5kcyBvYmplY3Q+KHg6IEEpOiBPbWl0PEEsICckaWQnPiB7XG4gIGNvbnN0IHJldCA9IHsgLi4ueCB9O1xuICBkZWxldGUgKHJldCBhcyBhbnkpLiRpZDtcbiAgcmV0dXJuIHJldDtcbn1cblxuZXhwb3J0IHR5cGUgTGluazxFLCBBPiA9IHsgcmVhZG9ubHkgZW50aXR5OiBFIH0gJiBBO1xuXG50eXBlIFJlbFdBdHRyczxSUz4gPSB7IFtLIGluIGtleW9mIFJTXToge30gZXh0ZW5kcyBSZWxUeXBlPFJTW0tdPlsnYXR0ciddID8gbmV2ZXIgOiBLIH1ba2V5b2YgUlNdO1xudHlwZSBSZWxXb0F0dHJzPFJTPiA9IHsgW0sgaW4ga2V5b2YgUlNdOiB7fSBleHRlbmRzIFJlbFR5cGU8UlNbS10+WydhdHRyJ10gPyBLIDogbmV2ZXIgfVtrZXlvZiBSU107XG5cbi8vIE5lY2Vzc2FyeSBiZWNhdXNlIHRoaXMgdHlwZSBtaWdodCBiZSBhIHVuaW9uXG50eXBlIEluZGV4TmFtZXNPZjxBPiA9IEEgZXh0ZW5kcyBFbnRpdHlDb2xsZWN0aW9uPGFueT4gPyBLZXlzT2ZVbmlvbjxBWydpbmRleGVzJ10+IDogbmV2ZXI7XG5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcmV0dGllci9wcmV0dGllclxudHlwZSBJbmRleE9mPEVDLCBJIGV4dGVuZHMgSW5kZXhOYW1lc09mPEVDPj4gPVxuICBFQyBleHRlbmRzIEVudGl0eUNvbGxlY3Rpb248YW55PlxuICA/IEVDWydpbmRleGVzJ11bSV0gZXh0ZW5kcyBFbnRpdHlJbmRleDxhbnksIGluZmVyIEluZGV4VHlwZT5cbiAgICA/IHtcbiAgICAgICAgdmFsdWVUeXBlOiBJbmRleFR5cGU7XG4gICAgICAgIGxvb2t1cHM6IGtleW9mIEVDWydpbmRleGVzJ11bSV1bJ2xvb2t1cHMnXTtcbiAgICAgIH1cbiAgICA6IG5ldmVyXG4gIDogbmV2ZXI7XG5cbnR5cGUgRW50aXR5VHlwZTxBPiA9IEEgZXh0ZW5kcyBFbnRpdHlDb2xsZWN0aW9uPGluZmVyIEI+ID8gQiA6IG5ldmVyO1xuXG50eXBlIFJlbFR5cGU8QT4gPSBBIGV4dGVuZHMgUmVsYXRpb25zaGlwQ29sbGVjdGlvbjxpbmZlciBSPiA/IFIgOiBuZXZlcjtcblxudHlwZSBSZXNvbHZlVW5pb248VD4gPSBUIGV4dGVuZHMgVCA/IFQgOiBuZXZlcjtcblxudHlwZSBLZXlzT2ZVbmlvbjxUPiA9IGtleW9mIFJlc29sdmVVbmlvbjxUPjtcblxuZXhwb3J0IHR5cGUgRW50aXRpZXNPZjxEQj4gPSBEQiBleHRlbmRzIERhdGFiYXNlPGluZmVyIEVTLCBhbnk+ID8geyBbayBpbiBrZXlvZiBFU106IEVudGl0eVR5cGU8RVNba10+IH0gOiB7fTtcblxuZXhwb3J0IGludGVyZmFjZSBSaWNoUmVhZG9ubHlBcnJheTxBPiBleHRlbmRzIFJlYWRvbmx5QXJyYXk8QT4ge1xuICAvKipcbiAgICogUmV0dXJuIHRoZSBmaXJzdCBhbmQgb25seSBlbGVtZW50LCB0aHJvd2luZyBpZiB0aGVyZSBhcmUgIT0gMSBlbGVtZW50c1xuICAgKi9cbiAgb25seSgpOiBBO1xufVxuXG5mdW5jdGlvbiBhZGRPbmx5TWV0aG9kPEE+KHhzOiBBW10sIGRlc2NyaXB0aW9uOiBzdHJpbmcpOiBSaWNoUmVhZG9ubHlBcnJheTxBPiB7XG4gIHJldHVybiBPYmplY3QuZGVmaW5lUHJvcGVydGllcyh4cywge1xuICAgIG9ubHk6IHtcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgdmFsdWU6ICgpID0+IHtcbiAgICAgICAgaWYgKHhzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgZXhhY3RseSAxICR7ZGVzY3JpcHRpb259LCBmb3VuZCAke3hzLmxlbmd0aH1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geHNbMF07XG4gICAgICB9LFxuICAgIH0sXG4gIH0pIGFzIGFueTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGtleXMgb2YgYW4gb2JqZWN0IHRoYXQgbWFwIHRvIGEgcGFydGljdWxhciB0eXBlXG4gKi9cbnR5cGUgS2V5c0ZvcjxPIGV4dGVuZHMgb2JqZWN0LCBUPiA9IHsgW2sgaW4ga2V5b2YgT106IE9ba10gZXh0ZW5kcyBUID8gayA6IG5ldmVyIH1ba2V5b2YgT107XG4iXX0=
|