@vesk/compiler 0.2.92 → 0.2.94

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.
@@ -106,7 +106,7 @@ export declare function resolveViaPackageExports(specifier: string, fromDir: str
106
106
  /** Rewrites an ESM program body (imports/exports removed) into CJS statements. */
107
107
  export declare function esmToCjs(body: Array<{
108
108
  type: string;
109
- } & Record<string, unknown>>): string;
109
+ } & Record<string, unknown>>, rewriteImports?: ReadonlySet<string>): string;
110
110
  export interface BundledModuleData {
111
111
  /** Synthetic loader key (e.g. `__veskMod0`), referenced by deps/bindings. */
112
112
  key: string;
@@ -142,6 +142,13 @@ export interface ModuleEntry {
142
142
  dir: string;
143
143
  /** Relative specifier (as written) -> sibling module key. */
144
144
  deps: Record<string, string>;
145
+ /**
146
+ * Absolute path the entry was registered under. Kept so a plan can be
147
+ * replayed into a fresh registry (see `precompile.ts`), where the module
148
+ * key is derived from this path. Never emitted into the deployment
149
+ * registry (which only serializes code/dir/deps).
150
+ */
151
+ absPath?: string;
145
152
  }
146
153
  /**
147
154
  * Global registry of bundled module source code, shared across every SSR
@@ -159,7 +166,7 @@ export declare class ModuleRegistry {
159
166
  has(absPath: string): boolean;
160
167
  getKey(absPath: string): string | undefined;
161
168
  get size(): number;
162
- /** Register a module's transpiled body, returning its globally-unique key. */
169
+ /** Register a module's transpiled body, returning its stable key. */
163
170
  register(absPath: string, entry: ModuleEntry): string;
164
171
  getModule(key: string): ModuleEntry | undefined;
165
172
  /** All registered modules as a plain object keyed by synthetic key, for
@@ -1 +1 @@
1
- {"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"module-imports.d.ts","sourceRoot":"","sources":["../src/module-imports.ts"],"names":[],"mappings":"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"}
@@ -259,12 +259,21 @@ export function loadSsrModule(absPath) {
259
259
  }
260
260
  else {
261
261
  exportsObj = {};
262
+ // Wrap exportsObj in a module object so CJS modules that do
263
+ // `module.exports = factory()` (e.g. qrcode-generator) have their
264
+ // export captured correctly. Without this, module.exports is replaced
265
+ // but exportsObj still points to the original empty object.
266
+ const moduleObj = { exports: exportsObj };
262
267
  EVALUATING.set(absPath, exportsObj);
263
- const ran = evaluateModuleFile(absPath, exportsObj, src);
268
+ const ran = evaluateModuleFile(absPath, moduleObj, src);
264
269
  // Runtime evaluation failure (already warned) — give Node's own loader
265
270
  // a chance before giving up.
266
271
  if (!ran)
267
272
  exportsObj = null;
273
+ // Prefer module.exports when a CJS module replaced it (e.g.
274
+ // qrcode-generator), otherwise fall back to exportsObj.
275
+ else if (moduleObj.exports !== exportsObj)
276
+ exportsObj = moduleObj.exports;
268
277
  }
269
278
  }
270
279
  if (exportsObj === null) {
@@ -601,7 +610,7 @@ function createLazyBarrelExports(spec, dir) {
601
610
  * `src` carries a read+parse already done by the caller (either a barrel probe
602
611
  * or a plain load) so big files aren't read/parsed twice.
603
612
  */
604
- function evaluateModuleFile(absPath, exportsObj, src) {
613
+ function evaluateModuleFile(absPath, moduleObj, src) {
605
614
  let raw;
606
615
  if (src) {
607
616
  raw = src.raw;
@@ -636,7 +645,7 @@ function evaluateModuleFile(absPath, exportsObj, src) {
636
645
  // Not parseable as ESM — run verbatim as CJS.
637
646
  try {
638
647
  const fn = new Function('require', 'module', 'exports', '__dirname', '__filename', raw);
639
- fn(createModuleRequire(dirname(absPath)), { exports: exportsObj }, exportsObj, dirname(absPath), absPath);
648
+ fn(createModuleRequire(dirname(absPath)), moduleObj, moduleObj.exports, dirname(absPath), absPath);
640
649
  }
641
650
  catch (err) {
642
651
  console.warn(`[vesk] SSR: failed to load ${absPath}: ${err?.message ?? String(err)}`);
@@ -661,7 +670,7 @@ function evaluateModuleFile(absPath, exportsObj, src) {
661
670
  // ESM modules are always strict; mirror per-spec `this === undefined`.
662
671
  try {
663
672
  const fn = new Function('require', 'module', 'exports', '__dirname', '__filename', "'use strict';\n" + body);
664
- fn(createModuleRequire(dirname(absPath)), { exports: exportsObj }, exportsObj, dirname(absPath), absPath);
673
+ fn(createModuleRequire(dirname(absPath)), moduleObj, moduleObj.exports, dirname(absPath), absPath);
665
674
  }
666
675
  catch (err) {
667
676
  console.warn(`[vesk] SSR: failed to load ${absPath}: ${err?.message ?? String(err)}`);
@@ -949,6 +958,12 @@ export function resolveImportPath(spec, fromDir) {
949
958
  const aliased = resolveAliasModule(spec, fromDir);
950
959
  if (aliased)
951
960
  return aliased;
961
+ // Bare npm specifiers (e.g. "vesk-qr") must resolve to absolute paths so
962
+ // the client-chunk bundler (esbuild from a temp dir) can find them in
963
+ // the app's node_modules via the package's exports map.
964
+ const resolved = resolveSsrModule(spec, fromDir);
965
+ if (resolved)
966
+ return isBuiltinPath(resolved) ? resolved.slice(BUILTIN_PREFIX.length) : resolved;
952
967
  }
953
968
  return spec;
954
969
  }
@@ -1161,8 +1176,13 @@ export function resolveViaPackageModuleField(specifier, fromDir) {
1161
1176
  if (statOrNull(pkgPath) !== null) {
1162
1177
  try {
1163
1178
  const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
1164
- if (typeof pkg.module === 'string' && pkg.module.length > 0) {
1165
- const found = probeFile(resolve(join(dir, 'node_modules', pkgName), pkg.module));
1179
+ const entry = typeof pkg.module === 'string' && pkg.module.length > 0
1180
+ ? pkg.module
1181
+ : typeof pkg.main === 'string' && pkg.main.length > 0
1182
+ ? pkg.main
1183
+ : null;
1184
+ if (entry) {
1185
+ const found = probeFile(resolve(join(dir, 'node_modules', pkgName), entry));
1166
1186
  if (found)
1167
1187
  return toRealPath(found);
1168
1188
  }
@@ -1325,10 +1345,82 @@ function exportGetter(lines, key, valueExpr) {
1325
1345
  lines.push(`Object.defineProperty(exports, ${JSON.stringify(key)}, { get: () => ${valueExpr}, enumerable: true });`);
1326
1346
  }
1327
1347
  let exportCounter = 0;
1348
+ /**
1349
+ * `Promise.resolve().then(() => require("<spec>"))` as an AST expression.
1350
+ * Reusing the original literal node keeps its raw quoting.
1351
+ */
1352
+ function promiseOfRequire(sourceNode) {
1353
+ return {
1354
+ type: 'CallExpression',
1355
+ optional: false,
1356
+ callee: {
1357
+ type: 'MemberExpression',
1358
+ optional: false,
1359
+ computed: false,
1360
+ object: {
1361
+ type: 'CallExpression',
1362
+ optional: false,
1363
+ callee: {
1364
+ type: 'MemberExpression',
1365
+ optional: false,
1366
+ computed: false,
1367
+ object: { type: 'Identifier', name: 'Promise' },
1368
+ property: { type: 'Identifier', name: 'resolve' },
1369
+ },
1370
+ arguments: [],
1371
+ },
1372
+ property: { type: 'Identifier', name: 'then' },
1373
+ },
1374
+ arguments: [
1375
+ {
1376
+ type: 'ArrowFunctionExpression',
1377
+ id: null,
1378
+ expression: true,
1379
+ generator: false,
1380
+ async: false,
1381
+ params: [],
1382
+ body: {
1383
+ type: 'CallExpression',
1384
+ optional: false,
1385
+ callee: { type: 'Identifier', name: 'require' },
1386
+ arguments: [sourceNode],
1387
+ },
1388
+ },
1389
+ ],
1390
+ };
1391
+ }
1392
+ /**
1393
+ * Rewrites `import("<spec>")` for specifiers the SSR module bundle resolved
1394
+ * (those present in the module's `deps`) into a promise of the same
1395
+ * `require` the static-import rewrite emits.
1396
+ *
1397
+ * Registry bodies run inside `new Function`, where a native dynamic `import()`
1398
+ * has no referrer and Node resolves it against the generated function's
1399
+ * location (`/var/task` on Vercel). That directory ships no node_modules, so
1400
+ * e.g. vesk-qr's lazy `import("qrcode-generator")` fails even though the
1401
+ * encoder is already in the bundle. Routing it through the require shim makes
1402
+ * it use `entry.deps`, exactly like a static import.
1403
+ *
1404
+ * Specifiers that were not bundled (framework-owned, `.vsk`, builtins) keep
1405
+ * their original form: the shim and the host loader know how to handle them.
1406
+ */
1407
+ function rewriteDynamicImports(node, specs) {
1408
+ return walk(node, null, {
1409
+ ImportExpression(n) {
1410
+ const spec = stringLiteralValue(n.source);
1411
+ if (!spec || !specs.has(spec))
1412
+ return;
1413
+ return promiseOfRequire(n.source);
1414
+ },
1415
+ });
1416
+ }
1328
1417
  /** Rewrites an ESM program body (imports/exports removed) into CJS statements. */
1329
- export function esmToCjs(body) {
1418
+ export function esmToCjs(body, rewriteImports) {
1419
+ const statements = rewriteImports
1420
+ ? body.map((stmt) => rewriteDynamicImports(stmt, rewriteImports))
1421
+ : body;
1330
1422
  const lines = [];
1331
- for (const stmt of body) {
1423
+ for (const stmt of statements) {
1332
1424
  switch (stmt.type) {
1333
1425
  case 'ImportDeclaration': {
1334
1426
  const source = printNode(stmt.source);
@@ -1437,6 +1529,35 @@ export function esmToCjs(body) {
1437
1529
  }
1438
1530
  return lines.join('\n');
1439
1531
  }
1532
+ /**
1533
+ * Synthetic key for a module. Derived from the absolute path rather than the
1534
+ * registry's insertion order so the SAME module always gets the same key in
1535
+ * every build. Positional keys (`__veskMod${size}`) made cross-build plan
1536
+ * caching unsafe: a second in-process build (the dev server after the prod
1537
+ * build) started with an empty registry, served cached plans whose keys
1538
+ * referred to modules it never registered, and emitted `export const
1539
+ * __veskModules = {}`. Paired with the plan cache replaying each plan's
1540
+ * modules into the fresh registry, a path-derived key makes that replay
1541
+ * idempotent and collision-free.
1542
+ */
1543
+ function moduleKeyFor(absPath) {
1544
+ // Four independent FNV-1a 32-bit lanes → 128 bits of key space, which makes
1545
+ // an accidental collision between two paths (which would silently swap one
1546
+ // module for another) effectively impossible. Hand-rolled rather than
1547
+ // `node:crypto` because this file is bundled into the edge/server runtime,
1548
+ // where a `node:` import fails to resolve.
1549
+ const seeds = [0x811c9dc5, 0x9e3779b1, 0x85ebca6b, 0xc2b2ae35];
1550
+ let hex = '';
1551
+ for (const seed of seeds) {
1552
+ let h = seed >>> 0;
1553
+ for (let i = 0; i < absPath.length; i++) {
1554
+ h ^= absPath.charCodeAt(i);
1555
+ h = Math.imul(h, 0x01000193) >>> 0;
1556
+ }
1557
+ hex += h.toString(16).padStart(8, '0');
1558
+ }
1559
+ return `__veskMod${hex}`;
1560
+ }
1440
1561
  /**
1441
1562
  * Global registry of bundled module source code, shared across every SSR
1442
1563
  * function in a single build. Without it, every page plan re-embedded the
@@ -1459,14 +1580,14 @@ export class ModuleRegistry {
1459
1580
  get size() {
1460
1581
  return this.data.size;
1461
1582
  }
1462
- /** Register a module's transpiled body, returning its globally-unique key. */
1583
+ /** Register a module's transpiled body, returning its stable key. */
1463
1584
  register(absPath, entry) {
1464
1585
  const existing = this.keysByAbs.get(absPath);
1465
1586
  if (existing)
1466
1587
  return existing;
1467
- const key = `__veskMod${this.data.size}`;
1588
+ const key = moduleKeyFor(absPath);
1468
1589
  this.keysByAbs.set(absPath, key);
1469
- this.data.set(key, entry);
1590
+ this.data.set(key, { ...entry, absPath });
1470
1591
  return key;
1471
1592
  }
1472
1593
  getModule(key) {
@@ -1486,9 +1607,6 @@ export class ModuleRegistry {
1486
1607
  return `export const __veskModules = {${parts.join(',')}};\n`;
1487
1608
  }
1488
1609
  }
1489
- function isRelativeSpec(spec) {
1490
- return spec.startsWith('./') || spec.startsWith('../');
1491
- }
1492
1610
  function stringLiteralValue(node) {
1493
1611
  const n = node;
1494
1612
  if (n && (n.type === 'Literal' || n.type === 'StringLiteral') && typeof n.value === 'string') {
@@ -1503,41 +1621,51 @@ function stringLiteralValue(node) {
1503
1621
  */
1504
1622
  function collectModuleSpecifiers(ast) {
1505
1623
  const specs = new Set();
1624
+ // Every type-specific visitor MUST call `next()`. zimmerframe only recurses
1625
+ // into a node's children when its visitor does — the default visitor is the
1626
+ // one that calls `next`. Without it, an `import()`/`require()` nested inside
1627
+ // an exported function (e.g. vesk-qr's lazy encoder load) was never seen, so
1628
+ // the module was neither bundled nor recorded in `deps`.
1506
1629
  walk(ast, null, {
1507
- ImportDeclaration(node) {
1508
- if (node.importKind === 'type')
1509
- return;
1510
- const v = stringLiteralValue(node.source);
1511
- if (v)
1512
- specs.add(v);
1630
+ ImportDeclaration(node, ctx) {
1631
+ if (node.importKind !== 'type') {
1632
+ const v = stringLiteralValue(node.source);
1633
+ if (v)
1634
+ specs.add(v);
1635
+ }
1636
+ ctx.next();
1513
1637
  },
1514
- ExportNamedDeclaration(node) {
1515
- if ((node.exportKind === 'type') || !node.source)
1516
- return;
1517
- const v = stringLiteralValue(node.source);
1518
- if (v)
1519
- specs.add(v);
1638
+ ExportNamedDeclaration(node, ctx) {
1639
+ if (node.exportKind !== 'type' && node.source) {
1640
+ const v = stringLiteralValue(node.source);
1641
+ if (v)
1642
+ specs.add(v);
1643
+ }
1644
+ ctx.next();
1520
1645
  },
1521
- ExportAllDeclaration(node) {
1522
- if (node.exportKind === 'type')
1523
- return;
1524
- const v = stringLiteralValue(node.source);
1525
- if (v)
1526
- specs.add(v);
1646
+ ExportAllDeclaration(node, ctx) {
1647
+ if (node.exportKind !== 'type') {
1648
+ const v = stringLiteralValue(node.source);
1649
+ if (v)
1650
+ specs.add(v);
1651
+ }
1652
+ ctx.next();
1527
1653
  },
1528
- CallExpression(node) {
1654
+ CallExpression(node, ctx) {
1529
1655
  const callee = node.callee;
1530
- if (!callee || callee.type !== 'Identifier' || callee.name !== 'require')
1531
- return;
1532
- const args = (node.arguments || []);
1533
- const v = stringLiteralValue(args[0]);
1534
- if (v)
1535
- specs.add(v);
1656
+ if (callee && callee.type === 'Identifier' && callee.name === 'require') {
1657
+ const args = (node.arguments || []);
1658
+ const v = stringLiteralValue(args[0]);
1659
+ if (v)
1660
+ specs.add(v);
1661
+ }
1662
+ ctx.next();
1536
1663
  },
1537
- ImportExpression(node) {
1664
+ ImportExpression(node, ctx) {
1538
1665
  const v = stringLiteralValue(node.source);
1539
1666
  if (v)
1540
1667
  specs.add(v);
1668
+ ctx.next();
1541
1669
  },
1542
1670
  });
1543
1671
  return specs;
@@ -1577,6 +1705,7 @@ export function collectModuleBundled(absPath, registry) {
1577
1705
  const cached = mtimeMs >= 0 ? bundledCodeCache.get(absPath) : undefined;
1578
1706
  let code;
1579
1707
  let specifiers;
1708
+ let deps = null;
1580
1709
  if (cached && cached.mtimeMs === mtimeMs) {
1581
1710
  code = cached.code;
1582
1711
  specifiers = cached.specifiers;
@@ -1597,20 +1726,38 @@ export function collectModuleBundled(absPath, registry) {
1597
1726
  stripped = stripTsTypes(src.ast);
1598
1727
  stripped.body = (stripped.body || []).filter((n) => (n ? !isTypeOnlyStatement(n) : false));
1599
1728
  specifiers = [...collectModuleSpecifiers(src.ast)];
1600
- code = esmToCjs(stripped.body);
1729
+ // Resolve the closure first: the emitter needs the set of specifiers that
1730
+ // became registry modules so it can route `import("<spec>")` through the
1731
+ // same require shim instead of leaving a bare dynamic import for the host
1732
+ // loader (see `rewriteDynamicImports`).
1733
+ deps = resolveBundledDeps(specifiers, dir, registry);
1734
+ code = esmToCjs(stripped.body, new Set(Object.keys(deps)));
1601
1735
  bundledCodeCache.set(absPath, { mtimeMs, code, specifiers });
1602
1736
  evict(bundledCodeCache);
1603
1737
  }
1738
+ if (!deps)
1739
+ deps = resolveBundledDeps(specifiers, dir, registry);
1740
+ return registry.register(absPath, { code, dir, deps });
1741
+ }
1742
+ /**
1743
+ * Resolves every specifier a module reaches for into the registry key of its
1744
+ * bundled closure. Compiler-owned (`@vesk/*`) targets are injected by the SSR
1745
+ * require shim at runtime (`precompile-runtime.ts`), never bundled: their built
1746
+ * JS may contain identifiers the `.vsk` grammar reserves (`component` in
1747
+ * ripple-runtime.js) and would fail to parse here. `.vsk`/`.css`/`.md` carry no
1748
+ * SSR value. Node builtins load natively through the shim.
1749
+ */
1750
+ function resolveBundledDeps(specifiers, dir, registry) {
1604
1751
  const deps = {};
1605
1752
  for (const spec of specifiers) {
1606
- if (!isRelativeSpec(spec))
1753
+ if (isCompilerOwnedTarget(spec) || isValueLessTarget(spec))
1607
1754
  continue;
1608
1755
  const depPath = resolveSsrModule(spec, dir);
1609
- if (!depPath)
1756
+ if (!depPath || isBuiltinPath(depPath))
1610
1757
  continue;
1611
1758
  deps[spec] = collectModuleBundled(depPath, registry);
1612
1759
  }
1613
- return registry.register(absPath, { code, dir, deps });
1760
+ return deps;
1614
1761
  }
1615
1762
  const bundledCodeCache = new Map();
1616
1763
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAOtC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CAmMjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAwFlE;AA2DD,wBAAgB,gBAAgB,IAAI,OAAO,KAAK,CAAC,MAAM,CAEtD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAM/D;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA6EzE"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../src/parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC;AAOtC,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,YAAY,CAAC;IACnB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,WAAW,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GAC9B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,cAAc,EAAE,CAAA;CAAE,CAmMjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAwFlE;AA2DD,wBAAgB,gBAAgB,IAAI,OAAO,KAAK,CAAC,MAAM,CAEtD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CAM/D;AAED,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CA+NzE"}