@hypen-space/core 0.4.5 → 0.4.12

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.
Files changed (50) hide show
  1. package/dist/app.js +171 -171
  2. package/dist/app.js.map +4 -4
  3. package/dist/components/builtin.js +171 -171
  4. package/dist/components/builtin.js.map +4 -4
  5. package/dist/context.js +1 -1
  6. package/dist/context.js.map +1 -1
  7. package/dist/discovery.js +171 -171
  8. package/dist/discovery.js.map +4 -4
  9. package/dist/disposable.js +1 -1
  10. package/dist/disposable.js.map +1 -1
  11. package/dist/engine.browser.js +119 -229
  12. package/dist/engine.browser.js.map +2 -2
  13. package/dist/engine.js +1 -1
  14. package/dist/engine.js.map +1 -1
  15. package/dist/events.js +1 -1
  16. package/dist/events.js.map +1 -1
  17. package/dist/index.browser.js +158 -367
  18. package/dist/index.browser.js.map +5 -6
  19. package/dist/index.js +171 -171
  20. package/dist/index.js.map +4 -4
  21. package/dist/loader.js +1 -1
  22. package/dist/loader.js.map +1 -1
  23. package/dist/logger.js +245 -0
  24. package/dist/logger.js.map +10 -0
  25. package/dist/plugin.js +1 -1
  26. package/dist/plugin.js.map +1 -1
  27. package/dist/remote/client.js +1 -1
  28. package/dist/remote/client.js.map +1 -1
  29. package/dist/remote/index.js +171 -171
  30. package/dist/remote/index.js.map +4 -4
  31. package/dist/remote/server.js +171 -171
  32. package/dist/remote/server.js.map +4 -4
  33. package/dist/renderer.js +1 -1
  34. package/dist/renderer.js.map +1 -1
  35. package/dist/router.js +1 -1
  36. package/dist/router.js.map +1 -1
  37. package/dist/types.d.ts +1 -1
  38. package/dist/types.js +2 -0
  39. package/dist/types.js.map +9 -0
  40. package/package.json +1 -1
  41. package/src/types.ts +1 -1
  42. package/wasm-browser/hypen_engine.d.ts +3 -3
  43. package/wasm-browser/hypen_engine.js +73 -66
  44. package/wasm-browser/hypen_engine_bg.wasm +0 -0
  45. package/wasm-browser/hypen_engine_bg.wasm.d.ts +3 -3
  46. package/wasm-browser/package.json +1 -1
  47. package/wasm-node/hypen_engine.js +74 -66
  48. package/wasm-node/hypen_engine_bg.wasm +0 -0
  49. package/wasm-node/hypen_engine_bg.wasm.d.ts +3 -3
  50. package/wasm-node/package.json +1 -1
