UNPKG

@jsprismarine/prismarine

Version:

Dedicated Minecraft Bedrock Edition server written in TypeScript

159 lines (158 loc) • 16.6 kB
import fs from "node:fs"; import { parseJSON5, parseYAML, stringifyYAML } from "confbox"; import { ConfigInvalidDataError } from "@jsprismarine/errors"; import path from "node:path"; //#region src/config/ConfigBuilder.ts var _ = { get: (obj, path, defaultValue = void 0) => { const travel = (regexp) => String.prototype.split.call(path, regexp).filter(Boolean).reduce((res, key) => res !== null && res !== void 0 ? res[key] : res, obj); const result = travel(/[,[\]]+?/) || travel(/[,[\].]+?/); return result === void 0 || result === obj ? defaultValue : result; }, set: (obj, path, value) => { if (Object(obj) !== obj) return obj; if (!Array.isArray(path)) path = path.toString().match(/[^.[\]]+/g) || []; path.slice(0, -1).reduce((a, c, i) => Object(a[c]) === a[c] ? a[c] : a[c] = Math.abs(path[i + 1]) >> 0 === Number(path[i + 1]) ? [] : {}, obj)[path.at(-1)] = value; return obj; }, has: (obj, key) => { const keyParts = key.split("."); return Boolean(obj && (keyParts.length > 1 ? _.has(obj[key.split(".")[0]], keyParts.slice(1).join(".")) : Object.hasOwnProperty.call(obj, key))); }, del: (obj, path) => { const pathArray = Array.isArray(path) ? path : path.match(/([^[.\]])+/g); pathArray.reduce((acc, key, i) => { if (i === pathArray.length - 1) delete acc[key]; return acc[key]; }, obj); return true; } }; var TypeDefaults = { json: "{}", yaml: " " }; /** * General config-file handler. */ var ConfigBuilder = class { type; path; /** * Config constructor. */ constructor(filePath) { const pathSplitted = path.parse(filePath); this.type = pathSplitted.ext.slice(1); if (!Object.keys(TypeDefaults).some((i) => i.toLowerCase() === this.type.toLowerCase())) throw new Error(`Unsupported config type. (Supported types: ${Object.keys(TypeDefaults).join(", ")})`); if (!fs.existsSync(pathSplitted.dir)) fs.mkdirSync(pathSplitted.dir, { recursive: true }); if (!fs.existsSync(filePath)) fs.writeFileSync(filePath, TypeDefaults[this.type], "utf8"); this.path = filePath; } /** * Get path to the config file on the filesystem. * * @returns {string} the path to the config file */ getPath() { return this.path; } /** * Get the config format (eg. type). * * @returns {'yaml' | 'json'} either `yaml` or `json` */ getType() { return this.type; } /** * @private */ setFileData(data = {}) { if (!data) throw new ConfigInvalidDataError(); fs.writeFileSync(this.path, this.stringify(data), "utf8"); } /** * @private */ stringify(data = {}) { switch (this.type) { case "json": return JSON.stringify(data, null, 4); case "yaml": return stringifyYAML(data, { indent: 4 }); default: throw new Error(`Unknown config type ${this.type}!`); } } getFileData() { const raw = fs.readFileSync(this.path, "utf8"); switch (this.type) { case "json": try { return parseJSON5(raw); } catch {} break; case "yaml": try { return parseYAML(raw); } catch {} break; default: throw new Error(`Unknown config type: ${this.type}!`); } return {}; } /** * Get a config value from a key. * * @param {string} key - the config key * @param {T} defaults - */ get(key, defaults) { const data = this.getFileData(); let result = _.get(data, key); if (typeof result === "undefined" && typeof defaults !== "undefined") { const newData = _.set(data, key, defaults); this.setFileData(newData); result = defaults; } return result; } /** * Sets a key - value pair in config. * * @returns true if the value was set successfully */ set(key, value) { const data = this.getFileData(); const newData = _.set(data, key, value); try { this.setFileData(newData); return true; } catch { return false; } } /** * Check if config value exists. * * @param key - the config key * @returns true if the config contains that key */ has(key) { const data = this.getFileData(); return _.has(data, key); } /** * Delete a config value. * * @param key - the config key * @returns true if the deletion was successful */ del(key) { const data = this.getFileData(); const isSuccessful = _.del(data, key); this.setFileData(data); return isSuccessful; } }; //#endregion export { ConfigBuilder }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQ29uZmlnQnVpbGRlci5lcy5qcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi9zcmMvY29uZmlnL0NvbmZpZ0J1aWxkZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29uZmlnSW52YWxpZERhdGFFcnJvciB9IGZyb20gJ0Bqc3ByaXNtYXJpbmUvZXJyb3JzJztcbmltcG9ydCB7IHBhcnNlSlNPTjUsIHBhcnNlWUFNTCwgc3RyaW5naWZ5WUFNTCB9IGZyb20gJ2NvbmZib3gnO1xuaW1wb3J0IGZzIGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcblxuY29uc3QgXyA9IHtcbiAgICBnZXQ6IChvYmo6IGFueSwgcGF0aDogc3RyaW5nLCBkZWZhdWx0VmFsdWUgPSB1bmRlZmluZWQpID0+IHtcbiAgICAgICAgY29uc3QgdHJhdmVsID0gKHJlZ2V4cDogYW55KSA9PlxuICAgICAgICAgICAgU3RyaW5nLnByb3RvdHlwZS5zcGxpdFxuICAgICAgICAgICAgICAgIC5jYWxsKHBhdGgsIHJlZ2V4cClcbiAgICAgICAgICAgICAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgICAgICAgICAgICAgLnJlZHVjZSgocmVzLCBrZXkpID0+IChyZXMgIT09IG51bGwgJiYgcmVzICE9PSB1bmRlZmluZWQgPyByZXNba2V5XSA6IHJlcyksIG9iaik7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHRyYXZlbCgvWyxbXFxdXSs/LykgfHwgdHJhdmVsKC9bLFtcXF0uXSs/Lyk7XG4gICAgICAgIHJldHVybiByZXN1bHQgPT09IHVuZGVmaW5lZCB8fCByZXN1bHQgPT09IG9iaiA/IGRlZmF1bHRWYWx1ZSA6IHJlc3VsdDtcbiAgICB9LFxuICAgIHNldDogKG9iajogYW55LCBwYXRoOiBhbnksIHZhbHVlOiBhbnkpID0+IHtcbiAgICAgICAgaWYgKE9iamVjdChvYmopICE9PSBvYmopIHJldHVybiBvYmo7XG4gICAgICAgIGlmICghQXJyYXkuaXNBcnJheShwYXRoKSkgcGF0aCA9IHBhdGgudG9TdHJpbmcoKS5tYXRjaCgvW14uW1xcXV0rL2cpIHx8IFtdO1xuICAgICAgICBwYXRoXG4gICAgICAgICAgICAuc2xpY2UoMCwgLTEpXG4gICAgICAgICAgICAucmVkdWNlKFxuICAgICAgICAgICAgICAgIChhOiBhbnksIGM6IGFueSwgaTogYW55KSA9PlxuICAgICAgICAgICAgICAgICAgICBPYmplY3QoYVtjXSkgPT09IGFbY11cbiAgICAgICAgICAgICAgICAgICAgICAgID8gYVtjXVxuICAgICAgICAgICAgICAgICAgICAgICAgOiAoYVtjXSA9IE1hdGguYWJzKHBhdGhbaSArIDFdKSA+PiAwID09PSBOdW1iZXIocGF0aFtpICsgMV0pID8gW10gOiB7fSksXG4gICAgICAgICAgICAgICAgb2JqXG4gICAgICAgICAgICApW3BhdGguYXQoLTEpXSA9IHZhbHVlO1xuICAgICAgICByZXR1cm4gb2JqO1xuICAgIH0sXG4gICAgaGFzOiAob2JqOiBhbnksIGtleTogc3RyaW5nKTogYm9vbGVhbiA9PiB7XG4gICAgICAgIGNvbnN0IGtleVBhcnRzID0ga2V5LnNwbGl0KCcuJyk7XG5cbiAgICAgICAgcmV0dXJuIEJvb2xlYW4oXG4gICAgICAgICAgICBvYmogJiZcbiAgICAgICAgICAgIChrZXlQYXJ0cy5sZW5ndGggPiAxXG4gICAgICAgICAgICAgICAgPyBfLmhhcyhvYmpba2V5LnNwbGl0KCcuJylbMF0hXSwga2V5UGFydHMuc2xpY2UoMSkuam9pbignLicpKVxuICAgICAgICAgICAgICAgIDogT2JqZWN0Lmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKVxuICAgICAgICApO1xuICAgIH0sXG4gICAgZGVsOiAob2JqOiBhbnksIHBhdGg6IGFueSkgPT4ge1xuICAgICAgICBjb25zdCBwYXRoQXJyYXkgPSBBcnJheS5pc0FycmF5KHBhdGgpID8gcGF0aCA6IHBhdGgubWF0Y2goLyhbXlsuXFxdXSkrL2cpO1xuXG4gICAgICAgIHBhdGhBcnJheS5yZWR1Y2UoKGFjYzogYW55LCBrZXk6IGFueSwgaTogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICBpZiAoaSA9PT0gcGF0aEFycmF5Lmxlbmd0aCAtIDEpIGRlbGV0ZSBhY2Nba2V5XTtcbiAgICAgICAgICAgIHJldHVybiBhY2Nba2V5XTtcbiAgICAgICAgfSwgb2JqKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxufTtcblxuY29uc3QgVHlwZURlZmF1bHRzID0ge1xuICAgIGpzb246ICd7fScsXG4gICAgeWFtbDogJyAnXG59O1xuXG5leHBvcnQgdHlwZSBDb25maWdEYXRhID0ge1xuICAgIFtrZXk6IHN0cmluZ106IGFueTtcbn07XG5cbi8qKlxuICogR2VuZXJhbCBjb25maWctZmlsZSBoYW5kbGVyLlxuICovXG5leHBvcnQgY2xhc3MgQ29uZmlnQnVpbGRlciB7XG4gICAgcHJpdmF0ZSB0eXBlOiAneWFtbCcgfCAnanNvbic7XG4gICAgcHJpdmF0ZSBwYXRoOiBzdHJpbmc7XG5cbiAgICAvKipcbiAgICAgKiBDb25maWcgY29uc3RydWN0b3IuXG4gICAgICovXG4gICAgcHVibGljIGNvbnN0cnVjdG9yKGZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgICAgICAgY29uc3QgcGF0aFNwbGl0dGVkID0gcGF0aC5wYXJzZShmaWxlUGF0aCk7XG5cbiAgICAgICAgdGhpcy50eXBlID0gcGF0aFNwbGl0dGVkLmV4dC5zbGljZSgxKSBhcyAneWFtbCcgfCAnanNvbic7XG5cbiAgICAgICAgaWYgKCFPYmplY3Qua2V5cyhUeXBlRGVmYXVsdHMpLnNvbWUoKGkpID0+IGkudG9Mb3dlckNhc2UoKSA9PT0gdGhpcy50eXBlLnRvTG93ZXJDYXNlKCkpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuc3VwcG9ydGVkIGNvbmZpZyB0eXBlLiAoU3VwcG9ydGVkIHR5cGVzOiAke09iamVjdC5rZXlzKFR5cGVEZWZhdWx0cykuam9pbignLCAnKX0pYCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBDcmVhdGUgdGhlIGNvbmZpZyBkaXJlY3RvcnkgaWYgaXQgZG9lc24ndCBleGlzdC5cbiAgICAgICAgaWYgKCFmcy5leGlzdHNTeW5jKHBhdGhTcGxpdHRlZC5kaXIpKSBmcy5ta2RpclN5bmMocGF0aFNwbGl0dGVkLmRpciwgeyByZWN1cnNpdmU6IHRydWUgfSk7XG4gICAgICAgIGlmICghZnMuZXhpc3RzU3luYyhmaWxlUGF0aCkpIGZzLndyaXRlRmlsZVN5bmMoZmlsZVBhdGgsIChUeXBlRGVmYXVsdHMgYXMgYW55KVt0aGlzLnR5cGVdLCAndXRmOCcpO1xuXG4gICAgICAgIHRoaXMucGF0aCA9IGZpbGVQYXRoO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBwYXRoIHRvIHRoZSBjb25maWcgZmlsZSBvbiB0aGUgZmlsZXN5c3RlbS5cbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtzdHJpbmd9IHRoZSBwYXRoIHRvIHRoZSBjb25maWcgZmlsZVxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRQYXRoKCk6IHN0cmluZyB7XG4gICAgICAgIHJldHVybiB0aGlzLnBhdGg7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogR2V0IHRoZSBjb25maWcgZm9ybWF0IChlZy4gdHlwZSkuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7J3lhbWwnIHwgJ2pzb24nfSBlaXRoZXIgYHlhbWxgIG9yIGBqc29uYFxuICAgICAqL1xuICAgIHB1YmxpYyBnZXRUeXBlKCk6ICd5YW1sJyB8ICdqc29uJyB7XG4gICAgICAgIHJldHVybiB0aGlzLnR5cGU7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQHByaXZhdGVcbiAgICAgKi9cbiAgICBwcml2YXRlIHNldEZpbGVEYXRhKGRhdGE6IENvbmZpZ0RhdGEgPSB7fSkge1xuICAgICAgICBpZiAoIShkYXRhIGFzIGFueSkpIHRocm93IG5ldyBDb25maWdJbnZhbGlkRGF0YUVycm9yKCk7XG4gICAgICAgIGZzLndyaXRlRmlsZVN5bmModGhpcy5wYXRoLCB0aGlzLnN0cmluZ2lmeShkYXRhKSwgJ3V0ZjgnKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAcHJpdmF0ZVxuICAgICAqL1xuICAgIHByaXZhdGUgc3RyaW5naWZ5KGRhdGE6IENvbmZpZ0RhdGEgPSB7fSkge1xuICAgICAgICAvLyBGSVhNRTogVGhpcyBvdmVyd3JpdGVzIGNvbW1lbnRzIGluIHRoZSBmaWxlLlxuICAgICAgICBzd2l0Y2ggKHRoaXMudHlwZSkge1xuICAgICAgICAgICAgY2FzZSAnanNvbic6XG4gICAgICAgICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGRhdGEsIG51bGwsIDQpO1xuICAgICAgICAgICAgY2FzZSAneWFtbCc6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0cmluZ2lmeVlBTUwoZGF0YSwgeyBpbmRlbnQ6IDQgfSk7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBjb25maWcgdHlwZSAke3RoaXMudHlwZX0hYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGdldEZpbGVEYXRhKCk6IENvbmZpZ0RhdGEge1xuICAgICAgICBjb25zdCByYXcgPSBmcy5yZWFkRmlsZVN5bmModGhpcy5wYXRoLCAndXRmOCcpO1xuXG4gICAgICAgIHN3aXRjaCAodGhpcy50eXBlKSB7XG4gICAgICAgICAgICBjYXNlICdqc29uJzpcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyc2VKU09ONShyYXcpO1xuICAgICAgICAgICAgICAgIH0gY2F0Y2gge31cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgJ3lhbWwnOlxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZVlBTUwocmF3KTtcbiAgICAgICAgICAgICAgICB9IGNhdGNoIHt9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5rbm93biBjb25maWcgdHlwZTogJHt0aGlzLnR5cGV9IWApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHt9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEdldCBhIGNvbmZpZyB2YWx1ZSBmcm9tIGEga2V5LlxuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IGtleSAtIHRoZSBjb25maWcga2V5XG4gICAgICogQHBhcmFtIHtUfSBkZWZhdWx0cyAtXG4gICAgICovXG4gICAgcHVibGljIGdldDxUID0gYW55PihrZXk6IHN0cmluZywgZGVmYXVsdHM/OiBUKTogVCB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSB0aGlzLmdldEZpbGVEYXRhKCk7XG4gICAgICAgIGxldCByZXN1bHQgPSBfLmdldChkYXRhLCBrZXkpO1xuXG4gICAgICAgIGlmICh0eXBlb2YgcmVzdWx0ID09PSAndW5kZWZpbmVkJyAmJiB0eXBlb2YgZGVmYXVsdHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBjb25zdCBuZXdEYXRhID0gXy5zZXQoZGF0YSwga2V5LCBkZWZhdWx0cyk7XG4gICAgICAgICAgICB0aGlzLnNldEZpbGVEYXRhKG5ld0RhdGEpO1xuICAgICAgICAgICAgcmVzdWx0ID0gZGVmYXVsdHM7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNldHMgYSBrZXkgLSB2YWx1ZSBwYWlyIGluIGNvbmZpZy5cbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIHZhbHVlIHdhcyBzZXQgc3VjY2Vzc2Z1bGx5XG4gICAgICovXG4gICAgcHVibGljIHNldChrZXk6IHN0cmluZywgdmFsdWU6IGFueSkge1xuICAgICAgICBjb25zdCBkYXRhID0gdGhpcy5nZXRGaWxlRGF0YSgpO1xuICAgICAgICBjb25zdCBuZXdEYXRhID0gXy5zZXQoZGF0YSwga2V5LCB2YWx1ZSk7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHRoaXMuc2V0RmlsZURhdGEobmV3RGF0YSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSBjYXRjaCB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDaGVjayBpZiBjb25maWcgdmFsdWUgZXhpc3RzLlxuICAgICAqXG4gICAgICogQHBhcmFtIGtleSAtIHRoZSBjb25maWcga2V5XG4gICAgICogQHJldHVybnMgdHJ1ZSBpZiB0aGUgY29uZmlnIGNvbnRhaW5zIHRoYXQga2V5XG4gICAgICovXG4gICAgcHVibGljIGhhcyhrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBkYXRhID0gdGhpcy5nZXRGaWxlRGF0YSgpO1xuICAgICAgICBjb25zdCByZXN1bHQgPSBfLmhhcyhkYXRhLCBrZXkpO1xuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIERlbGV0ZSBhIGNvbmZpZyB2YWx1ZS5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBrZXkgLSB0aGUgY29uZmlnIGtleVxuICAgICAqIEByZXR1cm5zIHRydWUgaWYgdGhlIGRlbGV0aW9uIHdhcyBzdWNjZXNzZnVsXG4gICAgICovXG4gICAgcHVibGljIGRlbChrZXk6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgICAgICBjb25zdCBkYXRhID0gdGhpcy5nZXRGaWxlRGF0YSgpO1xuXG4gICAgICAgIC8vIEl0IG11dGF0ZXMgdGhlIG9iamVjdCwgd2VcbiAgICAgICAgLy8gZG9uJ3QgbmVlZCB0byBkZWZpbmUgYSBuZXdcbiAgICAgICAgLy8gdmFyaWFibGUuXG4gICAgICAgIGNvbnN0IGlzU3VjY2Vzc2Z1bCA9IF8uZGVsKGRhdGEsIGtleSk7XG5cbiAgICAgICAgdGhpcy5zZXRGaWxlRGF0YShkYXRhKTtcbiAgICAgICAgcmV0dXJuIGlzU3VjY2Vzc2Z1bDtcbiAgICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7O0FBS0EsSUFBTSxJQUFJO0NBQ04sTUFBTSxLQUFVLE1BQWMsZUFBZSxLQUFBLE1BQWM7RUFDdkQsTUFBTSxVQUFVLFdBQ1osT0FBTyxVQUFVLE1BQ1osS0FBSyxNQUFNLE1BQU0sRUFDakIsT0FBTyxPQUFPLEVBQ2QsUUFBUSxLQUFLLFFBQVMsUUFBUSxRQUFRLFFBQVEsS0FBQSxJQUFZLElBQUksT0FBTyxLQUFNLEdBQUc7RUFDdkYsTUFBTSxTQUFTLE9BQU8sVUFBVSxLQUFLLE9BQU8sV0FBVztFQUN2RCxPQUFPLFdBQVcsS0FBQSxLQUFhLFdBQVcsTUFBTSxlQUFlO0NBQ25FO0NBQ0EsTUFBTSxLQUFVLE1BQVcsVUFBZTtFQUN0QyxJQUFJLE9BQU8sR0FBRyxNQUFNLEtBQUssT0FBTztFQUNoQyxJQUFJLENBQUMsTUFBTSxRQUFRLElBQUksR0FBRyxPQUFPLEtBQUssU0FBUyxFQUFFLE1BQU0sV0FBVyxLQUFLLENBQUM7RUFDeEUsS0FDSyxNQUFNLEdBQUcsRUFBRSxFQUNYLFFBQ0ksR0FBUSxHQUFRLE1BQ2IsT0FBTyxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQ2IsRUFBRSxLQUNELEVBQUUsS0FBSyxLQUFLLElBQUksS0FBSyxJQUFJLEVBQUUsS0FBSyxNQUFNLE9BQU8sS0FBSyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUM3RSxHQUNKLEVBQUUsS0FBSyxHQUFHLEVBQUUsS0FBSztFQUNyQixPQUFPO0NBQ1g7Q0FDQSxNQUFNLEtBQVUsUUFBeUI7RUFDckMsTUFBTSxXQUFXLElBQUksTUFBTSxHQUFHO0VBRTlCLE9BQU8sUUFDSCxRQUNDLFNBQVMsU0FBUyxJQUNiLEVBQUUsSUFBSSxJQUFJLElBQUksTUFBTSxHQUFHLEVBQUUsS0FBTSxTQUFTLE1BQU0sQ0FBQyxFQUFFLEtBQUssR0FBRyxDQUFDLElBQzFELE9BQU8sZUFBZSxLQUFL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