bc-deeplib 2.4.1 → 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.
@@ -271,7 +68,7 @@ var BaseModule = class {
271
68
  const defaults = this.defaultSettings;
272
69
  if (!storage || !defaults) return;
273
70
  if (Object.entries(this.defaultSettings).length === 0) return;
274
- target[storage] = deepMerge(this.defaultSettings, target[storage], { concatArrays: false });
71
+ target[storage] = deepMerge(this.defaultSettings, target[storage], { concatArrays: false, matchingOnly: true });
275
72
  }
276
73
  /**
277
74
  * Provides default settings for this 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. */
@@ -1439,7 +1263,7 @@ function isPlainObject(value) {
1439
1263
  return value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype && !Array.isArray(value);
1440
1264
  }
1441
1265
  __name(isPlainObject, "isPlainObject");
1442
- function deepMerge(target, source, options = { concatArrays: true }) {
1266
+ function deepMerge(target, source, options = { concatArrays: true, matchingOnly: false }) {
1443
1267
  if (target === void 0) return source;
1444
1268
  if (source === void 0) return target;
1445
1269
  if (Array.isArray(target) && Array.isArray(source) && options.concatArrays) {
@@ -1447,10 +1271,9 @@ function deepMerge(target, source, options = { concatArrays: true }) {
1447
1271
  }
1448
1272
  if (isPlainObject(target) && isPlainObject(source)) {
1449
1273
  const result = { ...target };
1450
- for (const key of Object.keys(source)) {
1451
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
1452
- continue;
1453
- }
1274
+ const keys = options.matchingOnly ? Object.keys(source).filter((k) => k in target) : Object.keys(source);
1275
+ for (const key of keys) {
1276
+ if (key === "__proto__" || key === "constructor" || key === "prototype") continue;
1454
1277
  result[key] = key in target ? deepMerge(target[key], source[key], options) : source[key];
1455
1278
  }
1456
1279
  return result;
@@ -1481,7 +1304,7 @@ function exportToGlobal(name, value) {
1481
1304
  current[keys[keys.length - 1]] = value;
1482
1305
  }
1483
1306
  __name(exportToGlobal, "exportToGlobal");
1484
- function hasGetter3(obj, prop) {
1307
+ function hasGetter(obj, prop) {
1485
1308
  while (obj && obj !== Object.prototype) {
1486
1309
  const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
1487
1310
  if (descriptor?.get) return true;
@@ -1489,8 +1312,8 @@ function hasGetter3(obj, prop) {
1489
1312
  }
1490
1313
  return false;
1491
1314
  }
1492
- __name(hasGetter3, "hasGetter");
1493
- function hasSetter3(obj, prop) {
1315
+ __name(hasGetter, "hasGetter");
1316
+ function hasSetter(obj, prop) {
1494
1317
  while (obj && obj !== Object.prototype) {
1495
1318
  const descriptor = Object.getOwnPropertyDescriptor(obj, prop);
1496
1319
  if (descriptor?.set) return true;
@@ -1498,7 +1321,7 @@ function hasSetter3(obj, prop) {
1498
1321
  }
1499
1322
  return false;
1500
1323
  }
1501
- __name(hasSetter3, "hasSetter");
1324
+ __name(hasSetter, "hasSetter");
1502
1325
  var byteToKB = /* @__PURE__ */ __name((nByte) => Math.round(nByte / 100) / 10, "byteToKB");
1503
1326
 
1504
1327
  // src/utilities/elements/elements.ts
@@ -1847,221 +1670,6 @@ function elementPrevNext(options) {
1847
1670
  return retElem;
1848
1671
  }
1849
1672
  __name(elementPrevNext, "elementPrevNext");
1850
- var Modal = class _Modal {
1851
- constructor(opts) {
1852
- this.opts = opts;
1853
- opts ??= {};
1854
- opts.closeOnBackdrop ??= true;
1855
- const promptId = `modal-prompt-${Date.now()}`;
1856
- const prompt = (CommonIsArray(opts.prompt) ? opts.prompt : [opts.prompt]).filter((i) => i != null) ?? [""];
1857
- this.dialog = ElementCreate({
1858
- tag: "dialog",
1859
- classList: ["deeplib-modal"],
1860
- attributes: {
1861
- role: "dialog",
1862
- "aria-modal": "true",
1863
- "aria-labelledby": promptId
1864
- },
1865
- style: {
1866
- fontFamily: CommonGetFontName()
1867
- },
1868
- children: [
1869
- {
1870
- tag: "div",
1871
- classList: ["deeplib-modal-prompt-container"],
1872
- children: [
1873
- ...prompt
1874
- ]
1875
- },
1876
- {
1877
- tag: "div",
1878
- classList: ["deeplib-modal-prompt"],
1879
- attributes: {
1880
- id: promptId
1881
- },
1882
- children: [
1883
- opts.input ? this.renderInput(opts.input) : void 0
1884
- ]
1885
- },
1886
- this.renderButtons()
1887
- ]
1888
- });
1889
- this.blocker = this.createBlocker();
1890
- this.renderButtons();
1891
- document.body.append(this.createBlocker(), this.dialog);
1892
- this.setupFocusTrap();
1893
- if (opts.timeoutMs) {
1894
- this.timeoutId = window.setTimeout(() => this.close("timeout"), opts.timeoutMs);
1895
- }
1896
- }
1897
- static {
1898
- __name(this, "Modal");
1899
- }
1900
- dialog;
1901
- blocker;
1902
- inputEl;
1903
- timeoutId;
1904
- /** Static modal queue. */
1905
- static queue = [];
1906
- /** Flag to indicate if a modal is currently being shown. */
1907
- static processing = false;
1908
- /**
1909
- * Displays the modal and resolves with the chosen action and input value.
1910
- */
1911
- show() {
1912
- return _Modal.enqueue(this);
1913
- }
1914
- /**
1915
- * Shows a simple alert modal with a single "OK" button.
1916
- */
1917
- static async alert(msg, timeoutMs) {
1918
- await new _Modal({
1919
- prompt: msg,
1920
- buttons: [{ action: "close", text: getText("modal.button.ok") }],
1921
- timeoutMs,
1922
- escapeAction: "close"
1923
- }).show();
1924
- }
1925
- /**
1926
- * Shows a confirmation modal with "Cancel" and "OK" buttons.
1927
- * Returns true if "OK" is clicked.
1928
- */
1929
- static async confirm(msg) {
1930
- const [action] = await new _Modal({
1931
- prompt: msg,
1932
- buttons: [{ text: getText("modal.button.decline"), action: "decline" }, { text: getText("modal.button.confirm"), action: "confirm" }],
1933
- escapeAction: "decline",
1934
- enterAction: "confirm"
1935
- }).show();
1936
- return action === "confirm";
1937
- }
1938
- /**
1939
- * Shows a prompt modal with an input field and "Submit"/"Cancel" buttons.
1940
- * Returns the input value if submitted, otherwise null.
1941
- */
1942
- static async prompt(msg, defaultValue = "") {
1943
- const [action, value] = await new _Modal({
1944
- prompt: msg,
1945
- timeoutMs: 0,
1946
- input: { type: "input", defaultValue },
1947
- buttons: [{ text: getText("modal.button.cancel"), action: "cancel" }, { text: getText("modal.button.submit"), action: "submit" }],
1948
- escapeAction: "cancel",
1949
- enterAction: "submit"
1950
- }).show();
1951
- return action === "submit" ? value : null;
1952
- }
1953
- /** Creates the input element for the modal, applying configuration and validation. */
1954
- renderInput(cfg) {
1955
- const el = document.createElement(cfg.type);
1956
- el.classList.add("deeplib-modal-input");
1957
- if (cfg.placeholder) el.placeholder = cfg.placeholder;
1958
- if (cfg.readOnly) el.readOnly = true;
1959
- if (cfg.defaultValue) el.value = cfg.defaultValue;
1960
- if (cfg.type === "textarea") el.rows = 5;
1961
- el.addEventListener("input", () => {
1962
- const err = cfg.validate?.(el.value);
1963
- el.setCustomValidity(err || "");
1964
- });
1965
- this.inputEl = el;
1966
- return el;
1967
- }
1968
- /** Creates modal action buttons from configuration. */
1969
- renderButtons() {
1970
- const container = document.createElement("div");
1971
- container.classList.add("deeplib-modal-button-container");
1972
- const btns = this.opts.buttons ? [...this.opts.buttons] : [];
1973
- btns.forEach((b) => {
1974
- const btn = advElement.createButton({
1975
- id: `deeplib-modal-${b.action}`,
1976
- onClick: /* @__PURE__ */ __name(() => this.close(b.action), "onClick"),
1977
- options: {
1978
- disabled: b.disabled,
1979
- label: b.text
1980
- }
1981
- });
1982
- container.append(btn);
1983
- });
1984
- return container;
1985
- }
1986
- /** Creates the modal backdrop blocker with optional click-to-close behavior. */
1987
- createBlocker() {
1988
- const blocker = document.createElement("div");
1989
- blocker.classList.add("deeplib-modal-blocker");
1990
- blocker.title = "Click to close";
1991
- if (this.opts.closeOnBackdrop !== false)
1992
- blocker.addEventListener("click", () => this.close("close"));
1993
- return blocker;
1994
- }
1995
- /** Implements a focus trap to keep keyboard navigation inside the modal. */
1996
- setupFocusTrap() {
1997
- const focusable = 'button, [href], input, textarea, select, [tabindex]:not([tabindex="-1"])';
1998
- const elements = Array.from(this.dialog.querySelectorAll(focusable));
1999
- const first = elements[0];
2000
- const last = elements[elements.length - 1];
2001
- this.dialog.addEventListener("keydown", (e) => {
2002
- if (e.key === "Tab") {
2003
- if (elements.length === 0) {
2004
- e.preventDefault();
2005
- return;
2006
- }
2007
- if (e.shiftKey) {
2008
- if (document.activeElement === first) {
2009
- last.focus();
2010
- e.preventDefault();
2011
- }
2012
- } else {
2013
- if (document.activeElement === last) {
2014
- first.focus();
2015
- e.preventDefault();
2016
- }
2017
- }
2018
- } else if (e.key === "Escape") {
2019
- e.stopPropagation();
2020
- this.close(this.opts.escapeAction ?? "close");
2021
- } else if (e.key === "Enter") {
2022
- if (elements.some((el) => el === document.activeElement) && document.activeElement !== this.inputEl) return;
2023
- e.preventDefault();
2024
- e.stopPropagation();
2025
- this.close(this.opts.enterAction ?? "submit");
2026
- }
2027
- });
2028
- window.requestAnimationFrame(() => {
2029
- (this.inputEl || first)?.focus();
2030
- });
2031
- }
2032
- /** Closes the modal, cleans up DOM, resolves promise, and shows next queued modal. */
2033
- close(action) {
2034
- if (this.timeoutId) clearTimeout(this.timeoutId);
2035
- this.dialog.close();
2036
- this.dialog.remove();
2037
- this.blocker.remove();
2038
- document.body.querySelector(".deeplib-modal-blocker")?.remove();
2039
- const value = this.inputEl?.value ?? "";
2040
- this.resolve([action, value]);
2041
- _Modal.dequeue();
2042
- }
2043
- /**
2044
- * An internal function where we will save promise function.
2045
- */
2046
- resolve = /* @__PURE__ */ __name(() => {
2047
- }, "resolve");
2048
- /** A function that adds a modal to the queue and returns a promise */
2049
- static enqueue(modal) {
2050
- _Modal.queue.push(modal);
2051
- if (!_Modal.processing) _Modal.dequeue();
2052
- return new Promise((resolve) => modal.resolve = resolve);
2053
- }
2054
- /** A function that processes the queue, removing the first modal */
2055
- static dequeue() {
2056
- const modal = _Modal.queue.shift();
2057
- if (modal) {
2058
- _Modal.processing = true;
2059
- modal.dialog.show();
2060
- } else {
2061
- _Modal.processing = false;
2062
- }
2063
- }
2064
- };
2065
1673
 
2066
1674
  // src/screens/main_menu.ts
2067
1675
  var MainMenu = class _MainMenu extends BaseSubscreen {
@@ -2101,7 +1709,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2101
1709
  ElementMenu.AppendButton(menu, exitButton);
2102
1710
  }
2103
1711
  for (const screen of this.subscreens) {
2104
- if (screen.options.name == "mainmenu") continue;
1712
+ if (screen.options.name === "mainmenu") continue;
2105
1713
  const button = advElement.createButton({
2106
1714
  id: `${screen.options.name}-button`,
2107
1715
  onClick: /* @__PURE__ */ __name(() => {
@@ -2175,7 +1783,7 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2175
1783
  }
2176
1784
  if (_MainMenu.options.storageFullnessIndicator) {
2177
1785
  const maxStorageCapacityKB = 180;
2178
- const currentStorageCapacityKB = byteToKB(ModStorage.measureSize(modStorage.extensionStorage));
1786
+ const currentStorageCapacityKB = byteToKB(modStorage.storageSize());
2179
1787
  const fullness = (currentStorageCapacityKB / maxStorageCapacityKB * 100).toFixed(1);
2180
1788
  const storageFullnessWrapper = advElement.createButton({
2181
1789
  id: CommonGenerateUniqueID(),
@@ -2257,14 +1865,316 @@ var MainMenu = class _MainMenu extends BaseSubscreen {
2257
1865
  }
2258
1866
  };
2259
1867
 
2260
- // src/screens/import_export.ts
2261
- var GuiImportExport = class extends BaseSubscreen {
1868
+ // src/utilities/translation.ts
1869
+ var Localization = class _Localization {
2262
1870
  static {
2263
- __name(this, "GuiImportExport");
1871
+ __name(this, "Localization");
2264
1872
  }
2265
- importExportOptions;
2266
- static subscreenOptions = {
2267
- name: "import-export"
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"
2268
2178
  };
2269
2179
  constructor(importExportOptions) {
2270
2180
  super();
@@ -2327,7 +2237,13 @@ var GuiImportExport = class extends BaseSubscreen {
2327
2237
  /** Exports the mod data using the specified method. */
2328
2238
  async dataExport(transferMethod) {
2329
2239
  try {
2330
- 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);
2331
2247
  if (transferMethod === "clipboard") {
2332
2248
  await this.exportToClipboard(data);
2333
2249
  } else if (transferMethod === "file") {
@@ -2340,34 +2256,22 @@ var GuiImportExport = class extends BaseSubscreen {
2340
2256
  ToastManager.success("Data exported successfully.");
2341
2257
  } catch (error) {
2342
2258
  ToastManager.error("Data export failed.");
2343
- deepLibLogger.error(`Data export failed for ${ModSdkManager.ModInfo.name}.`, error);
2259
+ modLogger.error("Data export failed.", error);
2344
2260
  }
2345
2261
  }
2346
2262
  /** Imports mod data using the specified method. */
2347
2263
  async dataImport(transferMethod) {
2348
2264
  try {
2349
- let importedData = "";
2350
- if (transferMethod === "clipboard") {
2351
- importedData = await this.importFromClipboard() ?? null;
2352
- } else if (transferMethod === "file") {
2353
- importedData = await this.importFromFile() ?? null;
2354
- }
2355
- if (!importedData) {
2356
- throw new Error("No data imported.");
2357
- }
2358
- const data = JSON.parse(LZString.decompressFromBase64(importedData) ?? "");
2359
- if (!data) {
2360
- throw new Error("Invalid data.");
2361
- }
2362
- for (const module of modules()) {
2363
- module.registerDefaultSettings(data);
2364
- }
2365
- 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;
2366
2270
  this.importExportOptions.onImport?.();
2367
2271
  ToastManager.success("Data imported successfully.");
2368
2272
  } catch (error) {
2369
2273
  ToastManager.error("Data import failed.");
2370
- deepLibLogger.error(`Data import failed for ${ModSdkManager.ModInfo.name}.`, error);
2274
+ modLogger.error("Data import failed.", error);
2371
2275
  }
2372
2276
  }
2373
2277
  /** Saves data to a file using the browser's save dialog. */
@@ -2393,7 +2297,7 @@ var GuiImportExport = class extends BaseSubscreen {
2393
2297
  throw new Error("File save cancelled or failed: " + error.message);
2394
2298
  }
2395
2299
  } else {
2396
- const fileName = await Modal.prompt("Enter file name", suggestedName);
2300
+ const fileName = await Modal.prompt("Enter file name", { defaultValue: suggestedName });
2397
2301
  if (fileName === null) {
2398
2302
  return false;
2399
2303
  } else if (fileName === "") {
@@ -2477,6 +2381,72 @@ var GuiImportExport = class extends BaseSubscreen {
2477
2381
  throw new Error("Failed to read data from clipboard." + error);
2478
2382
  });
2479
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
+ }
2480
2450
  };
2481
2451
 
2482
2452
  // src/utilities/data.ts
@@ -2521,7 +2491,7 @@ var ModStorage = class _ModStorage {
2521
2491
  const parsed = _ModStorage.dataDecompress(this.extensionStorage || "");
2522
2492
  if (parsed === null || !Object.hasOwn(parsed, "Version")) {
2523
2493
  this.playerStorage = {
2524
- Version: ModSdkManager.ModInfo.version
2494
+ Version: MOD_VERSION
2525
2495
  };
2526
2496
  } else {
2527
2497
  this.playerStorage = parsed;
@@ -2536,6 +2506,9 @@ var ModStorage = class _ModStorage {
2536
2506
  this.extensionStorage = _ModStorage.dataCompress(this.playerStorage);
2537
2507
  ServerPlayerExtensionSettingsSync(this.modName);
2538
2508
  }
2509
+ storageSize() {
2510
+ return _ModStorage.measureSize(this.extensionStorage);
2511
+ }
2539
2512
  static dataDecompress(string) {
2540
2513
  const d = LZString.decompressFromBase64(string);
2541
2514
  let data = null;
@@ -2543,7 +2516,7 @@ var ModStorage = class _ModStorage {
2543
2516
  const decoded = JSON.parse(d);
2544
2517
  data = decoded;
2545
2518
  } catch (error) {
2546
- deepLibLogger.error(error);
2519
+ modLogger.error(error);
2547
2520
  }
2548
2521
  return data;
2549
2522
  }
@@ -2600,15 +2573,18 @@ var domUtil = {
2600
2573
  function autoSetPosition(_, position) {
2601
2574
  let xPos = void 0;
2602
2575
  let yPos = void 0;
2576
+ let anchor = void 0;
2603
2577
  if (Array.isArray(position)) {
2604
2578
  xPos = position[0];
2605
2579
  yPos = position[1];
2580
+ anchor = position[2];
2606
2581
  } else if (typeof position === "function") {
2607
2582
  const result = position();
2608
2583
  xPos = result[0];
2609
2584
  yPos = result[1];
2585
+ anchor = result[2];
2610
2586
  }
2611
- if (xPos !== void 0 && yPos !== void 0) ElementSetPosition(_, xPos, yPos);
2587
+ if (xPos !== void 0 && yPos !== void 0) ElementSetPosition(_, xPos, yPos, anchor);
2612
2588
  }
2613
2589
  __name(autoSetPosition, "autoSetPosition");
2614
2590
  function autoSetSize(_, size) {
@@ -2843,9 +2819,6 @@ function sendActionMessage(msg, target = void 0, dictionary = []) {
2843
2819
  __name(sendActionMessage, "sendActionMessage");
2844
2820
 
2845
2821
  // src/utilities/sdk.ts
2846
- var import_bondage_club_mod_sdk = __toESM(require_bcmodsdk(), 1);
2847
- var rawSdk = import_bondage_club_mod_sdk.default;
2848
- var bcModSdkRef = rawSdk.default ?? rawSdk;
2849
2822
  var HookPriority = {
2850
2823
  Observe: 0,
2851
2824
  AddBehavior: 1,
@@ -2853,27 +2826,25 @@ var HookPriority = {
2853
2826
  OverrideBehavior: 10,
2854
2827
  Top: 100
2855
2828
  };
2856
- var ModSdkManager = class _ModSdkManager {
2829
+ var ModSdkManager = class {
2857
2830
  static {
2858
2831
  __name(this, "ModSdkManager");
2859
2832
  }
2860
- static SDK;
2861
- static patchedFunctions = /* @__PURE__ */ new Map();
2862
- static ModInfo;
2833
+ SDK;
2834
+ patchedFunctions = /* @__PURE__ */ new Map();
2863
2835
  /** Registers a mod with the SDK and stores mod information. */
2864
2836
  constructor(info, options) {
2865
- _ModSdkManager.SDK = bcModSdkRef.registerMod(info, options);
2866
- _ModSdkManager.ModInfo = info;
2837
+ this.SDK = bcModSdk.registerMod(info, options);
2867
2838
  }
2868
2839
  /** Retrieves or initializes patch data for a given target function. */
2869
2840
  initPatchableFunction(target) {
2870
- let result = _ModSdkManager.patchedFunctions.get(target);
2841
+ let result = this.patchedFunctions.get(target);
2871
2842
  if (!result) {
2872
2843
  result = {
2873
2844
  name: target,
2874
2845
  hooks: []
2875
2846
  };
2876
- _ModSdkManager.patchedFunctions.set(target, result);
2847
+ this.patchedFunctions.set(target, result);
2877
2848
  }
2878
2849
  return result;
2879
2850
  }
@@ -2887,7 +2858,7 @@ var ModSdkManager = class _ModSdkManager {
2887
2858
  if (data.hooks.some((h) => h.hook === hook)) {
2888
2859
  return () => null;
2889
2860
  }
2890
- const removeCallback = _ModSdkManager.SDK?.hookFunction(target, priority, hook);
2861
+ const removeCallback = this.SDK.hookFunction(target, priority, hook);
2891
2862
  data.hooks.push({
2892
2863
  hook,
2893
2864
  priority,
@@ -2903,13 +2874,13 @@ var ModSdkManager = class _ModSdkManager {
2903
2874
  * **This method is DANGEROUS** to use and has high potential to conflict with other mods.
2904
2875
  */
2905
2876
  patchFunction(target, patches) {
2906
- _ModSdkManager.SDK?.patchFunction(target, patches);
2877
+ this.SDK.patchFunction(target, patches);
2907
2878
  }
2908
2879
  /**
2909
2880
  * Removes all patches from a target function.
2910
2881
  */
2911
2882
  unpatchFunction(target) {
2912
- _ModSdkManager.SDK?.removePatches(target);
2883
+ this.SDK.removePatches(target);
2913
2884
  }
2914
2885
  /**
2915
2886
  * Removes all hooks associated with a specific module from a target function.
@@ -2928,7 +2899,7 @@ var ModSdkManager = class _ModSdkManager {
2928
2899
  * Removes all hooks associated with a specific module across all patched functions.
2929
2900
  */
2930
2901
  removeAllHooksByModule(module) {
2931
- for (const data of _ModSdkManager.patchedFunctions.values()) {
2902
+ for (const data of this.patchedFunctions.values()) {
2932
2903
  for (let i = data.hooks.length - 1; i >= 0; i--) {
2933
2904
  if (data.hooks[i].module === module) {
2934
2905
  data.hooks[i].removeCallback();
@@ -2938,6 +2909,12 @@ var ModSdkManager = class _ModSdkManager {
2938
2909
  }
2939
2910
  return true;
2940
2911
  }
2912
+ /**
2913
+ * Unloads the mod removing all hooks and patches by it.
2914
+ */
2915
+ unload() {
2916
+ this.SDK.unload();
2917
+ }
2941
2918
  };
2942
2919
 
2943
2920
  // src/utilities/style.ts
@@ -2990,87 +2967,6 @@ var Style = {
2990
2967
  }
2991
2968
  };
2992
2969
 
2993
- // src/utilities/translation.ts
2994
- var Localization = class _Localization {
2995
- static {
2996
- __name(this, "Localization");
2997
- }
2998
- static LibTranslation = {};
2999
- static ModTranslation = {};
3000
- static PathToModTranslation;
3001
- static PathToLibTranslation = `${PUBLIC_URL}/dl_translations/`;
3002
- static DefaultLanguage = "en";
3003
- /** Flag to prevent re-initialization */
3004
- static initialized = false;
3005
- /** Initialize the localization system by loading translation files. */
3006
- static async init(initOptions) {
3007
- if (_Localization.initialized) return;
3008
- _Localization.initialized = true;
3009
- _Localization.PathToModTranslation = (() => {
3010
- if (!initOptions?.pathToTranslationsFolder) return void 0;
3011
- return initOptions.pathToTranslationsFolder.endsWith("/") ? initOptions.pathToTranslationsFolder : `${initOptions.pathToTranslationsFolder}/`;
3012
- })();
3013
- _Localization.DefaultLanguage = initOptions?.defaultLanguage || _Localization.DefaultLanguage;
3014
- const lang = initOptions?.fixedLanguage ? _Localization.DefaultLanguage : TranslationLanguage.toLowerCase();
3015
- const libTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, lang);
3016
- if (lang === _Localization.DefaultLanguage) {
3017
- _Localization.LibTranslation = libTranslation;
3018
- } else {
3019
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToLibTranslation, _Localization.DefaultLanguage);
3020
- _Localization.LibTranslation = { ...fallbackTranslation, ...libTranslation };
3021
- }
3022
- if (!_Localization.PathToModTranslation) return;
3023
- const modTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, lang);
3024
- if (lang === _Localization.DefaultLanguage) {
3025
- _Localization.ModTranslation = modTranslation;
3026
- } else {
3027
- const fallbackTranslation = await _Localization.fetchLanguageFile(_Localization.PathToModTranslation, _Localization.DefaultLanguage);
3028
- _Localization.ModTranslation = { ...fallbackTranslation, ...modTranslation };
3029
- }
3030
- }
3031
- /** Get a translated string from mod translations by source tag. */
3032
- static getTextMod(srcTag) {
3033
- return _Localization.ModTranslation?.[srcTag] || void 0;
3034
- }
3035
- /** Get a translated string from library translations by source tag. */
3036
- static getTextLib(srcTag) {
3037
- return _Localization.LibTranslation?.[srcTag] || void 0;
3038
- }
3039
- /**
3040
- * Fetch and parse a language file from the given base URL and language code.
3041
- * Falls back to default language if the requested language file is unavailable.
3042
- */
3043
- static async fetchLanguageFile(baseUrl, lang) {
3044
- const response = await fetch(`${baseUrl}${lang}.lang`);
3045
- if (lang !== _Localization.DefaultLanguage && !response.ok) {
3046
- return this.fetchLanguageFile(baseUrl, _Localization.DefaultLanguage);
3047
- }
3048
- if (!response.ok) {
3049
- return {};
3050
- }
3051
- const langFileContent = await response.text();
3052
- return this.parseLanguageFile(langFileContent);
3053
- }
3054
- /**
3055
- * Parse the raw content of a language file into a TranslationDict.
3056
- * Ignores empty lines and comments starting with '#'.
3057
- */
3058
- static parseLanguageFile(content) {
3059
- const translations = {};
3060
- const lines = content.split("\n");
3061
- for (const line of lines) {
3062
- const trimmed = line.trim();
3063
- if (!trimmed || trimmed.startsWith("#")) continue;
3064
- const [key, ...rest] = trimmed.split("=");
3065
- translations[key.trim()] = rest.join("=").trim();
3066
- }
3067
- return translations;
3068
- }
3069
- };
3070
- var getText = /* @__PURE__ */ __name((srcTag) => {
3071
- return Localization.getTextMod(srcTag) || Localization.getTextLib(srcTag) || srcTag;
3072
- }, "getText");
3073
-
3074
2970
  // src/utilities/event_channel.ts
3075
2971
  var EventChannel = class {
3076
2972
  constructor(channelName) {
@@ -3141,6 +3037,7 @@ export {
3141
3037
  HookPriority,
3142
3038
  Localization,
3143
3039
  Logger,
3040
+ MOD_NAME,
3144
3041
  MainMenu,
3145
3042
  ModSdkManager,
3146
3043
  ModStorage,
@@ -3155,14 +3052,13 @@ export {
3155
3052
  exportToGlobal,
3156
3053
  getModule,
3157
3054
  getText,
3158
- hasGetter3 as hasGetter,
3159
- hasSetter3 as hasSetter,
3055
+ hasGetter,
3056
+ hasSetter,
3160
3057
  initMod,
3161
3058
  layout,
3162
- logger,
3059
+ modLogger,
3163
3060
  modStorage,
3164
3061
  modules,
3165
- modulesMap,
3166
3062
  registerModule,
3167
3063
  sdk,
3168
3064
  sendActionMessage,