@@ -1,33 +1,99 @@
1
- import { createRequire } from "node:module";
2
- var __create = Object.create;
3
- var __getProtoOf = Object.getPrototypeOf;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __hasOwnProp = Object.prototype.hasOwnProperty;
7
- var __toESM = (mod, isNodeMode, target) => {
8
- target = mod != null ? __create(__getProtoOf(mod)) : {};
9
- const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
- for (let key of __getOwnPropNames(mod))
11
- if (!__hasOwnProp.call(to, key))
12
- __defProp(to, key, {
13
- get: () => mod[key],
14
- enumerable: true
15
- });
16
- return to;
17
- };
18
- var __export = (target, all) => {
19
- for (var name in all)
20
- __defProp(target, name, {
21
- get: all[name],
22
- enumerable: true,
23
- configurable: true,
24
- set: (newValue) => all[name] = () => newValue
1
+ // src/result.ts
2
+ function Ok(value) {
3
+ return { ok: true, value };
4
+ }
5
+ function Err(error) {
6
+ return { ok: false, error };
7
+ }
8
+ class HypenError extends Error {
9
+ code;
10
+ context;
11
+ cause;
12
+ constructor(code, message, options) {
13
+ super(message);
14
+ this.name = "HypenError";
15
+ this.code = code;
16
+ this.context = options?.context;
17
+ this.cause = options?.cause;
18
+ Object.setPrototypeOf(this, new.target.prototype);
19
+ }
20
+ }
21
+
22
+ class ActionError extends HypenError {
23
+ actionName;
24
+ constructor(actionName, cause) {
25
+ super("ACTION_ERROR", `Action handler "${actionName}" failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
26
+ context: { actionName },
27
+ cause: cause instanceof Error ? cause : undefined
25
28
  });
26
- };
27
- var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
28
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
29
+ this.name = "ActionError";
30
+ this.actionName = actionName;
31
+ }
32
+ }
33
+
34
+ class ConnectionError extends HypenError {
35
+ url;
36
+ attempt;
37
+ constructor(url, cause, attempt) {
38
+ super("CONNECTION_ERROR", `Connection to "${url}" failed${attempt ? ` (attempt ${attempt})` : ""}: ${cause instanceof Error ? cause.message : String(cause)}`, {
39
+ context: { url, attempt },
40
+ cause: cause instanceof Error ? cause : undefined
41
+ });
42
+ this.name = "ConnectionError";
43
+ this.url = url;
44
+ this.attempt = attempt;
45
+ }
46
+ }
47
+
48
+ class StateError extends HypenError {
49
+ path;
50
+ constructor(message, path, cause) {
51
+ super("STATE_ERROR", message, {
52
+ context: { path },
53
+ cause: cause instanceof Error ? cause : undefined
54
+ });
55
+ this.name = "StateError";
56
+ this.path = path;
57
+ }
58
+ }
59
+
60
+ class ParseError extends HypenError {
61
+ source;
62
+ constructor(message, source, cause) {
63
+ super("PARSE_ERROR", message, {
64
+ context: { source },
65
+ cause: cause instanceof Error ? cause : undefined
66
+ });
67
+ this.name = "ParseError";
68
+ this.source = source;
69
+ }
70
+ }
71
+
72
+ class RenderError extends HypenError {
73
+ constructor(message, cause) {
74
+ super("RENDER_ERROR", message, {
75
+ cause: cause instanceof Error ? cause : undefined
76
+ });
77
+ this.name = "RenderError";
78
+ }
79
+ }
80
+ function classifyEngineError(err) {
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ if (message.startsWith("Parse error:")) {
83
+ return new ParseError(message);
84
+ }
85
+ if (message.startsWith("Invalid state:") || message.startsWith("Invalid state patch:")) {
86
+ return new StateError(message);
87
+ }
88
+ if (message.startsWith("Parent node not found:")) {
89
+ return new RenderError(message);
90
+ }
91
+ return new RenderError(message);
92
+ }
29
93
 
30
94
  // src/state.ts
95
+ var IS_PROXY = Symbol.for("hypen.isProxy");
96
+ var RAW_TARGET = Symbol.for("hypen.rawTarget");
31
97
  function deepClone(obj) {
32
98
  if (obj === null || typeof obj !== "object") {
33
99
  return obj;
@@ -260,198 +326,33 @@ function getStateSnapshot(state) {
260
326
  }
261
327
  return deepClone(state);
262
328
  }
263
- function isStateProxy(value) {
264
- return value !== null && typeof value === "object" && value[IS_PROXY] === true;
265
- }
266
- function unwrapProxy(value) {
267
- if (value !== null && typeof value === "object" && value[IS_PROXY]) {
268
- return value[RAW_TARGET];
269
- }
270
- return value;
271
- }
272
- var IS_PROXY, RAW_TARGET;
273
- var init_state = __esm(() => {
274
- IS_PROXY = Symbol.for("hypen.isProxy");
275
- RAW_TARGET = Symbol.for("hypen.rawTarget");
276
- });
277
-
278
- // src/result.ts
279
- function Ok(value) {
280
- return { ok: true, value };
281
- }
282
- function Err(error) {
283
- return { ok: false, error };
284
- }
285
- function isOk(result) {
286
- return result.ok;
287
- }
288
- function isErr(result) {
289
- return !result.ok;
290
- }
291
- async function fromPromise(promise, mapError) {
292
- try {
293
- const value = await promise;
294
- return Ok(value);
295
- } catch (e) {
296
- if (mapError) {
297
- return Err(mapError(e));
298
- }
299
- return Err(e);
300
- }
301
- }
302
- function fromTry(fn, mapError) {
303
- try {
304
- return Ok(fn());
305
- } catch (e) {
306
- if (mapError) {
307
- return Err(mapError(e));
308
- }
309
- return Err(e);
310
- }
311
- }
312
- function map(result, fn) {
313
- if (result.ok) {
314
- return Ok(fn(result.value));
315
- }
316
- return result;
317
- }
318
- function mapErr(result, fn) {
319
- if (!result.ok) {
320
- return Err(fn(result.error));
321
- }
322
- return result;
323
- }
324
- function flatMap(result, fn) {
325
- if (result.ok) {
326
- return fn(result.value);
327
- }
328
- return result;
329
- }
330
- function unwrap(result) {
331
- if (result.ok) {
332
- return result.value;
333
- }
334
- throw result.error;
335
- }
336
- function unwrapOr(result, defaultValue) {
337
- if (result.ok) {
338
- return result.value;
339
- }
340
- return defaultValue;
341
- }
342
- function unwrapOrElse(result, fn) {
343
- if (result.ok) {
344
- return result.value;
345
- }
346
- return fn(result.error);
347
- }
348
- function match(result, handlers) {
349
- if (result.ok) {
350
- return handlers.ok(result.value);
351
- }
352
- return handlers.err(result.error);
353
- }
354
- function all(results) {
355
- const values = [];
356
- for (const result of results) {
357
- if (!result.ok) {
358
- return result;
359
- }
360
- values.push(result.value);
361
- }
362
- return Ok(values);
363
- }
364
- function classifyEngineError(err) {
365
- const message = err instanceof Error ? err.message : String(err);
366
- if (message.startsWith("Parse error:")) {
367
- return new ParseError(message);
368
- }
369
- if (message.startsWith("Invalid state:") || message.startsWith("Invalid state patch:")) {
370
- return new StateError(message);
371
- }
372
- if (message.startsWith("Parent node not found:")) {
373
- return new RenderError(message);
374
- }
375
- return new RenderError(message);
376
- }
377
- var HypenError, ActionError, ConnectionError, StateError, ParseError, RenderError;
378
- var init_result = __esm(() => {
379
- HypenError = class HypenError extends Error {
380
- code;
381
- context;
382
- cause;
383
- constructor(code, message, options) {
384
- super(message);
385
- this.name = "HypenError";
386
- this.code = code;
387
- this.context = options?.context;
388
- this.cause = options?.cause;
389
- Object.setPrototypeOf(this, new.target.prototype);
390
- }
391
- };
392
- ActionError = class ActionError extends HypenError {
393
- actionName;
394
- constructor(actionName, cause) {
395
- super("ACTION_ERROR", `Action handler "${actionName}" failed: ${cause instanceof Error ? cause.message : String(cause)}`, {
396
- context: { actionName },
397
- cause: cause instanceof Error ? cause : undefined
398
- });
399
- this.name = "ActionError";
400
- this.actionName = actionName;
401
- }
402
- };
403
- ConnectionError = class ConnectionError extends HypenError {
404
- url;
405
- attempt;
406
- constructor(url, cause, attempt) {
407
- super("CONNECTION_ERROR", `Connection to "${url}" failed${attempt ? ` (attempt ${attempt})` : ""}: ${cause instanceof Error ? cause.message : String(cause)}`, {
408
- context: { url, attempt },
409
- cause: cause instanceof Error ? cause : undefined
410
- });
411
- this.name = "ConnectionError";
412
- this.url = url;
413
- this.attempt = attempt;
414
- }
415
- };
416
- StateError = class StateError extends HypenError {
417
- path;
418
- constructor(message, path, cause) {
419
- super("STATE_ERROR", message, {
420
- context: { path },
421
- cause: cause instanceof Error ? cause : undefined
422
- });
423
- this.name = "StateError";
424
- this.path = path;
425
- }
426
- };
427
- ParseError = class ParseError extends HypenError {
428
- source;
429
- constructor(message, source, cause) {
430
- super("PARSE_ERROR", message, {
431
- context: { source },
432
- cause: cause instanceof Error ? cause : undefined
433
- });
434
- this.name = "ParseError";
435
- this.source = source;
436
- }
437
- };
438
- RenderError = class RenderError extends HypenError {
439
- constructor(message, cause) {
440
- super("RENDER_ERROR", message, {
441
- cause: cause instanceof Error ? cause : undefined
442
- });
443
- this.name = "RenderError";
444
- }
445
- };
446
- });
447
329
 
448
330
  // src/logger.ts
331
+ var LOG_LEVEL_ORDER = {
332
+ debug: 0,
333
+ info: 1,
334
+ warn: 2,
335
+ error: 3,
336
+ none: 4
337
+ };
338
+ var LOG_LEVEL_COLORS = {
339
+ debug: "\x1B[36m",
340
+ info: "\x1B[32m",
341
+ warn: "\x1B[33m",
342
+ error: "\x1B[31m"
343
+ };
344
+ var RESET_COLOR = "\x1B[0m";
449
345
  function isProduction() {
450
346
  if (typeof process !== "undefined" && process.env) {
451
347
  return false;
452
348
  }
453
349
  return false;
454
350
  }
351
+ var config = {
352
+ level: isProduction() ? "error" : "debug",
353
+ colors: true,
354
+ timestamps: false
355
+ };
455
356
  function setLogLevel(level) {
456
357
  config.level = level;
457
358
  }
@@ -582,76 +483,49 @@ class Logger {
582
483
  function createLogger(tag) {
583
484
  return new Logger(tag);
584
485
  }
585
- var LOG_LEVEL_ORDER, LOG_LEVEL_COLORS, RESET_COLOR = "\x1B[0m", config, logger, log, frameworkLoggers;
586
- var init_logger = __esm(() => {
587
- LOG_LEVEL_ORDER = {
588
- debug: 0,
589
- info: 1,
590
- warn: 2,
591
- error: 3,
592
- none: 4
593
- };
594
- LOG_LEVEL_COLORS = {
595
- debug: "\x1B[36m",
596
- info: "\x1B[32m",
597
- warn: "\x1B[33m",
598
- error: "\x1B[31m"
599
- };
600
- config = {
601
- level: isProduction() ? "error" : "debug",
602
- colors: true,
603
- timestamps: false
604
- };
605
- logger = createLogger("Hypen");
606
- log = {
607
- debug: (tag, ...args) => {
608
- if (!shouldLog("debug"))
609
- return;
610
- console.log(formatTag(tag, "debug"), ...args);
611
- },
612
- info: (tag, ...args) => {
613
- if (!shouldLog("info"))
614
- return;
615
- console.info(formatTag(tag, "info"), ...args);
616
- },
617
- warn: (tag, ...args) => {
618
- if (!shouldLog("warn"))
619
- return;
620
- console.warn(formatTag(tag, "warn"), ...args);
621
- },
622
- error: (tag, ...args) => {
623
- if (!shouldLog("error"))
624
- return;
625
- console.error(formatTag(tag, "error"), ...args);
626
- }
627
- };
628
- frameworkLoggers = {
629
- hypen: createLogger("Hypen"),
630
- engine: createLogger("Engine"),
631
- router: createLogger("Router"),
632
- state: createLogger("State"),
633
- events: createLogger("Events"),
634
- remote: createLogger("Remote"),
635
- renderer: createLogger("Renderer"),
636
- module: createLogger("Module"),
637
- lifecycle: createLogger("Lifecycle"),
638
- loader: createLogger("Loader"),
639
- context: createLogger("Context"),
640
- discovery: createLogger("Discovery"),
641
- plugin: createLogger("Plugin"),
642
- canvas: createLogger("Canvas"),
643
- debug: createLogger("Debug")
644
- };
645
- });
486
+ var logger = createLogger("Hypen");
487
+ var log = {
488
+ debug: (tag, ...args) => {
489
+ if (!shouldLog("debug"))
490
+ return;
491
+ console.log(formatTag(tag, "debug"), ...args);
492
+ },
493
+ info: (tag, ...args) => {
494
+ if (!shouldLog("info"))
495
+ return;
496
+ console.info(formatTag(tag, "info"), ...args);
497
+ },
498
+ warn: (tag, ...args) => {
499
+ if (!shouldLog("warn"))
500
+ return;
501
+ console.warn(formatTag(tag, "warn"), ...args);
502
+ },
503
+ error: (tag, ...args) => {
504
+ if (!shouldLog("error"))
505
+ return;
506
+ console.error(formatTag(tag, "error"), ...args);
507
+ }
508
+ };
509
+ var frameworkLoggers = {
510
+ hypen: createLogger("Hypen"),
511
+ engine: createLogger("Engine"),
512
+ router: createLogger("Router"),
513
+ state: createLogger("State"),
514
+ events: createLogger("Events"),
515
+ remote: createLogger("Remote"),
516
+ renderer: createLogger("Renderer"),
517
+ module: createLogger("Module"),
518
+ lifecycle: createLogger("Lifecycle"),
519
+ loader: createLogger("Loader"),
520
+ context: createLogger("Context"),
521
+ discovery: createLogger("Discovery"),
522
+ plugin: createLogger("Plugin"),
523
+ canvas: createLogger("Canvas"),
524
+ debug: createLogger("Debug")
525
+ };
646
526
 
647
527
  // src/app.ts
648
- var exports_app = {};
649
- __export(exports_app, {
650
- app: () => app,
651
- HypenModuleInstance: () => HypenModuleInstance,
652
- HypenAppBuilder: () => HypenAppBuilder,
653
- HypenApp: () => HypenApp
654
- });
528
+ var log2 = createLogger("ModuleInstance");
655
529
 
656
530
  class HypenAppBuilder {
657
531
  initialState;
@@ -764,6 +638,7 @@ class HypenApp {
764
638
  this._registry.clear();
765
639
  }
766
640
  }
641
+ var app = new HypenApp;
767
642
 
768
643
  class HypenModuleInstance {
769
644
  engine;
@@ -935,17 +810,7 @@ class HypenModuleInstance {
935
810
  Object.assign(this.state, patch);
936
811
  }
937
812
  }
938
- var log2, app;
939
- var init_app = __esm(() => {
940
- init_result();
941
- init_state();
942
- init_logger();
943
- log2 = createLogger("ModuleInstance");
944
- app = new HypenApp;
945
- });
946
-
947
813
  // src/renderer.ts
948
- init_logger();
949
814
  var log3 = frameworkLoggers.renderer;
950
815
 
951
816
  class BaseRenderer {
@@ -995,10 +860,7 @@ class ConsoleRenderer {
995
860
  console.groupEnd();
996
861
  }
997
862
  }
998
-
999
863
  // src/router.ts
1000
- init_state();
1001
- init_logger();
1002
864
  var log4 = frameworkLoggers.router;
1003
865
 
1004
866
  class HypenRouter {
@@ -1147,12 +1009,12 @@ class HypenRouter {
1147
1009
  return "([^/]+)";
1148
1010
  }).replace(/\*/g, ".*");
1149
1011
  const regex = new RegExp(`^${regexPattern}$`);
1150
- const match2 = path.match(regex);
1151
- if (!match2)
1012
+ const match = path.match(regex);
1013
+ if (!match)
1152
1014
  return null;
1153
1015
  const params = {};
1154
1016
  paramNames.forEach((name, i) => {
1155
- const value = match2[i + 1];
1017
+ const value = match[i + 1];
1156
1018
  if (value !== undefined) {
1157
1019
  params[name] = decodeURIComponent(value);
1158
1020
  }
@@ -1195,9 +1057,7 @@ class HypenRouter {
1195
1057
  return `${path}?${queryString}`;
1196
1058
  }
1197
1059
  }
1198
-
1199
1060
  // src/events.ts
1200
- init_logger();
1201
1061
  var log5 = frameworkLoggers.events;
1202
1062
 
1203
1063
  class TypedEventEmitter {
@@ -1261,9 +1121,7 @@ class TypedEventEmitter {
1261
1121
  function createEventEmitter() {
1262
1122
  return new TypedEventEmitter;
1263
1123
  }
1264
-
1265
1124
  // src/context.ts
1266
- init_logger();
1267
1125
  var log6 = frameworkLoggers.context;
1268
1126
 
1269
1127
  class HypenGlobalContext {
@@ -1367,14 +1225,8 @@ class HypenGlobalContext {
1367
1225
  };
1368
1226
  }
1369
1227
  }
1370
-
1371
1228
  // src/disposable.ts
1372
- init_logger();
1373
1229
  var log7 = frameworkLoggers.lifecycle;
1374
- function isDisposable(obj) {
1375
- return obj !== null && typeof obj === "object" && "dispose" in obj && typeof obj.dispose === "function";
1376
- }
1377
-
1378
1230
  class DisposableStack {
1379
1231
  stack = [];
1380
1232
  disposed = false;
@@ -1463,17 +1315,6 @@ function getElementDisposables(element) {
1463
1315
  element[ELEMENT_DISPOSABLES] = stack;
1464
1316
  return stack;
1465
1317
  }
1466
- function disposeElement(element) {
1467
- const stack = element[ELEMENT_DISPOSABLES];
1468
- if (stack instanceof DisposableStack) {
1469
- stack.dispose();
1470
- delete element[ELEMENT_DISPOSABLES];
1471
- }
1472
- }
1473
- function hasElementDisposables(element) {
1474
- return element[ELEMENT_DISPOSABLES] instanceof DisposableStack;
1475
- }
1476
-
1477
1318
  class DisposableMixin {
1478
1319
  disposables = new DisposableStack;
1479
1320
  track(disposable) {
@@ -1486,41 +1327,8 @@ class DisposableMixin {
1486
1327
  this.disposables.dispose();
1487
1328
  }
1488
1329
  }
1489
- function compositeDisposable(...disposables) {
1490
- return {
1491
- dispose: () => {
1492
- for (const d of disposables) {
1493
- try {
1494
- d.dispose();
1495
- } catch (error) {
1496
- log7.error("Error during dispose:", error);
1497
- }
1498
- }
1499
- }
1500
- };
1501
- }
1502
- async function using(resource, fn) {
1503
- const r = typeof resource === "function" ? resource() : resource;
1504
- try {
1505
- return await fn(r);
1506
- } finally {
1507
- r.dispose();
1508
- }
1509
- }
1510
- function usingSync(resource, fn) {
1511
- const r = typeof resource === "function" ? resource() : resource;
1512
- try {
1513
- return fn(r);
1514
- } finally {
1515
- r.dispose();
1516
- }
1517
- }
1518
-
1519
- // src/remote/client.ts
1520
- init_result();
1521
1330
 
1522
1331
  // src/retry.ts
1523
- init_result();
1524
1332
  var DEFAULT_OPTIONS = {
1525
1333
  maxAttempts: 3,
1526
1334
  delayMs: 1000,
@@ -1584,17 +1392,6 @@ async function retry(fn, options = {}) {
1584
1392
  }
1585
1393
  throw lastError;
1586
1394
  }
1587
- async function retryResult(fn, options = {}) {
1588
- try {
1589
- const value = await retry(fn, options);
1590
- return Ok(value);
1591
- } catch (e) {
1592
- return Err(e instanceof Error ? e : new Error(String(e)));
1593
- }
1594
- }
1595
- function withRetry(fn, options = {}) {
1596
- return (...args) => retry(() => fn(...args), options);
1597
- }
1598
1395
  var RetryConditions = {
1599
1396
  networkErrors: (error) => {
1600
1397
  const message = error.message.toLowerCase();
@@ -1646,7 +1443,6 @@ var RetryPresets = {
1646
1443
  };
1647
1444
 
1648
1445
  // src/remote/client.ts
1649
- init_logger();
1650
1446
  var log8 = frameworkLoggers.remote;
1651
1447
 
1652
1448
  class RemoteEngine {
@@ -1892,11 +1688,6 @@ class RemoteEngine {
1892
1688
  }, this.options.reconnectInterval);
1893
1689
  }
1894
1690
  }
1895
-
1896
- // src/index.browser.ts
1897
- init_app();
1898
- init_state();
1899
- init_logger();
1900
1691
  export {
1901
1692
  setLogLevel,
1902
1693
  setDebugMode,
@@ -1934,4 +1725,4 @@ export {
1934
1725
  BaseRenderer
1935
1726
  };
1936
1727
 
1937
- //# debugId=60758C2F2D9B92CA64756E2164756E21
1728
+ //# debugId=FA72769E159DE77864756E2164756E21