swaf/dist/db/Model.js

291 lines
37 KiB
JavaScript

var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import MysqlConnectionManager, { query } from "./MysqlConnectionManager";
import Validator from "./Validator";
import Query from "./Query";
import Pagination from "../Pagination";
export default class Model {
constructor(data) {
this.properties = [];
this.relations = {};
this.defineProperty('id', new Validator());
this.defineProperties();
this.updateWithData(data);
}
static getById(id) {
return __awaiter(this, void 0, void 0, function* () {
const cachedModel = ModelCache.get(this.table, id);
if ((cachedModel === null || cachedModel === void 0 ? void 0 : cachedModel.constructor) === this) {
return cachedModel;
}
const models = yield this.models(this.select().where('id', id).first());
return models.length > 0 ? models[0] : null;
});
}
static paginate(request, perPage = 20) {
return __awaiter(this, void 0, void 0, function* () {
let page = request.params.page ? parseInt(request.params.page) : 1;
let query = this.select().limit(perPage, (page - 1) * perPage).withTotalRowCount();
if (request.params.sortBy) {
const dir = request.params.sortDirection;
query = query.sortBy(request.params.sortBy, dir === 'ASC' || dir === 'DESC' ? dir : undefined);
}
else {
query = query.sortBy('id');
}
const models = yield this.models(query);
// @ts-ignore
models.pagination = new Pagination(models, page, perPage, models.totalCount);
return models;
});
}
static select(...fields) {
return Query.select(this.table, ...fields);
}
static update(data) {
return Query.update(this.table, data);
}
static delete() {
return Query.delete(this.table);
}
static models(query) {
return __awaiter(this, void 0, void 0, function* () {
const results = yield query.execute();
const models = [];
const factory = this.getFactory();
for (const result of results.results) {
const cachedModel = ModelCache.get(this.table, result.id);
if (cachedModel && cachedModel.constructor === this) {
cachedModel.updateWithData(result);
models.push(cachedModel);
}
else {
models.push(factory(result));
}
}
// @ts-ignore
models.totalCount = results.foundRows;
return models;
});
}
static loadRelation(models, relation, model, localField) {
return __awaiter(this, void 0, void 0, function* () {
const loadMap = {};
const ids = models.map(m => {
m.relations[relation] = null;
if (m[localField])
loadMap[m[localField]] = v => m.relations[relation] = v;
return m[localField];
}).filter(id => id);
for (const v of yield model.models(model.select().whereIn('id', ids))) {
loadMap[v.id](v);
}
});
}
static getFactory(factory) {
if (factory === undefined) {
factory = this.FACTORY;
if (factory === undefined)
factory = data => new this(data);
}
return factory;
}
defineProperty(name, validator) {
if (validator === undefined)
validator = new Validator();
if (validator instanceof RegExp) {
const regexp = validator;
validator = new Validator().regexp(regexp);
}
const prop = new ModelProperty(name, validator);
this.properties.push(prop);
Object.defineProperty(this, name, {
get: () => prop.value,
set: (value) => prop.value = value,
});
}
updateWithData(data) {
this.id = data['id'];
for (const prop of this.properties) {
if (data[prop.name] !== undefined) {
this[prop.name] = data[prop.name];
}
}
}
beforeSave(exists, connection) {
return __awaiter(this, void 0, void 0, function* () {
});
}
afterSave() {
return __awaiter(this, void 0, void 0, function* () {
});
}
save(connection, postHook) {
return __awaiter(this, void 0, void 0, function* () {
yield this.validate(false, connection);
const exists = yield this.exists();
let needs_full_update = false;
if (connection) {
needs_full_update = yield this.saveTransaction(connection, exists, needs_full_update);
}
else {
needs_full_update = yield MysqlConnectionManager.wrapTransaction((connection) => __awaiter(this, void 0, void 0, function* () { return this.saveTransaction(connection, exists, needs_full_update); }));
}
const callback = () => __awaiter(this, void 0, void 0, function* () {
if (needs_full_update) {
this.updateWithData((yield this.constructor.select().where('id', this.id).first().execute()).results[0]);
}
if (!exists) {
this.cache();
}
yield this.afterSave();
});
if (connection) {
postHook(callback);
}
else {
yield callback();
}
});
}
saveTransaction(connection, exists, needs_full_update) {
return __awaiter(this, void 0, void 0, function* () {
// Before save
yield this.beforeSave(exists, connection);
if (exists && this.hasOwnProperty('updated_at')) {
this.updated_at = new Date();
}
const props = [];
const values = [];
if (exists) {
for (const prop of this.properties) {
if (prop.value !== undefined) {
props.push(prop.name + '=?');
values.push(prop.value);
}
else {
needs_full_update = true;
}
}
values.push(this.id);
yield query(`UPDATE ${this.table} SET ${props.join(',')} WHERE id=?`, values, connection);
}
else {
const props_holders = [];
for (const prop of this.properties) {
if (prop.value !== undefined) {
props.push(prop.name);
props_holders.push('?');
values.push(prop.value);
}
else {
needs_full_update = true;
}
}
const result = yield query(`INSERT INTO ${this.table} (${props.join(', ')}) VALUES(${props_holders.join(', ')})`, values, connection);
this.id = result.other.insertId;
}
return needs_full_update;
});
}
static get table() {
return this.name
.replace(/(?:^|\.?)([A-Z])/g, (x, y) => '_' + y.toLowerCase())
.replace(/^_/, '')
+ 's';
}
get table() {
// @ts-ignore
return this.constructor.table;
}
exists() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.id)
return false;
const result = yield query(`SELECT 1 FROM ${this.table} WHERE id=? LIMIT 1`, [
this.id,
]);
return result.results.length > 0;
});
}
delete() {
return __awaiter(this, void 0, void 0, function* () {
if (!(yield this.exists()))
throw new Error('This model instance doesn\'t exist in DB.');
yield query(`DELETE FROM ${this.table} WHERE id=?`, [
this.id,
]);
ModelCache.forget(this);
this.id = undefined;
});
}
validate(onlyFormat = false, connection) {
return __awaiter(this, void 0, void 0, function* () {
return yield Promise.all(this.properties.map(prop => prop.validate(onlyFormat, connection)));
});
}
cache() {
ModelCache.cache(this);
}
relation(name) {
if (this.relations[name] === undefined)
throw new Error('Model not loaded');
return this.relations[name];
}
}
class ModelProperty {
constructor(name, validator) {
this.name = name;
this.validator = validator;
}
validate(onlyFormat, connection) {
return __awaiter(this, void 0, void 0, function* () {
return yield this.validator.execute(this.name, this.value, onlyFormat, connection);
});
}
get value() {
return this.val;
}
set value(val) {
this.val = val;
}
}
export class ModelCache {
static cache(instance) {
if (instance.id === undefined)
throw new Error('Cannot cache an instance with an undefined id.');
let tableCache = this.caches[instance.table];
if (!tableCache)
tableCache = this.caches[instance.table] = {};
if (!tableCache[instance.id])
tableCache[instance.id] = instance;
}
static forget(instance) {
if (instance.id === undefined)
throw new Error('Cannot forget an instance with an undefined id.');
let tableCache = this.caches[instance.table];
if (!tableCache)
return;
if (tableCache[instance.id])
delete tableCache[instance.id];
}
static all(table) {
return this.caches[table];
}
static get(table, id) {
const tableCache = this.all(table);
if (!tableCache)
return undefined;
return tableCache[id];
}
}
ModelCache.caches = {};
export const EMAIL_REGEX = /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$/;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiTW9kZWwuanMiLCJzb3VyY2VSb290IjoiLi8iLCJzb3VyY2VzIjpbImRiL01vZGVsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sc0JBQXNCLEVBQUUsRUFBQyxLQUFLLEVBQUMsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RSxPQUFPLFNBQVMsTUFBTSxhQUFhLENBQUM7QUFFcEMsT0FBTyxLQUFLLE1BQU0sU0FBUyxDQUFDO0FBRTVCLE9BQU8sVUFBVSxNQUFNLGVBQWUsQ0FBQztBQUV2QyxNQUFNLENBQUMsT0FBTyxPQUFnQixLQUFLO0lBbUYvQixZQUFtQixJQUFTO1FBTlQsZUFBVSxHQUF5QixFQUFFLENBQUM7UUFDeEMsY0FBUyxHQUFvQyxFQUFFLENBQUM7UUFNN0QsSUFBSSxDQUFDLGNBQWMsQ0FBUyxJQUFJLEVBQUUsSUFBSSxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQ25ELElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQ3hCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDOUIsQ0FBQztJQXRGTSxNQUFNLENBQU8sT0FBTyxDQUFrQixFQUFVOztZQUNuRCxNQUFNLFdBQVcsR0FBRyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDbkQsSUFBSSxDQUFBLFdBQVcsYUFBWCxXQUFXLHVCQUFYLFdBQVcsQ0FBRSxXQUFXLE1BQUssSUFBSSxFQUFFO2dCQUNuQyxPQUFVLFdBQVcsQ0FBQzthQUN6QjtZQUVELE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLE1BQU0sQ0FBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFDO1lBQzNFLE9BQU8sTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENB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QUMsR0FBRyxDQUFDLEtBQWE7UUFHM0IsT0FBTyxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQzlCLENBQUM7SUFFTSxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQWEsRUFBRSxFQUFVO1FBQ3ZDLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsSUFBSSxDQUFDLFVBQVU7WUFBRSxPQUFPLFNBQVMsQ0FBQztRQUNsQyxPQUFPLFVBQVUsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUMxQixDQUFDOztBQWxDdUIsaUJBQU0sR0FJMUIsRUFBRSxDQUFDO0FBaUNYLE1BQU0sQ0FBQyxNQUFNLFdBQVcsR0FBRyx3SUFBd0ksQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLCB7cXVlcnl9IGZyb20gXCIuL015c3FsQ29ubmVjdGlvbk1hbmFnZXJcIjtcbmltcG9ydCBWYWxpZGF0b3IgZnJvbSBcIi4vVmFsaWRhdG9yXCI7XG5pbXBvcnQge0Nvbm5lY3Rpb259IGZyb20gXCJteXNxbFwiO1xuaW1wb3J0IFF1ZXJ5IGZyb20gXCIuL1F1ZXJ5XCI7XG5pbXBvcnQge1JlcXVlc3R9IGZyb20gXCJleHByZXNzXCI7XG5pbXBvcnQgUGFnaW5hdGlvbiBmcm9tIFwiLi4vUGFnaW5hdGlvblwiO1xuXG5leHBvcnQgZGVmYXVsdCBhYnN0cmFjdCBjbGFzcyBNb2RlbCB7XG4gICAgcHVibGljIHN0YXRpYyBhc3luYyBnZXRCeUlkPFQgZXh0ZW5kcyBNb2RlbD4oaWQ6IG51bWJlcik6IFByb21pc2U8VCB8IG51bGw+IHtcbiAgICAgICAgY29uc3QgY2FjaGVkTW9kZWwgPSBNb2RlbENhY2hlLmdldCh0aGlzLnRhYmxlLCBpZCk7XG4gICAgICAgIGlmIChjYWNoZWRNb2RlbD8uY29uc3RydWN0b3IgPT09IHRoaXMpIHtcbiAgICAgICAgICAgIHJldHVybiA8VD5jYWNoZWRNb2RlbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IG1vZGVscyA9IGF3YWl0IHRoaXMubW9kZWxzPFQ+KHRoaXMuc2VsZWN0KCkud2hlcmUoJ2lkJywgaWQpLmZpcnN0KCkpO1xuICAgICAgICByZXR1cm4gbW9kZWxzLmxlbmd0aCA+IDAgPyBtb2RlbHNbMF0gOiBudWxsO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgYXN5bmMgcGFnaW5hdGU8VCBleHRlbmRzIE1vZGVsPihyZXF1ZXN0OiBSZXF1ZXN0LCBwZXJQYWdlOiBudW1iZXIgPSAyMCk6IFByb21pc2U8VFtdPiB7XG4gICAgICAgIGxldCBwYWdlID0gcmVxdWVzdC5wYXJhbXMucGFnZSA/IHBhcnNlSW50KHJlcXVlc3QucGFyYW1zLnBhZ2UpIDogMTtcbiAgICAgICAgbGV0IHF1ZXJ5OiBRdWVyeSA9IHRoaXMuc2VsZWN0KCkubGltaXQocGVyUGFnZSwgKHBhZ2UgLSAxKSAqIHBlclBhZ2UpLndpdGhUb3RhbFJvd0NvdW50KCk7XG4gICAgICAgIGlmIChyZXF1ZXN0LnBhcmFtcy5zb3J0QnkpIHtcbiAgICAgICAgICAgIGNvbnN0IGRpciA9IHJlcXVlc3QucGFyYW1zLnNvcnREaXJlY3Rpb247XG4gICAgICAgICAgICBxdWVyeSA9IHF1ZXJ5LnNvcnRCeShyZXF1ZXN0LnBhcmFtcy5zb3J0QnksIGRpciA9PT0gJ0FTQycgfHwgZGlyID09PSAnREVTQycgPyBkaXIgOiB1bmRlZmluZWQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcXVlcnkgPSBxdWVyeS5zb3J0QnkoJ2lkJyk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgbW9kZWxzID0gYXdhaXQgdGhpcy5tb2RlbHM8VD4ocXVlcnkpO1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIG1vZGVscy5wYWdpbmF0aW9uID0gbmV3IFBhZ2luYXRpb24obW9kZWxzLCBwYWdlLCBwZXJQYWdlLCBtb2RlbHMudG90YWxDb3VudCk7XG4gICAgICAgIHJldHVybiBtb2RlbHM7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0YXRpYyBzZWxlY3QoLi4uZmllbGRzOiBzdHJpbmdbXSk6IFF1ZXJ5IHtcbiAgICAgICAgcmV0dXJuIFF1ZXJ5LnNlbGVjdCh0aGlzLnRhYmxlLCAuLi5maWVsZHMpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGF0aWMgdXBkYXRlKGRhdGE6IHsgW2tleTogc3RyaW5nXTogYW55IH0pOiBRdWVyeSB7XG4gICAgICAgIHJldHVybiBRdWVyeS51cGRhdGUodGhpcy50YWJsZSwgZGF0YSk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIHN0YXRpYyBkZWxldGUoKTogUXVlcnkge1xuICAgICAgICByZXR1cm4gUXVlcnkuZGVsZXRlKHRoaXMudGFibGUpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBzdGF0aWMgYXN5bmMgbW9kZWxzPFQgZXh0ZW5kcyBNb2RlbD4ocXVlcnk6IFF1ZXJ5KTogUHJvbWlzZTxUW10+IHtcbiAgICAgICAgY29uc3QgcmVzdWx0cyA9IGF3YWl0IHF1ZXJ5LmV4ZWN1dGUoKTtcbiAgICAgICAgY29uc3QgbW9kZWxzOiBUW10gPSBbXTtcbiAgICAgICAgY29uc3QgZmFjdG9yeSA9IHRoaXMuZ2V0RmFjdG9yeTxUPigpO1xuICAgICAgICBmb3IgKGNvbnN0IHJlc3VsdCBvZiByZXN1bHRzLnJlc3VsdHMpIHtcbiAgICAgICAgICAgIGNvbnN0IGNhY2hlZE1vZGVsID0gTW9kZWxDYWNoZS5nZXQodGhpcy50YWJsZSwgcmVzdWx0LmlkKTtcbiAgICAgICAgICAgIGlmIChjYWNoZWRNb2RlbCAmJiBjYWNoZWRNb2RlbC5jb25zdHJ1Y3RvciA9PT0gdGhpcykge1xuICAgICAgICAgICAgICAgIGNhY2hlZE1vZGVsLnVwZGF0ZVdpdGhEYXRhKHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgbW9kZWxzLnB1c2goPFQ+Y2FjaGVkTW9kZWwpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtb2RlbHMucHVzaChmYWN0b3J5KHJlc3VsdCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgbW9kZWxzLnRvdGFsQ291bnQgPSByZXN1bHRzLmZvdW5kUm93cztcbiAgICAgICAgcmV0dXJuIG1vZGVscztcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGFzeW5jIGxvYWRSZWxhdGlvbjxUIGV4dGVuZHMgTW9kZWw+KG1vZGVsczogVFtdLCByZWxhdGlvbjogc3RyaW5nLCBtb2RlbDogRnVuY3Rpb24sIGxvY2FsRmllbGQ6IHN0cmluZykge1xuICAgICAgICBjb25zdCBsb2FkTWFwOiB7IFtwOiBudW1iZXJdOiAobW9kZWw6IFQpID0+IHZvaWQgfSA9IHt9O1xuICAgICAgICBjb25zdCBpZHMgPSBtb2RlbHMubWFwKG0gPT4ge1xuICAgICAgICAgICAgbS5yZWxhdGlvbnNbcmVsYXRpb25dID0gbnVsbDtcbiAgICAgICAgICAgIGlmIChtW2xvY2FsRmllbGRdKSBsb2FkTWFwW21bbG9jYWxGaWVsZF1dID0gdiA9PiBtLnJlbGF0aW9uc1tyZWxhdGlvbl0gPSB2O1xuICAgICAgICAgICAgcmV0dXJuIG1bbG9jYWxGaWVsZF07XG4gICAgICAgIH0pLmZpbHRlcihpZCA9PiBpZCk7XG4gICAgICAgIGZvciAoY29uc3QgdiBvZiBhd2FpdCAoPGFueT5tb2RlbCkubW9kZWxzKCg8YW55Pm1vZGVsKS5zZWxlY3QoKS53aGVyZUluKCdpZCcsIGlkcykpKSB7XG4gICAgICAgICAgICBsb2FkTWFwW3YuaWQhXSh2KTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgc3RhdGljIGdldEZhY3Rvcnk8VCBleHRlbmRzIE1vZGVsPihmYWN0b3J5PzogTW9kZWxGYWN0b3J5PFQ+KTogTW9kZWxGYWN0b3J5PFQ+IHtcbiAgICAgICAgaWYgKGZhY3RvcnkgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZmFjdG9yeSA9ICg8YW55PnRoaXMpLkZBQ1RPUlk7XG4gICAgICAgICAgICBpZiAoZmFjdG9yeSA9PT0gdW5kZWZpbmVkKSBmYWN0b3J5ID0gZGF0YSA9PiBuZXcgKDxhbnk+dGhpcykoZGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhY3Rvcnk7XG4gICAgfVxuXG5cbiAgICBwcm90ZWN0ZWQgcmVhZG9ubHkgcHJvcGVydGllczogTW9kZWxQcm9wZXJ0eTxhbnk+W10gPSBbXTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlbGF0aW9uczogeyBbcDogc3RyaW5nXTogKE1vZGVsIHwgbnVsbCkgfSA9IHt9O1xuICAgIHB1YmxpYyBpZD86IG51bWJlcjtcblxuICAgIFtrZXk6IHN0cmluZ106IGFueTtcblxuICAgIHB1YmxpYyBjb25zdHJ1Y3RvcihkYXRhOiBhbnkpIHtcbiAgICAgICAgdGhpcy5kZWZpbmVQcm9wZXJ0eTxudW1iZXI+KCdpZCcsIG5ldyBWYWxpZGF0b3IoKSk7XG4gICAgICAgIHRoaXMuZGVmaW5lUHJvcGVydGllcygpO1xuICAgICAgICB0aGlzLnVwZGF0ZVdpdGhEYXRhKGRhdGEpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhYnN0cmFjdCBkZWZpbmVQcm9wZXJ0aWVzKCk6IHZvaWQ7XG5cbiAgICBwcm90ZWN0ZWQgZGVmaW5lUHJvcGVydHk8VD4obmFtZTogc3RyaW5nLCB2YWxpZGF0b3I/OiBWYWxpZGF0b3I8VD4gfCBSZWdFeHApIHtcbiAgICAgICAgaWYgKHZhbGlkYXRvciA9PT0gdW5kZWZpbmVkKSB2YWxpZGF0b3IgPSBuZXcgVmFsaWRhdG9yKCk7XG4gICAgICAgIGlmICh2YWxpZGF0b3IgaW5zdGFuY2VvZiBSZWdFeHApIHtcbiAgICAgICAgICAgIGNvbnN0IHJlZ2V4cCA9IHZhbGlkYXRvcjtcbiAgICAgICAgICAgIHZhbGlkYXRvciA9IG5ldyBWYWxpZGF0b3IoKS5yZWdleHAocmVnZXhwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByb3AgPSBuZXcgTW9kZWxQcm9wZXJ0eTxUPihuYW1lLCB2YWxpZGF0b3IpO1xuICAgICAgICB0aGlzLnByb3BlcnRpZXMucHVzaChwcm9wKTtcbiAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIG5hbWUsIHtcbiAgICAgICAgICAgIGdldDogKCkgPT4gcHJvcC52YWx1ZSxcbiAgICAgICAgICAgIHNldDogKHZhbHVlOiBUKSA9PiBwcm9wLnZhbHVlID0gdmFsdWUsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlV2l0aERhdGEoZGF0YTogYW55KSB7XG4gICAgICAgIHRoaXMuaWQgPSBkYXRhWydpZCddO1xuXG4gICAgICAgIGZvciAoY29uc3QgcHJvcCBvZiB0aGlzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgIGlmIChkYXRhW3Byb3AubmFtZV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRoaXNbcHJvcC5uYW1lXSA9IGRhdGFbcHJvcC5uYW1lXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBiZWZvcmVTYXZlKGV4aXN0czogYm9vbGVhbiwgY29ubmVjdGlvbjogQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgIH1cblxuICAgIHByb3RlY3RlZCBhc3luYyBhZnRlclNhdmUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHNhdmUoY29ubmVjdGlvbj86IENvbm5lY3Rpb24sIHBvc3RIb29rPzogKGNhbGxiYWNrOiAoKSA9PiBQcm9taXNlPHZvaWQ+KSA9PiB2b2lkKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGF3YWl0IHRoaXMudmFsaWRhdGUoZmFsc2UsIGNvbm5lY3Rpb24pO1xuXG4gICAgICAgIGNvbnN0IGV4aXN0cyA9IGF3YWl0IHRoaXMuZXhpc3RzKCk7XG4gICAgICAgIGxldCBuZWVkc19mdWxsX3VwZGF0ZSA9IGZhbHNlO1xuXG4gICAgICAgIGlmIChjb25uZWN0aW9uKSB7XG4gICAgICAgICAgICBuZWVkc19mdWxsX3VwZGF0ZSA9IGF3YWl0IHRoaXMuc2F2ZVRyYW5zYWN0aW9uKGNvbm5lY3Rpb24sIGV4aXN0cywgbmVlZHNfZnVsbF91cGRhdGUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbmVlZHNfZnVsbF91cGRhdGUgPSBhd2FpdCBNeXNxbENvbm5lY3Rpb25NYW5hZ2VyLndyYXBUcmFuc2FjdGlvbihhc3luYyBjb25uZWN0aW9uID0+IHRoaXMuc2F2ZVRyYW5zYWN0aW9uKGNvbm5lY3Rpb24sIGV4aXN0cywgbmVlZHNfZnVsbF91cGRhdGUpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGNhbGxiYWNrID0gYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgaWYgKG5lZWRzX2Z1bGxfdXBkYXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy51cGRhdGVXaXRoRGF0YSgoYXdhaXQgKDxNb2RlbD48dW5rbm93bj50aGlzLmNvbnN0cnVjdG9yKS5zZWxlY3QoKS53aGVyZSgnaWQnLCB0aGlzLmlkISkuZmlyc3QoKS5leGVjdXRlKCkpLnJlc3VsdHNbMF0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWV4aXN0cykge1xuICAgICAgICAgICAgICAgIHRoaXMuY2FjaGUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYXdhaXQgdGhpcy5hZnRlclNhdmUoKTtcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAoY29ubmVjdGlvbikge1xuICAgICAgICAgICAgcG9zdEhvb2shKGNhbGxiYWNrKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IGNhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGFzeW5jIHNhdmVUcmFuc2FjdGlvbihjb25uZWN0aW9uOiBDb25uZWN0aW9uLCBleGlzdHM6IGJvb2xlYW4sIG5lZWRzX2Z1bGxfdXBkYXRlOiBib29sZWFuKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIC8vIEJlZm9yZSBzYXZlXG4gICAgICAgIGF3YWl0IHRoaXMuYmVmb3JlU2F2ZShleGlzdHMsIGNvbm5lY3Rpb24pO1xuICAgICAgICBpZiAoZXhpc3RzICYmIHRoaXMuaGFzT3duUHJvcGVydHkoJ3VwZGF0ZWRfYXQnKSkge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVkX2F0ID0gbmV3IERhdGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHByb3BzID0gW107XG4gICAgICAgIGNvbnN0IHZhbHVlcyA9IFtdO1xuXG4gICAgICAgIGlmIChleGlzdHMpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgcHJvcCBvZiB0aGlzLnByb3BlcnRpZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAocHJvcC52YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHByb3BzLnB1c2gocHJvcC5uYW1lICsgJz0/Jyk7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcy5wdXNoKHByb3AudmFsdWUpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG5lZWRzX2Z1bGxfdXBkYXRlID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWx1ZXMucHVzaCh0aGlzLmlkKTtcbiAgICAgICAgICAgIGF3YWl0IHF1ZXJ5KGBVUERBVEUgJHt0aGlzLnRhYmxlfSBTRVQgJHtwcm9wcy5qb2luKCcsJyl9IFdIRVJFIGlkPT9gLCB2YWx1ZXMsIGNvbm5lY3Rpb24pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgcHJvcHNfaG9sZGVycyA9IFtdO1xuICAgICAgICAgICAgZm9yIChjb25zdCBwcm9wIG9mIHRoaXMucHJvcGVydGllcykge1xuICAgICAgICAgICAgICAgIGlmIChwcm9wLnZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvcHMucHVzaChwcm9wLm5hbWUpO1xuICAgICAgICAgICAgICAgICAgICBwcm9wc19ob2xkZXJzLnB1c2goJz8nKTtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzLnB1c2gocHJvcC52YWx1ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbmVlZHNfZnVsbF91cGRhdGUgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5KGBJTlNFUlQgSU5UTyAke3RoaXMudGFibGV9ICgke3Byb3BzLmpvaW4oJywgJyl9KSBWQUxVRVMoJHtwcm9wc19ob2xkZXJzLmpvaW4oJywgJyl9KWAsIHZhbHVlcywgY29ubmVjdGlvbik7XG5cbiAgICAgICAgICAgIHRoaXMuaWQgPSByZXN1bHQub3RoZXIuaW5zZXJ0SWQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbmVlZHNfZnVsbF91cGRhdGU7XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBnZXQgdGFibGUoKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubmFtZVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8oPzpefFxcLj8pKFtBLVpdKS9nLCAoeCwgeSkgPT4gJ18nICsgeS50b0xvd2VyQ2FzZSgpKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9eXy8sICcnKVxuICAgICAgICAgICAgKyAncyc7XG4gICAgfVxuXG4gICAgcHVibGljIGdldCB0YWJsZSgpOiBzdHJpbmcge1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLnRhYmxlO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBleGlzdHMoKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgICAgIGlmICghdGhpcy5pZCkgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHF1ZXJ5KGBTRUxFQ1QgMSBGUk9NICR7dGhpcy50YWJsZX0gV0hFUkUgaWQ9PyBMSU1JVCAxYCwgW1xuICAgICAgICAgICAgdGhpcy5pZCxcbiAgICAgICAgXSk7XG4gICAgICAgIHJldHVybiByZXN1bHQucmVzdWx0cy5sZW5ndGggPiAwO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyBkZWxldGUoKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgICAgIGlmICghKGF3YWl0IHRoaXMuZXhpc3RzKCkpKSB0aHJvdyBuZXcgRXJyb3IoJ1RoaXMgbW9kZWwgaW5zdGFuY2UgZG9lc25cXCd0IGV4aXN0IGluIERCLicpO1xuXG4gICAgICAgIGF3YWl0IHF1ZXJ5KGBERUxFVEUgRlJPTSAke3RoaXMudGFibGV9IFdIRVJFIGlkPT9gLCBbXG4gICAgICAgICAgICB0aGlzLmlkLFxuICAgICAgICBdKTtcbiAgICAgICAgTW9kZWxDYWNoZS5mb3JnZXQodGhpcyk7XG4gICAgICAgIHRoaXMuaWQgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIGFzeW5jIHZhbGlkYXRlKG9ubHlGb3JtYXQ6IGJvb2xlYW4gPSBmYWxzZSwgY29ubmVjdGlvbj86IENvbm5lY3Rpb24pOiBQcm9taXNlPHZvaWRbXT4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5wcm9wZXJ0aWVzLm1hcChwcm9wID0+IHByb3AudmFsaWRhdGUob25seUZvcm1hdCwgY29ubmVjdGlvbikpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNhY2hlKCkge1xuICAgICAgICBNb2RlbENhY2hlLmNhY2hlKHRoaXMpO1xuICAgIH1cblxuICAgIHByb3RlY3RlZCByZWxhdGlvbjxUIGV4dGVuZHMgTW9kZWw+KG5hbWU6IHN0cmluZyk6IFQgfCBudWxsIHtcbiAgICAgICAgaWYgKHRoaXMucmVsYXRpb25zW25hbWVdID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcignTW9kZWwgbm90IGxvYWRlZCcpO1xuICAgICAgICByZXR1cm4gPFQgfCBudWxsPnRoaXMucmVsYXRpb25zW25hbWVdO1xuICAgIH1cbn1cblxuZXhwb3J0IGludGVyZmFjZSBNb2RlbEZhY3Rvcnk8VCBleHRlbmRzIE1vZGVsPiB7XG4gICAgKGRhdGE6IGFueSk6IFQ7XG59XG5cbmNsYXNzIE1vZGVsUHJvcGVydHk8VD4ge1xuICAgIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG4gICAgcHJpdmF0ZSByZWFkb25seSB2YWxpZGF0b3I6IFZhbGlkYXRvcjxUPjtcbiAgICBwcml2YXRlIHZhbD86IFQ7XG5cbiAgICBjb25zdHJ1Y3RvcihuYW1lOiBzdHJpbmcsIHZhbGlkYXRvcjogVmFsaWRhdG9yPFQ+KSB7XG4gICAgICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgICAgIHRoaXMudmFsaWRhdG9yID0gdmFsaWRhdG9yO1xuICAgIH1cblxuICAgIHB1YmxpYyBhc3luYyB2YWxpZGF0ZShvbmx5Rm9ybWF0OiBib29sZWFuLCBjb25uZWN0aW9uPzogQ29ubmVjdGlvbik6IFByb21pc2U8dm9pZD4ge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy52YWxpZGF0b3IuZXhlY3V0ZSh0aGlzLm5hbWUsIHRoaXMudmFsdWUsIG9ubHlGb3JtYXQsIGNvbm5lY3Rpb24pO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXQgdmFsdWUoKTogVCB8IHVuZGVmaW5lZCB7XG4gICAgICAgIHJldHVybiB0aGlzLnZhbDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2V0IHZhbHVlKHZhbDogVCB8IHVuZGVmaW5lZCkge1xuICAgICAgICB0aGlzLnZhbCA9IHZhbDtcbiAgICB9XG59XG5cbmV4cG9ydCBjbGFzcyBNb2RlbENhY2hlIHtcbiAgICBwcml2YXRlIHN0YXRpYyByZWFkb25seSBjYWNoZXM6IHtcbiAgICAgICAgW2tleTogc3RyaW5nXToge1xuICAgICAgICAgICAgW2tleTogbnVtYmVyXTogTW9kZWxcbiAgICAgICAgfVxuICAgIH0gPSB7fTtcblxuICAgIHB1YmxpYyBzdGF0aWMgY2FjaGUoaW5zdGFuY2U6IE1vZGVsKSB7XG4gICAgICAgIGlmIChpbnN0YW5jZS5pZCA9PT0gdW5kZWZpbmVkKSB0aHJvdyBuZXcgRXJyb3IoJ0Nhbm5vdCBjYWNoZSBhbiBpbnN0YW5jZSB3aXRoIGFuIHVuZGVmaW5lZCBpZC4nKTtcblxuICAgICAgICBsZXQgdGFibGVDYWNoZSA9IHRoaXMuY2FjaGVzW2luc3RhbmNlLnRhYmxlXTtcbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlKSB0YWJsZUNhY2hlID0gdGhpcy5jYWNoZXNbaW5zdGFuY2UudGFibGVdID0ge307XG5cbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlW2luc3RhbmNlLmlkXSkgdGFibGVDYWNoZVtpbnN0YW5jZS5pZF0gPSBpbnN0YW5jZTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGZvcmdldChpbnN0YW5jZTogTW9kZWwpIHtcbiAgICAgICAgaWYgKGluc3RhbmNlLmlkID09PSB1bmRlZmluZWQpIHRocm93IG5ldyBFcnJvcignQ2Fubm90IGZvcmdldCBhbiBpbnN0YW5jZSB3aXRoIGFuIHVuZGVmaW5lZCBpZC4nKTtcblxuICAgICAgICBsZXQgdGFibGVDYWNoZSA9IHRoaXMuY2FjaGVzW2luc3RhbmNlLnRhYmxlXTtcbiAgICAgICAgaWYgKCF0YWJsZUNhY2hlKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRhYmxlQ2FjaGVbaW5zdGFuY2UuaWRdKSBkZWxldGUgdGFibGVDYWNoZVtpbnN0YW5jZS5pZF07XG4gICAgfVxuXG4gICAgcHVibGljIHN0YXRpYyBhbGwodGFibGU6IHN0cmluZyk6IHtcbiAgICAgICAgW2tleTogbnVtYmVyXTogTW9kZWxcbiAgICB9IHwgdW5kZWZpbmVkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2FjaGVzW3RhYmxlXTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldCh0YWJsZTogc3RyaW5nLCBpZDogbnVtYmVyKTogTW9kZWwgfCB1bmRlZmluZWQge1xuICAgICAgICBjb25zdCB0YWJsZUNhY2hlID0gdGhpcy5hbGwodGFibGUpO1xuICAgICAgICBpZiAoIXRhYmxlQ2FjaGUpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIHJldHVybiB0YWJsZUNhY2hlW2lkXTtcbiAgICB9XG59XG5cbmV4cG9ydCBjb25zdCBFTUFJTF9SRUdFWCA9IC9eW2EtekEtWjAtOS4hIyQlJicqK1xcXFwvPT9eX2B7fH1+LV0rQFthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPyg/OlxcLlthLXpBLVowLTldKD86W2EtekEtWjAtOS1dezAsNjF9W2EtekEtWjAtOV0pPykrJC87Il19