bc-deeplib 2.4.2 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/deeplib.js CHANGED
@@ -1,203 +1,5 @@
1
- var __create = Object.create;
2
1
  var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __getProtoOf = Object.getPrototypeOf;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
2
  var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
8
- var __commonJS = (cb, mod) => function __require() {
9
- return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
- };
11
- var __copyProps = (to, from, except, desc) => {
12
- if (from && typeof from === "object" || typeof from === "function") {
13
- for (let key of __getOwnPropNames(from))
14
- if (!__hasOwnProp.call(to, key) && key !== except)
15
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
- }
17
- return to;
18
- };
19
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
- // If the importer is in node compatibility mode or this is not an ESM
21
- // file that has been converted to a CommonJS file using a Babel-
22
- // compatible transform (i.e. "__esModule" has not been set), then set
23
- // "default" to the CommonJS "module.exports" for node compatibility.
24
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
- mod
26
- ));
27
-
28
- // node_modules/.pnpm/bondage-club-mod-sdk@1.2.0/node_modules/bondage-club-mod-sdk/dist/bcmodsdk.js
29
- var require_bcmodsdk = __commonJS({
30
- "node_modules/.pnpm/bondage-club-mod-sdk@1.2.0/node_modules/bondage-club-mod-sdk/dist/bcmodsdk.js"(exports) {
31
- var bcModSdk = (function() {
32
- "use strict";
33
- const o = "1.2.0";
34
- function e(o2) {
35
- alert("Mod ERROR:\n" + o2);
36
- const e2 = new Error(o2);
37
- throw console.error(e2), e2;
38
- }
39
- __name(e, "e");
40
- const t = new TextEncoder();
41
- function n(o2) {
42
- return !!o2 && "object" == typeof o2 && !Array.isArray(o2);
43
- }
44
- __name(n, "n");
45
- function r(o2) {
46
- const e2 = /* @__PURE__ */ new Set();
47
- return o2.filter(((o3) => !e2.has(o3) && e2.add(o3)));
48
- }
49
- __name(r, "r");
50
- const i = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Set();
51
- function c(o2) {
52
- a.has(o2) || (a.add(o2), console.warn(o2));
53
- }
54
- __name(c, "c");
55
- function s(o2) {
56
- const e2 = [], t2 = /* @__PURE__ */ new Map(), n2 = /* @__PURE__ */ new Set();
57
- for (const r3 of f.values()) {
58
- const i3 = r3.patching.get(o2.name);
59
- if (i3) {
60
- e2.push(...i3.hooks);
61
- for (const [e3, a2] of i3.patches.entries()) t2.has(e3) && t2.get(e3) !== a2 && c(`ModSDK: Mod '${r3.name}' is patching function ${o2.name} with same pattern that is already applied by different mod, but with different pattern:
62
- Pattern:
63
- ${e3}
64
- Patch1:
65
- ${t2.get(e3) || ""}
66
- Patch2:
67
- ${a2}`), t2.set(e3, a2), n2.add(r3.name);
68
- }
69
- }
70
- e2.sort(((o3, e3) => e3.priority - o3.priority));
71
- const r2 = (function(o3, e3) {
72
- if (0 === e3.size) return o3;
73
- let t3 = o3.toString().replaceAll("\r\n", "\n");
74
- for (const [n3, r3] of e3.entries()) t3.includes(n3) || c(`ModSDK: Patching ${o3.name}: Patch ${n3} not applied`), t3 = t3.replaceAll(n3, r3);
75
- return (0, eval)(`(${t3})`);
76
- })(o2.original, t2);
77
- let i2 = /* @__PURE__ */ __name(function(e3) {
78
- var t3, i3;
79
- const a2 = null === (i3 = (t3 = m.errorReporterHooks).hookChainExit) || void 0 === i3 ? void 0 : i3.call(t3, o2.name, n2), c2 = r2.apply(this, e3);
80
- return null == a2 || a2(), c2;
81
- }, "i");
82
- for (let t3 = e2.length - 1; t3 >= 0; t3--) {
83
- const n3 = e2[t3], r3 = i2;
84
- i2 = /* @__PURE__ */ __name(function(e3) {
85
- var t4, i3;
86
- const a2 = null === (i3 = (t4 = m.errorReporterHooks).hookEnter) || void 0 === i3 ? void 0 : i3.call(t4, o2.name, n3.mod), c2 = n3.hook.apply(this, [e3, (o3) => {
87
- if (1 !== arguments.length || !Array.isArray(e3)) throw new Error(`Mod ${n3.mod} failed to call next hook: Expected args to be array, got ${typeof o3}`);
88
- return r3.call(this, o3);
89
- }]);
90
- return null == a2 || a2(), c2;
91
- }, "i");
92
- }
93
- return { hooks: e2, patches: t2, patchesSources: n2, enter: i2, final: r2 };
94
- }
95
- __name(s, "s");
96
- function l(o2, e2 = false) {
97
- let r2 = i.get(o2);
98
- if (r2) e2 && (r2.precomputed = s(r2));
99
- else {
100
- let e3 = window;
101
- const a2 = o2.split(".");
102
- for (let t2 = 0; t2 < a2.length - 1; t2++) if (e3 = e3[a2[t2]], !n(e3)) throw new Error(`ModSDK: Function ${o2} to be patched not found; ${a2.slice(0, t2 + 1).join(".")} is not object`);
103
- const c2 = e3[a2[a2.length - 1]];
104
- if ("function" != typeof c2) throw new Error(`ModSDK: Function ${o2} to be patched not found`);
105
- const l2 = (function(o3) {
106
- let e4 = -1;
107
- for (const n2 of t.encode(o3)) {
108
- let o4 = 255 & (e4 ^ n2);
109
- for (let e5 = 0; e5 < 8; e5++) o4 = 1 & o4 ? -306674912 ^ o4 >>> 1 : o4 >>> 1;
110
- e4 = e4 >>> 8 ^ o4;
111
- }
112
- return ((-1 ^ e4) >>> 0).toString(16).padStart(8, "0").toUpperCase();
113
- })(c2.toString().replaceAll("\r\n", "\n")), d2 = { name: o2, original: c2, originalHash: l2 };
114
- r2 = Object.assign(Object.assign({}, d2), { precomputed: s(d2), router: /* @__PURE__ */ __name(() => {
115
- }, "router"), context: e3, contextProperty: a2[a2.length - 1] }), r2.router = /* @__PURE__ */ (function(o3) {
116
- return function(...e4) {
117
- return o3.precomputed.enter.apply(this, [e4]);
118
- };
119
- })(r2), i.set(o2, r2), e3[r2.contextProperty] = r2.router;
120
- }
121
- return r2;
122
- }
123
- __name(l, "l");
124
- function d() {
125
- for (const o2 of i.values()) o2.precomputed = s(o2);
126
- }
127
- __name(d, "d");
128
- function p() {
129
- const o2 = /* @__PURE__ */ new Map();
130
- for (const [e2, t2] of i) o2.set(e2, { name: e2, original: t2.original, originalHash: t2.originalHash, sdkEntrypoint: t2.router, currentEntrypoint: t2.context[t2.contextProperty], hookedByMods: r(t2.precomputed.hooks.map(((o3) => o3.mod))), patchedByMods: Array.from(t2.precomputed.patchesSources) });
131
- return o2;
132
- }
133
- __name(p, "p");
134
- const f = /* @__PURE__ */ new Map();
135
- function u(o2) {
136
- f.get(o2.name) !== o2 && e(`Failed to unload mod '${o2.name}': Not registered`), f.delete(o2.name), o2.loaded = false, d();
137
- }
138
- __name(u, "u");
139
- function g(o2, t2) {
140
- o2 && "object" == typeof o2 || e("Failed to register mod: Expected info object, got " + typeof o2), "string" == typeof o2.name && o2.name || e("Failed to register mod: Expected name to be non-empty string, got " + typeof o2.name);
141
- let r2 = `'${o2.name}'`;
142
- "string" == typeof o2.fullName && o2.fullName || e(`Failed to register mod ${r2}: Expected fullName to be non-empty string, got ${typeof o2.fullName}`), r2 = `'${o2.fullName} (${o2.name})'`, "string" != typeof o2.version && e(`Failed to register mod ${r2}: Expected version to be string, got ${typeof o2.version}`), o2.repository || (o2.repository = void 0), void 0 !== o2.repository && "string" != typeof o2.repository && e(`Failed to register mod ${r2}: Expected repository to be undefined or string, got ${typeof o2.version}`), null == t2 && (t2 = {}), t2 && "object" == typeof t2 || e(`Failed to register mod ${r2}: Expected options to be undefined or object, got ${typeof t2}`);
143
- const i2 = true === t2.allowReplace, a2 = f.get(o2.name);
144
- a2 && (a2.allowReplace && i2 || e(`Refusing to load mod ${r2}: it is already loaded and doesn't allow being replaced.
145
- Was the mod loaded multiple times?`), u(a2));
146
- const c2 = /* @__PURE__ */ __name((o3) => {
147
- let e2 = g2.patching.get(o3.name);
148
- return e2 || (e2 = { hooks: [], patches: /* @__PURE__ */ new Map() }, g2.patching.set(o3.name, e2)), e2;
149
- }, "c"), s2 = /* @__PURE__ */ __name((o3, t3) => (...n2) => {
150
- var i3, a3;
151
- const c3 = null === (a3 = (i3 = m.errorReporterHooks).apiEndpointEnter) || void 0 === a3 ? void 0 : a3.call(i3, o3, g2.name);
152
- g2.loaded || e(`Mod ${r2} attempted to call SDK function after being unloaded`);
153
- const s3 = t3(...n2);
154
- return null == c3 || c3(), s3;
155
- }, "s"), p2 = { unload: s2("unload", (() => u(g2))), hookFunction: s2("hookFunction", ((o3, t3, n2) => {
156
- "string" == typeof o3 && o3 || e(`Mod ${r2} failed to patch a function: Expected function name string, got ${typeof o3}`);
157
- const i3 = l(o3), a3 = c2(i3);
158
- "number" != typeof t3 && e(`Mod ${r2} failed to hook function '${o3}': Expected priority number, got ${typeof t3}`), "function" != typeof n2 && e(`Mod ${r2} failed to hook function '${o3}': Expected hook function, got ${typeof n2}`);
159
- const s3 = { mod: g2.name, priority: t3, hook: n2 };
160
- return a3.hooks.push(s3), d(), () => {
161
- const o4 = a3.hooks.indexOf(s3);
162
- o4 >= 0 && (a3.hooks.splice(o4, 1), d());
163
- };
164
- })), patchFunction: s2("patchFunction", ((o3, t3) => {
165
- "string" == typeof o3 && o3 || e(`Mod ${r2} failed to patch a function: Expected function name string, got ${typeof o3}`);
166
- const i3 = l(o3), a3 = c2(i3);
167
- n(t3) || e(`Mod ${r2} failed to patch function '${o3}': Expected patches object, got ${typeof t3}`);
168
- for (const [n2, i4] of Object.entries(t3)) "string" == typeof i4 ? a3.patches.set(n2, i4) : null === i4 ? a3.patches.delete(n2) : e(`Mod ${r2} failed to patch function '${o3}': Invalid format of patch '${n2}'`);
169
- d();
170
- })), removePatches: s2("removePatches", ((o3) => {
171
- "string" == typeof o3 && o3 || e(`Mod ${r2} failed to patch a function: Expected function name string, got ${typeof o3}`);
172
- const t3 = l(o3);
173
- c2(t3).patches.clear(), d();
174
- })), callOriginal: s2("callOriginal", ((o3, t3, n2) => {
175
- "string" == typeof o3 && o3 || e(`Mod ${r2} failed to call a function: Expected function name string, got ${typeof o3}`);
176
- const i3 = l(o3);
177
- return Array.isArray(t3) || e(`Mod ${r2} failed to call a function: Expected args array, got ${typeof t3}`), i3.original.apply(null != n2 ? n2 : globalThis, t3);
178
- })), getOriginalHash: s2("getOriginalHash", ((o3) => {
179
- "string" == typeof o3 && o3 || e(`Mod ${r2} failed to get hash: Expected function name string, got ${typeof o3}`);
180
- return l(o3).originalHash;
181
- })) }, g2 = { name: o2.name, fullName: o2.fullName, version: o2.version, repository: o2.repository, allowReplace: i2, api: p2, loaded: true, patching: /* @__PURE__ */ new Map() };
182
- return f.set(o2.name, g2), Object.freeze(p2);
183
- }
184
- __name(g, "g");
185
- function h() {
186
- const o2 = [];
187
- for (const e2 of f.values()) o2.push({ name: e2.name, fullName: e2.fullName, version: e2.version, repository: e2.repository });
188
- return o2;
189
- }
190
- __name(h, "h");
191
- let m;
192
- const y = void 0 === window.bcModSdk ? window.bcModSdk = (function() {
193
- const e2 = { version: o, apiVersion: 1, registerMod: g, getModsInfo: h, getPatchingInfo: p, errorReporterHooks: Object.seal({ apiEndpointEnter: null, hookEnter: null, hookChainExit: null }) };
194
- return m = e2, Object.freeze(e2);
195
- })() : (n(window.bcModSdk) || e("Failed to init Mod SDK: Name already in use"), 1 !== window.bcModSdk.apiVersion && e(`Failed to init Mod SDK: Different version already loaded ('1.2.0' vs '${window.bcModSdk.version}')`), window.bcModSdk.version !== o && alert(`Mod SDK warning: Loading different but compatible versions ('1.2.0' vs '${window.bcModSdk.version}')
196
- One of mods you are using is using an old version of SDK. It will work for now but please inform author to update`), window.bcModSdk);
197
- return "undefined" != typeof exports && (Object.defineProperty(exports, "__esModule", { value: true }), exports.default = y), y;
198
- })();
199
- }
200
- });
201
3
 
