zuzu-js 0.3.0 → 0.4.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.
@@ -206,279 +206,6 @@
206
206
  }
207
207
  });
208
208
 
209
- // modules/std/string.js
210
- var require_string = __commonJS({
211
- "modules/std/string.js"(exports2, module2) {
212
- "use strict";
213
- function toStringValue(value) {
214
- if (value instanceof RegExp) {
215
- return value.source;
216
- }
217
- if (value && typeof value.to_String === "function") {
218
- return String(value.to_String());
219
- }
220
- if (value instanceof Error) {
221
- return value.message || value.name || String(value);
222
- }
223
- return value == null ? "" : String(value);
224
- }
225
- function isRegexLike(value) {
226
- if (value == null) {
227
- return false;
228
- }
229
- if (value instanceof RegExp) {
230
- return true;
231
- }
232
- return Object.prototype.toString.call(value) === "[object RegExp]";
233
- }
234
- function index(text, needle, start = 0) {
235
- const haystack = [...toStringValue(text)];
236
- const find = [...toStringValue(needle)];
237
- const offset = Math.max(0, Math.trunc(Number(start ?? 0)));
238
- if (find.length === 0) {
239
- return Math.min(offset, haystack.length);
240
- }
241
- for (let i = offset; i <= haystack.length - find.length; i++) {
242
- let matched = true;
243
- for (let j = 0; j < find.length; j++) {
244
- if (haystack[i + j] !== find[j]) {
245
- matched = false;
246
- break;
247
- }
248
- }
249
- if (matched) {
250
- return i;
251
- }
252
- }
253
- return -1;
254
- }
255
- function rindex(text, needle, start = null) {
256
- const haystack = [...toStringValue(text)];
257
- const find = [...toStringValue(needle)];
258
- if (start == null) {
259
- start = haystack.length - find.length;
260
- } else {
261
- start = Math.trunc(Number(start));
262
- }
263
- if (find.length === 0) {
264
- return Math.min(Math.max(0, start), haystack.length);
265
- }
266
- start = Math.min(Math.max(0, start), haystack.length - find.length);
267
- for (let i = start; i >= 0; i--) {
268
- let matched = true;
269
- for (let j = 0; j < find.length; j++) {
270
- if (haystack[i + j] !== find[j]) {
271
- matched = false;
272
- break;
273
- }
274
- }
275
- if (matched) {
276
- return i;
277
- }
278
- }
279
- return -1;
280
- }
281
- function contains(text, needle) {
282
- return index(text, needle) >= 0;
283
- }
284
- function integerValue(value, label) {
285
- const number = Number(value ?? 0);
286
- if (!Number.isInteger(number)) {
287
- throw new Error(`${label} expects an integer`);
288
- }
289
- return number;
290
- }
291
- function chr(codepoint) {
292
- if (arguments.length !== 1) {
293
- throw new Error("chr() expects one argument");
294
- }
295
- const value = integerValue(codepoint, "chr()");
296
- if (value < 0 || value > 1114111) {
297
- throw new Error("chr() expects a Unicode code point in 0..0x10FFFF");
298
- }
299
- if (value >= 55296 && value <= 57343) {
300
- throw new Error("chr() rejects surrogate code points");
301
- }
302
- return String.fromCodePoint(value);
303
- }
304
- function ord(text, index2 = 0) {
305
- if (arguments.length < 1 || arguments.length > 2) {
306
- throw new Error("ord() expects one or two arguments");
307
- }
308
- const chars = [...toStringValue(text)];
309
- const offset = integerValue(index2, "ord()");
310
- if (offset < 0 || offset >= chars.length) {
311
- throw new Error("ord() index out of range");
312
- }
313
- return chars[offset].codePointAt(0);
314
- }
315
- function substr(text, offset, length = null) {
316
- const chars = [...toStringValue(text)];
317
- const from = Number(offset ?? 0);
318
- if (length == null) {
319
- return chars.slice(from).join("");
320
- }
321
- return chars.slice(from, from + Number(length)).join("");
322
- }
323
- function pattern_to_regexp(pattern, caseInsensitive = false) {
324
- return new RegExp(String(pattern ?? ""), caseInsensitive ? "i" : "");
325
- }
326
- var REGEXP_META_CHARS = /* @__PURE__ */ new Set([
327
- "\\",
328
- "/",
329
- "^",
330
- "$",
331
- ".",
332
- "|",
333
- "?",
334
- "*",
335
- "+",
336
- "(",
337
- ")",
338
- "[",
339
- "]",
340
- "{",
341
- "}",
342
- '"',
343
- "'"
344
- ]);
345
- function quotemeta(text) {
346
- return [...toStringValue(text)].map((ch) => REGEXP_META_CHARS.has(ch) ? `\\${ch}` : ch).join("");
347
- }
348
- function normalizePattern(pattern, flags = "") {
349
- if (isRegexLike(pattern)) {
350
- const mergedFlags = [...pattern.flags || "", ...flags || ""];
351
- const uniqFlags = [...new Set(mergedFlags)].join("");
352
- return new RegExp(pattern.source, uniqFlags);
353
- }
354
- return new RegExp(String(pattern ?? ""), flags);
355
- }
356
- function search(text, pattern, flags = "") {
357
- const match = toStringValue(text).match(normalizePattern(pattern, flags));
358
- return match ? match[0] : null;
359
- }
360
- function matches(text, pattern, flags = "") {
361
- return normalizePattern(pattern, flags).test(toStringValue(text));
362
- }
363
- function replace(text, pattern, replacement, flags = "") {
364
- return toStringValue(text).replace(normalizePattern(pattern, flags), toStringValue(replacement));
365
- }
366
- function sprint(format, ...args) {
367
- let idx = 0;
368
- return toStringValue(format).replace(/%([0-9]+)?(?:\.([0-9]+))?([sdfc])/gu, (_token, width, precision, kind) => {
369
- const value = args[idx++];
370
- let out = "";
371
- if (kind === "d") {
372
- out = String(Math.trunc(Number(value ?? 0)));
373
- } else if (kind === "f") {
374
- const num = Number(value ?? 0);
375
- out = precision != null ? num.toFixed(Number(precision)) : String(num);
376
- } else if (kind === "c") {
377
- out = String.fromCharCode(Number(value ?? 0));
378
- } else {
379
- out = toStringValue(value);
380
- }
381
- if (width != null) {
382
- const target = Number(width);
383
- if (out.length < target) {
384
- out = `${" ".repeat(target - out.length)}${out}`;
385
- }
386
- }
387
- return out;
388
- });
389
- }
390
- function join(separator, values) {
391
- const sep = toStringValue(separator);
392
- if (Array.isArray(values)) {
393
- return values.map((value) => toStringValue(value)).join(sep);
394
- }
395
- if (values == null) {
396
- return "";
397
- }
398
- if (typeof values.to_Iterator === "function") {
399
- const out = [];
400
- for (const value of values.to_Iterator()) {
401
- out.push(toStringValue(value));
402
- }
403
- return out.join(sep);
404
- }
405
- if (typeof values.to_Array === "function") {
406
- return join(sep, values.to_Array());
407
- }
408
- if (typeof values[Symbol.iterator] === "function") {
409
- return Array.from(values, (value) => toStringValue(value)).join(sep);
410
- }
411
- return toStringValue(values);
412
- }
413
- function split(text, pattern) {
414
- return toStringValue(text).split(pattern);
415
- }
416
- function starts_with(text, prefix) {
417
- return toStringValue(text).startsWith(toStringValue(prefix));
418
- }
419
- function ends_with(text, suffix) {
420
- return toStringValue(text).endsWith(toStringValue(suffix));
421
- }
422
- function trim(text) {
423
- return toStringValue(text).trim();
424
- }
425
- function pad(text, width, ch = " ", side = "right") {
426
- const src = toStringValue(text);
427
- const padChar = toStringValue(ch || " ");
428
- const target = Number(width ?? 0);
429
- if (src.length >= target) {
430
- return src;
431
- }
432
- const fill = padChar.repeat(target - src.length);
433
- return side === "left" ? `${fill}${src}` : `${src}${fill}`;
434
- }
435
- function chomp(text) {
436
- return toStringValue(text).replace(/\r?\n$/u, "");
437
- }
438
- function words(text) {
439
- return toStringValue(text).replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_\-]+/gu, " ").trim().split(/\s+/u).filter(Boolean);
440
- }
441
- function title(text) {
442
- return words(text).map((w) => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`).join(" ");
443
- }
444
- function snake(text) {
445
- return words(text).map((w) => w.toLowerCase()).join("_");
446
- }
447
- function kebab(text) {
448
- return words(text).map((w) => w.toLowerCase()).join("-");
449
- }
450
- function camel(text) {
451
- const ws = words(text).map((w) => w.toLowerCase());
452
- return ws.map((w, i) => i === 0 ? w : `${w[0].toUpperCase()}${w.slice(1)}`).join("");
453
- }
454
- module2.exports = {
455
- camel,
456
- chomp,
457
- chr,
458
- contains,
459
- ends_with,
460
- index,
461
- join,
462
- kebab,
463
- matches,
464
- ord,
465
- pad,
466
- pattern_to_regexp,
467
- quotemeta,
468
- rindex,
469
- replace,
470
- search,
471
- snake,
472
- split,
473
- starts_with,
474
- sprint,
475
- substr,
476
- title,
477
- trim
478
- };
479
- }
480
- });
481
-
482
209
  // lib/collections.js
483
210
  var require_collections = __commonJS({
484
211
  "lib/collections.js"(exports2, module2) {
@@ -501,6 +228,9 @@
501
228
  function makeSet(values) {
502
229
  return runtimeHelpers().makeSet(values);
503
230
  }
231
+ function stringSortComparator(a, b) {
232
+ return runtimeHelpers().stringSortComparator(a, b);
233
+ }
504
234
  var ZuzuBag = class _ZuzuBag {
505
235
  constructor(...items) {
506
236
  let values;
@@ -620,7 +350,7 @@
620
350
  return this.to_Array().sort(fn2);
621
351
  }
622
352
  sortstr() {
623
- return this.to_Array().sort((a, b) => String(a).localeCompare(String(b)));
353
+ return this.to_Array().sort(stringSortComparator);
624
354
  }
625
355
  sortnum() {
626
356
  return this.to_Array().map((item) => Number(item)).sort((a, b) => a - b);
@@ -911,7 +641,7 @@
911
641
  return this;
912
642
  });
913
643
  define("sortstr", function _sortstr() {
914
- return this.slice().sort((a, b) => String(a).localeCompare(String(b)));
644
+ return this.slice().sort(stringSortComparator);
915
645
  });
916
646
  define(
917
647
  "sortnum",
@@ -1758,6 +1488,32 @@
1758
1488
  }
1759
1489
  throw new Error(`TypeException: cannot coerce ${typeName2(value)} to String`);
1760
1490
  }
1491
+ var surrogatePattern = /[\uD800-\uDFFF]/;
1492
+ function codePointStringCompare(left, right) {
1493
+ if (left === right) {
1494
+ return 0;
1495
+ }
1496
+ if (surrogatePattern.test(left) || surrogatePattern.test(right)) {
1497
+ const leftPoints = Array.from(left);
1498
+ const rightPoints = Array.from(right);
1499
+ const shared = Math.min(leftPoints.length, rightPoints.length);
1500
+ for (let i = 0; i < shared; i++) {
1501
+ const a = leftPoints[i].codePointAt(0);
1502
+ const b = rightPoints[i].codePointAt(0);
1503
+ if (a !== b) {
1504
+ return a < b ? -1 : 1;
1505
+ }
1506
+ }
1507
+ if (leftPoints.length === rightPoints.length) {
1508
+ return 0;
1509
+ }
1510
+ return leftPoints.length < rightPoints.length ? -1 : 1;
1511
+ }
1512
+ return left < right ? -1 : 1;
1513
+ }
1514
+ function stringSortComparator(a, b) {
1515
+ return codePointStringCompare(String(a), String(b));
1516
+ }
1761
1517
  function operatorRegexp(value) {
1762
1518
  value = resolveWeakValue(value);
1763
1519
  if (value instanceof RegExp || Object.prototype.toString.call(value) === "[object RegExp]") {
@@ -1786,6 +1542,8 @@
1786
1542
  lengthOf,
1787
1543
  operatorString,
1788
1544
  operatorRegexp,
1545
+ codePointStringCompare,
1546
+ stringSortComparator,
1789
1547
  ZuzuBinary,
1790
1548
  BinaryString: BinaryString2,
1791
1549
  ZuzuWeakCell,
@@ -1810,6 +1568,295 @@
1810
1568
  }
1811
1569
  });
1812
1570
 
1571
+ // modules/std/string.js
1572
+ var require_string = __commonJS({
1573
+ "modules/std/string.js"(exports2, module2) {
1574
+ "use strict";
1575
+ var { BinaryString: BinaryString2 } = require_runtime_helpers();
1576
+ function toStringValue(value) {
1577
+ if (value instanceof RegExp) {
1578
+ return value.source;
1579
+ }
1580
+ if (value && typeof value.to_String === "function") {
1581
+ return String(value.to_String());
1582
+ }
1583
+ if (value instanceof Error) {
1584
+ return value.message || value.name || String(value);
1585
+ }
1586
+ return value == null ? "" : String(value);
1587
+ }
1588
+ function isRegexLike(value) {
1589
+ if (value == null) {
1590
+ return false;
1591
+ }
1592
+ if (value instanceof RegExp) {
1593
+ return true;
1594
+ }
1595
+ return Object.prototype.toString.call(value) === "[object RegExp]";
1596
+ }
1597
+ function index(text, needle, start = 0) {
1598
+ const haystack = [...toStringValue(text)];
1599
+ const find = [...toStringValue(needle)];
1600
+ const offset = Math.max(0, Math.trunc(Number(start ?? 0)));
1601
+ if (find.length === 0) {
1602
+ return Math.min(offset, haystack.length);
1603
+ }
1604
+ for (let i = offset; i <= haystack.length - find.length; i++) {
1605
+ let matched = true;
1606
+ for (let j = 0; j < find.length; j++) {
1607
+ if (haystack[i + j] !== find[j]) {
1608
+ matched = false;
1609
+ break;
1610
+ }
1611
+ }
1612
+ if (matched) {
1613
+ return i;
1614
+ }
1615
+ }
1616
+ return -1;
1617
+ }
1618
+ function rindex(text, needle, start = null) {
1619
+ const haystack = [...toStringValue(text)];
1620
+ const find = [...toStringValue(needle)];
1621
+ if (start == null) {
1622
+ start = haystack.length - find.length;
1623
+ } else {
1624
+ start = Math.trunc(Number(start));
1625
+ }
1626
+ if (find.length === 0) {
1627
+ return Math.min(Math.max(0, start), haystack.length);
1628
+ }
1629
+ start = Math.min(Math.max(0, start), haystack.length - find.length);
1630
+ for (let i = start; i >= 0; i--) {
1631
+ let matched = true;
1632
+ for (let j = 0; j < find.length; j++) {
1633
+ if (haystack[i + j] !== find[j]) {
1634
+ matched = false;
1635
+ break;
1636
+ }
1637
+ }
1638
+ if (matched) {
1639
+ return i;
1640
+ }
1641
+ }
1642
+ return -1;
1643
+ }
1644
+ function contains(text, needle) {
1645
+ return index(text, needle) >= 0;
1646
+ }
1647
+ function integerValue(value, label) {
1648
+ const number = Number(value ?? 0);
1649
+ if (!Number.isInteger(number)) {
1650
+ throw new Error(`${label} expects an integer`);
1651
+ }
1652
+ return number;
1653
+ }
1654
+ function chr(codepoint) {
1655
+ if (arguments.length !== 1) {
1656
+ throw new Error("chr() expects one argument");
1657
+ }
1658
+ const value = integerValue(codepoint, "chr()");
1659
+ if (value < 0 || value > 1114111) {
1660
+ throw new Error("chr() expects a Unicode code point in 0..0x10FFFF");
1661
+ }
1662
+ if (value >= 55296 && value <= 57343) {
1663
+ throw new Error("chr() rejects surrogate code points");
1664
+ }
1665
+ return String.fromCodePoint(value);
1666
+ }
1667
+ function ord(text, index2 = 0) {
1668
+ if (arguments.length < 1 || arguments.length > 2) {
1669
+ throw new Error("ord() expects one or two arguments");
1670
+ }
1671
+ const chars = [...toStringValue(text)];
1672
+ const offset = integerValue(index2, "ord()");
1673
+ if (offset < 0 || offset >= chars.length) {
1674
+ throw new Error("ord() index out of range");
1675
+ }
1676
+ return chars[offset].codePointAt(0);
1677
+ }
1678
+ function substr(text, offset, length = null) {
1679
+ const chars = [...toStringValue(text)];
1680
+ const from = Number(offset ?? 0);
1681
+ if (length == null) {
1682
+ return chars.slice(from).join("");
1683
+ }
1684
+ return chars.slice(from, from + Number(length)).join("");
1685
+ }
1686
+ function pattern_to_regexp(pattern, caseInsensitive = false) {
1687
+ return new RegExp(String(pattern ?? ""), caseInsensitive ? "i" : "");
1688
+ }
1689
+ var REGEXP_META_CHARS = /* @__PURE__ */ new Set([
1690
+ "\\",
1691
+ "/",
1692
+ "^",
1693
+ "$",
1694
+ ".",
1695
+ "|",
1696
+ "?",
1697
+ "*",
1698
+ "+",
1699
+ "(",
1700
+ ")",
1701
+ "[",
1702
+ "]",
1703
+ "{",
1704
+ "}",
1705
+ '"',
1706
+ "'"
1707
+ ]);
1708
+ function quotemeta(text) {
1709
+ return [...toStringValue(text)].map((ch) => REGEXP_META_CHARS.has(ch) ? `\\${ch}` : ch).join("");
1710
+ }
1711
+ function normalizePattern(pattern, flags = "") {
1712
+ if (isRegexLike(pattern)) {
1713
+ const mergedFlags = [...pattern.flags || "", ...flags || ""];
1714
+ const uniqFlags = [...new Set(mergedFlags)].join("");
1715
+ return new RegExp(pattern.source, uniqFlags);
1716
+ }
1717
+ return new RegExp(String(pattern ?? ""), flags);
1718
+ }
1719
+ function search(text, pattern, flags = "") {
1720
+ const match = toStringValue(text).match(normalizePattern(pattern, flags));
1721
+ return match ? match[0] : null;
1722
+ }
1723
+ function matches(text, pattern, flags = "") {
1724
+ return normalizePattern(pattern, flags).test(toStringValue(text));
1725
+ }
1726
+ function replace(text, pattern, replacement, flags = "") {
1727
+ return toStringValue(text).replace(normalizePattern(pattern, flags), toStringValue(replacement));
1728
+ }
1729
+ function sprint(format, ...args) {
1730
+ let idx = 0;
1731
+ return toStringValue(format).replace(/%([0-9]+)?(?:\.([0-9]+))?([sdfc])/gu, (_token, width, precision, kind) => {
1732
+ const value = args[idx++];
1733
+ let out = "";
1734
+ if (kind === "d") {
1735
+ out = String(Math.trunc(Number(value ?? 0)));
1736
+ } else if (kind === "f") {
1737
+ const num = Number(value ?? 0);
1738
+ out = precision != null ? num.toFixed(Number(precision)) : String(num);
1739
+ } else if (kind === "c") {
1740
+ out = String.fromCharCode(Number(value ?? 0));
1741
+ } else {
1742
+ out = toStringValue(value);
1743
+ }
1744
+ if (width != null) {
1745
+ const target = Number(width);
1746
+ if (out.length < target) {
1747
+ out = `${" ".repeat(target - out.length)}${out}`;
1748
+ }
1749
+ }
1750
+ return out;
1751
+ });
1752
+ }
1753
+ function join(separator, values) {
1754
+ const sep = toStringValue(separator);
1755
+ if (Array.isArray(values)) {
1756
+ return values.map((value) => toStringValue(value)).join(sep);
1757
+ }
1758
+ if (values == null) {
1759
+ return "";
1760
+ }
1761
+ if (typeof values.to_Iterator === "function") {
1762
+ const out = [];
1763
+ for (const value of values.to_Iterator()) {
1764
+ out.push(toStringValue(value));
1765
+ }
1766
+ return out.join(sep);
1767
+ }
1768
+ if (typeof values.to_Array === "function") {
1769
+ return join(sep, values.to_Array());
1770
+ }
1771
+ if (typeof values[Symbol.iterator] === "function") {
1772
+ return Array.from(values, (value) => toStringValue(value)).join(sep);
1773
+ }
1774
+ return toStringValue(values);
1775
+ }
1776
+ function split(text, pattern) {
1777
+ return toStringValue(text).split(pattern);
1778
+ }
1779
+ function starts_with(text, prefix) {
1780
+ return toStringValue(text).startsWith(toStringValue(prefix));
1781
+ }
1782
+ function ends_with(text, suffix) {
1783
+ return toStringValue(text).endsWith(toStringValue(suffix));
1784
+ }
1785
+ function trim(text) {
1786
+ return toStringValue(text).trim();
1787
+ }
1788
+ function pad(text, width, ch = " ", side = "right") {
1789
+ const src = toStringValue(text);
1790
+ const padChar = toStringValue(ch || " ");
1791
+ const target = Number(width ?? 0);
1792
+ if (src.length >= target) {
1793
+ return src;
1794
+ }
1795
+ const fill = padChar.repeat(target - src.length);
1796
+ return side === "left" ? `${fill}${src}` : `${src}${fill}`;
1797
+ }
1798
+ function chomp(text) {
1799
+ return toStringValue(text).replace(/\r?\n$/u, "");
1800
+ }
1801
+ function words(text) {
1802
+ return toStringValue(text).replace(/([a-z0-9])([A-Z])/gu, "$1 $2").replace(/[_\-]+/gu, " ").trim().split(/\s+/u).filter(Boolean);
1803
+ }
1804
+ function title(text) {
1805
+ return words(text).map((w) => `${w[0].toUpperCase()}${w.slice(1).toLowerCase()}`).join(" ");
1806
+ }
1807
+ function snake(text) {
1808
+ return words(text).map((w) => w.toLowerCase()).join("_");
1809
+ }
1810
+ function kebab(text) {
1811
+ return words(text).map((w) => w.toLowerCase()).join("-");
1812
+ }
1813
+ function camel(text) {
1814
+ const ws = words(text).map((w) => w.toLowerCase());
1815
+ return ws.map((w, i) => i === 0 ? w : `${w[0].toUpperCase()}${w.slice(1)}`).join("");
1816
+ }
1817
+ function to_binary(value) {
1818
+ if (typeof value !== "string" && !(value instanceof String)) {
1819
+ const type = value == null ? "Null" : value && value.bytes instanceof Uint8Array ? "BinaryString" : typeof value;
1820
+ throw new Error(`TypeException: to_binary expects String, got ${type}`);
1821
+ }
1822
+ return new BinaryString2(new TextEncoder().encode(String(value)));
1823
+ }
1824
+ function to_string(value) {
1825
+ if (!(value && value.bytes instanceof Uint8Array)) {
1826
+ throw new Error("TypeException: to_string expects BinaryString");
1827
+ }
1828
+ return new TextDecoder("utf-8", { fatal: true }).decode(value.bytes);
1829
+ }
1830
+ module2.exports = {
1831
+ camel,
1832
+ chomp,
1833
+ chr,
1834
+ contains,
1835
+ ends_with,
1836
+ index,
1837
+ join,
1838
+ kebab,
1839
+ matches,
1840
+ ord,
1841
+ pad,
1842
+ pattern_to_regexp,
1843
+ quotemeta,
1844
+ rindex,
1845
+ replace,
1846
+ search,
1847
+ snake,
1848
+ split,
1849
+ starts_with,
1850
+ sprint,
1851
+ substr,
1852
+ title,
1853
+ to_binary,
1854
+ to_string,
1855
+ trim
1856
+ };
1857
+ }
1858
+ });
1859
+
1813
1860
  // modules/std/string/base64.js
1814
1861
  var require_base64 = __commonJS({
1815
1862
  "modules/std/string/base64.js"(exports2, module2) {
@@ -1924,6 +1971,172 @@
1924
1971
  }
1925
1972
  });
1926
1973
 
1974
+ // modules/std/string/encode.js
1975
+ var require_encode = __commonJS({
1976
+ "modules/std/string/encode.js"(exports2, module2) {
1977
+ "use strict";
1978
+ var { BinaryString: BinaryString2 } = require_runtime_helpers();
1979
+ function typeName2(value) {
1980
+ if (value == null) {
1981
+ return "Null";
1982
+ }
1983
+ if (typeof value === "string" || value instanceof String) {
1984
+ return "String";
1985
+ }
1986
+ if (value.bytes instanceof Uint8Array) {
1987
+ return "BinaryString";
1988
+ }
1989
+ return value.constructor && value.constructor.name ? value.constructor.name : typeof value;
1990
+ }
1991
+ function canonicalEncoding(name2) {
1992
+ const upper = String(name2 == null ? "UTF-8" : name2).toUpperCase().replace(/\s+/g, "");
1993
+ if (upper === "UTF-8" || upper === "UTF8") {
1994
+ return "utf8";
1995
+ }
1996
+ if (upper === "UTF-16" || upper === "UTF16" || upper === "UTF-16BE") {
1997
+ return "utf16";
1998
+ }
1999
+ if (upper === "UTF-32" || upper === "UTF32" || upper === "UTF-32BE") {
2000
+ return "utf32";
2001
+ }
2002
+ if (upper === "ISO-8859-1" || upper === "ISO8859-1" || upper === "LATIN-1" || upper === "LATIN1" || upper === "LATIN") {
2003
+ return "latin1";
2004
+ }
2005
+ return null;
2006
+ }
2007
+ function codePoints(text) {
2008
+ return Array.from(text, (ch) => ch.codePointAt(0));
2009
+ }
2010
+ function encode(value, encoding) {
2011
+ if (typeName2(value) !== "String") {
2012
+ throw new Error(`TypeException: encode expects String, got ${typeName2(value)}`);
2013
+ }
2014
+ const text = String(value);
2015
+ const codec = canonicalEncoding(encoding);
2016
+ if (codec === "utf8") {
2017
+ return new BinaryString2(new TextEncoder().encode(text));
2018
+ }
2019
+ if (codec === "utf16") {
2020
+ const out = [];
2021
+ for (let i = 0; i < text.length; i++) {
2022
+ const unit = text.charCodeAt(i);
2023
+ out.push(unit >> 8 & 255, unit & 255);
2024
+ }
2025
+ return new BinaryString2(out);
2026
+ }
2027
+ if (codec === "utf32") {
2028
+ const out = [];
2029
+ for (const point of codePoints(text)) {
2030
+ out.push(
2031
+ point >>> 24 & 255,
2032
+ point >>> 16 & 255,
2033
+ point >>> 8 & 255,
2034
+ point & 255
2035
+ );
2036
+ }
2037
+ return new BinaryString2(out);
2038
+ }
2039
+ if (codec === "latin1") {
2040
+ const out = [];
2041
+ for (const point of codePoints(text)) {
2042
+ if (point > 255) {
2043
+ const hex = point.toString(16).toUpperCase().padStart(4, "0");
2044
+ throw new Error(`Exception: Character U+${hex} cannot be encoded as ISO-8859-1`);
2045
+ }
2046
+ out.push(point);
2047
+ }
2048
+ return new BinaryString2(out);
2049
+ }
2050
+ throw new Error(`Exception: Unsupported encoding: ${encoding}`);
2051
+ }
2052
+ function decode(value, encoding) {
2053
+ if (typeName2(value) !== "BinaryString") {
2054
+ throw new Error(`TypeException: decode expects BinaryString, got ${typeName2(value)}`);
2055
+ }
2056
+ let bytes = value.bytes;
2057
+ const codec = canonicalEncoding(encoding);
2058
+ if (codec === "utf8") {
2059
+ try {
2060
+ return new TextDecoder("utf-8", { fatal: true }).decode(bytes);
2061
+ } catch (_err) {
2062
+ throw new Error("Exception: Invalid UTF-8 in BinaryString");
2063
+ }
2064
+ }
2065
+ if (codec === "utf16") {
2066
+ let bigEndian = true;
2067
+ if (bytes.length >= 2 && bytes[0] === 254 && bytes[1] === 255) {
2068
+ bytes = bytes.subarray(2);
2069
+ } else if (bytes.length >= 2 && bytes[0] === 255 && bytes[1] === 254) {
2070
+ bigEndian = false;
2071
+ bytes = bytes.subarray(2);
2072
+ }
2073
+ if (bytes.length % 2 !== 0) {
2074
+ throw new Error("Exception: UTF-16 input length must be a multiple of 2 bytes");
2075
+ }
2076
+ const units = [];
2077
+ for (let i = 0; i < bytes.length; i += 2) {
2078
+ units.push(bigEndian ? bytes[i] << 8 | bytes[i + 1] : bytes[i + 1] << 8 | bytes[i]);
2079
+ }
2080
+ let out = "";
2081
+ for (let i = 0; i < units.length; i++) {
2082
+ const unit = units[i];
2083
+ if (unit >= 55296 && unit <= 56319) {
2084
+ const next = units[i + 1];
2085
+ if (next == null || next < 56320 || next > 57343) {
2086
+ throw new Error("Exception: Invalid UTF-16 in BinaryString");
2087
+ }
2088
+ out += String.fromCharCode(unit, next);
2089
+ i++;
2090
+ continue;
2091
+ }
2092
+ if (unit >= 56320 && unit <= 57343) {
2093
+ throw new Error("Exception: Invalid UTF-16 in BinaryString");
2094
+ }
2095
+ out += String.fromCharCode(unit);
2096
+ }
2097
+ return out;
2098
+ }
2099
+ if (codec === "utf32") {
2100
+ let bigEndian = true;
2101
+ if (bytes.length >= 4 && bytes[0] === 0 && bytes[1] === 0 && bytes[2] === 254 && bytes[3] === 255) {
2102
+ bytes = bytes.subarray(4);
2103
+ } else if (bytes.length >= 4 && bytes[0] === 255 && bytes[1] === 254 && bytes[2] === 0 && bytes[3] === 0) {
2104
+ bigEndian = false;
2105
+ bytes = bytes.subarray(4);
2106
+ }
2107
+ if (bytes.length % 4 !== 0) {
2108
+ throw new Error("Exception: UTF-32 input length must be a multiple of 4 bytes");
2109
+ }
2110
+ let out = "";
2111
+ for (let i = 0; i < bytes.length; i += 4) {
2112
+ const point = bigEndian ? bytes[i] * 16777216 + (bytes[i + 1] << 16) + (bytes[i + 2] << 8) + bytes[i + 3] : bytes[i + 3] * 16777216 + (bytes[i + 2] << 16) + (bytes[i + 1] << 8) + bytes[i];
2113
+ if (point > 1114111 || point >= 55296 && point <= 57343) {
2114
+ throw new Error("Exception: Invalid UTF-32 in BinaryString");
2115
+ }
2116
+ out += String.fromCodePoint(point);
2117
+ }
2118
+ return out;
2119
+ }
2120
+ if (codec === "latin1") {
2121
+ let out = "";
2122
+ for (const byte of bytes) {
2123
+ out += String.fromCharCode(byte);
2124
+ }
2125
+ return out;
2126
+ }
2127
+ throw new Error(`Exception: Unsupported encoding: ${encoding}`);
2128
+ }
2129
+ module2.exports = {
2130
+ encode,
2131
+ decode,
2132
+ ENCODING_UTF8: "UTF-8",
2133
+ ENCODING_UTF16: "UTF-16",
2134
+ ENCODING_UTF32: "UTF-32",
2135
+ ENCODING_LATIN: "ISO-8859-1"
2136
+ };
2137
+ }
2138
+ });
2139
+
1927
2140
  // modules/std/time.js
1928
2141
  var require_time = __commonJS({
1929
2142
  "modules/std/time.js"(exports2, module2) {
@@ -1955,6 +2168,7 @@
1955
2168
  ["dec", 12],
1956
2169
  ["december", 12]
1957
2170
  ]);
2171
+ var DAY_ABBR = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
1958
2172
  var WEEKDAY_BY_NAME = /* @__PURE__ */ new Set([
1959
2173
  "sun",
1960
2174
  "sunday",
@@ -2009,12 +2223,59 @@
2009
2223
  const seconds = Number(m[2]) * 3600 + Number(m[3]) * 60;
2010
2224
  return m[1] === "-" ? -seconds : seconds;
2011
2225
  }
2012
- function pad(value, width = 2) {
2013
- return String(value).padStart(width, "0");
2226
+ function pad(value, width = 2, fill = "0") {
2227
+ return String(value).padStart(width, fill);
2014
2228
  }
2015
2229
  function stripTrailingPeriod(text) {
2016
2230
  return String(text).replace(/\.+$/u, "").toLowerCase();
2017
2231
  }
2232
+ function weekdayIndex(parts) {
2233
+ const date = new Date(
2234
+ parts.year,
2235
+ parts.month - 1,
2236
+ parts.day
2237
+ );
2238
+ return (date.getDay() + 6) % 7 + 1;
2239
+ }
2240
+ function weekParts(parts) {
2241
+ const date = new Date(
2242
+ parts.year,
2243
+ parts.month - 1,
2244
+ parts.day
2245
+ );
2246
+ const weekDay = date.getDay() || 7;
2247
+ const shifted = new Date(date);
2248
+ shifted.setDate(date.getDate() + 4 - weekDay);
2249
+ const weekYear = shifted.getFullYear();
2250
+ const yearStart = new Date(weekYear, 0, 1);
2251
+ return {
2252
+ year: weekYear,
2253
+ week: Math.ceil((shifted - yearStart) / 864e5 / 7 + 1)
2254
+ };
2255
+ }
2256
+ function dayOfMonthForDisplay(day) {
2257
+ return String(day).padStart(2, " ");
2258
+ }
2259
+ function dayOfYear(parts) {
2260
+ const start = new Date(parts.year, 0, 1);
2261
+ const now = new Date(parts.year, parts.month - 1, parts.day);
2262
+ return (now - start) / 864e5;
2263
+ }
2264
+ function julianDay(parts) {
2265
+ let year = parts.year;
2266
+ let month = parts.month;
2267
+ const day = parts.day;
2268
+ if (month <= 2) {
2269
+ year -= 1;
2270
+ month += 12;
2271
+ }
2272
+ const a = Math.floor((14 - month) / 12);
2273
+ const y = year + 4800 - a;
2274
+ const m = month + 12 * a - 3;
2275
+ const jd = day + Math.floor((153 * m + 2) / 5) + 365 * y + Math.floor(y / 4) - Math.floor(y / 100) + Math.floor(y / 400) - 32045;
2276
+ const fraction = (parts.hour * 3600 + parts.minute * 60 + parts.second) / 86400;
2277
+ return jd + fraction - 0.5;
2278
+ }
2018
2279
  function isLeapYear(year) {
2019
2280
  if (year % 4 !== 0) return false;
2020
2281
  if (year % 100 !== 0) return true;
@@ -2432,6 +2693,59 @@
2432
2693
  year() {
2433
2694
  return this._parts().year;
2434
2695
  }
2696
+ yy() {
2697
+ return pad(this._parts().year % 100, 2);
2698
+ }
2699
+ day_of_week() {
2700
+ return weekdayIndex(this._parts());
2701
+ }
2702
+ day() {
2703
+ return DAY_ABBR[this.day_of_week() - 1];
2704
+ }
2705
+ day_of_year() {
2706
+ return dayOfYear(this._parts());
2707
+ }
2708
+ month_last_day() {
2709
+ return daysInMonth(this._parts().year, this._parts().month);
2710
+ }
2711
+ hms(separator = ":") {
2712
+ const p = this._parts();
2713
+ return `${pad(p.hour)}${String(separator)}${pad(p.minute)}${String(separator)}${pad(p.second)}`;
2714
+ }
2715
+ ymd(separator = "-") {
2716
+ const p = this._parts();
2717
+ const sep = String(separator);
2718
+ return `${pad(p.year, 4)}${sep}${pad(p.month)}${sep}${pad(p.day)}`;
2719
+ }
2720
+ mdy(separator = "-") {
2721
+ const p = this._parts();
2722
+ const sep = String(separator);
2723
+ return `${pad(p.month)}${sep}${pad(p.day)}${sep}${pad(p.year, 4)}`;
2724
+ }
2725
+ dmy(separator = "-") {
2726
+ const p = this._parts();
2727
+ const sep = String(separator);
2728
+ return `${pad(p.day)}${sep}${pad(p.month)}${sep}${pad(p.year, 4)}`;
2729
+ }
2730
+ cdate() {
2731
+ const p = this._parts();
2732
+ return `${DAY_ABBR[weekdayIndex(p) - 1]} ${MONTHS[p.month - 1]} ${dayOfMonthForDisplay(p.day)} ${pad(p.hour)}:${pad(p.minute)}:${pad(p.second)} ${p.year}`;
2733
+ }
2734
+ tzoffset() {
2735
+ return offsetForEpoch(this._epoch, this._timezone);
2736
+ }
2737
+ is_leap_year() {
2738
+ return isLeapYear(this._parts().year);
2739
+ }
2740
+ week() {
2741
+ return weekParts(this._parts()).week;
2742
+ }
2743
+ week_year() {
2744
+ return weekParts(this._parts()).year;
2745
+ }
2746
+ julian_day() {
2747
+ return julianDay(this._parts());
2748
+ }
2435
2749
  add_seconds(n) {
2436
2750
  return this._clone(this._epoch + Number(n));
2437
2751
  }
@@ -2546,8 +2860,7 @@
2546
2860
  }
2547
2861
  to_rfc5322(options = {}) {
2548
2862
  const p = this._parts();
2549
- const d = new Date(Date.UTC(p.year, p.month - 1, p.day));
2550
- const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][d.getUTCDay()];
2863
+ const weekday = DAY_ABBR[weekdayIndex(p) - 1];
2551
2864
  const core = `${pad(p.day)} ${MONTHS[p.month - 1]} ${pad(p.year, 4)} ${pad(p.hour)}:${pad(p.minute)}:${pad(p.second)} ${formatOffset(offsetForEpoch(this._epoch, this._timezone), false)}`;
2552
2865
  return options.include_weekday === false ? core : `${weekday}, ${core}`;
2553
2866
  }
@@ -4544,6 +4857,7 @@
4544
4857
  "throw",
4545
4858
  "sub",
4546
4859
  "union",
4860
+ "divides",
4547
4861
  "intersection",
4548
4862
  "difference",
4549
4863
  "subsetof",
@@ -5159,6 +5473,18 @@
5159
5473
  continue;
5160
5474
  }
5161
5475
  if (isDigit(ch)) {
5476
+ const radixDigitOk = ch === "0" ? peek(1) === "x" ? (c) => /[0-9a-fA-F]/.test(c || "") : peek(1) === "b" ? (c) => c === "0" || c === "1" : peek(1) === "o" ? (c) => /[0-7]/.test(c || "") : null : null;
5477
+ if (radixDigitOk && radixDigitOk(peek(2))) {
5478
+ const radix = peek(1) === "x" ? 16 : peek(1) === "b" ? 2 : 8;
5479
+ advance();
5480
+ advance();
5481
+ let digits = "";
5482
+ while (radixDigitOk(peek())) {
5483
+ digits += advance();
5484
+ }
5485
+ addToken("number", String(parseInt(digits, radix)), start, cursor());
5486
+ continue;
5487
+ }
5162
5488
  let value = "";
5163
5489
  while (isDigit(peek())) {
5164
5490
  value += advance();
@@ -5169,6 +5495,15 @@
5169
5495
  value += advance();
5170
5496
  }
5171
5497
  }
5498
+ if (peek() === "E" && (isDigit(peek(1)) || (peek(1) === "+" || peek(1) === "-") && isDigit(peek(2)))) {
5499
+ value += advance();
5500
+ if (peek() === "+" || peek() === "-") {
5501
+ value += advance();
5502
+ }
5503
+ while (isDigit(peek())) {
5504
+ value += advance();
5505
+ }
5506
+ }
5172
5507
  addToken("number", value, start, cursor());
5173
5508
  continue;
5174
5509
  }
@@ -5194,7 +5529,7 @@
5194
5529
  addToken("operator", ch, start, cursor());
5195
5530
  continue;
5196
5531
  }
5197
- if (["\u2261", "\u2262", "\u2260", "\u2264", "\u2265", "\u2192", "\u221A", "\u230A", "\u230B", "\u2308", "\u2309", "\u2208", "\u2209", "\u22C3", "\u22C2", "\u2216", "\u2282", "\u2283", "\xAB", "\xBB", "\u2276", "\u2277", "\u25B7", "\u25C1"].includes(ch)) {
5532
+ if (["\u2261", "\u2262", "\u2260", "\u2264", "\u2265", "\u2192", "\u221A", "\u230A", "\u230B", "\u2308", "\u2309", "\u2208", "\u2209", "\u22C3", "\u22C2", "\u2216", "\u2282", "\u2283", "\xAB", "\xBB", "\u2276", "\u2277", "\u25B7", "\u25C1", "\u2223", "\u2224"].includes(ch)) {
5198
5533
  advance();
5199
5534
  addToken("operator", ch, start, cursor());
5200
5535
  continue;
@@ -5252,6 +5587,7 @@
5252
5587
  UnsupportedSyntaxError
5253
5588
  } = require_errors();
5254
5589
  function parse(tokens, options = {}) {
5590
+ const pendingSetClosers = [];
5255
5591
  let index = 0;
5256
5592
  let asyncContextDepth = 1;
5257
5593
  function startLocFromToken(token) {
@@ -6636,14 +6972,20 @@
6636
6972
  }
6637
6973
  function parseBitwise() {
6638
6974
  return parseLeftAssociative(
6639
- parseComparison,
6975
+ parseShift,
6640
6976
  (token) => token.type === "operator" && ["&", "|", "^"].includes(token.value)
6641
6977
  );
6642
6978
  }
6979
+ function parseShift() {
6980
+ return parseLeftAssociative(
6981
+ parseComparison,
6982
+ (token) => token.type === "operator" && ["<<", ">>", "\xAB", "\xBB"].includes(token.value) && token.value !== pendingSetClosers[pendingSetClosers.length - 1]
6983
+ );
6984
+ }
6643
6985
  function parseComparison() {
6644
6986
  return parseLeftAssociative(
6645
6987
  parseRange,
6646
- (token) => token.type === "operator" && ["<", "<=", ">", ">=", "\u2264", "\u2265", "~", "<=>", "@", "@@", "@?", "\\", "\u2208", "\u2209", "\u22C3", "\u22C2", "\u2216", "\u2282", "\u2283", "\u2282\u2283", "\u2276", "\u2277"].includes(token.value) || token.type === "keyword" && ["gt", "ge", "lt", "le", "cmp", "eqi", "nei", "gti", "gei", "lti", "lei", "cmpi", "in", "not_in", "union", "intersection", "difference", "subsetof", "supersetof", "equivalentof", "does", "can"].includes(token.value) || token.type === "identifier" && token.value === "instanceof"
6988
+ (token) => token.type === "operator" && ["<", "<=", ">", ">=", "\u2264", "\u2265", "~", "<=>", "@", "@@", "@?", "\\", "\u2208", "\u2209", "\u22C3", "\u22C2", "\u2216", "\u2282", "\u2283", "\u2282\u2283", "\u2276", "\u2277", "\u2223", "\u2224"].includes(token.value) || token.type === "keyword" && ["gt", "ge", "lt", "le", "cmp", "eqi", "nei", "gti", "gei", "lti", "lei", "cmpi", "in", "not_in", "union", "intersection", "difference", "subsetof", "supersetof", "equivalentof", "does", "can", "divides"].includes(token.value) || token.type === "identifier" && token.value === "instanceof"
6647
6989
  );
6648
6990
  }
6649
6991
  function parseRange() {
@@ -7286,18 +7628,23 @@
7286
7628
  if (match("operator", closer)) {
7287
7629
  return elements;
7288
7630
  }
7289
- while (true) {
7290
- if (match("punctuation", ",")) {
7291
- continue;
7292
- }
7293
- if (match("operator", closer)) {
7294
- break;
7295
- }
7296
- elements.push(parseExpression());
7297
- if (match("operator", closer)) {
7298
- break;
7631
+ pendingSetClosers.push(closer);
7632
+ try {
7633
+ while (true) {
7634
+ if (match("punctuation", ",")) {
7635
+ continue;
7636
+ }
7637
+ if (match("operator", closer)) {
7638
+ break;
7639
+ }
7640
+ elements.push(parseExpression());
7641
+ if (match("operator", closer)) {
7642
+ break;
7643
+ }
7644
+ match("punctuation", ",");
7299
7645
  }
7300
- match("punctuation", ",");
7646
+ } finally {
7647
+ pendingSetClosers.pop();
7301
7648
  }
7302
7649
  return elements;
7303
7650
  }
@@ -9191,6 +9538,17 @@ ${cleanup}
9191
9538
  return `__zuzu_bit_or( ${left}, ${right} )`;
9192
9539
  case "^":
9193
9540
  return `__zuzu_bit_xor( ${left}, ${right} )`;
9541
+ case "<<":
9542
+ case "\xAB":
9543
+ return `__zuzu_shift_left( ${left}, ${right} )`;
9544
+ case "\u2223":
9545
+ case "divides":
9546
+ return `__zuzu_divides( ${left}, ${right} )`;
9547
+ case "\u2224":
9548
+ return `__zuzu_ndivides( ${left}, ${right} )`;
9549
+ case ">>":
9550
+ case "\xBB":
9551
+ return `__zuzu_shift_right( ${left}, ${right} )`;
9194
9552
  default:
9195
9553
  return `( ${left} ${node.operator} ${right} )`;
9196
9554
  }
@@ -10746,7 +11104,7 @@ ${cleanup}
10746
11104
  "package.json"(exports2, module2) {
10747
11105
  module2.exports = {
10748
11106
  name: "zuzu-js",
10749
- version: "0.3.0",
11107
+ version: "0.4.0",
10750
11108
  description: "JavaScript runtime, compiler, and browser bundle for ZuzuScript.",
10751
11109
  main: "lib/zuzu.js",
10752
11110
  bin: {
@@ -10794,6 +11152,7 @@ ${cleanup}
10794
11152
  node: ">=16"
10795
11153
  },
10796
11154
  dependencies: {
11155
+ "@std-uritemplate/std-uritemplate": "^2.0.10",
10797
11156
  "@xmldom/xmldom": "^0.9.10",
10798
11157
  "adm-zip": "^0.5.17",
10799
11158
  "better-sqlite3": "^11.10.0",
@@ -11328,7 +11687,9 @@ ${cleanup}
11328
11687
  releaseCollectionValues,
11329
11688
  addSetValue,
11330
11689
  assignStrongValue,
11331
- assignWeakValue
11690
+ assignWeakValue,
11691
+ codePointStringCompare,
11692
+ stringSortComparator
11332
11693
  } = require_runtime_helpers();
11333
11694
  var taskRuntime2 = require_task();
11334
11695
  var textEncoder = new TextEncoder();
@@ -11514,10 +11875,16 @@ ${cleanup}
11514
11875
  function stringCompare(left, right, options = {}) {
11515
11876
  const l = options.insensitive ? zuzuOperatorString(left).toLowerCase() : zuzuOperatorString(left);
11516
11877
  const r = options.insensitive ? zuzuOperatorString(right).toLowerCase() : zuzuOperatorString(right);
11517
- return l.localeCompare(r);
11878
+ return codePointStringCompare(l, r);
11518
11879
  }
11519
11880
  function parseNumericString(value) {
11520
11881
  const text = String(value).trim();
11882
+ const radix = text.match(/^([+-]?)0([xX][0-9a-fA-F]+|[bB][01]+|[oO][0-7]+)$/);
11883
+ if (radix) {
11884
+ const base = "xX".includes(radix[2][0]) ? 16 : "bB".includes(radix[2][0]) ? 2 : 8;
11885
+ const magnitude = parseInt(radix[2].slice(1), base);
11886
+ return radix[1] === "-" ? -magnitude : magnitude;
11887
+ }
11521
11888
  const match = text.match(/^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/);
11522
11889
  if (!match) {
11523
11890
  throw new Error(`TypeException: cannot coerce String to Number: ${JSON.stringify(String(value))}`);
@@ -11816,6 +12183,46 @@ ${cleanup}
11816
12183
  }
11817
12184
  return ~(zuzuToNumber(value) >>> 0) >>> 0;
11818
12185
  }
12186
+ function shiftBitstream(bytes, count, left) {
12187
+ const len = bytes.length;
12188
+ const out = new Uint8Array(len);
12189
+ if (len === 0 || count >= len * 8) {
12190
+ return out;
12191
+ }
12192
+ const byteShift = Math.floor(count / 8);
12193
+ const bitShift = count % 8;
12194
+ for (let i = 0; i < len; i++) {
12195
+ let value;
12196
+ if (left) {
12197
+ const src = i + byteShift;
12198
+ const hi = src < len ? bytes[src] : 0;
12199
+ const lo = src + 1 < len ? bytes[src + 1] : 0;
12200
+ value = (hi << 8 | lo) << bitShift >> 8;
12201
+ } else {
12202
+ if (i < byteShift) {
12203
+ continue;
12204
+ }
12205
+ const lo = bytes[i - byteShift];
12206
+ const hi = i > byteShift ? bytes[i - byteShift - 1] : 0;
12207
+ value = (hi << 8 | lo) >> bitShift;
12208
+ }
12209
+ out[i] = value & 255;
12210
+ }
12211
+ return out;
12212
+ }
12213
+ function shiftValue(left, right, leftward) {
12214
+ left = resolveWeakValue(left);
12215
+ const count = Math.trunc(zuzuToNumber(right));
12216
+ if (!(count >= 0) || !Number.isFinite(count)) {
12217
+ throw new Error("Exception: shift count must be a non-negative integer");
12218
+ }
12219
+ if (left instanceof ZuzuBinary) {
12220
+ return new BinaryString2(shiftBitstream(left.bytes, count, leftward));
12221
+ }
12222
+ const value = Math.trunc(zuzuToNumber(left));
12223
+ const factor = Math.pow(2, count);
12224
+ return leftward ? value * factor : Math.floor(value / factor);
12225
+ }
11819
12226
  function zuzuComparableValue(value) {
11820
12227
  value = resolveWeakValue(value);
11821
12228
  if (typeof value === "function" && value.length === 0) {
@@ -13191,7 +13598,12 @@ ${cleanup}
13191
13598
  }
13192
13599
  const moduleSearchRoots = this.getModuleSearchRoots();
13193
13600
  const emit = (value) => {
13194
- const line = String(value);
13601
+ let line = String(value);
13602
+ if (line === "Infinity") {
13603
+ line = "Inf";
13604
+ } else if (line === "-Infinity") {
13605
+ line = "-Inf";
13606
+ }
13195
13607
  if (this.outputLines) {
13196
13608
  this.outputLines.push(line);
13197
13609
  }
@@ -13469,7 +13881,7 @@ ${cleanup}
13469
13881
  return [...this].sort(fn2);
13470
13882
  });
13471
13883
  defineRuntimeMethod(Set.prototype, "sortstr", function _setSortstr() {
13472
- return [...this].sort((a, b) => String(a).localeCompare(String(b)));
13884
+ return [...this].sort(stringSortComparator);
13473
13885
  });
13474
13886
  defineRuntimeMethod(Set.prototype, "sortnum", function _setSortnum() {
13475
13887
  return [...this].map((item) => Number(item)).sort((a, b) => a - b);
@@ -13875,6 +14287,12 @@ ${cleanup}
13875
14287
  if (input == null) {
13876
14288
  return [];
13877
14289
  }
14290
+ if (input instanceof ZuzuBinary) {
14291
+ return Array.from(input.bytes, (byte) => new BinaryString2([byte]));
14292
+ }
14293
+ if (typeof input === "string" || input instanceof String) {
14294
+ return Array.from(String(input));
14295
+ }
13878
14296
  if (typeof input[Symbol.iterator] === "function") {
13879
14297
  return input;
13880
14298
  }
@@ -14024,6 +14442,19 @@ ${cleanup}
14024
14442
  __zuzu_bit_and(left, right) {
14025
14443
  return bitwiseAnd(left, right);
14026
14444
  },
14445
+ __zuzu_shift_left(left, right) {
14446
+ return shiftValue(left, right, true);
14447
+ },
14448
+ // The left operand is the divisor: a ∣ b tests b mod a.
14449
+ __zuzu_divides(left, right) {
14450
+ return zuzuToNumber(right) % zuzuToNumber(left) === 0;
14451
+ },
14452
+ __zuzu_ndivides(left, right) {
14453
+ return zuzuToNumber(right) % zuzuToNumber(left);
14454
+ },
14455
+ __zuzu_shift_right(left, right) {
14456
+ return shiftValue(left, right, false);
14457
+ },
14027
14458
  __zuzu_bit_or(left, right) {
14028
14459
  return bitwiseOr(left, right);
14029
14460
  },
@@ -14380,7 +14811,7 @@ ${cleanup}
14380
14811
  define( Array.prototype, 'shuffle', function _shuffle() { return this.slice(); } );
14381
14812
  define( Array.prototype, 'sample', function _sample( n ) { return this.slice( 0, n ); } );
14382
14813
  define( Array.prototype, 'for_each_value', function _for_each_value( fn ) { this.forEach( fn ); return this; } );
14383
- define( Array.prototype, 'sortstr', function _sortstr() { return this.slice().sort( (a, b) => String( a ).localeCompare( String( b ) ) ); } );
14814
+ define( Array.prototype, 'sortstr', function _sortstr() { return this.slice().sort( stringSortComparator ); } );
14384
14815
  define( Array.prototype, 'sortnum', function _sortnum() { return this.map( (item) => Number( item ) ).sort( (a, b) => a - b ); } );
14385
14816
  define( Array.prototype, 'to_Array', function _to_array() { return __zuzu_array( this ); } );
14386
14817
  define( Array.prototype, 'to_Set', function _to_set() { return __zuzu_set( this ); } );
@@ -14410,7 +14841,7 @@ ${cleanup}
14410
14841
  define( Set.prototype, 'is_disjoint', function _is_disjoint( other ) { return this.intersection( other ).size === 0 ? 1 : 0; } );
14411
14842
  define( Set.prototype, 'equals', function _equals( other ) { return __zuzu_equivalentof( this, other ); } );
14412
14843
  define( Set.prototype, 'sort', function _sort( fn ) { return [ ...this ].sort( fn ); } );
14413
- define( Set.prototype, 'sortstr', function _sortstr() { return [ ...this ].sort( (a, b) => String( a ).localeCompare( String( b ) ) ); } );
14844
+ define( Set.prototype, 'sortstr', function _sortstr() { return [ ...this ].sort( stringSortComparator ); } );
14414
14845
  define( Set.prototype, 'sortnum', function _sortnum() { return [ ...this ].map( (item) => Number( item ) ).sort( (a, b) => a - b ); } );
14415
14846
  define( Set.prototype, 'map', function _map( fn ) { return new Set( [ ...this ].map( fn ) ); } );
14416
14847
  define( Set.prototype, 'grep', function _grep( fn ) { return new Set( [ ...this ].filter( fn ) ); } );
@@ -37312,7 +37743,9 @@ ${lines.join("\n")}
37312
37743
  return values;
37313
37744
  }
37314
37745
  var ZMath = {
37315
- pi: PI,
37746
+ pi() {
37747
+ return PI;
37748
+ },
37316
37749
  sin(value) {
37317
37750
  return Math.sin(Number(value ?? 0));
37318
37751
  },
@@ -37443,6 +37876,12 @@ ${lines.join("\n")}
37443
37876
  "use strict";
37444
37877
  var BigNum = class _BigNum {
37445
37878
  constructor(value, text = null, isInt = null) {
37879
+ if (typeof value === "bigint") {
37880
+ this._value = value;
37881
+ this._text = text == null ? String(value) : String(text);
37882
+ this._isInt = isInt == null ? true : Boolean(isInt);
37883
+ return;
37884
+ }
37446
37885
  this._value = Number(value ?? 0);
37447
37886
  this._text = text == null ? String(this._value) : String(text);
37448
37887
  this._isInt = isInt == null ? Number.isInteger(this._value) : Boolean(isInt);
@@ -37458,19 +37897,46 @@ ${lines.join("\n")}
37458
37897
  }
37459
37898
  static from_dec(value) {
37460
37899
  const text = String(value ?? "0").trim();
37461
- return new _BigNum(Number(text || "0"), text || "0", !/[.eE]/.test(text));
37900
+ const safeText = text || "0";
37901
+ if (_BigNum._isIntegerText(safeText)) {
37902
+ return new _BigNum(BigInt(safeText), safeText, true);
37903
+ }
37904
+ return new _BigNum(Number(safeText), safeText, !/[.eE]/.test(safeText));
37462
37905
  }
37463
37906
  static from_hex(value) {
37464
- const text = String(value ?? "0").trim().toLowerCase().replace(/^0x/u, "") || "0";
37465
- const parsed = Number.parseInt(text, 16);
37907
+ const text = String(value ?? "0").trim().replace(/^0x/u, "").toLowerCase() || "0";
37908
+ const negative = text.startsWith("-");
37909
+ const digits = text.replace(/^[+-]/u, "");
37910
+ const parsed = BigInt(`0x${digits}`) * (negative ? -1n : 1n);
37466
37911
  return new _BigNum(parsed, String(parsed), true);
37467
37912
  }
37468
- get is_int() {
37913
+ is_int() {
37469
37914
  return this._isInt;
37470
37915
  }
37916
+ _toBigInt() {
37917
+ if (!this._isInt) {
37918
+ return null;
37919
+ }
37920
+ if (typeof this._value === "bigint") {
37921
+ return this._value;
37922
+ }
37923
+ try {
37924
+ return BigInt(this._text);
37925
+ } catch {
37926
+ return null;
37927
+ }
37928
+ }
37929
+ _toNumber() {
37930
+ return typeof this._value === "bigint" ? Number(this._value) : this._value;
37931
+ }
37471
37932
  bcmp(other) {
37472
- const rhs = _BigNum._coerce(other)._value;
37473
- return this._value < rhs ? -1 : this._value > rhs ? 1 : 0;
37933
+ const rhs = _BigNum._coerce(other);
37934
+ const lhsBigInt = this._toBigInt();
37935
+ const rhsBigInt = rhs._toBigInt();
37936
+ if (lhsBigInt !== null && rhsBigInt !== null) {
37937
+ return lhsBigInt < rhsBigInt ? -1 : lhsBigInt > rhsBigInt ? 1 : 0;
37938
+ }
37939
+ return this._toNumber() < rhs._toNumber() ? -1 : this._toNumber() > rhs._toNumber() ? 1 : 0;
37474
37940
  }
37475
37941
  beq(other) {
37476
37942
  return this.bcmp(other) === 0;
@@ -37490,71 +37956,136 @@ ${lines.join("\n")}
37490
37956
  bge(other) {
37491
37957
  return this.bcmp(other) >= 0;
37492
37958
  }
37493
- get babs() {
37494
- return new _BigNum(Math.abs(this._value), String(Math.abs(this._value)), this._isInt);
37959
+ babs() {
37960
+ const value = this._toBigInt();
37961
+ if (value !== null) {
37962
+ return new _BigNum(value < 0n ? -value : value, String(value < 0n ? -value : value), this._isInt);
37963
+ }
37964
+ return new _BigNum(Math.abs(this._toNumber()), String(Math.abs(this._toNumber())), this._isInt);
37495
37965
  }
37496
- get bneg() {
37497
- return new _BigNum(-this._value, String(-this._value), this._isInt);
37966
+ bneg() {
37967
+ const value = this._toBigInt();
37968
+ if (value !== null) {
37969
+ return new _BigNum(-value, String(-value), this._isInt);
37970
+ }
37971
+ return new _BigNum(-this._toNumber(), String(-this._toNumber()), this._isInt);
37498
37972
  }
37499
- get binv() {
37500
- return new _BigNum(1 / this._value);
37973
+ binv() {
37974
+ return new _BigNum(1 / this._toNumber());
37501
37975
  }
37502
- get bsin() {
37503
- return new _BigNum(Math.sin(this._value), String(Math.sin(this._value)), false);
37976
+ bsin() {
37977
+ return new _BigNum(Math.sin(this._toNumber()), String(Math.sin(this._toNumber())), false);
37504
37978
  }
37505
- get bcos() {
37506
- return new _BigNum(Math.cos(this._value));
37979
+ bcos() {
37980
+ return new _BigNum(Math.cos(this._toNumber()));
37507
37981
  }
37508
- get btan() {
37509
- return new _BigNum(Math.tan(this._value), String(Math.tan(this._value)), false);
37982
+ btan() {
37983
+ return new _BigNum(Math.tan(this._toNumber()), String(Math.tan(this._toNumber())), false);
37510
37984
  }
37511
- get bsqrt() {
37512
- return new _BigNum(Math.sqrt(this._value));
37985
+ bsqrt() {
37986
+ return new _BigNum(Math.sqrt(this._toNumber()));
37513
37987
  }
37514
- get bround() {
37515
- return new _BigNum(Math.round(this._value));
37988
+ bround() {
37989
+ return new _BigNum(Math.round(this._toNumber()));
37516
37990
  }
37517
- get bfloor() {
37518
- return new _BigNum(Math.floor(this._value));
37991
+ bfloor() {
37992
+ return new _BigNum(Math.floor(this._toNumber()));
37519
37993
  }
37520
- get bceil() {
37521
- return new _BigNum(Math.ceil(this._value));
37994
+ bceil() {
37995
+ return new _BigNum(Math.ceil(this._toNumber()));
37522
37996
  }
37523
37997
  badd(other) {
37524
- return new _BigNum(this._value + _BigNum._coerce(other)._value, String(this._value + _BigNum._coerce(other)._value), false);
37998
+ const rhs = _BigNum._coerce(other);
37999
+ const lhsInt = this._toBigInt();
38000
+ const rhsInt = rhs._toBigInt();
38001
+ if (lhsInt !== null && rhsInt !== null) {
38002
+ return new _BigNum(lhsInt + rhsInt, String(lhsInt + rhsInt), false);
38003
+ }
38004
+ return new _BigNum(this._toNumber() + rhs._toNumber(), String(this._toNumber() + rhs._toNumber()), false);
37525
38005
  }
37526
38006
  bsub(other) {
37527
- return new _BigNum(this._value - _BigNum._coerce(other)._value, String(this._value - _BigNum._coerce(other)._value), false);
38007
+ const rhs = _BigNum._coerce(other);
38008
+ const lhsInt = this._toBigInt();
38009
+ const rhsInt = rhs._toBigInt();
38010
+ if (lhsInt !== null && rhsInt !== null) {
38011
+ return new _BigNum(lhsInt - rhsInt, String(lhsInt - rhsInt), false);
38012
+ }
38013
+ return new _BigNum(this._toNumber() - rhs._toNumber(), String(this._toNumber() - rhs._toNumber()), false);
37528
38014
  }
37529
38015
  bmul(other) {
37530
- return new _BigNum(this._value * _BigNum._coerce(other)._value, String(this._value * _BigNum._coerce(other)._value), false);
38016
+ const rhs = _BigNum._coerce(other);
38017
+ const lhsInt = this._toBigInt();
38018
+ const rhsInt = rhs._toBigInt();
38019
+ if (lhsInt !== null && rhsInt !== null) {
38020
+ return new _BigNum(lhsInt * rhsInt, String(lhsInt * rhsInt), false);
38021
+ }
38022
+ return new _BigNum(this._toNumber() * rhs._toNumber(), String(this._toNumber() * rhs._toNumber()), false);
37531
38023
  }
37532
38024
  bdiv(other) {
37533
- return new _BigNum(this._value / _BigNum._coerce(other)._value);
38025
+ const rhs = _BigNum._coerce(other);
38026
+ return new _BigNum(this._toNumber() / rhs._toNumber());
37534
38027
  }
37535
38028
  bmod(other) {
37536
- return new _BigNum(this._value % _BigNum._coerce(other)._value);
38029
+ const rhs = _BigNum._coerce(other);
38030
+ const lhsInt = this._toBigInt();
38031
+ const rhsInt = rhs._toBigInt();
38032
+ if (lhsInt !== null && rhsInt !== null && rhsInt !== 0n) {
38033
+ return new _BigNum(lhsInt % rhsInt, String(lhsInt % rhsInt), true);
38034
+ }
38035
+ return new _BigNum(this._toNumber() % rhs._toNumber());
37537
38036
  }
37538
38037
  bpow(other) {
37539
- return new _BigNum(this._value ** _BigNum._coerce(other)._value);
38038
+ const rhs = _BigNum._coerce(other);
38039
+ const lhsInt = this._toBigInt();
38040
+ const rhsInt = rhs._toBigInt();
38041
+ if (lhsInt !== null && rhsInt !== null && rhsInt >= 0n) {
38042
+ let base = lhsInt;
38043
+ let power = rhsInt;
38044
+ let result = 1n;
38045
+ while (power > 0n) {
38046
+ if (power & 1n) {
38047
+ result *= base;
38048
+ }
38049
+ power >>= 1n;
38050
+ if (power > 0n) {
38051
+ base *= base;
38052
+ }
38053
+ }
38054
+ return new _BigNum(result, String(result), true);
38055
+ }
38056
+ return new _BigNum(this._toNumber() ** rhs._toNumber());
37540
38057
  }
37541
- get to_hex() {
37542
- return `0x${Math.trunc(this._value).toString(16)}`;
38058
+ to_hex() {
38059
+ const value = this._toBigInt();
38060
+ if (value === null) {
38061
+ return `0x${Math.trunc(this._toNumber()).toString(16)}`;
38062
+ }
38063
+ if (value === 0n) {
38064
+ return "0x0";
38065
+ }
38066
+ const absolute = value < 0n ? -value : value;
38067
+ return value < 0n ? `-0x${absolute.toString(16)}` : `0x${absolute.toString(16)}`;
37543
38068
  }
37544
- get to_dec() {
37545
- return this._isInt ? Math.trunc(this._value) : this._textify();
38069
+ to_dec() {
38070
+ return this._textify();
37546
38071
  }
37547
- get to_String() {
37548
- return this.to_dec;
38072
+ to_String() {
38073
+ return this.to_dec();
37549
38074
  }
37550
- get to_Number() {
37551
- return this._value;
38075
+ toString() {
38076
+ return String(this.to_String());
38077
+ }
38078
+ to_Number() {
38079
+ return this._toNumber();
38080
+ }
38081
+ static _isIntegerText(text) {
38082
+ return /^[+-]?(?:\d+)$/u.test(text);
37552
38083
  }
37553
38084
  _textify() {
37554
38085
  if (this._text != null && /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)$/u.test(this._text)) {
37555
38086
  return this._text.replace(/\.0+$/u, "").replace(/(\.\d*?)0+$/u, "$1").replace(/\.$/u, "");
37556
38087
  }
37557
- return String(this._value);
38088
+ return this._toBigInt() !== null ? this._toBigInt().toString() : String(this._value);
37558
38089
  }
37559
38090
  };
37560
38091
  module2.exports = {
@@ -39529,6 +40060,436 @@ ${lines.join("\n")}
39529
40060
  }
39530
40061
  });
39531
40062
 
40063
+ // node_modules/@std-uritemplate/std-uritemplate/dist/index.cjs
40064
+ var require_dist = __commonJS({
40065
+ "node_modules/@std-uritemplate/std-uritemplate/dist/index.cjs"(exports2) {
40066
+ "use strict";
40067
+ var StdUriTemplate = class _StdUriTemplate {
40068
+ static expand(template, substitutions) {
40069
+ return _StdUriTemplate.expandImpl(template, substitutions);
40070
+ }
40071
+ static validateLiteral(c, col) {
40072
+ switch (c) {
40073
+ case "+":
40074
+ case "#":
40075
+ case "/":
40076
+ case ";":
40077
+ case "?":
40078
+ case "&":
40079
+ case " ":
40080
+ case "!":
40081
+ case "=":
40082
+ case "$":
40083
+ case "|":
40084
+ case "*":
40085
+ case ":":
40086
+ case "~":
40087
+ case "-":
40088
+ throw new Error(`Illegal character identified in the token at col: ${col}`);
40089
+ }
40090
+ }
40091
+ static getMaxChar(buffer, col) {
40092
+ if (!buffer) {
40093
+ return -1;
40094
+ } else {
40095
+ const value = buffer.join("");
40096
+ if (value.length === 0) {
40097
+ return -1;
40098
+ } else {
40099
+ try {
40100
+ return parseInt(value, 10);
40101
+ } catch (e) {
40102
+ throw new Error(`Cannot parse max chars at col: ${col}`);
40103
+ }
40104
+ }
40105
+ }
40106
+ }
40107
+ static getOperator(c, token, col) {
40108
+ switch (c) {
40109
+ case "+":
40110
+ return 1;
40111
+ case "#":
40112
+ return 2;
40113
+ case ".":
40114
+ return 3;
40115
+ case "/":
40116
+ return 4;
40117
+ case ";":
40118
+ return 5;
40119
+ case "?":
40120
+ return 6;
40121
+ case "&":
40122
+ return 7;
40123
+ default:
40124
+ _StdUriTemplate.validateLiteral(c, col);
40125
+ token.push(c);
40126
+ return 0;
40127
+ }
40128
+ }
40129
+ static expandImpl(str, substitutions) {
40130
+ const result = [];
40131
+ let token = null;
40132
+ let operator = null;
40133
+ let composite = false;
40134
+ let maxCharBuffer = null;
40135
+ let firstToken = true;
40136
+ for (let i = 0; i < str.length; i++) {
40137
+ const character = str.charAt(i);
40138
+ switch (character) {
40139
+ case "{":
40140
+ token = [];
40141
+ firstToken = true;
40142
+ break;
40143
+ case "}":
40144
+ if (token !== null) {
40145
+ const expanded = _StdUriTemplate.expandToken(
40146
+ operator,
40147
+ token.join(""),
40148
+ composite,
40149
+ _StdUriTemplate.getMaxChar(maxCharBuffer, i),
40150
+ firstToken,
40151
+ substitutions,
40152
+ result,
40153
+ i
40154
+ );
40155
+ if (expanded && firstToken) {
40156
+ firstToken = false;
40157
+ }
40158
+ token = null;
40159
+ operator = null;
40160
+ composite = false;
40161
+ maxCharBuffer = null;
40162
+ } else {
40163
+ throw new Error(`Failed to expand token, invalid at col: ${i}`);
40164
+ }
40165
+ break;
40166
+ case ",":
40167
+ if (token !== null) {
40168
+ const expanded = _StdUriTemplate.expandToken(
40169
+ operator,
40170
+ token.join(""),
40171
+ composite,
40172
+ _StdUriTemplate.getMaxChar(maxCharBuffer, i),
40173
+ firstToken,
40174
+ substitutions,
40175
+ result,
40176
+ i
40177
+ );
40178
+ if (expanded && firstToken) {
40179
+ firstToken = false;
40180
+ }
40181
+ token = [];
40182
+ composite = false;
40183
+ maxCharBuffer = null;
40184
+ break;
40185
+ }
40186
+ // Intentional fall-through for commas outside the {}
40187
+ default:
40188
+ if (token !== null) {
40189
+ if (operator === null) {
40190
+ operator = _StdUriTemplate.getOperator(character, token, i);
40191
+ } else if (maxCharBuffer !== null) {
40192
+ if (character.match(/^\d$/)) {
40193
+ maxCharBuffer.push(character);
40194
+ } else {
40195
+ throw new Error(`Illegal character identified in the token at col: ${i}`);
40196
+ }
40197
+ } else {
40198
+ if (character === ":") {
40199
+ maxCharBuffer = [];
40200
+ } else if (character === "*") {
40201
+ composite = true;
40202
+ } else {
40203
+ _StdUriTemplate.validateLiteral(character, i);
40204
+ token.push(character);
40205
+ }
40206
+ }
40207
+ } else {
40208
+ result.push(character);
40209
+ }
40210
+ break;
40211
+ }
40212
+ }
40213
+ if (token === null) {
40214
+ return result.join("");
40215
+ } else {
40216
+ throw new Error("Unterminated token");
40217
+ }
40218
+ }
40219
+ static addPrefix(op, result) {
40220
+ switch (op) {
40221
+ case 2:
40222
+ result.push("#");
40223
+ break;
40224
+ case 3:
40225
+ result.push(".");
40226
+ break;
40227
+ case 4:
40228
+ result.push("/");
40229
+ break;
40230
+ case 5:
40231
+ result.push(";");
40232
+ break;
40233
+ case 6:
40234
+ result.push("?");
40235
+ break;
40236
+ case 7:
40237
+ result.push("&");
40238
+ break;
40239
+ default:
40240
+ return;
40241
+ }
40242
+ }
40243
+ static addSeparator(op, result) {
40244
+ switch (op) {
40245
+ case 3:
40246
+ result.push(".");
40247
+ break;
40248
+ case 4:
40249
+ result.push("/");
40250
+ break;
40251
+ case 5:
40252
+ result.push(";");
40253
+ break;
40254
+ case 6:
40255
+ case 7:
40256
+ result.push("&");
40257
+ break;
40258
+ default:
40259
+ result.push(",");
40260
+ return;
40261
+ }
40262
+ }
40263
+ static addValue(op, token, value, result, maxChar) {
40264
+ switch (op) {
40265
+ case 1:
40266
+ case 2:
40267
+ _StdUriTemplate.addExpandedValue(null, value, result, maxChar, false);
40268
+ break;
40269
+ case 6:
40270
+ case 7:
40271
+ result.push(`${token}=`);
40272
+ _StdUriTemplate.addExpandedValue(null, value, result, maxChar, true);
40273
+ break;
40274
+ case 5:
40275
+ result.push(token);
40276
+ _StdUriTemplate.addExpandedValue("=", value, result, maxChar, true);
40277
+ break;
40278
+ case 3:
40279
+ case 4:
40280
+ case 0:
40281
+ _StdUriTemplate.addExpandedValue(null, value, result, maxChar, true);
40282
+ break;
40283
+ }
40284
+ }
40285
+ static addValueElement(op, token, value, result, maxChar) {
40286
+ switch (op) {
40287
+ case 1:
40288
+ case 2:
40289
+ _StdUriTemplate.addExpandedValue(null, value, result, maxChar, false);
40290
+ break;
40291
+ case 6:
40292
+ case 7:
40293
+ case 5:
40294
+ case 3:
40295
+ case 4:
40296
+ case 0:
40297
+ _StdUriTemplate.addExpandedValue(null, value, result, maxChar, true);
40298
+ break;
40299
+ }
40300
+ }
40301
+ static isSurrogate(cp) {
40302
+ const codeUnit = cp.charCodeAt(0);
40303
+ return codeUnit >= 55296 && codeUnit <= 56319;
40304
+ }
40305
+ static isIprivate(cp) {
40306
+ return 57344 <= cp.charCodeAt(0) && cp.charCodeAt(0) <= 63743;
40307
+ }
40308
+ static isUcschar(cp) {
40309
+ const codePoint = cp.codePointAt(0) || 0;
40310
+ return 160 <= codePoint && codePoint <= 55295 || 63744 <= codePoint && codePoint <= 64975 || 65008 <= codePoint && codePoint <= 65519;
40311
+ }
40312
+ static addExpandedValue(prefix, value, result, maxChar, replaceReserved) {
40313
+ const stringValue = _StdUriTemplate.convertNativeTypes(value);
40314
+ const max = maxChar !== -1 ? Math.min(maxChar, stringValue.length) : stringValue.length;
40315
+ let reservedBuffer = void 0;
40316
+ if (max > 0 && prefix != null) {
40317
+ result.push(prefix);
40318
+ }
40319
+ for (let i = 0; i < max; i++) {
40320
+ const character = stringValue.charAt(i);
40321
+ if (character === "%" && !replaceReserved) {
40322
+ reservedBuffer = [];
40323
+ }
40324
+ let toAppend = character;
40325
+ if (_StdUriTemplate.isSurrogate(character)) {
40326
+ toAppend = encodeURIComponent(stringValue.charAt(i) + stringValue.charAt(i + 1));
40327
+ i++;
40328
+ } else if (replaceReserved || _StdUriTemplate.isUcschar(character) || _StdUriTemplate.isIprivate(character)) {
40329
+ if (character === "!") {
40330
+ toAppend = "%21";
40331
+ } else {
40332
+ toAppend = encodeURIComponent(toAppend);
40333
+ }
40334
+ }
40335
+ if (reservedBuffer) {
40336
+ reservedBuffer.push(toAppend);
40337
+ if (reservedBuffer.length === 3) {
40338
+ let isEncoded = false;
40339
+ try {
40340
+ const reserved = reservedBuffer.join("");
40341
+ const decoded = decodeURIComponent(reservedBuffer.join(""));
40342
+ isEncoded = reserved !== decoded;
40343
+ } catch (e) {
40344
+ }
40345
+ if (isEncoded) {
40346
+ result.push(reservedBuffer.join(""));
40347
+ } else {
40348
+ result.push("%25");
40349
+ result.push(reservedBuffer.slice(1).join(""));
40350
+ }
40351
+ reservedBuffer = void 0;
40352
+ }
40353
+ } else {
40354
+ if (character === " ") {
40355
+ result.push("%20");
40356
+ } else if (character === "%") {
40357
+ result.push("%25");
40358
+ } else {
40359
+ result.push(toAppend);
40360
+ }
40361
+ }
40362
+ }
40363
+ if (reservedBuffer) {
40364
+ result.push("%25");
40365
+ result.push(reservedBuffer.slice(1).join(""));
40366
+ }
40367
+ }
40368
+ static isList(value) {
40369
+ return Array.isArray(value) || value instanceof Set;
40370
+ }
40371
+ static isMap(value) {
40372
+ return value instanceof Map || typeof value === "object";
40373
+ }
40374
+ static getSubstitutionType(value, col) {
40375
+ if (value === void 0 || value === null) {
40376
+ return 0;
40377
+ } else if (_StdUriTemplate.isNativeType(value)) {
40378
+ return 1;
40379
+ } else if (_StdUriTemplate.isList(value)) {
40380
+ return 2;
40381
+ } else if (_StdUriTemplate.isMap(value)) {
40382
+ return 3;
40383
+ } else {
40384
+ throw new Error(`Illegal class passed as substitution, found ${typeof value} at col: ${col}`);
40385
+ }
40386
+ }
40387
+ static isEmpty(substType, value) {
40388
+ if (value === void 0 || value === null) {
40389
+ return true;
40390
+ } else {
40391
+ switch (substType) {
40392
+ case 1:
40393
+ return false;
40394
+ case 2:
40395
+ return value.length === 0;
40396
+ case 3:
40397
+ return Object.keys(value).length === 0;
40398
+ default:
40399
+ return true;
40400
+ }
40401
+ }
40402
+ }
40403
+ static isNativeType(value) {
40404
+ return typeof value === "string" || typeof value === "number" || typeof value === "boolean";
40405
+ }
40406
+ static convertNativeTypes(value) {
40407
+ if (typeof value === "string") {
40408
+ return value;
40409
+ } else if (typeof value === "number" || typeof value === "boolean") {
40410
+ return value.toString();
40411
+ } else {
40412
+ throw new Error(`Illegal class passed as substitution, found ${typeof value}`);
40413
+ }
40414
+ }
40415
+ static expandToken(operator, token, composite, maxChar, firstToken, substitutions, result, col) {
40416
+ if (token.length === 0) {
40417
+ throw new Error(`Found an empty token at col: ${col}`);
40418
+ }
40419
+ const value = substitutions[token];
40420
+ const substType = _StdUriTemplate.getSubstitutionType(value, col);
40421
+ if (substType === 0 || _StdUriTemplate.isEmpty(substType, value)) {
40422
+ return false;
40423
+ }
40424
+ if (firstToken) {
40425
+ _StdUriTemplate.addPrefix(operator, result);
40426
+ } else {
40427
+ _StdUriTemplate.addSeparator(operator, result);
40428
+ }
40429
+ switch (substType) {
40430
+ case 1:
40431
+ _StdUriTemplate.addStringValue(operator, token, value, result, maxChar);
40432
+ break;
40433
+ case 2:
40434
+ _StdUriTemplate.addListValue(operator, token, value, result, maxChar, composite);
40435
+ break;
40436
+ case 3:
40437
+ _StdUriTemplate.addMapValue(operator, token, value, result, maxChar, composite);
40438
+ break;
40439
+ }
40440
+ return true;
40441
+ }
40442
+ static addStringValue(operator, token, value, result, maxChar) {
40443
+ _StdUriTemplate.addValue(operator, token, value, result, maxChar);
40444
+ }
40445
+ static addListValue(operator, token, value, result, maxChar, composite) {
40446
+ let first = true;
40447
+ for (const v of value) {
40448
+ if (first) {
40449
+ _StdUriTemplate.addValue(operator, token, v, result, maxChar);
40450
+ first = false;
40451
+ } else {
40452
+ if (composite) {
40453
+ _StdUriTemplate.addSeparator(operator, result);
40454
+ _StdUriTemplate.addValue(operator, token, v, result, maxChar);
40455
+ } else {
40456
+ result.push(",");
40457
+ _StdUriTemplate.addValueElement(operator, token, v, result, maxChar);
40458
+ }
40459
+ }
40460
+ }
40461
+ }
40462
+ static addMapValue(operator, token, value, result, maxChar, composite) {
40463
+ let first = true;
40464
+ if (maxChar !== -1) {
40465
+ throw new Error("Value trimming is not allowed on Maps");
40466
+ }
40467
+ for (const key in value) {
40468
+ const v = value[key];
40469
+ if (composite) {
40470
+ if (!first) {
40471
+ _StdUriTemplate.addSeparator(operator, result);
40472
+ }
40473
+ _StdUriTemplate.addValueElement(operator, token, key, result, maxChar);
40474
+ result.push("=");
40475
+ } else {
40476
+ if (first) {
40477
+ _StdUriTemplate.addValue(operator, token, key, result, maxChar);
40478
+ } else {
40479
+ result.push(",");
40480
+ _StdUriTemplate.addValueElement(operator, token, key, result, maxChar);
40481
+ }
40482
+ result.push(",");
40483
+ }
40484
+ _StdUriTemplate.addValueElement(operator, token, v, result, maxChar);
40485
+ first = false;
40486
+ }
40487
+ }
40488
+ };
40489
+ exports2.StdUriTemplate = StdUriTemplate;
40490
+ }
40491
+ });
40492
+
39532
40493
  // modules/std/net/url.js
39533
40494
  var require_url = __commonJS({
39534
40495
  "modules/std/net/url.js"(exports2, module2) {
@@ -39595,29 +40556,42 @@ ${lines.join("\n")}
39595
40556
  }
39596
40557
  return out;
39597
40558
  }
39598
- function _templateVar(values, name2) {
39599
- if (values[name2] == null) {
39600
- return "";
40559
+ var { StdUriTemplate } = require_dist();
40560
+ function _templateValue(value) {
40561
+ if (value == null) {
40562
+ return null;
39601
40563
  }
39602
- return encodeURIComponent(_str(values[name2]));
39603
- }
39604
- function _templateQuery(values, namesText) {
39605
- const names = String(namesText).split(/\s*,\s*/u).filter(Boolean);
39606
- const parts = [];
39607
- for (const name2 of names) {
39608
- if (values[name2] == null) {
39609
- continue;
40564
+ if (Array.isArray(value)) {
40565
+ return value.map((item) => _str(item));
40566
+ }
40567
+ if (typeof value === "boolean") {
40568
+ return value ? "true" : "false";
40569
+ }
40570
+ if (typeof value === "object" && !(value.bytes instanceof Uint8Array)) {
40571
+ const out = {};
40572
+ for (const key of Object.keys(value).sort()) {
40573
+ out[key] = _str(value[key]);
39610
40574
  }
39611
- const key = encodeURIComponent(name2);
39612
- const val = encodeURIComponent(_str(values[name2]));
39613
- parts.push(`${key}=${val}`);
40575
+ return out;
39614
40576
  }
39615
- return parts.length > 0 ? `?${parts.join("&")}` : "";
40577
+ return _str(value);
39616
40578
  }
39617
40579
  function fill_template(template, values) {
39618
40580
  const source = _str(template);
39619
- const data = values && typeof values === "object" && !Array.isArray(values) ? values : {};
39620
- return source.replace(/\{\?([^}]+)\}/gu, (_, names) => _templateQuery(data, names)).replace(/\{([a-zA-Z_][a-zA-Z0-9_]*)\}/gu, (_, name2) => _templateVar(data, name2));
40581
+ const data = {};
40582
+ if (values && typeof values === "object" && !Array.isArray(values)) {
40583
+ for (const key of Object.keys(values)) {
40584
+ const converted = _templateValue(values[key]);
40585
+ if (converted != null) {
40586
+ data[key] = converted;
40587
+ }
40588
+ }
40589
+ }
40590
+ try {
40591
+ return StdUriTemplate.expand(source, data);
40592
+ } catch (err) {
40593
+ throw new Error(`Exception: invalid URL template: ${source}`);
40594
+ }
39621
40595
  }
39622
40596
  module2.exports = {
39623
40597
  escape,
@@ -39628,15 +40602,16 @@ ${lines.join("\n")}
39628
40602
  }
39629
40603
  });
39630
40604
 
39631
- // ../../../../../tmp/zuzu-browser-build.mbIbiI/browser-stdlib.generated.js
40605
+ // ../../../../../tmp/zuzu-browser-build.fADF4k/browser-stdlib.generated.js
39632
40606
  var require_browser_stdlib_generated = __commonJS({
39633
- "../../../../../tmp/zuzu-browser-build.mbIbiI/browser-stdlib.generated.js"(exports2, module2) {
40607
+ "../../../../../tmp/zuzu-browser-build.fADF4k/browser-stdlib.generated.js"(exports2, module2) {
39634
40608
  "use strict";
39635
40609
  function createBrowserStdlib2() {
39636
40610
  const jsModules = /* @__PURE__ */ Object.create(null);
39637
40611
  jsModules["/modules/javascript.js"] = require_javascript();
39638
40612
  jsModules["/modules/std/string.js"] = require_string();
39639
40613
  jsModules["/modules/std/string/base64.js"] = require_base64();
40614
+ jsModules["/modules/std/string/encode.js"] = require_encode();
39640
40615
  jsModules["/modules/std/time.js"] = require_time();
39641
40616
  jsModules["/modules/std/marshal.js"] = require_marshal();
39642
40617
  jsModules["/modules/std/task.js"] = require_task();
@@ -39657,7 +40632,7 @@ ${lines.join("\n")}
39657
40632
  jsModules["/modules/std/internals.js"] = require_internals();
39658
40633
  jsModules["/modules/std/net/url.js"] = require_url();
39659
40634
  const virtualFiles = /* @__PURE__ */ Object.create(null);
39660
- virtualFiles["/modules/std/colour.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/colour - Colour parsing helpers.\n\n=head1 SYNOPSIS\n\n from std/colour import parse_colour;\n\n say( parse_colour("red") ); # #ff0000\n say( parse_colour("#abc") ); # #aabbcc\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nC<parse_colour> accepts three- and six-digit hexadecimal colours and the\nCSS3 extended colour keywords. It returns a lowercase six-digit\nhexadecimal colour string.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item C<< parse_colour(String x) >>\n\nParameters: C<x> is a CSS colour keyword or a three- or six-digit\nhexadecimal colour string. Returns: C<String>. Returns the normalized\nlowercase C<#rrggbb> colour string, or throws if C<x> is not recognised.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/colour >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/string import trim;\n\nconst _COLOUR_KEYWORDS := {\n aliceblue: "#f0f8ff",\n antiquewhite: "#faebd7",\n aqua: "#00ffff",\n aquamarine: "#7fffd4",\n azure: "#f0ffff",\n beige: "#f5f5dc",\n bisque: "#ffe4c4",\n black: "#000000",\n blanchedalmond: "#ffebcd",\n blue: "#0000ff",\n blueviolet: "#8a2be2",\n brown: "#a52a2a",\n burlywood: "#deb887",\n cadetblue: "#5f9ea0",\n chartreuse: "#7fff00",\n chocolate: "#d2691e",\n coral: "#ff7f50",\n cornflowerblue: "#6495ed",\n cornsilk: "#fff8dc",\n crimson: "#dc143c",\n cyan: "#00ffff",\n darkblue: "#00008b",\n darkcyan: "#008b8b",\n darkgoldenrod: "#b8860b",\n darkgray: "#a9a9a9",\n darkgreen: "#006400",\n darkgrey: "#a9a9a9",\n darkkhaki: "#bdb76b",\n darkmagenta: "#8b008b",\n darkolivegreen: "#556b2f",\n darkorange: "#ff8c00",\n darkorchid: "#9932cc",\n darkred: "#8b0000",\n darksalmon: "#e9967a",\n darkseagreen: "#8fbc8f",\n darkslateblue: "#483d8b",\n darkslategray: "#2f4f4f",\n darkslategrey: "#2f4f4f",\n darkturquoise: "#00ced1",\n darkviolet: "#9400d3",\n deeppink: "#ff1493",\n deepskyblue: "#00bfff",\n dimgray: "#696969",\n dimgrey: "#696969",\n dodgerblue: "#1e90ff",\n firebrick: "#b22222",\n floralwhite: "#fffaf0",\n forestgreen: "#228b22",\n fuchsia: "#ff00ff",\n gainsboro: "#dcdcdc",\n ghostwhite: "#f8f8ff",\n gold: "#ffd700",\n goldenrod: "#daa520",\n gray: "#808080",\n green: "#008000",\n greenyellow: "#adff2f",\n grey: "#808080",\n honeydew: "#f0fff0",\n hotpink: "#ff69b4",\n indianred: "#cd5c5c",\n indigo: "#4b0082",\n ivory: "#fffff0",\n khaki: "#f0e68c",\n lavender: "#e6e6fa",\n lavenderblush: "#fff0f5",\n lawngreen: "#7cfc00",\n lemonchiffon: "#fffacd",\n lightblue: "#add8e6",\n lightcoral: "#f08080",\n lightcyan: "#e0ffff",\n lightgoldenrodyellow: "#fafad2",\n lightgray: "#d3d3d3",\n lightgreen: "#90ee90",\n lightgrey: "#d3d3d3",\n lightpink: "#ffb6c1",\n lightsalmon: "#ffa07a",\n lightseagreen: "#20b2aa",\n lightskyblue: "#87cefa",\n lightslategray: "#778899",\n lightslategrey: "#778899",\n lightsteelblue: "#b0c4de",\n lightyellow: "#ffffe0",\n lime: "#00ff00",\n limegreen: "#32cd32",\n linen: "#faf0e6",\n magenta: "#ff00ff",\n maroon: "#800000",\n mediumaquamarine: "#66cdaa",\n mediumblue: "#0000cd",\n mediumorchid: "#ba55d3",\n mediumpurple: "#9370db",\n mediumseagreen: "#3cb371",\n mediumslateblue: "#7b68ee",\n mediumspringgreen: "#00fa9a",\n mediumturquoise: "#48d1cc",\n mediumvioletred: "#c71585",\n midnightblue: "#191970",\n mintcream: "#f5fffa",\n mistyrose: "#ffe4e1",\n moccasin: "#ffe4b5",\n navajowhite: "#ffdead",\n navy: "#000080",\n oldlace: "#fdf5e6",\n olive: "#808000",\n olivedrab: "#6b8e23",\n orange: "#ffa500",\n orangered: "#ff4500",\n orchid: "#da70d6",\n palegoldenrod: "#eee8aa",\n palegreen: "#98fb98",\n paleturquoise: "#afeeee",\n palevioletred: "#db7093",\n papayawhip: "#ffefd5",\n peachpuff: "#ffdab9",\n peru: "#cd853f",\n pink: "#ffc0cb",\n plum: "#dda0dd",\n powderblue: "#b0e0e6",\n purple: "#800080",\n red: "#ff0000",\n rosybrown: "#bc8f8f",\n royalblue: "#4169e1",\n saddlebrown: "#8b4513",\n salmon: "#fa8072",\n sandybrown: "#f4a460",\n seagreen: "#2e8b57",\n seashell: "#fff5ee",\n sienna: "#a0522d",\n silver: "#c0c0c0",\n skyblue: "#87ceeb",\n slateblue: "#6a5acd",\n slategray: "#708090",\n slategrey: "#708090",\n snow: "#fffafa",\n springgreen: "#00ff7f",\n steelblue: "#4682b4",\n tan: "#d2b48c",\n teal: "#008080",\n thistle: "#d8bfd8",\n tomato: "#ff6347",\n turquoise: "#40e0d0",\n violet: "#ee82ee",\n wheat: "#f5deb3",\n white: "#ffffff",\n whitesmoke: "#f5f5f5",\n yellow: "#ffff00",\n yellowgreen: "#9acd32",\n};\n\nfunction parse_colour ( String x ) {\n let text := lc( trim(x) );\n\n if ( text ~ /^#[0-9a-f]{6}$/ ) {\n return text;\n }\n\n let short := text ~ /^#([0-9a-f])([0-9a-f])([0-9a-f])$/;\n if ( short ) {\n return "#"\n _ short[1] _ short[1]\n _ short[2] _ short[2]\n _ short[3] _ short[3];\n }\n\n if ( _COLOUR_KEYWORDS.exists(text) ) {\n return _COLOUR_KEYWORDS.get(text);\n }\n\n die `Invalid colour: ${x}`;\n}\n';
40635
+ virtualFiles["/modules/std/colour.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/colour - Colour parsing helpers.\n\n=head1 SYNOPSIS\n\n from std/colour import parse_colour;\n\n say( parse_colour("red") ); # #ff0000\n say( parse_colour("#abc") ); # #aabbcc\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nC<parse_colour> accepts three- and six-digit hexadecimal colours and the\nCSS3 extended colour keywords. It returns a lowercase six-digit\nhexadecimal colour string.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item C<< parse_colour(String x) >>\n\nParameters: C<x> is a CSS colour keyword or a three- or six-digit\nhexadecimal colour string. Returns: C<String>. Returns the normalized\nlowercase C<#rrggbb> colour string, or throws if C<x> is not recognised.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/colour >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/string import trim;\n\nconst _COLOUR_KEYWORDS := {\n aliceblue: "#f0f8ff",\n antiquewhite: "#faebd7",\n aqua: "#00ffff",\n aquamarine: "#7fffd4",\n azure: "#f0ffff",\n beige: "#f5f5dc",\n bisque: "#ffe4c4",\n black: "#000000",\n blanchedalmond: "#ffebcd",\n blue: "#0000ff",\n blueviolet: "#8a2be2",\n brown: "#a52a2a",\n burlywood: "#deb887",\n cadetblue: "#5f9ea0",\n chartreuse: "#7fff00",\n chocolate: "#d2691e",\n coral: "#ff7f50",\n cornflowerblue: "#6495ed",\n cornsilk: "#fff8dc",\n crimson: "#dc143c",\n cyan: "#00ffff",\n darkblue: "#00008b",\n darkcyan: "#008b8b",\n darkgoldenrod: "#b8860b",\n darkgray: "#a9a9a9",\n darkgreen: "#006400",\n darkgrey: "#a9a9a9",\n darkkhaki: "#bdb76b",\n darkmagenta: "#8b008b",\n darkolivegreen: "#556b2f",\n darkorange: "#ff8c00",\n darkorchid: "#9932cc",\n darkred: "#8b0000",\n darksalmon: "#e9967a",\n darkseagreen: "#8fbc8f",\n darkslateblue: "#483d8b",\n darkslategray: "#2f4f4f",\n darkslategrey: "#2f4f4f",\n darkturquoise: "#00ced1",\n darkviolet: "#9400d3",\n deeppink: "#ff1493",\n deepskyblue: "#00bfff",\n dimgray: "#696969",\n dimgrey: "#696969",\n dodgerblue: "#1e90ff",\n firebrick: "#b22222",\n floralwhite: "#fffaf0",\n forestgreen: "#228b22",\n fuchsia: "#ff00ff",\n gainsboro: "#dcdcdc",\n ghostwhite: "#f8f8ff",\n gold: "#ffd700",\n goldenrod: "#daa520",\n gray: "#808080",\n green: "#008000",\n greenyellow: "#adff2f",\n grey: "#808080",\n honeydew: "#f0fff0",\n hotpink: "#ff69b4",\n indianred: "#cd5c5c",\n indigo: "#4b0082",\n ivory: "#fffff0",\n khaki: "#f0e68c",\n lavender: "#e6e6fa",\n lavenderblush: "#fff0f5",\n lawngreen: "#7cfc00",\n lemonchiffon: "#fffacd",\n lightblue: "#add8e6",\n lightcoral: "#f08080",\n lightcyan: "#e0ffff",\n lightgoldenrodyellow: "#fafad2",\n lightgray: "#d3d3d3",\n lightgreen: "#90ee90",\n lightgrey: "#d3d3d3",\n lightpink: "#ffb6c1",\n lightsalmon: "#ffa07a",\n lightseagreen: "#20b2aa",\n lightskyblue: "#87cefa",\n lightslategray: "#778899",\n lightslategrey: "#778899",\n lightsteelblue: "#b0c4de",\n lightyellow: "#ffffe0",\n lime: "#00ff00",\n limegreen: "#32cd32",\n linen: "#faf0e6",\n magenta: "#ff00ff",\n maroon: "#800000",\n mediumaquamarine: "#66cdaa",\n mediumblue: "#0000cd",\n mediumorchid: "#ba55d3",\n mediumpurple: "#9370db",\n mediumseagreen: "#3cb371",\n mediumslateblue: "#7b68ee",\n mediumspringgreen: "#00fa9a",\n mediumturquoise: "#48d1cc",\n mediumvioletred: "#c71585",\n midnightblue: "#191970",\n mintcream: "#f5fffa",\n mistyrose: "#ffe4e1",\n moccasin: "#ffe4b5",\n navajowhite: "#ffdead",\n navy: "#000080",\n oldlace: "#fdf5e6",\n olive: "#808000",\n olivedrab: "#6b8e23",\n orange: "#ffa500",\n orangered: "#ff4500",\n orchid: "#da70d6",\n palegoldenrod: "#eee8aa",\n palegreen: "#98fb98",\n paleturquoise: "#afeeee",\n palevioletred: "#db7093",\n papayawhip: "#ffefd5",\n peachpuff: "#ffdab9",\n peru: "#cd853f",\n pink: "#ffc0cb",\n plum: "#dda0dd",\n powderblue: "#b0e0e6",\n purple: "#800080",\n rebeccapurple: "#663399",\n red: "#ff0000",\n rosybrown: "#bc8f8f",\n royalblue: "#4169e1",\n saddlebrown: "#8b4513",\n salmon: "#fa8072",\n sandybrown: "#f4a460",\n seagreen: "#2e8b57",\n seashell: "#fff5ee",\n sienna: "#a0522d",\n silver: "#c0c0c0",\n skyblue: "#87ceeb",\n slateblue: "#6a5acd",\n slategray: "#708090",\n slategrey: "#708090",\n snow: "#fffafa",\n springgreen: "#00ff7f",\n steelblue: "#4682b4",\n tan: "#d2b48c",\n teal: "#008080",\n thistle: "#d8bfd8",\n tomato: "#ff6347",\n turquoise: "#40e0d0",\n violet: "#ee82ee",\n wheat: "#f5deb3",\n white: "#ffffff",\n whitesmoke: "#f5f5f5",\n yellow: "#ffff00",\n yellowgreen: "#9acd32",\n};\n\nfunction parse_colour ( String x ) {\n let text := lc( trim(x) );\n\n if ( text ~ /^#[0-9a-f]{6}$/ ) {\n return text;\n }\n\n let short := text ~ /^#([0-9a-f])([0-9a-f])([0-9a-f])$/;\n if ( short ) {\n return "#"\n _ short[1] _ short[1]\n _ short[2] _ short[2]\n _ short[3] _ short[3];\n }\n\n if ( _COLOUR_KEYWORDS.exists(text) ) {\n return _COLOUR_KEYWORDS.get(text);\n }\n\n die `Invalid colour: ${x}`;\n}\n';
39661
40636
  virtualFiles["/modules/std/result.zzm"] = "=encoding utf8\n\n=head1 NAME\n\nstd/result - A simple Result object for explicit success and failure values.\n\n=head1 SYNOPSIS\n\n from std/result import Result;\n\n let r := Result.ok(42);\n\n if ( r.is_ok() ) {\n say r.unwrap();\n }\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nC<Result> is a small, subclassable object modelled on a simplified version\nof Rust's C<Result> concept. It is useful when a function, task, or worker\nwants to return an explicit success or failure value without throwing an\nexception.\n\nIt is a normal ZuzuScript class. Workers do not require C<Result>; any value\nsupported by C<std/marshal> may be returned.\n\n=head1 EXPORTS\n\n=head2 Classes\n\n=over\n\n=item C<Result>\n\nContainer for either an ok value or an error value.\n\n=over\n\n=item C<< Result.ok(value) >>\n\nParameters: C<value> is any success value. Returns: C<Result>. Creates an\nok result wrapping C<value>.\n\n=item C<< Result.err(error) >>\n\nParameters: C<error> is any error value. Returns: C<Result>. Creates an\nerror result wrapping C<error>.\n\n=item C<< result.is_ok() >>\n\nParameters: none. Returns: C<Boolean>. Returns true when the result is an\nok value.\n\n=item C<< result.is_err() >>\n\nParameters: none. Returns: C<Boolean>. Returns true when the result is an\nerror value.\n\n=item C<< result.value() >>\n\nParameters: none. Returns: value. Returns the stored ok value, or\nC<null> for an error result.\n\n=item C<< result.error() >>\n\nParameters: none. Returns: value. Returns the stored error value, or\nC<null> for an ok result.\n\n=item C<< result.unwrap() >>\n\nParameters: none. Returns: value. Returns the ok value, or throws if the\nresult is an error.\n\n=item C<< result.unwrap_err() >>\n\nParameters: none. Returns: value. Returns the error value, or throws if\nthe result is ok.\n\n=back\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/result >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nclass Result {\n let Boolean _is_ok := true;\n let _value := null;\n let _error := null;\n\n static method ok ( value ) {\n return new self(\n _is_ok: true,\n _value: value,\n _error: null,\n );\n }\n\n static method err ( error ) {\n return new self(\n _is_ok: false,\n _value: null,\n _error: error,\n );\n }\n\n method is_ok () {\n return _is_ok;\n }\n\n method is_err () {\n return not _is_ok;\n }\n\n method value () {\n return _value;\n }\n\n method error () {\n return _error;\n }\n\n method unwrap () {\n if ( _is_ok ) {\n return _value;\n }\n\n die `called Result.unwrap() on an err value: ${_error}`;\n }\n\n method unwrap_err () {\n if ( not _is_ok ) {\n return _error;\n }\n\n die `called Result.unwrap_err() on an ok value: ${_value}`;\n }\n}\n";
39662
40637
  virtualFiles["/modules/std/string/quoted_printable.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/string/quoted_printable - Quoted-printable encoders and decoders.\n\n=head1 SYNOPSIS\n\n from std/string/quoted_printable import encode, decode;\n\n let raw := to_binary( "Hello, world!\\r\\n" );\n\n let text := encode(raw);\n let bytes := decode(text);\n\n let binary_text := encode(raw, binary: true);\n let short_lines := encode(raw, line_length: 40, newline: "\\n");\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by all implementations of ZuzuScript.\n\n=head1 DESCRIPTION\n\nThis module provides quoted-printable encoding and decoding helpers for\nRFC 2045-style byte transport. Encoding returns ASCII C<String> text.\nDecoding returns a C<BinaryString>, because quoted-printable is a byte\ntransfer encoding rather than a Unicode text format.\n\nThe C<binary> option controls how input line break bytes are encoded.\nIn the default non-binary mode, CRLF, CR, and LF bytes are normalized to\nthe configured C<newline> string. In binary mode, CR and LF bytes are\nencoded as C<=0D> and C<=0A>.\n\n=head1 EXPORTS\n\n=head2 Functions\n\n=over\n\n=item * C<encode(BinaryString bytes, ... PairList options)>\n\nParameters: C<bytes> is binary input data and C<options> controls\nencoding. Returns: C<String>. Encodes C<bytes> as quoted-printable ASCII\ntext.\n\n=item * C<decode(String text, ... PairList options)>\n\nParameters: C<text> is quoted-printable text and C<options> controls\nstrictness. Returns: C<BinaryString>. Decodes quoted-printable text into\nbytes.\n\n=back\n\n=head1 OPTIONS\n\n=over\n\n=item * C<line_length>\n\nMaximum encoded line length. Defaults to C<76> and must be at least\nC<4>.\n\n=item * C<newline>\n\nOutput newline for hard line breaks and encoded soft breaks. Defaults\nto CRLF.\n\n=item * C<binary>\n\nWhen true, encode CR and LF bytes as C<=0D> and C<=0A>. Defaults to\nfalse.\n\n=item * C<strict>\n\nWhen true, malformed quoted-printable escape sequences throw during\ndecoding. Non-strict decoding preserves malformed escape text\nliterally.\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/string/quoted_printable >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\n\nlet encode := null;\nlet decode := null;\n\n{\n from std/string import chr, index, ord, substr;\n from std/string/base64 import\n encode as _base64_encode,\n decode as _base64_decode;\n\n let _B64_ALPHABET := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"\n _ "abcdefghijklmnopqrstuvwxyz0123456789+/";\n let _HEX := "0123456789ABCDEF";\n\n function _div_floor ( Number n, Number d ) {\n return floor( n / d );\n }\n\n function _mod ( Number n, Number d ) {\n return n - _div_floor( n, d ) * d;\n }\n\n function _bytes_to_binary ( Array bytes ) {\n let out := "";\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b0 := bytes[i];\n let b1 := null;\n let b2 := null;\n if ( i + 1 < n ) {\n b1 := bytes[i + 1];\n }\n if ( i + 2 < n ) {\n b2 := bytes[i + 2];\n }\n\n let c0 := _div_floor( b0, 4 );\n let c1 := _mod( b0, 4 ) * 16;\n let c2 := 64;\n let c3 := 64;\n\n if ( not( b1 == null ) ) {\n c1 += _div_floor( b1, 16 );\n c2 := _mod( b1, 16 ) * 4;\n if ( not( b2 == null ) ) {\n c2 += _div_floor( b2, 64 );\n c3 := _mod( b2, 64 );\n }\n }\n\n out _= substr( _B64_ALPHABET, c0, 1 );\n out _= substr( _B64_ALPHABET, c1, 1 );\n out _= c2 == 64 ? "=" : substr( _B64_ALPHABET, c2, 1 );\n out _= c3 == 64 ? "=" : substr( _B64_ALPHABET, c3, 1 );\n i += 3;\n }\n\n return _base64_decode(out);\n }\n\n function _binary_to_bytes ( BinaryString raw ) {\n let b64 := _base64_encode(raw);\n let out := [];\n let i := 0;\n let n := length b64;\n\n while ( i < n ) {\n let c0 := index( _B64_ALPHABET, substr( b64, i, 1 ) );\n let c1 := index( _B64_ALPHABET, substr( b64, i + 1, 1 ) );\n let ch2 := substr( b64, i + 2, 1 );\n let ch3 := substr( b64, i + 3, 1 );\n let c2 := -1;\n let c3 := -1;\n if ( ch2 ne "=" ) {\n c2 := index( _B64_ALPHABET, ch2 );\n }\n if ( ch3 ne "=" ) {\n c3 := index( _B64_ALPHABET, ch3 );\n }\n\n out.push( c0 * 4 + _div_floor( c1, 16 ) );\n if ( c2 >= 0 ) {\n out.push( _mod( c1, 16 ) * 16 + _div_floor( c2, 4 ) );\n }\n if ( c3 >= 0 ) {\n out.push( _mod( c2, 4 ) * 64 + c3 );\n }\n\n i += 4;\n }\n\n return out;\n }\n\n function _parse_options ( PairList options ) {\n let line_length := 76;\n let newline := "\\r\\n";\n let binary := false;\n let strict := false;\n\n for ( let option in options.enumerate() ) {\n let key := option.key;\n let value := option.value;\n\n if ( key eq "line_length" ) {\n line_length := value;\n }\n else if ( key eq "newline" ) {\n newline := value;\n }\n else if ( key eq "binary" ) {\n binary := value;\n }\n else if ( key eq "strict" ) {\n strict := value;\n }\n else {\n die `quoted_printable option \'${key}\' is not supported`;\n }\n }\n\n if ( not( line_length instanceof Number ) ) {\n die "quoted_printable line_length option expects Number";\n }\n if ( line_length < 4 ) {\n die "quoted_printable line_length option must be at least 4";\n }\n if ( not( newline instanceof String ) ) {\n die "quoted_printable newline option expects String";\n }\n if ( not( binary instanceof Boolean ) ) {\n die "quoted_printable binary option expects Boolean";\n }\n if ( not( strict instanceof Boolean ) ) {\n die "quoted_printable strict option expects Boolean";\n }\n\n return {\n line_length: int(line_length),\n newline: newline,\n binary: binary,\n strict: strict,\n };\n }\n\n function _is_safe_literal ( Number b ) {\n return ( b >= 33 and b <= 60 ) or ( b >= 62 and b <= 126 );\n }\n\n function _byte_to_hex_token ( Number b ) {\n return "="\n _ substr( _HEX, _div_floor( b, 16 ), 1 )\n _ substr( _HEX, _mod( b, 16 ), 1 );\n }\n\n function _simple_token_length ( Number b, Boolean final_byte ) {\n if ( ( b == 9 or b == 32 ) and not final_byte ) {\n return 1;\n }\n if ( _is_safe_literal(b) ) {\n return 1;\n }\n return 3;\n }\n\n function _space_tab_needs_escape (\n Array bytes,\n Number i,\n Number column,\n Number line_length,\n ) {\n let n := bytes.length();\n if ( i + 1 >= n ) {\n return true;\n }\n\n let j := i + 1;\n while ( j < n and ( bytes[j] == 9 or bytes[j] == 32 ) ) {\n j++;\n }\n if ( j >= n ) {\n return true;\n }\n\n let next_is_final := i + 2 >= n;\n let next_len := _simple_token_length( bytes[i + 1], next_is_final );\n let max := next_is_final ? line_length : line_length - 1;\n return column + 1 + next_len > max;\n }\n\n function _token_for_byte (\n Array bytes,\n Number i,\n Number column,\n Number line_length,\n ) {\n let b := bytes[i];\n\n if ( b == 9 or b == 32 ) {\n if ( _space_tab_needs_escape( bytes, i, column, line_length ) ) {\n return _byte_to_hex_token(b);\n }\n return chr(b);\n }\n\n if ( _is_safe_literal(b) ) {\n return chr(b);\n }\n\n return _byte_to_hex_token(b);\n }\n\n function _emit_token (\n String out,\n Number column,\n String token,\n Boolean more_after,\n Number line_length,\n String newline,\n ) {\n let max := more_after ? line_length - 1 : line_length;\n let updated_out := out;\n let updated_column := column;\n\n if ( updated_column > 0 and updated_column + ( length token ) > max ) {\n updated_out _= "=" _ newline;\n updated_column := 0;\n }\n\n updated_out _= token;\n updated_column += length token;\n\n return [ updated_out, updated_column ];\n }\n\n function _encode_segment (\n Array bytes,\n Number line_length,\n String newline,\n ) {\n let out := "";\n let column := 0;\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let token := _token_for_byte( bytes, i, column, line_length );\n let emitted := _emit_token(\n out,\n column,\n token,\n i + 1 < n,\n line_length,\n newline,\n );\n out := emitted[0];\n column := emitted[1];\n i++;\n }\n\n return out;\n }\n\n function _encode_text_bytes (\n Array bytes,\n Number line_length,\n String newline,\n ) {\n let out := "";\n let line := [];\n let i := 0;\n let n := bytes.length();\n\n while ( i < n ) {\n let b := bytes[i];\n if ( b == 13 or b == 10 ) {\n out _= _encode_segment( line, line_length, newline );\n out _= newline;\n line := [];\n\n if ( b == 13 and i + 1 < n and bytes[i + 1] == 10 ) {\n i++;\n }\n }\n else {\n line.push(b);\n }\n\n i++;\n }\n\n out _= _encode_segment( line, line_length, newline );\n return out;\n }\n\n function _hex_value ( String ch ) {\n let cp := ord(ch);\n if ( cp >= 48 and cp <= 57 ) {\n return cp - 48;\n }\n if ( cp >= 65 and cp <= 70 ) {\n return cp - 55;\n }\n if ( cp >= 97 and cp <= 102 ) {\n return cp - 87;\n }\n return -1;\n }\n\n function _decode_text_bytes ( String text, Boolean strict ) {\n let out := [];\n let i := 0;\n let n := length text;\n\n while ( i < n ) {\n let ch := substr( text, i, 1 );\n let cp := ord( text, i );\n\n if ( cp > 127 ) {\n die "quoted_printable.decode rejects non-ASCII input";\n }\n\n if ( ch eq "=" ) {\n if ( i + 1 >= n ) {\n die "malformed quoted-printable escape" if strict;\n out.push(61);\n i++;\n next;\n }\n\n let ch1 := substr( text, i + 1, 1 );\n if ( ch1 eq "\\r" ) {\n if ( i + 2 < n and substr( text, i + 2, 1 ) eq "\\n" ) {\n i += 3;\n }\n else {\n i += 2;\n }\n next;\n }\n if ( ch1 eq "\\n" ) {\n i += 2;\n next;\n }\n\n if ( i + 2 < n ) {\n let hi := _hex_value(ch1);\n let lo := _hex_value( substr( text, i + 2, 1 ) );\n if ( hi >= 0 and lo >= 0 ) {\n out.push( hi * 16 + lo );\n i += 3;\n next;\n }\n }\n\n die "malformed quoted-printable escape" if strict;\n out.push(61);\n i++;\n next;\n }\n\n out.push(cp);\n i++;\n }\n\n return out;\n }\n\n encode := function ( BinaryString bytes, ... PairList options ) {\n let opts := _parse_options(options);\n let raw := _binary_to_bytes(bytes);\n\n if ( opts{binary} ) {\n return _encode_segment(\n raw,\n opts{line_length},\n opts{newline},\n );\n }\n\n return _encode_text_bytes(\n raw,\n opts{line_length},\n opts{newline},\n );\n };\n\n decode := function ( String text, ... PairList options ) {\n let opts := _parse_options(options);\n return _bytes_to_binary( _decode_text_bytes( text, opts{strict} ) );\n };\n}\n';
39663
40638
  virtualFiles["/modules/std/gui.zzm"] = '=encoding utf8\n\n=head1 NAME\n\nstd/gui - User-facing GUI constructor helpers.\n\n=head1 SYNOPSIS\n\n from std/gui import *;\n\n let w := Window(\n title: "Demo",\n VBox(\n Label( text: "Name:" ),\n Input( id: "name" ),\n Button( text: "OK", id: "submit" ),\n ),\n );\n\n=head1 IMPLEMENTATION SUPPORT\n\nThis module is supported by zuzu.pl, zuzu-rust, and zuzu-js on Electron.\nIt is not supported by zuzu-js on Node. It is partially supported by\nzuzu-js in the browser: core GUI and widget lifecycle coverage passes,\nbut filesystem-backed file and directory dialogue coverage is unsupported.\n\n=head1 DESCRIPTION\n\nThis module provides thin constructor helpers over C<std/gui/objects>.\nHost runtimes expose the shared widget, object tree, event, and window\nlifecycle APIs when GUI support is available. It also re-exports\nbackend-native file and directory dialogue hooks for C<std/gui/dialogue>.\n\nThe module exports C<EM>, the standard UI font height in logical\npixels, derived from C<std/gui/objects> metadata.\n\n=head1 EXPORTS\n\n=head2 Constants\n\n=over\n\n=item C<EM>\n\nType: C<Number>. Standard UI font height in logical pixels.\n\n=item C<GUI_XML_NS>\n\nType: C<String>. XML namespace URI used by GUI XML serialization and\nparsing.\n\n=back\n\n=head2 Functions\n\n=over\n\n=item C<< Window(... PairList p, Array c) >>, C<< VBox(... PairList p, Array c) >>, C<< HBox(... PairList p, Array c) >>, C<< Frame(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs window and layout widgets.\n\n=item C<< Label(... PairList p, Array c) >>, C<< Text(... PairList p, Array c) >>, C<< RichText(... PairList p, Array c) >>, C<< Image(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs content widgets.\n\n=item C<< Input(... PairList p, Array c) >>, C<< DatePicker(... PairList p, Array c) >>, C<< Checkbox(... PairList p, Array c) >>, C<< Radio(... PairList p, Array c) >>, C<< RadioGroup(... PairList p, Array c) >>, C<< Select(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs input widgets.\n\n=item C<< Menu(... PairList p, Array c) >>, C<< MenuItem(... PairList p, Array c) >>, C<< Button(... PairList p, Array c) >>, C<< Separator(... PairList p, Array c) >>, C<< Slider(... PairList p, Array c) >>, C<< Progress(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs command and control widgets.\n\n=item C<< Tabs(... PairList p, Array c) >>, C<< Tab(... PairList p, Array c) >>, C<< ListView(... PairList p, Array c) >>, C<< TreeView(... PairList p, Array c) >>\n\nParameters: C<p> are widget properties and C<c> contains child widgets.\nReturns: widget object. Constructs tabular and collection widgets.\n\n=item C<< unbind(BindingToken token) >>\n\nParameters: C<token> is a binding token. Returns: C<null>. Removes a GUI\nbinding.\n\n=item C<< gui_from_xml(String xml) >>, C<< gui_from_xml_file(path) >>\n\nParameters: C<xml> is GUI XML text and C<path> is a file path. Returns:\nwidget object. Builds a GUI object tree from XML.\n\n=item C<< gui_to_xml(Widget root) >>\n\nParameters: C<root> is a GUI widget. Returns: C<String>. Serializes a\nGUI object tree to XML.\n\n=back\n\n=head2 Classes\n\n=over\n\n=item C<BindingToken>\n\nRepresents a model/widget binding.\n\n=over\n\n=item C<< token.is_active() >>\n\nParameters: none. Returns: C<Boolean>. Returns true while the binding is\nactive.\n\n=item C<< token.set_listener(token) >>\n\nParameters: C<token> is a listener token. Returns: C<BindingToken>.\nStores the listener token associated with the binding.\n\n=item C<< token.sync_model_to_widget() >>, C<< token.sync_widget_to_model() >>\n\nParameters: none. Returns: C<null>. Synchronizes the bound values.\n\n=item C<< token.unbind() >>\n\nParameters: none. Returns: C<null>. Removes the binding.\n\n=back\n\n=back\n\n=head1 COPYRIGHT AND LICENCE\n\nB<< std/gui >> is copyright Toby Inkster.\n\nIt is free software; you may redistribute it and/or modify it under\nthe terms of either the Artistic License 1.0 or the GNU General Public\nLicense version 2.\n\n=cut\n\nfrom std/gui/objects import\n Window as _WindowClass,\n VBox as _VBoxClass,\n HBox as _HBoxClass,\n Frame as _FrameClass,\n Label as _LabelClass,\n Text as _TextClass,\n RichText as _RichTextClass,\n Image as _ImageClass,\n Input as _InputClass,\n DatePicker as _DatePickerClass,\n Checkbox as _CheckboxClass,\n Radio as _RadioClass,\n RadioGroup as _RadioGroupClass,\n Select as _SelectClass,\n Menu as _MenuClass,\n MenuItem as _MenuItemClass,\n Button as _ButtonClass,\n Separator as _SeparatorClass,\n Slider as _SliderClass,\n Progress as _ProgressClass,\n Tabs as _TabsClass,\n Tab as _TabClass,\n ListView as _ListViewClass,\n TreeView as _TreeViewClass,\n Widget,\n Event,\n ListenerToken,\n native_file_open,\n native_file_save,\n native_directory_open,\n native_directory_save,\n native_colour_picker,\n meta as _gui_meta;\n\nfrom std/gui/objects try import\n native_alert,\n native_confirm,\n native_prompt;\n\nfrom std/data/xml import XML;\nfrom std/data/xml/escape import escape_xml;\nfrom std/internals import getupperprop;\nfrom std/path/zz import ZZPath;\nfrom std/string import join, split, substr, trim;\n\n\nconst Number EM := _gui_meta{font_size_pixels};\n\nfunction _assert_known_props ( String ctor, PairList props, Array allowed ) {\n let geometry := [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ];\n for ( let key in props.keys() ) {\n if ( key \u2209 allowed and key \u2209 geometry ) {\n die `GUI_PROP_UNKNOWN: ${ctor} does not accept property \'${key}\'`;\n }\n }\n}\n\nfunction _assert_prop_value ( String ctor, String prop, value, Array allowed ) {\n if ( value \u2209 allowed ) {\n die `GUI_PROP_TYPE: ${ctor} property \'${prop}\' has invalid value`;\n }\n}\n\nfunction _assert_prop_array ( String ctor, String prop, value ) {\n if ( not( value instanceof Array ) ) {\n die `GUI_PROP_TYPE: ${ctor} property \'${prop}\' expects Array`;\n }\n}\n\nfunction _with_geometry_props ( Array allowed ) {\n for ( let key in [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ] ) {\n allowed.push(key) unless key \u2208 allowed;\n }\n return allowed;\n}\n\nfunction _apply_geometry ( Widget widget, PairList p ) {\n for ( let key in [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ] ) {\n if ( p.has(key) ) {\n widget.(key)( p.get(key) );\n }\n }\n return widget;\n}\n\nfunction Window ( ... PairList p, Array c ) {\n _assert_known_props(\n "Window",\n p,\n _with_geometry_props( [\n "id",\n "title",\n "width",\n "height",\n "resizable",\n "modal",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n return new _WindowClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n width: p.get( "width", 800 ),\n height: p.get( "height", 600 ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n resizable: p.get( "resizable", true ),\n modal: p.get( "modal", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction VBox ( ... PairList p, Array c ) {\n _assert_known_props(\n "VBox",\n p,\n [\n "id",\n "align",\n "gap",\n "padding",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "VBox",\n "align",\n p.get( "align", "top" ),\n [ "top", "centre", "bottom", "stretch" ],\n );\n\n return _apply_geometry( new _VBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "top" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction HBox ( ... PairList p, Array c ) {\n _assert_known_props(\n "HBox",\n p,\n _with_geometry_props( [\n "id",\n "align",\n "gap",\n "padding",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n _assert_prop_value(\n "HBox",\n "align",\n p.get( "align", "left" ),\n [ "left", "centre", "right", "stretch" ],\n );\n\n return new _HBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "left" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n width: p.get( "width", null ),\n height: p.get( "height", null ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction Frame ( ... PairList p, Array c ) {\n _assert_known_props(\n "Frame",\n p,\n [\n "id",\n "label",\n "collapsible",\n "collapsed",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _FrameClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n collapsible: p.get( "collapsible", false ),\n collapsed: p.get( "collapsed", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Label ( ... PairList p, Array c ) {\n _assert_known_props(\n "Label",\n p,\n [ "id", "text", "for", "visible", "enabled", "disabled" ],\n );\n\n let label := new _LabelClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n if ( p.has("for") ) {\n label.set_for_id( p.get( "for", null ) );\n }\n\n return _apply_geometry( label, p );\n}\n\nfunction Text ( ... PairList p, Array c ) {\n _assert_known_props(\n "Text",\n p,\n [\n "id",\n "value",\n "multiline",\n "readonly",\n "wrap",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _TextClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n wrap: p.get( "wrap", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction RichText ( ... PairList p, Array c ) {\n _assert_known_props(\n "RichText",\n p,\n [\n "id",\n "value",\n "multiline",\n "readonly",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RichTextClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", true ),\n readonly: p.get( "readonly", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Image ( ... PairList p, Array c ) {\n _assert_known_props(\n "Image",\n p,\n [ "id", "src", "alt", "fit", "visible", "enabled", "disabled" ],\n );\n\n _assert_prop_value(\n "Image",\n "fit",\n p.get( "fit", "none" ),\n [ "none", "contain", "cover", "stretch" ],\n );\n\n return _apply_geometry( new _ImageClass(\n id: p.get( "id", null ),\n src: p.get( "src", "" ),\n alt: p.get( "alt", "" ),\n fit: p.get( "fit", "none" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Input ( ... PairList p, Array c ) {\n _assert_known_props(\n "Input",\n p,\n [\n "id",\n "value",\n "placeholder",\n "multiline",\n "readonly",\n "password",\n "required",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _InputClass(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n placeholder: p.get( "placeholder", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n password: p.get( "password", false ),\n required: p.get( "required", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction DatePicker ( ... PairList p, Array c ) {\n _assert_known_props(\n "DatePicker",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "first_day_of_week",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _DatePickerClass(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n min: p.get( "min", null ),\n max: p.get( "max", null ),\n first_day_of_week: p.get( "first_day_of_week", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Checkbox ( ... PairList p, Array c ) {\n _assert_known_props(\n "Checkbox",\n p,\n [\n "id",\n "label",\n "checked",\n "indeterminate",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _CheckboxClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n checked: p.get( "checked", false ),\n indeterminate: p.get( "indeterminate", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Radio ( ... PairList p, Array c ) {\n _assert_known_props(\n "Radio",\n p,\n [\n "id",\n "label",\n "value",\n "group",\n "checked",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RadioClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n value: p.get( "value", "" ),\n group: p.get( "group", null ),\n checked: p.get( "checked", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction RadioGroup ( ... PairList p, Array c ) {\n _assert_known_props(\n "RadioGroup",\n p,\n [\n "id",\n "name",\n "value",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _RadioGroupClass(\n id: p.get( "id", null ),\n name: p.get( "name", "" ),\n value: p.get( "value", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Select ( ... PairList p, Array c ) {\n _assert_known_props(\n "Select",\n p,\n [\n "id",\n "value",\n "options",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("options") ) {\n _assert_prop_array( "Select", "options", p.get("options") );\n }\n\n return _apply_geometry( new _SelectClass(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n options: p.get( "options", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Menu ( ... PairList p, Array c ) {\n _assert_known_props(\n "Menu",\n p,\n [ "id", "text", "visible", "enabled", "disabled" ],\n );\n\n return _apply_geometry( new _MenuClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction MenuItem ( ... PairList p, Array c ) {\n _assert_known_props(\n "MenuItem",\n p,\n [ "id", "text", "disabled", "visible", "enabled" ],\n );\n\n return _apply_geometry( new _MenuItemClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Button ( ... PairList p, Array c ) {\n _assert_known_props(\n "Button",\n p,\n _with_geometry_props( [\n "id",\n "text",\n "variant",\n "visible",\n "enabled",\n "disabled",\n ] ),\n );\n\n _assert_prop_value(\n "Button",\n "variant",\n p.get( "variant", "default" ),\n [ "default", "primary", "danger" ],\n );\n\n return new _ButtonClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n variant: p.get( "variant", "default" ),\n width: p.get( "width", null ),\n height: p.get( "height", null ),\n minwidth: p.get( "minwidth", null ),\n minheight: p.get( "minheight", null ),\n maxwidth: p.get( "maxwidth", null ),\n maxheight: p.get( "maxheight", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n );\n}\n\nfunction Separator ( ... PairList p, Array c ) {\n _assert_known_props(\n "Separator",\n p,\n [ "id", "orientation", "visible", "enabled", "disabled" ],\n );\n\n _assert_prop_value(\n "Separator",\n "orientation",\n p.get( "orientation", "horizontal" ),\n [ "horizontal", "vertical" ],\n );\n\n return _apply_geometry( new _SeparatorClass(\n id: p.get( "id", null ),\n orientation: p.get( "orientation", "horizontal" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Slider ( ... PairList p, Array c ) {\n _assert_known_props(\n "Slider",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "step",\n "orientation",\n "readonly",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "Slider",\n "orientation",\n p.get( "orientation", "horizontal" ),\n [ "horizontal", "vertical" ],\n );\n\n return _apply_geometry( new _SliderClass(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n step: p.get( "step", 1 ),\n orientation: p.get( "orientation", "horizontal" ),\n readonly: p.get( "readonly", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Progress ( ... PairList p, Array c ) {\n _assert_known_props(\n "Progress",\n p,\n [\n "id",\n "value",\n "min",\n "max",\n "indeterminate",\n "show_text",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _ProgressClass(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n indeterminate: p.get( "indeterminate", false ),\n show_text: p.get( "show_text", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Tabs ( ... PairList p, Array c ) {\n _assert_known_props(\n "Tabs",\n p,\n [\n "id",\n "selected",\n "placement",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n _assert_prop_value(\n "Tabs",\n "placement",\n p.get( "placement", "top" ),\n [ "top", "bottom", "left", "right" ],\n );\n\n return _apply_geometry( new _TabsClass(\n id: p.get( "id", null ),\n selected: p.get( "selected", null ),\n placement: p.get( "placement", "top" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction Tab ( ... PairList p, Array c ) {\n _assert_known_props(\n "Tab",\n p,\n [\n "id",\n "title",\n "value",\n "selected",\n "closable",\n "icon",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n return _apply_geometry( new _TabClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n value: p.get( "value", "" ),\n selected: p.get( "selected", false ),\n closable: p.get( "closable", false ),\n icon: p.get( "icon", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction ListView ( ... PairList p, Array c ) {\n _assert_known_props(\n "ListView",\n p,\n [\n "id",\n "items",\n "selected_index",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("items") ) {\n _assert_prop_array( "ListView", "items", p.get("items") );\n }\n\n return _apply_geometry( new _ListViewClass(\n id: p.get( "id", null ),\n items: p.get( "items", [] ),\n selected_index: p.get( "selected_index", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction TreeView ( ... PairList p, Array c ) {\n _assert_known_props(\n "TreeView",\n p,\n [\n "id",\n "items",\n "selected_path",\n "multiple",\n "visible",\n "enabled",\n "disabled",\n ],\n );\n\n if ( p.has("items") ) {\n _assert_prop_array( "TreeView", "items", p.get("items") );\n }\n if ( p.has("selected_path") ) {\n _assert_prop_array( "TreeView", "selected_path", p.get("selected_path") );\n }\n\n return _apply_geometry( new _TreeViewClass(\n id: p.get( "id", null ),\n items: p.get( "items", [] ),\n selected_path: p.get( "selected_path", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: c,\n ), p );\n}\n\nfunction _binding_path_class ( path_class ) {\n if ( path_class \u2261 null ) {\n return ZZPath;\n }\n if ( not( path_class instanceof Class ) ) {\n die "GUI_BIND_PATH: paths special property must be Class or null";\n }\n return path_class;\n}\n\nfunction _binding_compile_path ( String path_text, path_class ) {\n if ( path_class \u2261 null ) {\n try {\n return new ZZPath( path: path_text );\n }\n catch ( Exception e ) {\n die `GUI_BIND_PATH: ${e{message}}`;\n }\n }\n\n let path_type := _binding_path_class(path_class);\n try {\n return new path_type( path: path_text );\n }\n catch ( Exception e ) {\n die `GUI_BIND_PATH: ${e{message}}`;\n }\n}\n\nfunction _binding_path ( pathish, path_class ) {\n if ( pathish instanceof String ) {\n return _binding_compile_path( pathish, path_class );\n }\n if (\n pathish can first\n and ( pathish can assign_first or pathish can ref_first )\n ) {\n return pathish;\n }\n\n die "GUI_BIND_PATH: binding path must be String or path-like Object";\n}\n\nfunction _binding_get ( model, path ) {\n return path.first( model, null );\n}\n\nfunction _binding_set ( model, path, value ) {\n if ( path can assign_first ) {\n return path.assign_first( model, value );\n }\n\n let ref := path.ref_first(model);\n return ref(value);\n}\n\nclass BindingToken {\n let Widget widget but weak;\n let String widget_prop;\n let model;\n let model_path;\n let String event := "change";\n let listener := null;\n let Boolean _active := true;\n\n method is_active () {\n return _active;\n }\n\n method set_listener ( token ) {\n listener := token;\n return self;\n }\n\n method sync_model_to_widget () {\n widget.(widget_prop)( _binding_get( model, model_path ) );\n return self;\n }\n\n method sync_widget_to_model () {\n _binding_set( model, model_path, widget.(widget_prop)() );\n return self;\n }\n\n method unbind () {\n if ( _active and listener \u2262 null ) {\n widget.off(listener);\n }\n _active := false;\n return self;\n }\n}\n\nfunction bind (\n Widget widget,\n String widget_prop,\n model,\n model_path,\n ... PairList p\n) {\n let path := _binding_path( model_path, getupperprop( 1, "paths" ) );\n\n let token := new BindingToken(\n widget: widget,\n widget_prop: widget_prop,\n model: model,\n model_path: path,\n event: p.get( "event", "change" ),\n );\n let event_name := p.get( "event", "change" );\n\n switch ( p.get( "initial", "model" ): eq ) {\n case "model":\n token.sync_model_to_widget();\n case "widget":\n token.sync_widget_to_model();\n case "none":\n // No initial sync.\n default:\n die "GUI_BIND_INITIAL: initial must be model, widget, or none";\n }\n\n token.set_listener(\n widget.on( event_name, function () {\n if ( token.is_active() ) {\n token.sync_widget_to_model();\n }\n } ),\n );\n return token;\n}\n\nfunction unbind ( BindingToken token ) {\n return token.unbind();\n}\n\nlet GUI_XML_NS := "https://zuzulang.org/ns/std/gui";\n\nfunction _xml_error ( String code, String message ) {\n die `${code}: ${message}`;\n}\n\nfunction _xml_tag_name ( node ) {\n return node.localName() ?: node.nodeName();\n}\n\nfunction _xml_assert_namespace ( node ) {\n let ns := node.namespaceURI();\n if ( ns \u2262 null and ns \u2262 "" and ns \u2262 GUI_XML_NS ) {\n _xml_error(\n "GUI_XML_STRUCTURE",\n `unsupported GUI XML namespace \'${ns}\'`,\n );\n }\n}\n\nfunction _xml_common_allowed ( Array extra ) {\n let out := [\n "id",\n "visible",\n "enabled",\n "disabled",\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n ];\n for ( let attr in extra ) {\n out.push(attr);\n }\n return out;\n}\n\nfunction _xml_allowed_attrs ( String tag ) {\n switch ( tag: eq ) {\n case "Window":\n return _xml_common_allowed(\n [ "title", "width", "height", "resizable", "modal" ],\n );\n case "VBox", "HBox":\n return _xml_common_allowed( [ "align", "gap", "padding" ] );\n case "Frame":\n return _xml_common_allowed( [ "label", "collapsible", "collapsed" ] );\n case "Label":\n return _xml_common_allowed( [ "text", "for" ] );\n case "Text":\n return _xml_common_allowed(\n [ "value", "multiline", "readonly", "wrap" ],\n );\n case "RichText":\n return _xml_common_allowed(\n [ "value", "multiline", "readonly" ],\n );\n case "Image":\n return _xml_common_allowed( [ "src", "alt", "fit" ] );\n case "Input":\n return _xml_common_allowed( [\n "value",\n "placeholder",\n "multiline",\n "readonly",\n "password",\n "required",\n ] );\n case "DatePicker":\n return _xml_common_allowed(\n [ "value", "min", "max", "first_day_of_week" ],\n );\n case "Checkbox":\n return _xml_common_allowed( [ "label", "checked", "indeterminate" ] );\n case "Radio":\n return _xml_common_allowed( [ "label", "value", "group", "checked" ] );\n case "RadioGroup":\n return _xml_common_allowed( [ "name", "value" ] );\n case "Select":\n return _xml_common_allowed( [ "value", "multiple" ] );\n case "Menu":\n return _xml_common_allowed( [ "text" ] );\n case "MenuItem":\n return _xml_common_allowed( [ "text" ] );\n case "Button":\n return _xml_common_allowed( [ "text", "variant" ] );\n case "Separator":\n return _xml_common_allowed( [ "orientation" ] );\n case "Slider":\n return _xml_common_allowed( [\n "value",\n "min",\n "max",\n "step",\n "orientation",\n "readonly",\n ] );\n case "Progress":\n return _xml_common_allowed( [\n "value",\n "min",\n "max",\n "indeterminate",\n "show_text",\n ] );\n case "Tabs":\n return _xml_common_allowed( [ "selected", "placement" ] );\n case "Tab":\n return _xml_common_allowed(\n [ "title", "value", "selected", "closable", "icon" ],\n );\n case "ListView":\n return _xml_common_allowed( [ "selected_index", "multiple" ] );\n case "TreeView":\n return _xml_common_allowed( [ "selected_path", "multiple" ] );\n }\n\n _xml_error( "GUI_XML_STRUCTURE", `unsupported GUI XML element \'${tag}\'` );\n}\n\nfunction _xml_bool_attrs ( String tag ) {\n return [\n "visible",\n "enabled",\n "disabled",\n "resizable",\n "modal",\n "collapsible",\n "collapsed",\n "multiline",\n "readonly",\n "wrap",\n "password",\n "required",\n "checked",\n "indeterminate",\n "multiple",\n "show_text",\n "selected",\n "closable",\n ];\n}\n\nfunction _xml_number_attrs ( String tag ) {\n return [\n "width",\n "height",\n "minwidth",\n "minheight",\n "maxwidth",\n "maxheight",\n "gap",\n "padding",\n "first_day_of_week",\n "selected_index",\n "value",\n "min",\n "max",\n "step",\n ];\n}\n\nfunction _xml_bool ( String tag, String attr, String raw ) {\n switch ( lc(raw): eq ) {\n case "true", "1", "yes", "on": return true;\n case "false", "0", "no", "off": return false;\n }\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects a boolean XML attribute`,\n );\n}\n\nfunction _xml_number ( String tag, String attr, String raw ) {\n if ( not ( raw ~ /^-?[0-9]+(\\.[0-9]+)?$/ ) ) {\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects a numeric XML attribute`,\n );\n }\n return 0 + raw;\n}\n\nfunction _xml_int_list ( String tag, String attr, String raw ) {\n let out := [];\n return out if raw eq "";\n for ( let part in split( raw, "," ) ) {\n let item := trim(part);\n if ( not ( item ~ /^-?[0-9]+$/ ) ) {\n _xml_error(\n "GUI_XML_ATTR_TYPE",\n `${tag}.${attr} expects comma-separated integers`,\n );\n }\n out.push( 0 + item );\n }\n return out;\n}\n\nfunction _xml_coerce_attr ( String tag, String attr, String raw ) {\n if ( attr eq "selected" and tag eq "Tabs" ) {\n return raw;\n }\n if ( attr eq "value" and tag \u2209 [ "Slider", "Progress" ] ) {\n return raw;\n }\n if ( attr eq "min" and tag eq "DatePicker" ) {\n return raw;\n }\n if ( attr eq "max" and tag eq "DatePicker" ) {\n return raw;\n }\n if ( attr eq "selected_path" ) {\n return _xml_int_list( tag, attr, raw );\n }\n if ( attr \u2208 _xml_bool_attrs(tag) ) {\n return _xml_bool( tag, attr, raw );\n }\n if ( attr \u2208 _xml_number_attrs(tag) ) {\n return _xml_number( tag, attr, raw );\n }\n return raw;\n}\n\nfunction _xml_attrs ( node ) {\n let tag := _xml_tag_name(node);\n let props := {};\n let meta := {};\n let meta_keys := [];\n let style := {};\n let style_keys := [];\n let allowed := _xml_allowed_attrs(tag);\n\n for ( let attr in node.attributeNames() ) {\n next if attr eq "xmlns";\n next if substr( attr, 0, 6 ) eq "xmlns:";\n let value := node.getAttribute(attr);\n if ( substr( attr, 0, 5 ) eq "meta." ) {\n let key := substr( attr, 5 );\n _xml_error( "GUI_XML_ATTR_UNKNOWN", "empty meta attribute name" )\n if key eq "";\n meta{(key)} := value;\n meta_keys.push(key);\n next;\n }\n if ( substr( attr, 0, 6 ) eq "style." ) {\n let key := substr( attr, 6 );\n _xml_error( "GUI_XML_ATTR_UNKNOWN", "empty style attribute name" )\n if key eq "";\n style{(key)} := value;\n style_keys.push(key);\n next;\n }\n if ( attr \u2209 allowed ) {\n _xml_error(\n "GUI_XML_ATTR_UNKNOWN",\n `${tag} does not accept XML attribute \'${attr}\'`,\n );\n }\n props{(attr)} := _xml_coerce_attr( tag, attr, value );\n }\n\n return {\n props: props,\n meta: meta,\n meta_keys: meta_keys,\n style: style,\n style_keys: style_keys,\n };\n}\n\nfunction _xml_apply_meta ( Widget widget, Dict meta, Array keys ) {\n for ( let key in keys ) {\n widget.meta( key, meta{(key)} );\n }\n if ( keys.length() > 0 ) {\n widget.meta( "__xml_meta_keys", keys );\n }\n return widget;\n}\n\nfunction _xml_apply_style ( Widget widget, Dict style, Array keys ) {\n for ( let key in keys ) {\n widget.style( key, style{(key)} );\n }\n if ( keys.length() > 0 ) {\n widget.meta( "__xml_style_keys", keys );\n }\n return widget;\n}\n\nfunction _xml_widget_from_node ( node ) {\n _xml_assert_namespace(node);\n\n let tag := _xml_tag_name(node);\n let child_widgets := [];\n for ( let child in node.children() ) {\n child_widgets.push( _xml_widget_from_node(child) );\n }\n let parsed := _xml_attrs(node);\n let p := parsed{props};\n let widget;\n\n switch ( tag: eq ) {\n case "Window":\n widget := new _WindowClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n width: p.get( "width", 800 ),\n height: p.get( "height", 600 ),\n resizable: p.get( "resizable", true ),\n modal: p.get( "modal", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "VBox":\n widget := new _VBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "top" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "HBox":\n widget := new _HBoxClass(\n id: p.get( "id", null ),\n align: p.get( "align", "left" ),\n gap: p.get( "gap", 0 ),\n padding: p.get( "padding", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Frame":\n widget := new _FrameClass(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n collapsible: p.get( "collapsible", false ),\n collapsed: p.get( "collapsed", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Label":\n widget := Label(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n ("for"): p.get( "for", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Text":\n widget := Text(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n wrap: p.get( "wrap", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "RichText":\n widget := RichText(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n multiline: p.get( "multiline", true ),\n readonly: p.get( "readonly", true ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Image":\n widget := Image(\n id: p.get( "id", null ),\n src: p.get( "src", "" ),\n alt: p.get( "alt", "" ),\n fit: p.get( "fit", "none" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Input":\n widget := Input(\n id: p.get( "id", null ),\n value: p.get( "value", "" ),\n placeholder: p.get( "placeholder", "" ),\n multiline: p.get( "multiline", false ),\n readonly: p.get( "readonly", false ),\n password: p.get( "password", false ),\n required: p.get( "required", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "DatePicker":\n widget := DatePicker(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n min: p.get( "min", null ),\n max: p.get( "max", null ),\n first_day_of_week: p.get( "first_day_of_week", 0 ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Checkbox":\n widget := Checkbox(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n checked: p.get( "checked", false ),\n indeterminate: p.get( "indeterminate", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Radio":\n widget := Radio(\n id: p.get( "id", null ),\n label: p.get( "label", "" ),\n value: p.get( "value", "" ),\n group: p.get( "group", null ),\n checked: p.get( "checked", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "RadioGroup":\n widget := new _RadioGroupClass(\n id: p.get( "id", null ),\n name: p.get( "name", "" ),\n value: p.get( "value", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Select":\n widget := Select(\n id: p.get( "id", null ),\n value: p.get( "value", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Menu":\n widget := new _MenuClass(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "MenuItem":\n widget := MenuItem(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Button":\n widget := Button(\n id: p.get( "id", null ),\n text: p.get( "text", "" ),\n variant: p.get( "variant", "default" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Separator":\n widget := Separator(\n id: p.get( "id", null ),\n orientation: p.get( "orientation", "horizontal" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Slider":\n widget := Slider(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n step: p.get( "step", 1 ),\n orientation: p.get( "orientation", "horizontal" ),\n readonly: p.get( "readonly", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Progress":\n widget := Progress(\n id: p.get( "id", null ),\n value: p.get( "value", 0 ),\n min: p.get( "min", 0 ),\n max: p.get( "max", 100 ),\n indeterminate: p.get( "indeterminate", false ),\n show_text: p.get( "show_text", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "Tabs":\n widget := new _TabsClass(\n id: p.get( "id", null ),\n selected: p.get( "selected", null ),\n placement: p.get( "placement", "top" ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "Tab":\n widget := new _TabClass(\n id: p.get( "id", null ),\n title: p.get( "title", "" ),\n value: p.get( "value", "" ),\n selected: p.get( "selected", false ),\n closable: p.get( "closable", false ),\n icon: p.get( "icon", null ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n children: child_widgets,\n );\n case "ListView":\n widget := ListView(\n id: p.get( "id", null ),\n selected_index: p.get( "selected_index", null ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n case "TreeView":\n widget := TreeView(\n id: p.get( "id", null ),\n selected_path: p.get( "selected_path", [] ),\n multiple: p.get( "multiple", false ),\n visible: p.get( "visible", true ),\n enabled: p.get( "enabled", true ),\n disabled: p.get( "disabled", false ),\n );\n default:\n _xml_error(\n "GUI_XML_STRUCTURE",\n `unsupported GUI XML element \'${tag}\'`,\n );\n }\n\n _xml_apply_meta( widget, parsed{meta}, parsed{meta_keys} );\n return _xml_apply_style( widget, parsed{style}, parsed{style_keys} );\n}\n\nfunction gui_from_xml ( String xml ) {\n return _xml_widget_from_node( XML.parse(xml).documentElement() );\n}\n\nfunction gui_from_xml_file ( path ) {\n die "XML.load is denied by runtime policy" if __system__{deny_fs};\n from std/io import Path;\n let file := path instanceof Path ? path : new Path(path);\n return _xml_widget_from_node( XML.load(file).documentElement() );\n}\n\nfunction _xml_tag_for_widget ( Widget widget ) {\n if ( widget instanceof _WindowClass ) { return "Window"; }\n if ( widget instanceof _VBoxClass ) { return "VBox"; }\n if ( widget instanceof _HBoxClass ) { return "HBox"; }\n if ( widget instanceof _FrameClass ) { return "Frame"; }\n if ( widget instanceof _LabelClass ) { return "Label"; }\n if ( widget instanceof _TextClass ) { return "Text"; }\n if ( widget instanceof _RichTextClass ) { return "RichText"; }\n if ( widget instanceof _ImageClass ) { return "Image"; }\n if ( widget instanceof _InputClass ) { return "Input"; }\n if ( widget instanceof _DatePickerClass ) { return "DatePicker"; }\n if ( widget instanceof _CheckboxClass ) { return "Checkbox"; }\n if ( widget instanceof _RadioClass ) { return "Radio"; }\n if ( widget instanceof _RadioGroupClass ) { return "RadioGroup"; }\n if ( widget instanceof _SelectClass ) { return "Select"; }\n if ( widget instanceof _MenuClass ) { return "Menu"; }\n if ( widget instanceof _MenuItemClass ) { return "MenuItem"; }\n if ( widget instanceof _ButtonClass ) { return "Button"; }\n if ( widget instanceof _SeparatorClass ) { return "Separator"; }\n if ( widget instanceof _SliderClass ) { return "Slider"; }\n if ( widget instanceof _ProgressClass ) { return "Progress"; }\n if ( widget instanceof _TabsClass ) { return "Tabs"; }\n if ( widget instanceof _TabClass ) { return "Tab"; }\n if ( widget instanceof _ListViewClass ) { return "ListView"; }\n if ( widget instanceof _TreeViewClass ) { return "TreeView"; }\n _xml_error( "GUI_XML_STRUCTURE", "unsupported widget for gui_to_xml" );\n}\n\nfunction _xml_attr ( String name, value ) {\n return "" if value \u2261 null;\n return ` ${name}="${escape_xml(value)}"`;\n}\n\nfunction _xml_attr_if ( String name, value, fallback ) {\n return "" if value \u2261 fallback;\n return _xml_attr( name, value );\n}\n\nfunction _xml_bool_attr_if ( String name, value, fallback ) {\n let normalized := value ? true : false;\n let normalized_fallback := fallback ? true : false;\n return "" if normalized \u2261 normalized_fallback;\n return _xml_attr( name, normalized ? "true" : "false" );\n}\n\nfunction _xml_attr_nonempty ( String name, value ) {\n return "" if value \u2261 null or value eq "";\n return _xml_attr( name, value );\n}\n\nfunction _xml_join_ints ( Array values ) {\n let out := [];\n for ( let value in values ) {\n out.push( "" _ value );\n }\n return join( ",", out );\n}\n\nfunction _xml_meta_attrs ( Widget widget ) {\n let keys := widget.meta( "__xml_meta_keys" ) ?: [];\n let out := "";\n for ( let key in keys ) {\n out _= _xml_attr( "meta." _ key, widget.meta(key) );\n }\n return out;\n}\n\nfunction _xml_style_attrs ( Widget widget ) {\n let keys := widget.meta( "__xml_style_keys" ) ?: [];\n let out := "";\n for ( let key in keys ) {\n out _= _xml_attr( "style." _ key, widget.style(key) );\n }\n return out;\n}\n\nfunction _xml_common_attrs ( Widget widget ) {\n let out := "";\n out _= _xml_attr( "id", widget.id() ) if widget.id() \u2262 null;\n out _= _xml_bool_attr_if( "visible", widget.visible(), true );\n out _= _xml_bool_attr_if( "disabled", not widget.enabled(), false );\n out _= _xml_meta_attrs(widget);\n out _= _xml_style_attrs(widget);\n return out;\n}\n\nfunction _xml_widget_attrs ( Widget widget ) {\n let out := _xml_common_attrs(widget);\n if ( widget instanceof _WindowClass ) {\n out _= _xml_attr_if( "title", widget.title(), "" );\n }\n else if ( widget instanceof _VBoxClass or widget instanceof _HBoxClass ) {\n let default_align := widget instanceof _VBoxClass ? "top" : "left";\n out _= _xml_attr_if( "align", widget.align(), default_align );\n out _= _xml_attr_if( "gap", widget.gap(), 0 );\n out _= _xml_attr_if( "padding", widget.padding(), 0 )\n unless widget.padding() instanceof Array;\n }\n else if ( widget instanceof _FrameClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_bool_attr_if( "collapsible", widget.collapsible(), false );\n out _= _xml_bool_attr_if( "collapsed", widget.collapsed(), false );\n }\n else if ( widget instanceof _LabelClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n out _= _xml_attr_nonempty( "for", widget.for_id() );\n }\n else if ( widget instanceof _TextClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), false );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n out _= _xml_bool_attr_if( "wrap", widget.wrap(), true );\n }\n else if ( widget instanceof _RichTextClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), true );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), true );\n }\n else if ( widget instanceof _ImageClass ) {\n out _= _xml_attr_if( "src", widget.src(), "" );\n out _= _xml_attr_if( "alt", widget.alt(), "" );\n out _= _xml_attr_if( "fit", widget.fit(), "none" );\n }\n else if ( widget instanceof _InputClass ) {\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr_if( "placeholder", widget.placeholder(), "" );\n out _= _xml_bool_attr_if( "multiline", widget.multiline(), false );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n out _= _xml_bool_attr_if( "password", widget.password(), false );\n out _= _xml_bool_attr_if( "required", widget.required(), false );\n }\n else if ( widget instanceof _DatePickerClass ) {\n out _= _xml_attr( "value", widget.value() );\n out _= _xml_attr( "min", widget.min() ) if widget.min() \u2262 null;\n out _= _xml_attr( "max", widget.max() ) if widget.max() \u2262 null;\n out _= _xml_attr_if(\n "first_day_of_week",\n widget.first_day_of_week(),\n 0,\n );\n }\n else if ( widget instanceof _CheckboxClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_bool_attr_if( "checked", widget.checked(), false );\n out _= _xml_bool_attr_if( "indeterminate", widget.indeterminate(), false );\n }\n else if ( widget instanceof _RadioClass ) {\n out _= _xml_attr_if( "label", widget.label(), "" );\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr_nonempty( "group", widget.group() );\n out _= _xml_bool_attr_if( "checked", widget.checked(), false );\n }\n else if ( widget instanceof _RadioGroupClass ) {\n out _= _xml_attr_if( "name", widget.name(), "" );\n out _= _xml_attr( "value", widget.value() ) if widget.value() \u2262 null;\n }\n else if ( widget instanceof _SelectClass ) {\n out _= _xml_attr( "value", widget.value() ) if widget.value() \u2262 null;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n else if ( widget instanceof _MenuClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n }\n else if ( widget instanceof _MenuItemClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n }\n else if ( widget instanceof _ButtonClass ) {\n out _= _xml_attr_if( "text", widget.text(), "" );\n out _= _xml_attr_if( "variant", widget.variant(), "default" );\n }\n else if ( widget instanceof _SeparatorClass ) {\n out _= _xml_attr_if( "orientation", widget.orientation(), "horizontal" );\n }\n else if ( widget instanceof _SliderClass ) {\n out _= _xml_attr_if( "value", widget.value(), 0 );\n out _= _xml_attr_if( "min", widget.min(), 0 );\n out _= _xml_attr_if( "max", widget.max(), 100 );\n out _= _xml_attr_if( "step", widget.step(), 1 );\n out _= _xml_attr_if( "orientation", widget.orientation(), "horizontal" );\n out _= _xml_bool_attr_if( "readonly", widget.readonly(), false );\n }\n else if ( widget instanceof _ProgressClass ) {\n out _= _xml_attr_if( "value", widget.value(), 0 );\n out _= _xml_attr_if( "min", widget.min(), 0 );\n out _= _xml_attr_if( "max", widget.max(), 100 );\n out _= _xml_bool_attr_if( "indeterminate", widget.indeterminate(), false );\n out _= _xml_bool_attr_if( "show_text", widget.show_text(), false );\n }\n else if ( widget instanceof _TabsClass ) {\n out _= _xml_attr( "selected", widget.selected() )\n if widget.selected() \u2262 null;\n out _= _xml_attr_if( "placement", widget.placement(), "top" );\n }\n else if ( widget instanceof _TabClass ) {\n out _= _xml_attr_if( "title", widget.title(), "" );\n out _= _xml_attr_if( "value", widget.value(), "" );\n out _= _xml_attr( "icon", widget.icon() ) if widget.icon() \u2262 null;\n out _= _xml_bool_attr_if( "selected", widget.selected(), false );\n out _= _xml_bool_attr_if( "closable", widget.closable(), false );\n }\n else if ( widget instanceof _ListViewClass ) {\n out _= _xml_attr( "selected_index", widget.selected_index() )\n if widget.selected_index() \u2262 null;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n else if ( widget instanceof _TreeViewClass ) {\n let selected_path := widget.selected_path();\n out _= _xml_attr( "selected_path", _xml_join_ints(selected_path) )\n if selected_path.length() > 0;\n out _= _xml_bool_attr_if( "multiple", widget.multiple(), false );\n }\n return out;\n}\n\nfunction _xml_serialize_widget ( Widget widget, Number depth ) {\n let indent := "";\n let i := 0;\n while ( i < depth ) {\n indent _= "\\t";\n i++;\n }\n\n let tag := _xml_tag_for_widget(widget);\n let attrs := _xml_widget_attrs(widget);\n attrs _= _xml_attr( "xmlns", GUI_XML_NS ) if depth = 0;\n let children := widget.children();\n if ( children.length() = 0 ) {\n return indent _ "<" _ tag _ attrs _ " />";\n }\n\n let parts := [];\n for ( let child in children ) {\n parts.push( _xml_serialize_widget( child, depth + 1 ) );\n }\n\n return indent _ "<" _ tag _ attrs _ ">\\n"\n _ join( "\\n", parts )\n _ "\\n" _ indent _ "</" _ tag _ ">";\n}\n\nfunction gui_to_xml ( Widget root ) {\n return _xml_serialize_widget( root, 0 ) _ "\\n";\n}\n';
@@ -45866,7 +46841,7 @@ class ZZTemplate extends ZTemplate {
45866
46841
  }
45867
46842
  });
45868
46843
 
45869
- // ../../../../../tmp/zuzu-browser-build.mbIbiI/browser-worker-entry.generated.js
46844
+ // ../../../../../tmp/zuzu-browser-build.fADF4k/browser-worker-entry.generated.js
45870
46845
  var { createBrowserStdlib } = require_browser_stdlib_generated();
45871
46846
  globalThis.__ZUZU_BROWSER_DEFAULT_RUNTIME_OPTIONS__ = createBrowserStdlib();
45872
46847
  var { installBrowserWorker } = require_browser_worker_entry();