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