202
4
  // src/base/base_module.ts
203
5
  var BaseModule = class {
@@ -226,10 +28,8 @@ var BaseModule = class {
226
28
  * If no settings exist yet, registers default settings first.
227
29
  */
228
30
  get settings() {
229
- const modName = ModSdkManager.ModInfo.name;
230
- if (!this.settingsStorage) return {};
31
+ if (!this.settingsStorage) return null;
231
32
  if (!modStorage.playerStorage) {
232
- Player[modName] = {};
233
33
  this.registerDefaultSettings(modStorage.playerStorage);
234
34
  } else if (!modStorage.playerStorage[this.settingsStorage]) {
235
35
  this.registerDefaultSettings(modStorage.playerStorage);
@@ -241,16 +41,13 @@ var BaseModule = class {
241
41
  * Automatically initializes storage and defaults if they don't exist.
242
42
  */
243
43
  set settings(value) {
244
- const modName = ModSdkManager.ModInfo.name;
245
- const storage = new ModStorage(modName);
246
44
  if (!this.settingsStorage) return;
247
- if (!storage.playerStorage) {
248
- Player[modName] = {};
45
+ if (!modStorage.playerStorage) {
249
46
  this.registerDefaultSettings(modStorage.playerStorage);
250
- } else if (!storage.playerStorage[this.settingsStorage]) {
47
+ } else if (!modStorage.playerStorage[this.settingsStorage]) {
251
48
  this.registerDefaultSettings(modStorage.playerStorage);
252
49
  }
253
- storage.playerStorage[this.settingsStorage] = value;
50
+ modStorage.playerStorage[this.settingsStorage] = value;
254
51
  }
255
52
  /**
256
53
  * Initializes the module.
@@ -406,7 +203,7 @@ var BaseSubscreen = class _BaseSubscreen {
406
203
  this.pageStructure.forEach((item, ix) => {
407
204
  item.forEach((setting) => {
408
205
  const element = ElementWrap(`${setting.id}-container`) ?? ElementWrap(`${setting.id}`);
409
- if (ix != _BaseSubscreen.currentPage - 1) {
206
+ if (ix !== _BaseSubscreen.currentPage - 1) {
410
207
  if (element) domUtil.hide(element);
411
208
  } else {
412
209
  if (element) domUtil.unhide(element);
@@ -474,7 +271,7 @@ var BaseSubscreen = class _BaseSubscreen {
474
271
  if (this.options.doShowTitle) {
475
272
  const subscreenTitle = advElement.createLabel({
476
273
  id: "deeplib-subscreen-title",
477
- label: getText(`${this.options.name}.title`).replace("$ModVersion", ModSdkManager.ModInfo.version)
274
+ label: getText(`${this.options.name}.title`).replace("$ModVersion", MOD_VERSION_CAPTION)
478
275
  });
479
276
  layout.appendToSubscreen(subscreenTitle);
480
277
  }
@@ -576,7 +373,7 @@ var BaseSubscreen = class _BaseSubscreen {
576
373
  ElementSetSize(settingsDiv, this.options.settingsWidth ?? 1e3 + offset, 660);
577
374
  if (this.options.doShowTitle) {
578
375
  ElementSetPosition("deeplib-subscreen-title", 530 - offset, 75);
579
- ElementSetSize("deeplib-subscreen-title", 800, 60);
376
+ ElementSetSize("deeplib-subscreen-title", 800, 90);
580
377
  }
581
378
  ElementSetPosition("deeplib-nav-menu", 1905, 75, "top-right");
582
379
  ElementSetSize("deeplib-nav-menu", null, 90);
@@ -677,6 +474,8 @@ var styles_default = `.deeplib-subscreen,
677
474
  color: var(--deeplib-text-color);
678
475
  user-select: none;
679
476
  pointer-events: none;
477
+ display: flex;
478
+ align-items: center;
680
479
  }
681
480
 
682
481
  .deeplib-text {
@@ -949,52 +748,76 @@ var styles_default = `.deeplib-subscreen,
949
748
  height: 100dvh;
950
749
  background-color: rgba(0, 0, 0, 0.5);
951
750
  }
952
- /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiL21udC9zaGluZG93cy9TdHVmZi9Db2RlL2JjL0JDLURlZXBMaWIvc3JjL3N0eWxlcyIsInNvdXJjZXMiOlsidmFycy5zY3NzIiwiYnV0dG9ucy5zY3NzIiwiZWxlbWVudHMuc2NzcyIsImlucHV0cy5zY3NzIiwibWVzc2FnZXMuc2NzcyIsIm1vZGFsLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFBQTtFQUVFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUNkRjtFQUNFO0VBQ0E7RUFDQTs7QUFFQTtFQUVFOztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUVBO0VBQ0E7RUFDQTs7QUFHRjtFQUNFOztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBR0Y7RUFDRTs7O0FDM0NKO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7OztBQUdGO0VBQ0U7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUdFO0VBQ0U7RUFDQTs7QUFISjtFQU1FO0VBQ0E7O0FBR0Y7RUFDRTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7OztBQUlKO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBO0VBQ0E7OztBQ2pISjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7OztBQUtOO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFOztBQUdGO0VBQ0U7RUFDQTs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7OztBQU9SO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7QUFHRjtFQUNFOzs7QUN2Rko7RUFDRTtFQUNBOzs7QUFHRjtBQUFBO0VBRUU7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7QUFBQTtFQUVFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTs7O0FDN0JGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7RUFDQTtFQUNBOztBQUdGO0VBQ0U7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTs7QUFLTjtFQUNFO0VBQ0E7RUFDQTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBIiwic291cmNlc0NvbnRlbnQiOlsiLmRlZXBsaWItc3Vic2NyZWVuLFxuLmRlZXBsaWItbW9kYWwge1xuICAtLWRlZXBsaWItYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tdG1kLW1haW4sIHdoaXRlKTtcbiAgLS1kZWVwbGliLWVsZW1lbnQtY29sb3I6IHZhcigtLXRtZC1lbGVtZW50LCB3aGl0ZSk7XG4gIC0tZGVlcGxpYi1lbGVtZW50LWhvdmVyLWNvbG9yOiB2YXIoLS10bWQtZWxlbWVudC1ob3ZlciwgY3lhbik7XG4gIC0tZGVlcGxpYi1hY2NlbnQtY29sb3I6IHZhcigtLXRtZC1hY2NlbnQsICNGRkZGODgpO1xuICAtLWRlZXBsaWItYmxvY2tlZC1jb2xvcjogdmFyKC0tdG1kLWJsb2NrZWQsIHJlZCk7XG4gIC0tZGVlcGxpYi10ZXh0LWNvbG9yOiB2YXIoLS10bWQtdGV4dCwgYmxhY2spO1xuICAtLWRlZXBsaWItaWNvbi1jb2xvcjogdmFyKC0tdG1kLWFjY2VudCwgYmxhY2spO1xuICAtLWRlZXBsaWItaWNvbi1ob3Zlci1jb2xvcjogdmFyKC0tdG1kLWFjY2VudC1ob3ZlciwgYmxhY2spO1xuICAtLWRlZXBsaWItYm9yZGVyLWNvbG9yOiB2YXIoLS10bWQtYWNjZW50LCBibGFjayk7XG4gIC0tZGVlcGxpYi1ib3JkZXItd2lkdGg6IG1pbigwLjJ2aCwgMC4xdncpO1xuICAtLWRlZXBsaWItYm9yZGVyLXdpZHRoOiBtaW4oMC4yZHZoLCAwLjFkdncpO1xuICAtLWRlZXBsaWItYm9yZGVyLXJhZGl1czogbWluKDF2aCwgMC41dncpO1xuICAtLWRlZXBsaWItYm9yZGVyLXJhZGl1czogbWluKDFkdmgsIDAuNWR2dyk7XG59XG4iLCIuZGVlcGxpYi1idXR0b24ge1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogMTAwJTtcblxuICAmLmJ1dHRvbi1zdHlsaW5nLFxuICAmLmJ1dHRvbi1zdHlsaW5nOjpiZWZvcmUge1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIH1cblxuICBpbWcge1xuICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgICB0b3A6IDAlO1xuICAgIGxlZnQ6IDAlO1xuICAgIHdpZHRoOiAxMDAlO1xuICAgIGhlaWdodDogMTAwJTtcbiAgICBiYWNrZ3JvdW5kLXBvc2l0aW9uOiBsZWZ0O1xuICAgIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItaWNvbi1jb2xvcik7XG4gICAgYmFja2dyb3VuZC1ibGVuZC1tb2RlOiBtdWx0aXBseTtcbiAgICBiYWNrZ3JvdW5kLXNpemU6IGNvbnRhaW47XG4gICAgbWFzay1wb3NpdGlvbjogbGVmdDtcbiAgICBtYXNrLXNpemU6IGNvbnRhaW47XG4gICAgYmFja2dyb3VuZC1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgICBtYXNrLXJlcGVhdDogbm8tcmVwZWF0O1xuICAgIGNvbG9yOiB0cmFuc3BhcmVudDtcblxuICAgIGJhY2tncm91bmQtaW1hZ2U6IHZhcigtLWltYWdlKTtcbiAgICBtYXNrLWltYWdlOiB2YXIoLS1pbWFnZSk7XG4gICAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gIH1cblxuICAmOmhvdmVyIGltZyB7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1pY29uLWhvdmVyLWNvbG9yKTtcbiAgfVxuXG4gIC5idXR0b24tbGFiZWwge1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50ICFpbXBvcnRhbnQ7XG4gICAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gICAgZm9udC1zaXplOiBtaW4oMy42ZHZoLCAxLjhkdncpO1xuICAgIGRpc3BsYXk6IGNvbnRlbnRzO1xuICB9XG5cbiAgLmJ1dHRvbi10b29sdGlwIHtcbiAgICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xuICB9XG59IiwiI2RlZXBsaWItcGFnZS1sYWJlbCB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuI2RlZXBsaWItc3Vic2NyZWVuLXRpdGxlIHtcbiAgdGV4dC1hbGlnbjogbGVmdDtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLmRlZXBsaWItdGV4dCB7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xufVxuXG4uZGVlcGxpYi1zdWJzY3JlZW4ge1xuICBwYWRkaW5nOiAwO1xuICBtYXJnaW46IDA7XG4gIHBvaW50ZXItZXZlbnRzOiBub25lO1xufVxuXG4uZGVlcGxpYi1zdWJzY3JlZW4gKiB7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIHBvaW50ZXItZXZlbnRzOiBhbGw7XG59XG5cbi5kZWVwbGliLXNldHRpbmdzIHtcbiAgZGlzcGxheTogZ3JpZDtcbiAgZ3JpZC1hdXRvLXJvd3M6IG1pbi1jb250ZW50O1xuICBwYWRkaW5nOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xuICBnYXA6IDAuM2VtO1xufVxuXG4uZGVlcGxpYi1taXNjIHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbi1yZXZlcnNlO1xuICBnYXA6IG1pbigxdmgsIDAuNXZ3KTtcbn1cblxuLmRlZXBsaWItdG9vbHRpcCB7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgcGFkZGluZzogbWluKDF2aCwgMC41dncpO1xuICBmb250LXNpemU6IDAuOGVtO1xuICBib3JkZXI6IG1pbigwLjJ2aCwgMC4xdncpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLWNvbG9yKTtcbiAgei1pbmRleDogMTtcbn1cblxuLmRlZXBsaWItb3ZlcmZsb3ctYm94IHtcbiAgYm9yZGVyOiB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcikgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItd2lkdGgpO1xufVxuXG4uZGVlcGxpYi1wcmV2LW5leHQge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGdhcDogbWluKDJkdmgsIDFkdncpO1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgYm9yZGVyOiBtaW4oMC4ydmgsIDAuMXZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG5cbiAgLmRlZXBsaWItcHJldi1uZXh0LWJ1dHRvbiB7XG4gICAgJjpob3ZlciB7XG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtaG92ZXItY29sb3IpO1xuICAgICAgYm9yZGVyLXJhZGl1czogdmFyKC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzKTtcbiAgICB9XG5cbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgYXNwZWN0LXJhdGlvOiAxO1xuICB9XG5cbiAgLmRlZXBsaWItcHJldi1uZXh0LWxhYmVsIHtcbiAgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgIHVzZXItc2VsZWN0OiBub25lO1xuICB9XG59XG5cbiNkZWVwbGliLW5hdi1tZW51IHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IHJvdztcbiAgZ2FwOiBtaW4oMmR2aCwgMWR2dyk7XG4gIHotaW5kZXg6IDE7XG5cbiAgJj4uZGVlcGxpYi1idXR0b24ge1xuICAgIGZsZXg6IDEgMCBhdXRvO1xuICB9XG59XG5cbiNkZWVwbGliLXN0b3JhZ2UtbWV0ZXIge1xuICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gIHRvcDogMHB4O1xuICBsZWZ0OiAwcHg7XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IDEwMCU7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGJvcmRlcjogdmFyKC0tZGVlcGxpYi1ib3JkZXItd2lkdGgpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLWNvbG9yKTtcbiAgYm9yZGVyLXJhZGl1czogdmFyKC0tZGVlcGxpYi1ib3JkZXItcmFkaXVzKTtcbiAgei1pbmRleDogLTE7XG5cbiAgI2RlZXBsaWItc3RvcmFnZS1iYXIge1xuICAgIGhlaWdodDogMTAwJTtcbiAgICB3aWR0aDogMCU7XG4gICAgYmFja2dyb3VuZDogdmFyKC0tZGVlcGxpYi1hY2NlbnQtY29sb3IpO1xuICB9XG59IiwiLmRlZXBsaWItY2hlY2tib3gtY29udGFpbmVyIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC1kaXJlY3Rpb246IHJvdztcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgZ2FwOiAwLjNlbTtcbiAgd2lkdGg6IGZpdC1jb250ZW50O1xuXG4gIHNwYW4ge1xuICAgIHVzZXItc2VsZWN0OiBub25lO1xuICB9XG5cbiAgLmRlZXBsaWItaW5wdXQge1xuICAgIHdpZHRoOiBtaW4oNXZoLCAyLjV2dyk7XG4gICAgaGVpZ2h0OiBtaW4oNXZoLCAyLjV2dyk7XG4gICAgd2lkdGg6IG1pbig1ZHZoLCAyLjVkdncpO1xuICAgIGhlaWdodDogbWluKDVkdmgsIDIuNWR2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMHZoLCAwLjV2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcblxuICAgICZbdHlwZT1cImNoZWNrYm94XCJdOmNoZWNrZWQ6OmJlZm9yZSB7XG4gICAgICB3aWR0aDogODAlO1xuICAgICAgaGVpZ2h0OiA4MCU7XG4gICAgfVxuICB9XG59XG5cbi5kZWVwbGliLWlucHV0LWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogMC4zZW07XG4gIHdpZHRoOiBmaXQtY29udGVudDtcblxuICBzcGFuIHtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgfVxuXG4gICY6aGFzKC5kZWVwbGliLXRleHQpIHtcbiAgICBtYXJnaW4tdG9wOiBtaW4oMXZoLCAwLjV2dyk7XG4gICAgbWFyZ2luLXRvcDogbWluKDFkdmgsIDAuNWR2dyk7XG4gIH1cblxuICAuZGVlcGxpYi1pbnB1dCB7XG4gICAgZm9udC1zaXplOiAwLjZlbTtcbiAgICBwYWRkaW5nOiBtaW4oMXZoLCAwLjV2dyk7XG4gICAgcGFkZGluZzogbWluKDFkdmgsIDAuNWR2dyk7XG4gICAgYmFja2dyb3VuZC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gICAgb3V0bGluZTogbm9uZTtcbiAgICBtaW4taGVpZ2h0OiBtaW4oNXZoLCAyLjV2dyk7XG4gICAgbWluLWhlaWdodDogbWluKDVkdmgsIDIuNWR2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMHZoLCAwLjV2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcblxuICAgICZbdHlwZT1cImNvbG9yXCJdIHtcbiAgICAgIHBhZGRpbmc6IDBweDtcbiAgICAgIHdpZHRoOiBtaW4oNXZoLCAyLjV2dyk7XG4gICAgICBoZWlnaHQ6IG1pbig1dmgsIDIuNXZ3KTtcbiAgICAgIHdpZHRoOiBtaW4oNWR2aCwgMi41ZHZ3KTtcbiAgICAgIGhlaWdodDogbWluKDVkdmgsIDIuNWR2dyk7XG4gICAgICBib3JkZXItcmFkaXVzOiAwcHg7XG5cbiAgICAgICY6ZGlzYWJsZWQge1xuICAgICAgICBib3JkZXI6IHZhcigtLWRlZXBsaWItYmxvY2tlZC1jb2xvcikgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItd2lkdGgpO1xuICAgICAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5cbi5kZWVwbGliLWRyb3Bkb3duLWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogbWluKDJ2aCwgMXZ3KTtcbiAgZ2FwOiBtaW4oMmR2aCwgMWR2dyk7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICB3aWR0aDogZml0LWNvbnRlbnQ7XG5cbiAgc2VsZWN0IHtcbiAgICBwYWRkaW5nOiAwIG1pbigxdmgsIDAuNXZ3KTtcbiAgICBwYWRkaW5nOiAwIG1pbigxZHZoLCAwLjVkdncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxdmgsIDAuNXZ3KTtcbiAgICBib3JkZXItcmFkaXVzOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbiAgfVxuXG4gIHNwYW4ge1xuICAgIHVzZXItc2VsZWN0OiBub25lO1xuICB9XG59IiwiLmRlZXBsaWItaGlnaGxpZ2h0LXRleHQge1xuICBmb250LXdlaWdodDogYm9sZDtcbiAgY29sb3I6IHJnYigyMDMsIDE4NSwgMjMpO1xufVxuXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyayddIGRpdi5DaGF0TWVzc2FnZS5kZWVwbGliLW1lc3NhZ2UsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIHtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgYm9yZGVyOiBtaW4oMC4yZHZoLCAwLjFkdncpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbiNUZXh0QXJlYUNoYXRMb2cgZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSB7XG4gIGJhY2tncm91bmQtY29sb3I6ICNlZWU7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCAjNDQwMTcxO1xuICBjb2xvcjogIzExMTtcbiAgcGFkZGluZy1sZWZ0OiBtaW4oMC42ZHZoLCAwLjNkdncpO1xuICBkaXNwbGF5OiBibG9jaztcbiAgd2hpdGUtc3BhY2U6IG5vcm1hbDtcbn1cblxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsnXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEsXG4jVGV4dEFyZWFDaGF0TG9nW2RhdGEtY29sb3J0aGVtZT0nZGFyazInXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbn1cblxuI1RleHRBcmVhQ2hhdExvZyBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlIGEge1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtd2VpZ2h0OiBib2xkO1xuICBjb2xvcjogIzExMTtcbn1cbiIsIi5kZWVwbGliLW1vZGFsIHtcbiAgcG9zaXRpb246IGZpeGVkO1xuICB0b3A6IDEwJTtcbiAgbGVmdDogNTAlO1xuICB0cmFuc2Zvcm06IHRyYW5zbGF0ZVgoLTUwJSk7XG4gIHotaW5kZXg6IDEwMDE7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuNWVtO1xuICB3aWR0aDogbWF4KDUwZHZ3LCAyNWR2aCk7XG4gIGZvbnQtc2l6ZTogbWluKDRkdmgsIDJkdncpO1xuICBwYWRkaW5nOiBtaW4oMmR2aCwgMWR2dyk7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjJkdmgsIDAuNmR2dyk7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuXG4gIC5kZWVwbGliLW1vZGFsLWlucHV0IHtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBmb250LXNpemU6IG1pbigyLjZkdmgsIDEuOGR2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgICBwYWRkaW5nOiBtaW4oMWR2aCwgMC41ZHZ3KTtcbiAgfVxuXG4gIGlucHV0LmRlZXBsaWItbW9kYWwtaW5wdXQge1xuICAgIG1heC13aWR0aDogbWF4KDUwZHZoLCAyNWR2dyk7XG4gIH1cblxuICAuZGVlcGxpYi1tb2RhbC1idXR0b24tY29udGFpbmVyIHtcbiAgICBkaXNwbGF5OiBmbGV4O1xuICAgIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gICAganVzdGlmeS1jb250ZW50OiBmbGV4LWVuZDtcbiAgICBnYXA6IDAuNWVtO1xuICAgIHdpZHRoOiAxMDAlO1xuXG4gICAgLmRlZXBsaWItYnV0dG9uIHtcbiAgICAgIGZvbnQtc2l6ZTogMC44ZW07XG4gICAgICBkaXNwbGF5OiBmbGV4O1xuICAgICAgd2lkdGg6IGF1dG87XG4gICAgICBwYWRkaW5nOiBtaW4oMC40dmgsIDAuMnZ3KSBtaW4oMnZoLCAxdncpO1xuXG4gICAgICAuYnV0dG9uLWxhYmVsIHtcbiAgICAgICAgZGlzcGxheTogY29udGVudHM7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLmRlZXBsaWItbW9kYWwtcHJvbXB0LWNvbnRhaW5lciB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIH1cbn1cblxuLmRlZXBsaWItbW9kYWwtYmxvY2tlciB7XG4gIHotaW5kZXg6IDEwMDA7XG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAwO1xuICBsZWZ0OiAwO1xuICB3aWR0aDogMTAwZHZ3O1xuICBoZWlnaHQ6IDEwMGR2aDtcbiAgYmFja2dyb3VuZC1jb2xvcjogcmdiYSgwLCAwLCAwLCAwLjUpO1xufVxuIl19 */`;
751
+
752
+ #deeplib-modal-import_export .deeplib-modal-checkbox-container {
753
+ margin-top: 0.5em;
754
+ display: flex;
755
+ flex-direction: column;
756
+ gap: var(--half-gap);
757
+ }
758
+ /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VSb290IjoiL21udC9zaGluZG93cy9TdHVmZi9Db2RlL2JjL0JDLURlZXBMaWIvc3JjL3N0eWxlcyIsInNvdXJjZXMiOlsidmFycy5zY3NzIiwiYnV0dG9ucy5zY3NzIiwiZWxlbWVudHMuc2NzcyIsImlucHV0cy5zY3NzIiwibWVzc2FnZXMuc2NzcyIsIm1vZGFsLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFBQTtFQUVFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUNkRjtFQUNFO0VBQ0E7RUFDQTs7QUFFQTtFQUVFOztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUVBO0VBQ0E7RUFDQTs7QUFHRjtFQUNFOztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBR0Y7RUFDRTs7O0FDM0NKO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOzs7QUFHRjtFQUNFOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFHRTtFQUNFO0VBQ0E7O0FBSEo7RUFNRTtFQUNBOztBQUdGO0VBQ0U7RUFDQTs7O0FBSUo7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTtFQUNBOzs7QUNuSEo7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOzs7QUFLTjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTs7QUFHRjtFQUNFO0VBQ0E7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOzs7QUFPUjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7O0FBR0Y7RUFDRTs7O0FDdkZKO0VBQ0U7RUFDQTs7O0FBR0Y7QUFBQTtFQUVFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0FBQUE7RUFFRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7OztBQzdCRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBO0VBQ0E7RUFDQTs7QUFHRjtFQUNFOztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7QUFFQTtFQUNFO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7O0FBS047RUFDRTtFQUNBO0VBQ0E7RUFDQTs7O0FBSUo7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBSUE7RUFDRTtFQUNBO0VBQ0E7RUFDQSIsInNvdXJjZXNDb250ZW50IjpbIi5kZWVwbGliLXN1YnNjcmVlbixcbi5kZWVwbGliLW1vZGFsIHtcbiAgLS1kZWVwbGliLWJhY2tncm91bmQtY29sb3I6IHZhcigtLXRtZC1tYWluLCB3aGl0ZSk7XG4gIC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yOiB2YXIoLS10bWQtZWxlbWVudCwgd2hpdGUpO1xuICAtLWRlZXBsaWItZWxlbWVudC1ob3Zlci1jb2xvcjogdmFyKC0tdG1kLWVsZW1lbnQtaG92ZXIsIGN5YW4pO1xuICAtLWRlZXBsaWItYWNjZW50LWNvbG9yOiB2YXIoLS10bWQtYWNjZW50LCAjRkZGRjg4KTtcbiAgLS1kZWVwbGliLWJsb2NrZWQtY29sb3I6IHZhcigtLXRtZC1ibG9ja2VkLCByZWQpO1xuICAtLWRlZXBsaWItdGV4dC1jb2xvcjogdmFyKC0tdG1kLXRleHQsIGJsYWNrKTtcbiAgLS1kZWVwbGliLWljb24tY29sb3I6IHZhcigtLXRtZC1hY2NlbnQsIGJsYWNrKTtcbiAgLS1kZWVwbGliLWljb24taG92ZXItY29sb3I6IHZhcigtLXRtZC1hY2NlbnQtaG92ZXIsIGJsYWNrKTtcbiAgLS1kZWVwbGliLWJvcmRlci1jb2xvcjogdmFyKC0tdG1kLWFjY2VudCwgYmxhY2spO1xuICAtLWRlZXBsaWItYm9yZGVyLXdpZHRoOiBtaW4oMC4ydmgsIDAuMXZ3KTtcbiAgLS1kZWVwbGliLWJvcmRlci13aWR0aDogbWluKDAuMmR2aCwgMC4xZHZ3KTtcbiAgLS1kZWVwbGliLWJvcmRlci1yYWRpdXM6IG1pbigxdmgsIDAuNXZ3KTtcbiAgLS1kZWVwbGliLWJvcmRlci1yYWRpdXM6IG1pbigxZHZoLCAwLjVkdncpO1xufVxuIiwiLmRlZXBsaWItYnV0dG9uIHtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IDEwMCU7XG5cbiAgJi5idXR0b24tc3R5bGluZyxcbiAgJi5idXR0b24tc3R5bGluZzo6YmVmb3JlIHtcbiAgICBib3JkZXItcmFkaXVzOiBtaW4oMS4wZHZoLCAwLjVkdncpO1xuICB9XG5cbiAgaW1nIHtcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgdG9wOiAwJTtcbiAgICBsZWZ0OiAwJTtcbiAgICB3aWR0aDogMTAwJTtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgYmFja2dyb3VuZC1wb3NpdGlvbjogbGVmdDtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWljb24tY29sb3IpO1xuICAgIGJhY2tncm91bmQtYmxlbmQtbW9kZTogbXVsdGlwbHk7XG4gICAgYmFja2dyb3VuZC1zaXplOiBjb250YWluO1xuICAgIG1hc2stcG9zaXRpb246IGxlZnQ7XG4gICAgbWFzay1zaXplOiBjb250YWluO1xuICAgIGJhY2tncm91bmQtcmVwZWF0OiBuby1yZXBlYXQ7XG4gICAgbWFzay1yZXBlYXQ6IG5vLXJlcGVhdDtcbiAgICBjb2xvcjogdHJhbnNwYXJlbnQ7XG5cbiAgICBiYWNrZ3JvdW5kLWltYWdlOiB2YXIoLS1pbWFnZSk7XG4gICAgbWFzay1pbWFnZTogdmFyKC0taW1hZ2UpO1xuICAgIHBvaW50ZXItZXZlbnRzOiBub25lO1xuICB9XG5cbiAgJjpob3ZlciBpbWcge1xuICAgIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItaWNvbi1ob3Zlci1jb2xvcik7XG4gIH1cblxuICAuYnV0dG9uLWxhYmVsIHtcbiAgICBiYWNrZ3JvdW5kLWNvbG9yOiB0cmFuc3BhcmVudCAhaW1wb3J0YW50O1xuICAgIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICAgIGZvbnQtc2l6ZTogbWluKDMuNmR2aCwgMS44ZHZ3KTtcbiAgICBkaXNwbGF5OiBjb250ZW50cztcbiAgfVxuXG4gIC5idXR0b24tdG9vbHRpcCB7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgfVxufSIsIiNkZWVwbGliLXBhZ2UtbGFiZWwge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG59XG5cbiNkZWVwbGliLXN1YnNjcmVlbi10aXRsZSB7XG4gIHRleHQtYWxpZ246IGxlZnQ7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xuICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG59XG5cbi5kZWVwbGliLXRleHQge1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbn1cblxuLmRlZXBsaWItc3Vic2NyZWVuIHtcbiAgcGFkZGluZzogMDtcbiAgbWFyZ2luOiAwO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbn1cblxuLmRlZXBsaWItc3Vic2NyZWVuICoge1xuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xuICBwb2ludGVyLWV2ZW50czogYWxsO1xufVxuXG4uZGVlcGxpYi1zZXR0aW5ncyB7XG4gIGRpc3BsYXk6IGdyaWQ7XG4gIGdyaWQtYXV0by1yb3dzOiBtaW4tY29udGVudDtcbiAgcGFkZGluZzogbWluKDEuMGR2aCwgMC41ZHZ3KTtcbiAgZ2FwOiAwLjNlbTtcbn1cblxuLmRlZXBsaWItbWlzYyB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW4tcmV2ZXJzZTtcbiAgZ2FwOiBtaW4oMXZoLCAwLjV2dyk7XG59XG5cbi5kZWVwbGliLXRvb2x0aXAge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIHBhZGRpbmc6IG1pbigxdmgsIDAuNXZ3KTtcbiAgZm9udC1zaXplOiAwLjhlbTtcbiAgYm9yZGVyOiBtaW4oMC4ydmgsIDAuMXZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIHotaW5kZXg6IDE7XG59XG5cbi5kZWVwbGliLW92ZXJmbG93LWJveCB7XG4gIGJvcmRlcjogdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbn1cblxuLmRlZXBsaWItcHJldi1uZXh0IHtcbiAgZGlzcGxheTogZmxleDtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAganVzdGlmeS1jb250ZW50OiBzcGFjZS1iZXR3ZWVuO1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBnYXA6IG1pbigyZHZoLCAxZHZ3KTtcbiAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gIGJvcmRlcjogbWluKDAuMnZoLCAwLjF2dykgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpO1xuXG4gIC5kZWVwbGliLXByZXYtbmV4dC1idXR0b24ge1xuICAgICY6aG92ZXIge1xuICAgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tZGVlcGxpYi1lbGVtZW50LWhvdmVyLWNvbG9yKTtcbiAgICAgIGJvcmRlci1yYWRpdXM6IHZhcigtLWRlZXBsaWItYm9yZGVyLXJhZGl1cyk7XG4gICAgfVxuXG4gICAgaGVpZ2h0OiAxMDAlO1xuICAgIGFzcGVjdC1yYXRpbzogMTtcbiAgfVxuXG4gIC5kZWVwbGliLXByZXYtbmV4dC1sYWJlbCB7XG4gICAgd2hpdGUtc3BhY2U6IG5vd3JhcDtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgfVxufVxuXG4jZGVlcGxpYi1uYXYtbWVudSB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGdhcDogbWluKDJkdmgsIDFkdncpO1xuICB6LWluZGV4OiAxO1xuXG4gICY+LmRlZXBsaWItYnV0dG9uIHtcbiAgICBmbGV4OiAxIDAgYXV0bztcbiAgfVxufVxuXG4jZGVlcGxpYi1zdG9yYWdlLW1ldGVyIHtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB0b3A6IDBweDtcbiAgbGVmdDogMHB4O1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBvdmVyZmxvdzogaGlkZGVuO1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBib3JkZXI6IHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLWRlZXBsaWItYm9yZGVyLXJhZGl1cyk7XG4gIHotaW5kZXg6IC0xO1xuXG4gICNkZWVwbGliLXN0b3JhZ2UtYmFyIHtcbiAgICBoZWlnaHQ6IDEwMCU7XG4gICAgd2lkdGg6IDAlO1xuICAgIGJhY2tncm91bmQ6IHZhcigtLWRlZXBsaWItYWNjZW50LWNvbG9yKTtcbiAgfVxufSIsIi5kZWVwbGliLWNoZWNrYm94LWNvbnRhaW5lciB7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGZsZXgtZGlyZWN0aW9uOiByb3c7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGdhcDogMC4zZW07XG4gIHdpZHRoOiBmaXQtY29udGVudDtcblxuICBzcGFuIHtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgfVxuXG4gIC5kZWVwbGliLWlucHV0IHtcbiAgICB3aWR0aDogbWluKDV2aCwgMi41dncpO1xuICAgIGhlaWdodDogbWluKDV2aCwgMi41dncpO1xuICAgIHdpZHRoOiBtaW4oNWR2aCwgMi41ZHZ3KTtcbiAgICBoZWlnaHQ6IG1pbig1ZHZoLCAyLjVkdncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjB2aCwgMC41dncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG5cbiAgICAmW3R5cGU9XCJjaGVja2JveFwiXTpjaGVja2VkOjpiZWZvcmUge1xuICAgICAgd2lkdGg6IDgwJTtcbiAgICAgIGhlaWdodDogODAlO1xuICAgIH1cbiAgfVxufVxuXG4uZGVlcGxpYi1pbnB1dC1jb250YWluZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDAuM2VtO1xuICB3aWR0aDogZml0LWNvbnRlbnQ7XG5cbiAgc3BhbiB7XG4gICAgdXNlci1zZWxlY3Q6IG5vbmU7XG4gIH1cblxuICAmOmhhcyguZGVlcGxpYi10ZXh0KSB7XG4gICAgbWFyZ2luLXRvcDogbWluKDF2aCwgMC41dncpO1xuICAgIG1hcmdpbi10b3A6IG1pbigxZHZoLCAwLjVkdncpO1xuICB9XG5cbiAgLmRlZXBsaWItaW5wdXQge1xuICAgIGZvbnQtc2l6ZTogMC42ZW07XG4gICAgcGFkZGluZzogbWluKDF2aCwgMC41dncpO1xuICAgIHBhZGRpbmc6IG1pbigxZHZoLCAwLjVkdncpO1xuICAgIGJhY2tncm91bmQtY29sb3I6IHRyYW5zcGFyZW50O1xuICAgIG91dGxpbmU6IG5vbmU7XG4gICAgbWluLWhlaWdodDogbWluKDV2aCwgMi41dncpO1xuICAgIG1pbi1oZWlnaHQ6IG1pbig1ZHZoLCAyLjVkdncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjB2aCwgMC41dncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG5cbiAgICAmW3R5cGU9XCJjb2xvclwiXSB7XG4gICAgICBwYWRkaW5nOiAwcHg7XG4gICAgICB3aWR0aDogbWluKDV2aCwgMi41dncpO1xuICAgICAgaGVpZ2h0OiBtaW4oNXZoLCAyLjV2dyk7XG4gICAgICB3aWR0aDogbWluKDVkdmgsIDIuNWR2dyk7XG4gICAgICBoZWlnaHQ6IG1pbig1ZHZoLCAyLjVkdncpO1xuICAgICAgYm9yZGVyLXJhZGl1czogMHB4O1xuXG4gICAgICAmOmRpc2FibGVkIHtcbiAgICAgICAgYm9yZGVyOiB2YXIoLS1kZWVwbGliLWJsb2NrZWQtY29sb3IpIHNvbGlkIHZhcigtLWRlZXBsaWItYm9yZGVyLXdpZHRoKTtcbiAgICAgICAgY3Vyc29yOiBub3QtYWxsb3dlZDtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuXG4uZGVlcGxpYi1kcm9wZG93bi1jb250YWluZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IG1pbigydmgsIDF2dyk7XG4gIGdhcDogbWluKDJkdmgsIDFkdncpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcbiAgd2lkdGg6IGZpdC1jb250ZW50O1xuXG4gIHNlbGVjdCB7XG4gICAgcGFkZGluZzogMCBtaW4oMXZoLCAwLjV2dyk7XG4gICAgcGFkZGluZzogMCBtaW4oMWR2aCwgMC41ZHZ3KTtcbiAgICBib3JkZXItcmFkaXVzOiBtaW4oMXZoLCAwLjV2dyk7XG4gICAgYm9yZGVyLXJhZGl1czogbWluKDFkdmgsIDAuNWR2dyk7XG4gIH1cblxuICBzcGFuIHtcbiAgICB1c2VyLXNlbGVjdDogbm9uZTtcbiAgfVxufSIsIi5kZWVwbGliLWhpZ2hsaWdodC10ZXh0IHtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7XG4gIGNvbG9yOiByZ2IoMjAzLCAxODUsIDIzKTtcbn1cblxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsnXSBkaXYuQ2hhdE1lc3NhZ2UuZGVlcGxpYi1tZXNzYWdlLFxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsyJ10gZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSB7XG4gIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWRlZXBsaWItZWxlbWVudC1jb2xvcik7XG4gIGJvcmRlcjogbWluKDAuMmR2aCwgMC4xZHZ3KSBzb2xpZCB2YXIoLS1kZWVwbGliLWJvcmRlci1jb2xvcik7XG4gIGNvbG9yOiB2YXIoLS1kZWVwbGliLXRleHQtY29sb3IpO1xufVxuXG4jVGV4dEFyZWFDaGF0TG9nIGRpdi5DaGF0TWVzc2FnZS5kZWVwbGliLW1lc3NhZ2Uge1xuICBiYWNrZ3JvdW5kLWNvbG9yOiAjZWVlO1xuICBib3JkZXI6IG1pbigwLjJkdmgsIDAuMWR2dykgc29saWQgIzQ0MDE3MTtcbiAgY29sb3I6ICMxMTE7XG4gIHBhZGRpbmctbGVmdDogbWluKDAuNmR2aCwgMC4zZHZ3KTtcbiAgZGlzcGxheTogYmxvY2s7XG4gIHdoaXRlLXNwYWNlOiBub3JtYWw7XG59XG5cbiNUZXh0QXJlYUNoYXRMb2dbZGF0YS1jb2xvcnRoZW1lPSdkYXJrJ10gZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSBhLFxuI1RleHRBcmVhQ2hhdExvZ1tkYXRhLWNvbG9ydGhlbWU9J2RhcmsyJ10gZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSBhIHtcbiAgY29sb3I6IHZhcigtLWRlZXBsaWItdGV4dC1jb2xvcik7XG59XG5cbiNUZXh0QXJlYUNoYXRMb2cgZGl2LkNoYXRNZXNzYWdlLmRlZXBsaWItbWVzc2FnZSBhIHtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBmb250LXdlaWdodDogYm9sZDtcbiAgY29sb3I6ICMxMTE7XG59XG4iLCIuZGVlcGxpYi1tb2RhbCB7XG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAxMCU7XG4gIGxlZnQ6IDUwJTtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVYKC01MCUpO1xuICB6LWluZGV4OiAxMDAxO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgYWxpZ24taXRlbXM6IGNlbnRlcjtcbiAgZ2FwOiAwLjVlbTtcbiAgd2lkdGg6IG1heCg1MGR2dywgMjVkdmgpO1xuICBmb250LXNpemU6IG1pbig0ZHZoLCAyZHZ3KTtcbiAgcGFkZGluZzogbWluKDJkdmgsIDFkdncpO1xuICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1kZWVwbGliLWVsZW1lbnQtY29sb3IpO1xuICBib3JkZXItcmFkaXVzOiBtaW4oMS4yZHZoLCAwLjZkdncpO1xuICBib3JkZXI6IG1pbigwLjJkdmgsIDAuMWR2dykgc29saWQgdmFyKC0tZGVlcGxpYi1ib3JkZXItY29sb3IpO1xuICBjb2xvcjogdmFyKC0tZGVlcGxpYi10ZXh0LWNvbG9yKTtcblxuICAuZGVlcGxpYi1tb2RhbC1pbnB1dCB7XG4gICAgd2lkdGg6IDEwMCU7XG4gICAgZm9udC1zaXplOiBtaW4oMi42ZHZoLCAxLjhkdncpO1xuICAgIGJvcmRlci1yYWRpdXM6IG1pbigxLjBkdmgsIDAuNWR2dyk7XG4gICAgcGFkZGluZzogbWluKDFkdmgsIDAuNWR2dyk7XG4gIH1cblxuICBpbnB1dC5kZWVwbGliLW1vZGFsLWlucHV0IHtcbiAgICBtYXgtd2lkdGg6IG1heCg1MGR2aCwgMjVkdncpO1xuICB9XG5cbiAgLmRlZXBsaWItbW9kYWwtYnV0dG9uLWNvbnRhaW5lciB7XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBmbGV4LWRpcmVjdGlvbjogcm93O1xuICAgIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7XG4gICAgZ2FwOiAwLjVlbTtcbiAgICB3aWR0aDogMTAwJTtcblxuICAgIC5kZWVwbGliLWJ1dHRvbiB7XG4gICAgICBmb250LXNpemU6IDAuOGVtO1xuICAgICAgZGlzcGxheTogZmxleDtcbiAgICAgIHdpZHRoOiBhdXRvO1xuICAgICAgcGFkZGluZzogbWluKDAuNHZoLCAwLjJ2dykgbWluKDJ2aCwgMXZ3KTtcblxuICAgICAgLmJ1dHRvbi1sYWJlbCB7XG4gICAgICAgIGRpc3BsYXk6IGNvbnRlbnRzO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC5kZWVwbGliLW1vZGFsLXByb21wdC1jb250YWluZXIge1xuICAgIGRpc3BsYXk6IGZsZXg7XG4gICAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjtcbiAgICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjtcbiAgICBhbGlnbi1pdGVtczogY2VudGVyO1xuICB9XG59XG5cbi5kZWVwbGliLW1vZGFsLWJsb2NrZXIge1xuICB6LWluZGV4OiAxMDAwO1xuICBwb3NpdGlvbjogZml4ZWQ7XG4gIHRvcDogMDtcbiAgbGVmdDogMDtcbiAgd2lkdGg6IDEwMGR2dztcbiAgaGVpZ2h0OiAxMDBkdmg7XG4gIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTtcbn1cblxuI2RlZXBsaWItbW9kYWwtaW1wb3J0X2V4cG9ydCB7XG4gIC5kZWVwbGliLW1vZGFsLWNoZWNrYm94LWNvbnRhaW5lciB7XG4gICAgbWFyZ2luLXRvcDogMC41ZW07XG4gICAgZGlzcGxheTogZmxleDtcbiAgICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICAgIGdhcDogdmFyKC0taGFsZi1nYXApO1xuICB9XG59Il19 */`;
953
759
 
954
760
  // src/base/initialization.ts
955
761
  var modStorage;
956
762
  var sdk;
957
- var logger;
763
+ var modLogger;
764
+ var MOD_NAME;
958
765
  function initMod(options) {
959
- sdk = new ModSdkManager(options.modInfo.info, options.modInfo.options);
960
- const MOD_NAME = ModSdkManager.ModInfo.name;
961
- modStorage = new ModStorage(ModSdkManager.ModInfo.name);
962
- logger = new Logger(MOD_NAME);
963
- Style.injectInline("deeplib-style", styles_default);
964
- logger.debug("Init wait");
965
- if (CurrentScreen == null || CurrentScreen === "Login") {
966
- options.beforeLogin?.();
967
- const removeHook = sdk.hookFunction("LoginResponse", 0, (args, next) => {
968
- logger.debug("Init! LoginResponse caught: ", args);
969
- next(args);
970
- const response = args[0];
971
- if (response === "InvalidNamePassword") return next(args);
972
- if (response && typeof response.Name === "string" && typeof response.AccountName === "string") {
973
- init(options);
974
- removeHook();
975
- }
766
+ const url = "https://cdn.jsdelivr.net/npm/bondage-club-mod-sdk@1.2.0/+esm";
767
+ import(`${url}`).then(() => {
768
+ sdk = new ModSdkManager({
769
+ name: options.modName,
770
+ fullName: options.modName,
771
+ version: MOD_VERSION,
772
+ repository: options.modRepository
976
773
  });
977
- } else {
978
- logger.debug(`Already logged in, initing ${MOD_NAME}`);
979
- init(options);
980
- }
774
+ MOD_NAME = options.modName;
775
+ modStorage = new ModStorage(options.modName);
776
+ modLogger = new Logger(MOD_NAME);
777
+ Style.injectInline("deeplib-style", styles_default);
778
+ modLogger.debug("Init wait");
779
+ if (!CurrentScreen || CurrentScreen === "Login") {
780
+ options.beforeLogin?.();
781
+ const removeHook = sdk.hookFunction("LoginResponse", 0, (args, next) => {
782
+ modLogger.debug("Init! LoginResponse caught: ", args);
783
+ next(args);
784
+ const response = args[0];
785
+ if (response === "InvalidNamePassword") return next(args);
786
+ if (response && typeof response.Name === "string" && typeof response.AccountName === "string") {
787
+ init(options);
788
+ removeHook();
789
+ }
790
+ });
791
+ } else {
792
+ modLogger.debug(`Already logged in, initing ${MOD_NAME}`);
793
+ init(options);
794
+ }
795
+ });
981
796
  }
982
797
  __name(initMod, "initMod");
983
798
  async function init(options) {
984
- const MOD_NAME = ModSdkManager.ModInfo.name;
985
- const MOD_VERSION = ModSdkManager.ModInfo.version;
986
- if (window[MOD_NAME + "Loaded"]) return;
799
+ if (window[options.modName + "Loaded"]) return;
987
800
  modStorage.load();
988
801
  await Localization.init(options.translationOptions);
989
- if (options.modules && !initModules(options.modules)) {
802
+ options.modules ??= [];
803
+ const modulesToRegister = [];
804
+ if (!options.modules.some((m) => m instanceof VersionModule)) {
805
+ modulesToRegister.push(new VersionModule());
806
+ }
807
+ modulesToRegister.push(...options.modules);
808
+ if (!initModules(modulesToRegister)) {
990
809
  unloadMod();
991
810
  return;
992
811
  }
993
812
  await options.initFunction?.();
994
- if (options.mainMenuOptions)
995
- MainMenu.setOptions(options.mainMenuOptions);
996
- window[MOD_NAME + "Loaded"] = true;
997
- logger.log(`Loaded! Version: ${MOD_VERSION}`);
813
+ if (options.mainMenuOptions && getModule("GUI")) {
814
+ MainMenu.setOptions({
815
+ ...options.mainMenuOptions,
816
+ repoLink: options.modRepository
817
+ });
818
+ }
819
+ window[options.modName + "Loaded"] = true;
820
+ modLogger.log(`Loaded! Version: ${MOD_VERSION_CAPTION}`);
998
821
  }
999
822
  __name(init, "init");
1000
823
  function initModules(modulesToRegister) {
@@ -1013,15 +836,15 @@ function initModules(modulesToRegister) {
1013
836
  for (const module of modules()) {
1014
837
  module.registerDefaultSettings(modStorage.playerStorage);
1015
838
  }
1016
- logger.debug("Modules Loaded.");
839
+ modLogger.debug("Modules Loaded.");
1017
840
  return true;
1018
841
  }
1019
842
  __name(initModules, "initModules");
1020
843
  function unloadMod() {
1021
- const MOD_NAME = ModSdkManager.ModInfo.name;
1022
844
  unloadModules();
845
+ sdk.unload();
1023
846
  delete window[MOD_NAME + "Loaded"];
1024
- logger.debug("Unloaded.");
847
+ modLogger.debug("Unloaded.");
1025
848
  return true;
1026
849
  }
1027
850
  __name(unloadMod, "unloadMod");
@@ -1143,6 +966,7 @@ var VersionModule = class _VersionModule extends BaseModule {
1143
966
  static afterAll;
1144
967
  constructor(options) {
1145
968
  super();
969
+ options ??= {};
1146
970
  _VersionModule.newVersionMessage = options.newVersionMessage;
1147
971
  if (options.migrators) {
1148
972
  _VersionModule.migrators = options.migrators;
@@ -1159,7 +983,7 @@ var VersionModule = class _VersionModule extends BaseModule {
1159
983
  * - Hooks into `ChatRoomSync` to show a "new version" message when applicable.
1160
984
  */
1161
985
  load() {
1162
- _VersionModule.version = ModSdkManager.ModInfo.version;
986
+ _VersionModule.version = MOD_VERSION;
1163
987
  _VersionModule.checkVersionUpdate();
1164
988
  if (modStorage.playerStorage.GlobalModule.doShowNewVersionMessage && _VersionModule.isItNewVersion) {
1165
989
  _VersionModule.sendNewVersionMessage();
@@ -1197,8 +1021,8 @@ var VersionModule = class _VersionModule extends BaseModule {
1197
1021
  for (const migrator of toMigrate) {
1198
1022
  _VersionModule.beforeEach?.();
1199
1023
  migrator.migrate();
1200
- deepLibLogger.info(
1201
- `Migrating ${ModSdkManager.ModInfo.name} from ${previousVersion} to ${migrator.migrationVersion} with ${migrator.constructor.name}`
1024
+ modLogger.info(
1025
+ `Migrating from ${previousVersion} to ${migrator.migrationVersion} with ${migrator.constructor.name}`
1202
1026
  );
1203
1027
  _VersionModule.afterEach?.();
1204
1028
  }
@@ -1209,7 +1033,7 @@ var VersionModule = class _VersionModule extends BaseModule {
1209
1033
  if (!_VersionModule.newVersionMessage) return;
1210
1034
  const beepLogLength = FriendListBeepLog.push({
1211
1035
  MemberNumber: Player.MemberNumber,
1212
- MemberName: ModSdkManager.ModInfo.name,
1036
+ MemberName: MOD_NAME,
1213
1037
  ChatRoomName: getText("module.version.version_update"),
1214
1038
  ChatRoomSpace: "X",
1215
1039
  Private: false,
@@ -1219,7 +1043,7 @@ var VersionModule = class _VersionModule extends BaseModule {
1219
1043
  });
1220
1044
  const beepIdx = beepLogLength - 1;
1221
1045
  const title = CommonStringPartitionReplace(getText("module.version.new_version_toast_title"), {
1222
- $modName$: ModSdkManager.ModInfo.name,
1046
+ $modName$: MOD_NAME,
1223
1047
  $modVersion$: _VersionModule.version
1224
1048
  }).join("");
1225
1049
  const data = FriendListBeepLog[beepIdx];
@@ -1257,7 +1081,7 @@ var VersionModule = class _VersionModule extends BaseModule {
1257
1081
  /** Saves the current mod version into persistent player storage. */
1258
1082
  static saveVersion() {
1259
1083
  if (modStorage.playerStorage) {
1260
- Player[ModSdkManager.ModInfo.name].Version = _VersionModule.version;
1084
+ modStorage.playerStorage.Version = _VersionModule.version;
1261
1085
  }
1262
1086
  }
1263
1087
  /** Loads the stored mod version from persistent player storage. */
@@ -1846,221 +1670,6 @@ function elementPrevNext(options) {
1846
1670
  return retElem;
1847
1671
  }
1848
1672
  __name(elementPrevNext, "elementPrevNext");
1849
- var Modal = class _Modal {
1850
- constructor(opts) {
1851
- this.opts = opts;
1852
- opts ??= {};
1853
- opts.closeOnBackdrop ??= true;
1854
- const promptId = `modal-prompt-${Date.now()}`;
1855
- const prompt = (CommonIsArray(opts.prompt) ? opts.prompt : [opts.prompt]).filter((i) => i != null) ?? [""];
1856
- this.dialog = ElementCreate({
1857
- tag: "dialog",
1858
- classList: ["deeplib-modal"],
1859
- attributes: {
1860
- role: "dialog",
1861
- "aria-modal": "true",
1862
- "aria-labelledby": promptId
1863
- },
1864
- style: {
1865
- fontFamily: CommonGetFontName()
1866
- },
1867
- children: [
1868
- {
1869
- tag: "div",
1870
- classList: ["deeplib-modal-prompt-container"],
1871
- children: [
1872
- ...prompt
1873
- ]
1874
- },
1875
- {
1876
- tag: "div",
1877
- classList: ["deeplib-modal-prompt"],
1878
- attributes: {
1879
- id: promptId
1880
- },
1881
- children: [
1882
- opts.input ? this.renderInput(opts.input) : void 0
1883
- ]
1884
- },
1885
- this.renderButtons()
1886
- ]
1887
- });
1888
- this.blocker = this.createBlocker();
1889
- this.renderButtons();
1890
- document.body.append(this.createBlocker(), this.dialog);
1891
- this.setupFocusTrap();
1892
- if (opts.timeoutMs) {
1893
- this.timeoutId = window.setTimeout(() => this.close("timeout"), opts.timeoutMs);
1894
- }
1895
- }
1896
- static {
1897
- __name(this, "Modal");
1898
- }
1899
- dialog;
1900
- blocker;
1901
- inputEl;
1902
- timeoutId;
1903
- /** Static modal queue. */
1904
- static queue = [];
1905
- /** Flag to indicate if a modal is currently being shown. */
1906
- static processing = false;
1907
- /**
1908
- * Displays the modal and resolves with the chosen action and input value.
1909
- */
1910
- show() {
1911
- return _Modal.enqueue(this);
1912
- }
1913
- /**
1914
- * Shows a simple alert modal with a single "OK" button.
1915
- */
1916
- static async alert(msg, timeoutMs) {
1917
- await new _Modal({
1918
- prompt: msg,
1919
- buttons: [{ action: "close", text: getText("modal.button.ok") }],
1920
- timeoutMs,
1921
- escapeAction: "close"
1922
- }).show();
1923
- }
1924
- /**
1925
- * Shows a confirmation modal with "Cancel" and "OK" buttons.
1926
- * Returns true if "OK" is clicked.
1927
- */
1928
- static async confirm(msg) {
1929
- const [action] = await new _Modal({
1930
- prompt: msg,
1931
- buttons: [{ text: getText("modal.button.decline"), action: "decline" }, { text: getText("modal.button.confirm"), action: "confirm" }],
1932
- escapeAction: "decline",
1933
- enterAction: "confirm"
1934
- }).show();
1935
- return action === "confirm";
1936
- }
1937
- /**
1938
- * Shows a prompt modal with an input field and "Submit"/"Cancel" buttons.
1939
- * Returns the input value if submitted, otherwise null.
1940
- */
1941
- static async prompt(msg, defaultValue = "") {
1942
- const [action, value] = await new _Modal({
1943
- prompt: msg,
1944
- timeoutMs: 0,
1945
- input: { type: "input", defaultValue },
1946
- buttons: [{ text: getText("modal.button.cancel"), action: "cancel" }, { text: getText("modal.button.submit"), action: "submit" }],
1947
- escapeAction: "cancel",
1948
- enterAction: "submit"
1949
- }).show();
1950
- return action === "submit" ? value : null;
1951
- }
1952
- /** Creates the input element for the modal, applying configuration and validation. */
1953
- renderInput(cfg) {
1954
- const el = document.createElement(cfg.type);
1955
- el.classList.add("deeplib-modal-input");
1956
- if (cfg.placeholder) el.placeholder = cfg.placeholder;
1957
- if (cfg.readOnly) el.readOnly = true;
1958
- if (cfg.defaultValue) el.value = cfg.defaultValue;
1959
- if (cfg.type === "textarea") el.rows = 5;
1960
- el.addEventListener("input", () => {
1961
- const err = cfg.validate?.(el.value);
1962
- el.setCustomValidity(err || "");
1963
- });
1964
- this.inputEl = el;
1965
- return el;
1966
- }
1967
- /** Creates modal action buttons from configuration. */
1968
- renderButtons() {
1969
- const container = document.createElement("div");
1970
- container.classList.add("deeplib-modal-button-container");
1971
- const btns = this.opts.buttons ? [...this.opts.buttons] : [];
1972
- btns.forEach((b) => {
1973
- const btn = advElement.createButton({
1974
- id: `deeplib-modal-${b.action}`,
1975
- onClick: /* @__PURE__ */ __name(() => this.close(b.action), "onClick"),
1976
- options: {
1977
- disabled: b.disabled,
1978
- label: b.text
1979
- }
1980
- });
1981
- container.append(btn);
1982
- });
1983
- return container;
1984
- }
1985
- /** Creates the modal backdrop blocker with optional click-to-close behavior. */
1986
- createBlocker() {
1987
- const blocker = document.createElement("div");
1988
- blocker.classList.add("deeplib-modal-blocker");
1989
- blocker.title = "Click to close";
1990
- if (this.opts.closeOnBackdrop !== false)
1991
- blocker.addEventListener("click", () => this.close("close"));
1992
- return blocker;
1993
- }
1994
- /** Implements a focus trap to keep keyboard navigation inside the modal. */
1995
- setupFocusTrap() {
1996
- const focusable = 'button, [href], input, textarea, select, [tabindex]:not([tabindex="-1"])';
1997
- const elements = Array.from(this.dialog.querySelectorAll(focusable));
1998
- const first = elements[0];
1999
- const last = elements[elements.length - 1];
2000
- this.dialog.addEventListener("keydown", (e) => {
2001
- if (e.key === "Tab") {
2002
- if (elements.length === 0) {
2003
- e.preventDefault();
2004
- return;
2005
- }
2006
- if (e.shiftKey) {
2007
- if (document.activeElement === first) {
2008
- last.focus();
2009
- e.preventDefault();
2010
- }
2011
- } else {
2012
- if (document.activeElement === last) {
2013
- first.focus();
2014
- e.preventDefault();
2015
- }
2016
- }
2017
- } else if (e.key === "Escape") {
2018
- e.stopPropagation();
2019
- this.close(this.opts.escapeAction ?? "close");
2020
- } else if (e.key === "Enter") {
2021
- if (elements.some((el) => el === document.activeElement) && document.activeElement !== this.inputEl) return;
2022
- e.preventDefault();
2023
- e.stopPropagation();
2024
- this.close(this.opts.enterAction ?? "submit");
2025
- }
2026
- });
2027
- window.requestAnimationFrame(() => {
2028
- (this.inputEl || first)?.focus();
2029
- });
2030
- }
2031
- /** Closes the modal, cleans up DOM, resolves promise, and shows next queued modal. */
2032
- close(action) {
2033
- if (this.timeoutId) clearTimeout(this.timeoutId);
2034
- this.dialog.close();
2035
- this.dialog.remove();
2036
- this.blocker.remove();
2037
- document.body.querySelector(".deeplib-modal-blocker")?.remove();
2038
- const value = this.inputEl?.value ?? "";
2039
- this.resolve([action, value]);
2040
- _Modal.dequeue();
2041
- }
2042
- /**
2043
- * An internal function where we will save promise function.
2044
- */
2045
- resolve = /* @__PURE__ */ __name(() => {
2046
- }, "resolve");
2047
- /** A function that adds a modal to the queue and returns a promise */
2048
- static enqueue(modal) {
2049
- _Modal.queue.push(modal);
2050
- if (!_Modal.processing) _Modal.dequeue();
2051
- return new Promise((resolve) => modal.resolve = resolve);
2052
- }
2053
- /** A function that processes the queue, removing the first modal */
2054
- static dequeue() {
2055
- const modal = _Modal.queue.shift();
2056
- if (modal) {
2057
- _Modal.processing = true;
2058
- modal.dialog.show();
2059
- } else {
2060
- _Modal.processing = false;
2061
- }
2062
- }
2063
- };
2064
1673
 
2065
1674
  // src/screens/main_menu.ts
2066
1675
  var MainMenu = class _MainMenu extends BaseSubscreen {
@@ -2100,7 +1709,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2100
1709
  ElementMenu.AppendButton(menu, exitButton);
2101
1710
  }
2102
1711
  for (const screen of this.subscreens) {
2103
- if (screen.options.name == "mainmenu") continue;
1712
+ if (screen.options.name === "mainmenu") continue;
2104
1713
  const button = advElement.createButton({
2105
1714
  id: `${screen.options.name}-button`,
2106
1715
  onClick: /* @__PURE__ */ __name(() => {
@@ -2174,7 +1783,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2174
1783
  }
2175
1784
  if (_MainMenu.options.storageFullnessIndicator) {
2176
1785
  const maxStorageCapacityKB = 180;
2177
- const currentStorageCapacityKB = byteToKB(ModStorage.measureSize(modStorage.extensionStorage));
1786
+ const currentStorageCapacityKB = byteToKB(modStorage.storageSize());
2178
1787
  const fullness = (currentStorageCapacityKB / maxStorageCapacityKB * 100).toFixed(1);
2179
1788
  const storageFullnessWrapper = advElement.createButton({
2180
1789
  id: CommonGenerateUniqueID(),
@@ -2256,15 +1865,317 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2256
1865
  }
2257
1866
  };
2258
1867
 
2259
- // src/screens/import_export.ts
2260
- var GuiImportExport = class extends BaseSubscreen {
1868
+ // src/utilities/translation.ts
1869
+ var Localization = class _Localization {
2261
1870
  static {
2262
- __name(this, "GuiImportExport");
1871
+ __name(this, "Localization");
2263
1872
  }
2264
- importExportOptions;
2265
- static subscreenOptions = {
2266
- name: "import-export"
2267
- };
1873
+ static LibTranslation = {};
1874
+ static ModTranslation = {};
1875
+ static PathToModTranslation;
1876
+ static PathToLibTranslation = `${PUBLIC_URL}/dl_translations/`;
1877
+ static DefaultLanguage = "en";
1878
+ /** Flag to prevent re-initialization */
1879
+ static initialized = false;
1880
+ /** Initialize the localization system by loading translation files. */
1881
+ static async init(initOptions) {
1882
+ if (_Localization.initialized) return;
1883
+ _Localization.initialized = true;
1884
+ _Localization.PathToModTranslation = (() => {
1885
+ if (!initOptions?.pathToTranslationsFolder) return void 0;
1886
+ return initOptions.pathToTranslationsFolder.endsWith("/") ? initOptions.pathToTranslationsFolder : `${initOptions.pathToTranslationsFolder}/`;
1887
+ })();
1888
+ _Localization.DefaultLanguage = initOptions?.defaultLanguage || _Localization.DefaultLanguage;
1889
+ const lang = initOptions?.fixedLanguage ? _Localization.DefaultLanguage : TranslationLanguage.toLowerCase();
1890
+ const libTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, lang);
1891
+ if (lang === _Localization.DefaultLanguage) {
1892
+ _Localization.LibTranslation = libTranslation;
1893
+ } else {
1894
+ const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, _Localization.DefaultLanguage);
1895
+ _Localization.LibTranslation = { ...fallbackTranslation, ...libTranslation };
1896
+ }
1897
+ if (!_Localization.PathToModTranslation) return;
1898
+ const modTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, lang);
1899
+ if (lang === _Localization.DefaultLanguage) {
1900
+ _Localization.ModTranslation = modTranslation;
1901
+ } else {
1902
+ const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, _Localization.DefaultLanguage);
1903
+ _Localization.ModTranslation = { ...fallbackTranslation, ...modTranslation };
1904
+ }
1905
+ }
1906
+ /** Get a translated string from mod translations by source tag. */
1907
+ static getTextMod(srcTag) {
1908
+ return _Localization.ModTranslation?.[srcTag] || void 0;
1909
+ }
1910
+ /** Get a translated string from library translations by source tag. */
1911
+ static getTextLib(srcTag) {
1912
+ return _Localization.LibTranslation?.[srcTag] || void 0;
1913
+ }
1914
+ /**
1915
+ * Fetch and parse a language file from the given base URL and language code.
1916
+ * Falls back to default language if the requested language file is unavailable.
1917
+ */
1918
+ static async fetchLanguageFile(baseUrl, lang) {
1919
+ const response = await fetch(`${baseUrl}${lang}.lang`);
1920
+ if (lang !== _Localization.DefaultLanguage && !response.ok) {
1921
+ return this.fetchLanguageFile(baseUrl, _Localization.DefaultLanguage);
1922
+ }
1923
+ if (!response.ok) {
1924
+ return {};
1925
+ }
1926
+ const langFileContent = await response.text();
1927
+ return this.parseLanguageFile(langFileContent);
1928
+ }
1929
+ /**
1930
+ * Parse the raw content of a language file into a TranslationDict.
1931
+ * Ignores empty lines and comments starting with '#'.
1932
+ */
1933
+ static parseLanguageFile(content) {
1934
+ const translations = {};
1935
+ const lines = content.split("\n");
1936
+ for (const line of lines) {
1937
+ const trimmed = line.trim();
1938
+ if (!trimmed || trimmed.startsWith("#")) continue;
1939
+ const [key, ...rest] = trimmed.split("=");
1940
+ translations[key.trim()] = rest.join("=").trim();
1941
+ }
1942
+ return translations;
1943
+ }
1944
+ };
1945
+ var getText = /* @__PURE__ */ __name((srcTag) => {
1946
+ return Localization.getTextMod(srcTag) || Localization.getTextLib(srcTag) || srcTag;
1947
+ }, "getText");
1948
+
1949
+ // src/utilities/elements/modal.ts
1950
+ var Modal = class _Modal {
1951
+ constructor(opts) {
1952
+ this.opts = opts;
1953
+ opts ??= {};
1954
+ opts.closeOnBackdrop ??= true;
1955
+ const promptId = `modal-prompt-${Date.now()}`;
1956
+ const prompt = (CommonIsArray(opts.prompt) ? opts.prompt : [opts.prompt]).filter((i) => i !== null) ?? [""];
1957
+ this.dialog = ElementCreate({
1958
+ tag: "dialog",
1959
+ classList: ["deeplib-modal"],
1960
+ attributes: {
1961
+ id: this.opts.modalId ?? `modal-${Date.now()}`,
1962
+ role: "dialog",
1963
+ "aria-modal": "true",
1964
+ "aria-labelledby": promptId
1965
+ },
1966
+ style: {
1967
+ fontFamily: CommonGetFontName()
1968
+ },
1969
+ children: [
1970
+ {
1971
+ tag: "div",
1972
+ classList: ["deeplib-modal-prompt-container"],
1973
+ children: [
1974
+ ...prompt
1975
+ ]
1976
+ },
1977
+ {
1978
+ tag: "div",
1979
+ classList: ["deeplib-modal-prompt"],
1980
+ attributes: {
1981
+ id: promptId
1982
+ },
1983
+ children: [
1984
+ opts.input ? this.renderInput(opts.input) : void 0
1985
+ ]
1986
+ },
1987
+ this.renderButtons()
1988
+ ]
1989
+ });
1990
+ this.blocker = this.createBlocker();
1991
+ this.renderButtons();
1992
+ document.body.append(this.createBlocker(), this.dialog);
1993
+ this.setupFocusTrap();
1994
+ if (opts.timeoutMs) {
1995
+ this.timeoutId = window.setTimeout(() => this.close("timeout"), opts.timeoutMs);
1996
+ }
1997
+ }
1998
+ static {
1999
+ __name(this, "Modal");
2000
+ }
2001
+ dialog;
2002
+ blocker;
2003
+ inputEl;
2004
+ timeoutId;
2005
+ /** Static modal queue. */
2006
+ static queue = [];
2007
+ /** Flag to indicate if a modal is currently being shown. */
2008
+ static processing = false;
2009
+ /**
2010
+ * Displays the modal and resolves with the chosen action and input value.
2011
+ */
2012
+ show() {
2013
+ return _Modal.enqueue(this);
2014
+ }
2015
+ /**
2016
+ * Shows a simple alert modal with a single "OK" button.
2017
+ */
2018
+ static async alert(msg, opts = {}) {
2019
+ await new _Modal({
2020
+ prompt: msg,
2021
+ buttons: [{ action: "close", text: getText("modal.button.ok") }],
2022
+ timeoutMs: opts.timeoutMs,
2023
+ escapeAction: "close",
2024
+ modalId: opts.modalId
2025
+ }).show();
2026
+ }
2027
+ /**
2028
+ * Shows a confirmation modal with "Cancel" and "OK" buttons.
2029
+ * Returns true if "OK" is clicked.
2030
+ */
2031
+ static async confirm(msg, opts = {}) {
2032
+ const [action] = await new _Modal({
2033
+ prompt: msg,
2034
+ buttons: [{ text: getText("modal.button.decline"), action: "decline" }, { text: getText("modal.button.confirm"), action: "confirm" }],
2035
+ escapeAction: "decline",
2036
+ enterAction: "confirm",
2037
+ modalId: opts.modalId
2038
+ }).show();
2039
+ return action === "confirm";
2040
+ }
2041
+ /**
2042
+ * Shows a prompt modal with an input field and "Submit"/"Cancel" buttons.
2043
+ * Returns the input value if submitted, otherwise null.
2044
+ */
2045
+ static async prompt(msg, opts = {}) {
2046
+ const [action, value] = await new _Modal({
2047
+ prompt: msg,
2048
+ timeoutMs: 0,
2049
+ input: { type: "input", defaultValue: opts.defaultValue },
2050
+ buttons: [{ text: getText("modal.button.cancel"), action: "cancel" }, { text: getText("modal.button.submit"), action: "submit" }],
2051
+ escapeAction: "cancel",
2052
+ enterAction: "submit",
2053
+ modalId: opts.modalId
2054
+ }).show();
2055
+ return action === "submit" ? value : null;
2056
+ }
2057
+ /** Creates the input element for the modal, applying configuration and validation. */
2058
+ renderInput(cfg) {
2059
+ const el = document.createElement(cfg.type);
2060
+ el.classList.add("deeplib-modal-input");
2061
+ if (cfg.placeholder) el.placeholder = cfg.placeholder;
2062
+ if (cfg.readOnly) el.readOnly = true;
2063
+ if (cfg.defaultValue) el.value = cfg.defaultValue;
2064
+ if (cfg.type === "textarea") el.rows = 5;
2065
+ el.addEventListener("input", () => {
2066
+ const err = cfg.validate?.(el.value);
2067
+ el.setCustomValidity(err || "");
2068
+ });
2069
+ this.inputEl = el;
2070
+ return el;
2071
+ }
2072
+ /** Creates modal action buttons from configuration. */
2073
+ renderButtons() {
2074
+ const container = document.createElement("div");
2075
+ container.classList.add("deeplib-modal-button-container");
2076
+ const btns = this.opts.buttons ? [...this.opts.buttons] : [];
2077
+ btns.forEach((b) => {
2078
+ const btn = advElement.createButton({
2079
+ id: `deeplib-modal-${b.action}`,
2080
+ onClick: /* @__PURE__ */ __name(() => this.close(b.action), "onClick"),
2081
+ options: {
2082
+ disabled: b.disabled,
2083
+ label: b.text
2084
+ }
2085
+ });
2086
+ container.append(btn);
2087
+ });
2088
+ return container;
2089
+ }
2090
+ /** Creates the modal backdrop blocker with optional click-to-close behavior. */
2091
+ createBlocker() {
2092
+ const blocker = document.createElement("div");
2093
+ blocker.classList.add("deeplib-modal-blocker");
2094
+ blocker.title = "Click to close";
2095
+ if (this.opts.closeOnBackdrop !== false)
2096
+ blocker.addEventListener("click", () => this.close("close"));
2097
+ return blocker;
2098
+ }
2099
+ /** Implements a focus trap to keep keyboard navigation inside the modal. */
2100
+ setupFocusTrap() {
2101
+ const focusable = 'button, [href], input, textarea, select, [tabindex]:not([tabindex="-1"])';
2102
+ const elements = Array.from(this.dialog.querySelectorAll(focusable));
2103
+ const first = elements[0];
2104
+ const last = elements[elements.length - 1];
2105
+ this.dialog.addEventListener("keydown", (e) => {
2106
+ if (e.key === "Tab") {
2107
+ if (elements.length === 0) {
2108
+ e.preventDefault();
2109
+ return;
2110
+ }
2111
+ if (e.shiftKey) {
2112
+ if (document.activeElement === first) {
2113
+ last.focus();
2114
+ e.preventDefault();
2115
+ }
2116
+ } else {
2117
+ if (document.activeElement === last) {
2118
+ first.focus();
2119
+ e.preventDefault();
2120
+ }
2121
+ }
2122
+ } else if (e.key === "Escape") {
2123
+ e.stopPropagation();
2124
+ this.close(this.opts.escapeAction ?? "close");
2125
+ } else if (e.key === "Enter") {
2126
+ if (elements.some((el) => el === document.activeElement) && document.activeElement !== this.inputEl) return;
2127
+ e.preventDefault();
2128
+ e.stopPropagation();
2129
+ this.close(this.opts.enterAction ?? "submit");
2130
+ }
2131
+ });
2132
+ window.requestAnimationFrame(() => {
2133
+ (this.inputEl || first)?.focus();
2134
+ });
2135
+ }
2136
+ /** Closes the modal, cleans up DOM, resolves promise, and shows next queued modal. */
2137
+ close(action) {
2138
+ if (this.timeoutId) clearTimeout(this.timeoutId);
2139
+ this.dialog.close();
2140
+ this.dialog.remove();
2141
+ this.blocker.remove();
2142
+ document.body.querySelector(".deeplib-modal-blocker")?.remove();
2143
+ const value = this.inputEl?.value ?? "";
2144
+ this.resolve([action, value]);
2145
+ _Modal.dequeue();
2146
+ }
2147
+ /**
2148
+ * An internal function where we will save promise function.
2149
+ */
2150
+ resolve = /* @__PURE__ */ __name(() => {
2151
+ }, "resolve");
2152
+ /** A function that adds a modal to the queue and returns a promise */
2153
+ static enqueue(modal) {
2154
+ _Modal.queue.push(modal);
2155
+ if (!_Modal.processing) _Modal.dequeue();
2156
+ return new Promise((resolve) => modal.resolve = resolve);
2157
+ }
2158
+ /** A function that processes the queue, removing the first modal */
2159
+ static dequeue() {
2160
+ const modal = _Modal.queue.shift();
2161
+ if (modal) {
2162
+ _Modal.processing = true;
2163
+ modal.dialog.show();
2164
+ } else {
2165
+ _Modal.processing = false;
2166
+ }
2167
+ }
2168
+ };
2169
+
2170
+ // src/screens/import_export.ts
2171
+ var GuiImportExport = class extends BaseSubscreen {
2172
+ static {
2173
+ __name(this, "GuiImportExport");
2174
+ }
2175
+ importExportOptions;
2176
+ static subscreenOptions = {
2177
+ name: "import-export"
2178
+ };
2268
2179
  constructor(importExportOptions) {
2269
2180
  super();
2270
2181
  this.importExportOptions = importExportOptions;
@@ -2326,7 +2237,13 @@ var GuiImportExport = class extends BaseSubscreen {
2326
2237
  /** Exports the mod data using the specified method. */
2327
2238
  async dataExport(transferMethod) {
2328
2239
  try {
2329
- const data = LZString.compressToBase64(JSON.stringify(modStorage.playerStorage));
2240
+ const selected = await this.getSelectedModules(modules(), "export");
2241
+ if (!selected) return;
2242
+ if (selected.length === 0) {
2243
+ ToastManager.error("No modules selected for export.");
2244
+ return;
2245
+ }
2246
+ const data = this.buildExportPayload(selected);
2330
2247
  if (transferMethod === "clipboard") {
2331
2248
  await this.exportToClipboard(data);
2332
2249
  } else if (transferMethod === "file") {
@@ -2339,34 +2256,22 @@ var GuiImportExport = class extends BaseSubscreen {
2339
2256
  ToastManager.success("Data exported successfully.");
2340
2257
  } catch (error) {
2341
2258
  ToastManager.error("Data export failed.");
2342
- deepLibLogger.error(`Data export failed for ${ModSdkManager.ModInfo.name}.`, error);
2259
+ modLogger.error("Data export failed.", error);
2343
2260
  }
2344
2261
  }
2345
2262
  /** Imports mod data using the specified method. */
2346
2263
  async dataImport(transferMethod) {
2347
2264
  try {
2348
- let importedData = "";
2349
- if (transferMethod === "clipboard") {
2350
- importedData = await this.importFromClipboard() ?? null;
2351
- } else if (transferMethod === "file") {
2352
- importedData = await this.importFromFile() ?? null;
2353
- }
2354
- if (!importedData) {
2355
- throw new Error("No data imported.");
2356
- }
2357
- const data = JSON.parse(LZString.decompressFromBase64(importedData) ?? "");
2358
- if (!data) {
2359
- throw new Error("Invalid data.");
2360
- }
2361
- for (const module of modules()) {
2362
- module.registerDefaultSettings(data);
2363
- }
2364
- modStorage.playerStorage = data;
2265
+ const raw = transferMethod === "clipboard" ? await this.importFromClipboard() : await this.importFromFile();
2266
+ if (raw === null) return;
2267
+ if (!raw) throw new Error("No data");
2268
+ const importResult = await this.applyImportPayload(raw);
2269
+ if (!importResult) return;
2365
2270
  this.importExportOptions.onImport?.();
2366
2271
  ToastManager.success("Data imported successfully.");
2367
2272
  } catch (error) {
2368
2273
  ToastManager.error("Data import failed.");
2369
- deepLibLogger.error(`Data import failed for ${ModSdkManager.ModInfo.name}.`, error);
2274
+ modLogger.error("Data import failed.", error);
2370
2275
  }
2371
2276
  }
2372
2277
  /** Saves data to a file using the browser's save dialog. */
@@ -2392,7 +2297,7 @@ var GuiImportExport = class extends BaseSubscreen {
2392
2297
  throw new Error("File save cancelled or failed: " + error.message);
2393
2298
  }
2394
2299
  } else {
2395
- const fileName = await Modal.prompt("Enter file name", suggestedName);
2300
+ const fileName = await Modal.prompt("Enter file name", { defaultValue: suggestedName });
2396
2301
  if (fileName === null) {
2397
2302
  return false;
2398
2303
  } else if (fileName === "") {
@@ -2476,6 +2381,72 @@ var GuiImportExport = class extends BaseSubscreen {
2476
2381
  throw new Error("Failed to read data from clipboard." + error);
2477
2382
  });
2478
2383
  }
2384
+ async getSelectedModules(modulesToChoose, transferDirection) {
2385
+ const modulesFiltered = modulesToChoose.filter((m) => hasGetter(m, "settings") && !!m.settings);
2386
+ const checkedModules = Object.fromEntries(
2387
+ modulesFiltered.map((m) => [m.constructor.name, true])
2388
+ );
2389
+ if (modulesFiltered.length === 0) {
2390
+ throw new Error("No modules to choose from.");
2391
+ }
2392
+ const checkboxes = modulesFiltered.map((m) => advElement.createCheckbox({
2393
+ id: m.constructor.name,
2394
+ label: getText(m.constructor.name),
2395
+ setElementValue: /* @__PURE__ */ __name(() => checkedModules[m.constructor.name], "setElementValue"),
2396
+ setSettingValue: /* @__PURE__ */ __name((val) => checkedModules[m.constructor.name] = val, "setSettingValue")
2397
+ }));
2398
+ const text = transferDirection === "import" ? "import_export.import.select_modules" : "import_export.export.select_modules";
2399
+ const response = await Modal.confirm([
2400
+ getText(text),
2401
+ ElementCreate({ tag: "br" }),
2402
+ getText("import_export.text.not_sure"),
2403
+ {
2404
+ tag: "div",
2405
+ classList: ["deeplib-modal-checkbox-container"],
2406
+ children: checkboxes
2407
+ }
2408
+ ], { modalId: "deeplib-modal-import_export" });
2409
+ if (!response) {
2410
+ return null;
2411
+ }
2412
+ const ret = Object.entries(checkedModules).filter(([_, checked]) => checked).map(([id]) => getModule(id)).filter((m) => !!m);
2413
+ if (ret.length === 0) {
2414
+ throw new Error("No modules selected.");
2415
+ }
2416
+ return ret;
2417
+ }
2418
+ buildExportPayload(selectedModules) {
2419
+ const payload = {};
2420
+ for (const module of selectedModules) {
2421
+ if (!hasGetter(module, "settings") || module.settings === null) continue;
2422
+ payload[module.constructor.name] = module.settings;
2423
+ }
2424
+ return LZString.compressToBase64(JSON.stringify(payload));
2425
+ }
2426
+ async applyImportPayload(raw) {
2427
+ const decoded = JSON.parse(
2428
+ LZString.decompressFromBase64(raw) ?? ""
2429
+ );
2430
+ if (!decoded) {
2431
+ throw new Error("Invalid import format.");
2432
+ }
2433
+ const modules2 = Object.keys(decoded).map((id) => getModule(id)).filter((m) => !!m);
2434
+ const selectedModules = await this.getSelectedModules(modules2, "import");
2435
+ if (!selectedModules) {
2436
+ return false;
2437
+ }
2438
+ if (selectedModules.length === 0) {
2439
+ throw new Error("No modules selected.");
2440
+ }
2441
+ for (const module of selectedModules) {
2442
+ const data = decoded[module.constructor.name];
2443
+ if (!data) continue;
2444
+ const merged = deepMerge(module.defaultSettings, data);
2445
+ if (!merged) continue;
2446
+ module.settings = merged;
2447
+ }
2448
+ return true;
2449
+ }
2479
2450
  };
2480
2451
 
2481
2452
  // src/utilities/data.ts
@@ -2520,7 +2491,7 @@ var ModStorage = class _ModStorage {
2520
2491
  const parsed = _ModStorage.dataDecompress(this.extensionStorage || "");
2521
2492
  if (parsed === null || !Object.hasOwn(parsed, "Version")) {
2522
2493
  this.playerStorage = {
2523
- Version: ModSdkManager.ModInfo.version
2494
+ Version: MOD_VERSION
2524
2495
  };
2525
2496
  } else {
2526
2497
  this.playerStorage = parsed;
@@ -2535,6 +2506,9 @@ var ModStorage = class _ModStorage {
2535
2506
  this.extensionStorage = _ModStorage.dataCompress(this.playerStorage);
2536
2507
  ServerPlayerExtensionSettingsSync(this.modName);
2537
2508
  }
2509
+ storageSize() {
2510
+ return _ModStorage.measureSize(this.extensionStorage);
2511
+ }
2538
2512
  static dataDecompress(string) {
2539
2513
  const d = LZString.decompressFromBase64(string);
2540
2514
  let data = null;
@@ -2542,7 +2516,7 @@ var ModStorage = class _ModStorage {
2542
2516
  const decoded = JSON.parse(d);
2543
2517
  data = decoded;
2544
2518
  } catch (error) {
2545
- deepLibLogger.error(error);
2519
+ modLogger.error(error);
2546
2520
  }
2547
2521
  return data;
2548
2522
  }
@@ -2599,15 +2573,18 @@ var domUtil = {
2599
2573
  function autoSetPosition(_, position) {
2600
2574
  let xPos = void 0;
2601
2575
  let yPos = void 0;
2576
+ let anchor = void 0;
2602
2577
  if (Array.isArray(position)) {
2603
2578
  xPos = position[0];
2604
2579
  yPos = position[1];
2580
+ anchor = position[2];
2605
2581
  } else if (typeof position === "function") {
2606
2582
  const result = position();
2607
2583
  xPos = result[0];
2608
2584
  yPos = result[1];
2585
+ anchor = result[2];
2609
2586
  }
2610
- if (xPos !== void 0 && yPos !== void 0) ElementSetPosition(_, xPos, yPos);
2587
+ if (xPos !== void 0 && yPos !== void 0) ElementSetPosition(_, xPos, yPos, anchor);
2611
2588
  }
2612
2589
  __name(autoSetPosition, "autoSetPosition");
2613
2590
  function autoSetSize(_, size) {
@@ -2842,9 +2819,6 @@ function sendActionMessage(msg, target = void 0, dictionary = []) {
2842
2819
  __name(sendActionMessage, "sendActionMessage");
2843
2820
 
2844
2821
  // src/utilities/sdk.ts
2845
- var import_bondage_club_mod_sdk = __toESM(require_bcmodsdk(), 1);
2846
- var rawSdk = import_bondage_club_mod_sdk.default;
2847
- var bcModSdkRef = rawSdk.default ?? rawSdk;
2848
2822
  var HookPriority = {
2849
2823
  Observe: 0,
2850
2824
  AddBehavior: 1,
@@ -2852,27 +2826,25 @@ var HookPriority = {
2852
2826
  OverrideBehavior: 10,
2853
2827
  Top: 100
2854
2828
  };
2855
- var ModSdkManager = class _ModSdkManager {
2829
+ var ModSdkManager = class {
2856
2830
  static {
2857
2831
  __name(this, "ModSdkManager");
2858
2832
  }
2859
- static SDK;
2860
- static patchedFunctions = /* @__PURE__ */ new Map();
2861
- static ModInfo;
2833
+ SDK;
2834
+ patchedFunctions = /* @__PURE__ */ new Map();
2862
2835
  /** Registers a mod with the SDK and stores mod information. */
2863
2836
  constructor(info, options) {
2864
- _ModSdkManager.SDK = bcModSdkRef.registerMod(info, options);
2865
- _ModSdkManager.ModInfo = info;
2837
+ this.SDK = bcModSdk.registerMod(info, options);
2866
2838
  }
2867
2839
  /** Retrieves or initializes patch data for a given target function. */
2868
2840
  initPatchableFunction(target) {
2869
- let result = _ModSdkManager.patchedFunctions.get(target);
2841
+ let result = this.patchedFunctions.get(target);
2870
2842
  if (!result) {
2871
2843
  result = {
2872
2844
  name: target,
2873
2845
  hooks: []
2874
2846
  };
2875
- _ModSdkManager.patchedFunctions.set(target, result);
2847
+ this.patchedFunctions.set(target, result);
2876
2848
  }
2877
2849
  return result;
2878
2850
  }
@@ -2886,7 +2858,7 @@ var ModSdkManager = class _ModSdkManager {
2886
2858
  if (data.hooks.some((h) => h.hook === hook)) {
2887
2859
  return () => null;
2888
2860
  }
2889
- const removeCallback = _ModSdkManager.SDK?.hookFunction(target, priority, hook);
2861
+ const removeCallback = this.SDK.hookFunction(target, priority, hook);
2890
2862
  data.hooks.push({
2891
2863
  hook,
2892
2864
  priority,
@@ -2902,13 +2874,13 @@ var ModSdkManager = class _ModSdkManager {
2902
2874
  * **This method is DANGEROUS** to use and has high potential to conflict with other mods.
2903
2875
  */
2904
2876
  patchFunction(target, patches) {
2905
- _ModSdkManager.SDK?.patchFunction(target, patches);
2877
+ this.SDK.patchFunction(target, patches);
2906
2878
  }
2907
2879
  /**
2908
2880
  * Removes all patches from a target function.
2909
2881
  */
2910
2882
  unpatchFunction(target) {
2911
- _ModSdkManager.SDK?.removePatches(target);
2883
+ this.SDK.removePatches(target);
2912
2884
  }
2913
2885
  /**
2914
2886
  * Removes all hooks associated with a specific module from a target function.
@@ -2927,7 +2899,7 @@ var ModSdkManager = class _ModSdkManager {
2927
2899
  * Removes all hooks associated with a specific module across all patched functions.
2928
2900
  */
2929
2901
  removeAllHooksByModule(module) {
2930
- for (const data of _ModSdkManager.patchedFunctions.values()) {
2902
+ for (const data of this.patchedFunctions.values()) {
2931
2903
  for (let i = data.hooks.length - 1; i >= 0; i--) {
2932
2904
  if (data.hooks[i].module === module) {
2933
2905
  data.hooks[i].removeCallback();
@@ -2937,6 +2909,12 @@ var ModSdkManager = class _ModSdkManager {
2937
2909
  }
2938
2910
  return true;
2939
2911
  }
2912
+ /**
2913
+ * Unloads the mod removing all hooks and patches by it.
2914
+ */
2915
+ unload() {
2916
+ this.SDK.unload();
2917
+ }
2940
2918
  };
2941
2919
 
2942
2920
  // src/utilities/style.ts
@@ -2989,87 +2967,6 @@ var Style = {
2989
2967
  }
2990
2968
  };
2991
2969
 
2992
- // src/utilities/translation.ts
2993
- var Localization = class _Localization {
2994
- static {
2995
- __name(this, "Localization");
2996
- }
2997
- static LibTranslation = {};
2998
- static ModTranslation = {};
2999
- static PathToModTranslation;
3000
- static PathToLibTranslation = `${PUBLIC_URL}/dl_translations/`;
3001
- static DefaultLanguage = "en";
3002
- /** Flag to prevent re-initialization */
3003
- static initialized = false;
3004
- /** Initialize the localization system by loading translation files. */
3005
- static async init(initOptions) {
3006
- if (_Localization.initialized) return;
3007
- _Localization.initialized = true;
3008
- _Localization.PathToModTranslation = (() => {
3009
- if (!initOptions?.pathToTranslationsFolder) return void 0;
3010
- return initOptions.pathToTranslationsFolder.endsWith("/") ? initOptions.pathToTranslationsFolder : `${initOptions.pathToTranslationsFolder}/`;
3011
- })();
3012
- _Localization.DefaultLanguage = initOptions?.defaultLanguage || _Localization.DefaultLanguage;
3013
- const lang = initOptions?.fixedLanguage ? _Localization.DefaultLanguage : TranslationLanguage.toLowerCase();
3014
- const libTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, lang);
3015
- if (lang === _Localization.DefaultLanguage) {
3016
- _Localization.LibTranslation = libTranslation;
3017
- } else {
3018
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, _Localization.DefaultLanguage);
3019
- _Localization.LibTranslation = { ...fallbackTranslation, ...libTranslation };
3020
- }
3021
- if (!_Localization.PathToModTranslation) return;
3022
- const modTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, lang);
3023
- if (lang === _Localization.DefaultLanguage) {
3024
- _Localization.ModTranslation = modTranslation;
3025
- } else {
3026
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, _Localization.DefaultLanguage);
3027
- _Localization.ModTranslation = { ...fallbackTranslation, ...modTranslation };
3028
- }
3029
- }
3030
- /** Get a translated string from mod translations by source tag. */
3031
- static getTextMod(srcTag) {
3032
- return _Localization.ModTranslation?.[srcTag] || void 0;
3033
- }
3034
- /** Get a translated string from library translations by source tag. */
3035
- static getTextLib(srcTag) {
3036
- return _Localization.LibTranslation?.[srcTag] || void 0;
3037
- }
3038
- /**
3039
- * Fetch and parse a language file from the given base URL and language code.
3040
- * Falls back to default language if the requested language file is unavailable.
3041
- */
3042
- static async fetchLanguageFile(baseUrl, lang) {
3043
- const response = await fetch(`${baseUrl}${lang}.lang`);
3044
- if (lang !== _Localization.DefaultLanguage && !response.ok) {
3045
- return this.fetchLanguageFile(baseUrl, _Localization.DefaultLanguage);
3046
- }
3047
- if (!response.ok) {
3048
- return {};
3049
- }
3050
- const langFileContent = await response.text();
3051
- return this.parseLanguageFile(langFileContent);
3052
- }
3053
- /**
3054
- * Parse the raw content of a language file into a TranslationDict.
3055
- * Ignores empty lines and comments starting with '#'.
3056
- */
3057
- static parseLanguageFile(content) {
3058
- const translations = {};
3059
- const lines = content.split("\n");
3060
- for (const line of lines) {
3061
- const trimmed = line.trim();
3062
- if (!trimmed || trimmed.startsWith("#")) continue;
3063
- const [key, ...rest] = trimmed.split("=");
3064
- translations[key.trim()] = rest.join("=").trim();
3065
- }
3066
- return translations;
3067
- }
3068
- };
3069
- var getText = /* @__PURE__ */ __name((srcTag) => {
3070
- return Localization.getTextMod(srcTag) || Localization.getTextLib(srcTag) || srcTag;
3071
- }, "getText");
3072
-
3073
2970
  // src/utilities/event_channel.ts
3074
2971
  var EventChannel = class {
3075
2972
  constructor(channelName) {
@@ -3140,6 +3037,7 @@ export {
3140
3037
  HookPriority,
3141
3038
  Localization,
3142
3039
  Logger,
3040
+ MOD_NAME,
3143
3041
  MainMenu,
3144
3042
  ModSdkManager,
3145
3043
  ModStorage,
@@ -3158,10 +3056,9 @@ export {
3158
3056
  hasSetter,
3159
3057
  initMod,
3160
3058
  layout,
3161
- logger,
3059
+ modLogger,
3162
3060
  modStorage,
3163
3061
  modules,
3164
- modulesMap,
3165
3062
  registerModule,
3166
3063
  sdk,
3167
3064
  sendActionMessage,