@scanly/core 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +3 -0
  2. package/dist/barcode/contracts.d.ts +44 -0
  3. package/dist/barcode/contracts.d.ts.map +1 -0
  4. package/dist/barcode/contracts.js +33 -0
  5. package/dist/barcode/contracts.js.map +1 -0
  6. package/dist/barcode/format-selection.d.ts +12 -0
  7. package/dist/barcode/format-selection.d.ts.map +1 -0
  8. package/dist/barcode/format-selection.js +32 -0
  9. package/dist/barcode/format-selection.js.map +1 -0
  10. package/dist/barcode/format.d.ts +7 -0
  11. package/dist/barcode/format.d.ts.map +1 -0
  12. package/dist/barcode/format.js +20 -0
  13. package/dist/barcode/format.js.map +1 -0
  14. package/dist/barcode/index.d.ts +5 -0
  15. package/dist/barcode/index.d.ts.map +1 -0
  16. package/dist/barcode/index.js +5 -0
  17. package/dist/barcode/index.js.map +1 -0
  18. package/dist/barcode/retail.d.ts +16 -0
  19. package/dist/barcode/retail.d.ts.map +1 -0
  20. package/dist/barcode/retail.js +95 -0
  21. package/dist/barcode/retail.js.map +1 -0
  22. package/dist/contracts/engine.d.ts +84 -0
  23. package/dist/contracts/engine.d.ts.map +1 -0
  24. package/dist/contracts/engine.js +2 -0
  25. package/dist/contracts/engine.js.map +1 -0
  26. package/dist/contracts/errors.d.ts +17 -0
  27. package/dist/contracts/errors.d.ts.map +1 -0
  28. package/dist/contracts/errors.js +31 -0
  29. package/dist/contracts/errors.js.map +1 -0
  30. package/dist/contracts/frame.d.ts +37 -0
  31. package/dist/contracts/frame.d.ts.map +1 -0
  32. package/dist/contracts/frame.js +77 -0
  33. package/dist/contracts/frame.js.map +1 -0
  34. package/dist/contracts/operator.d.ts +46 -0
  35. package/dist/contracts/operator.d.ts.map +1 -0
  36. package/dist/contracts/operator.js +14 -0
  37. package/dist/contracts/operator.js.map +1 -0
  38. package/dist/contracts/result.d.ts +135 -0
  39. package/dist/contracts/result.d.ts.map +1 -0
  40. package/dist/contracts/result.js +2 -0
  41. package/dist/contracts/result.js.map +1 -0
  42. package/dist/contracts/validator.d.ts +15 -0
  43. package/dist/contracts/validator.d.ts.map +1 -0
  44. package/dist/contracts/validator.js +2 -0
  45. package/dist/contracts/validator.js.map +1 -0
  46. package/dist/index.d.ts +29 -0
  47. package/dist/index.d.ts.map +1 -0
  48. package/dist/index.js +28 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/industrial/candidate-region.d.ts +15 -0
  51. package/dist/industrial/candidate-region.d.ts.map +1 -0
  52. package/dist/industrial/candidate-region.js +108 -0
  53. package/dist/industrial/candidate-region.js.map +1 -0
  54. package/dist/industrial/coordinate-transform.d.ts +9 -0
  55. package/dist/industrial/coordinate-transform.d.ts.map +1 -0
  56. package/dist/industrial/coordinate-transform.js +42 -0
  57. package/dist/industrial/coordinate-transform.js.map +1 -0
  58. package/dist/industrial/decode-candidate-conflict.d.ts +8 -0
  59. package/dist/industrial/decode-candidate-conflict.d.ts.map +1 -0
  60. package/dist/industrial/decode-candidate-conflict.js +97 -0
  61. package/dist/industrial/decode-candidate-conflict.js.map +1 -0
  62. package/dist/industrial/difficulty-diagnosis.d.ts +15 -0
  63. package/dist/industrial/difficulty-diagnosis.d.ts.map +1 -0
  64. package/dist/industrial/difficulty-diagnosis.js +291 -0
  65. package/dist/industrial/difficulty-diagnosis.js.map +1 -0
  66. package/dist/industrial/index.d.ts +13 -0
  67. package/dist/industrial/index.d.ts.map +1 -0
  68. package/dist/industrial/index.js +13 -0
  69. package/dist/industrial/index.js.map +1 -0
  70. package/dist/industrial/memory.d.ts +28 -0
  71. package/dist/industrial/memory.d.ts.map +1 -0
  72. package/dist/industrial/memory.js +65 -0
  73. package/dist/industrial/memory.js.map +1 -0
  74. package/dist/industrial/pixels.d.ts +44 -0
  75. package/dist/industrial/pixels.d.ts.map +1 -0
  76. package/dist/industrial/pixels.js +295 -0
  77. package/dist/industrial/pixels.js.map +1 -0
  78. package/dist/industrial/recovery-pipeline.d.ts +26 -0
  79. package/dist/industrial/recovery-pipeline.d.ts.map +1 -0
  80. package/dist/industrial/recovery-pipeline.js +149 -0
  81. package/dist/industrial/recovery-pipeline.js.map +1 -0
  82. package/dist/industrial/recovery-planner.d.ts +10 -0
  83. package/dist/industrial/recovery-planner.d.ts.map +1 -0
  84. package/dist/industrial/recovery-planner.js +107 -0
  85. package/dist/industrial/recovery-planner.js.map +1 -0
  86. package/dist/industrial/recovery-route-registry.d.ts +12 -0
  87. package/dist/industrial/recovery-route-registry.d.ts.map +1 -0
  88. package/dist/industrial/recovery-route-registry.js +15 -0
  89. package/dist/industrial/recovery-route-registry.js.map +1 -0
  90. package/dist/industrial/recovery-routes.d.ts +89 -0
  91. package/dist/industrial/recovery-routes.d.ts.map +1 -0
  92. package/dist/industrial/recovery-routes.js +280 -0
  93. package/dist/industrial/recovery-routes.js.map +1 -0
  94. package/dist/industrial/scan-evidence.d.ts +5 -0
  95. package/dist/industrial/scan-evidence.d.ts.map +1 -0
  96. package/dist/industrial/scan-evidence.js +63 -0
  97. package/dist/industrial/scan-evidence.js.map +1 -0
  98. package/dist/industrial/scanner-diagnostics.d.ts +19 -0
  99. package/dist/industrial/scanner-diagnostics.d.ts.map +1 -0
  100. package/dist/industrial/scanner-diagnostics.js +35 -0
  101. package/dist/industrial/scanner-diagnostics.js.map +1 -0
  102. package/dist/industrial/types.d.ts +189 -0
  103. package/dist/industrial/types.d.ts.map +1 -0
  104. package/dist/industrial/types.js +2 -0
  105. package/dist/industrial/types.js.map +1 -0
  106. package/dist/node.d.ts +2 -0
  107. package/dist/node.d.ts.map +1 -0
  108. package/dist/node.js +2 -0
  109. package/dist/node.js.map +1 -0
  110. package/dist/qr/candidate-dedupe.d.ts +6 -0
  111. package/dist/qr/candidate-dedupe.d.ts.map +1 -0
  112. package/dist/qr/candidate-dedupe.js +27 -0
  113. package/dist/qr/candidate-dedupe.js.map +1 -0
  114. package/dist/qr/candidate-generation.d.ts +46 -0
  115. package/dist/qr/candidate-generation.d.ts.map +1 -0
  116. package/dist/qr/candidate-generation.js +277 -0
  117. package/dist/qr/candidate-generation.js.map +1 -0
  118. package/dist/qr/decode-pipeline.d.ts +14 -0
  119. package/dist/qr/decode-pipeline.d.ts.map +1 -0
  120. package/dist/qr/decode-pipeline.js +615 -0
  121. package/dist/qr/decode-pipeline.js.map +1 -0
  122. package/dist/qr/geometry.d.ts +24 -0
  123. package/dist/qr/geometry.d.ts.map +1 -0
  124. package/dist/qr/geometry.js +64 -0
  125. package/dist/qr/geometry.js.map +1 -0
  126. package/dist/qr/grayscale.d.ts +13 -0
  127. package/dist/qr/grayscale.d.ts.map +1 -0
  128. package/dist/qr/grayscale.js +46 -0
  129. package/dist/qr/grayscale.js.map +1 -0
  130. package/dist/qr/image-loader-node.d.ts +4 -0
  131. package/dist/qr/image-loader-node.d.ts.map +1 -0
  132. package/dist/qr/image-loader-node.js +26 -0
  133. package/dist/qr/image-loader-node.js.map +1 -0
  134. package/dist/qr/index.d.ts +15 -0
  135. package/dist/qr/index.d.ts.map +1 -0
  136. package/dist/qr/index.js +15 -0
  137. package/dist/qr/index.js.map +1 -0
  138. package/dist/qr/jsqr-decoder.d.ts +10 -0
  139. package/dist/qr/jsqr-decoder.d.ts.map +1 -0
  140. package/dist/qr/jsqr-decoder.js +18 -0
  141. package/dist/qr/jsqr-decoder.js.map +1 -0
  142. package/dist/qr/preprocess.d.ts +18 -0
  143. package/dist/qr/preprocess.d.ts.map +1 -0
  144. package/dist/qr/preprocess.js +165 -0
  145. package/dist/qr/preprocess.js.map +1 -0
  146. package/dist/qr/region-detection.d.ts +25 -0
  147. package/dist/qr/region-detection.d.ts.map +1 -0
  148. package/dist/qr/region-detection.js +129 -0
  149. package/dist/qr/region-detection.js.map +1 -0
  150. package/dist/qr/result-normalizer.d.ts +9 -0
  151. package/dist/qr/result-normalizer.d.ts.map +1 -0
  152. package/dist/qr/result-normalizer.js +70 -0
  153. package/dist/qr/result-normalizer.js.map +1 -0
  154. package/dist/qr/rotate.d.ts +5 -0
  155. package/dist/qr/rotate.d.ts.map +1 -0
  156. package/dist/qr/rotate.js +51 -0
  157. package/dist/qr/rotate.js.map +1 -0
  158. package/dist/qr/types.d.ts +186 -0
  159. package/dist/qr/types.d.ts.map +1 -0
  160. package/dist/qr/types.js +67 -0
  161. package/dist/qr/types.js.map +1 -0
  162. package/dist/qr/zxing-decoder.d.ts +8 -0
  163. package/dist/qr/zxing-decoder.d.ts.map +1 -0
  164. package/dist/qr/zxing-decoder.js +33 -0
  165. package/dist/qr/zxing-decoder.js.map +1 -0
  166. package/dist/runtime/artifacts.d.ts +16 -0
  167. package/dist/runtime/artifacts.d.ts.map +1 -0
  168. package/dist/runtime/artifacts.js +52 -0
  169. package/dist/runtime/artifacts.js.map +1 -0
  170. package/dist/runtime/builtin-operators.d.ts +12 -0
  171. package/dist/runtime/builtin-operators.d.ts.map +1 -0
  172. package/dist/runtime/builtin-operators.js +487 -0
  173. package/dist/runtime/builtin-operators.js.map +1 -0
  174. package/dist/runtime/capabilities.d.ts +32 -0
  175. package/dist/runtime/capabilities.d.ts.map +1 -0
  176. package/dist/runtime/capabilities.js +18 -0
  177. package/dist/runtime/capabilities.js.map +1 -0
  178. package/dist/runtime/engine-registry.d.ts +19 -0
  179. package/dist/runtime/engine-registry.d.ts.map +1 -0
  180. package/dist/runtime/engine-registry.js +136 -0
  181. package/dist/runtime/engine-registry.js.map +1 -0
  182. package/dist/runtime/execution-budget.d.ts +25 -0
  183. package/dist/runtime/execution-budget.d.ts.map +1 -0
  184. package/dist/runtime/execution-budget.js +41 -0
  185. package/dist/runtime/execution-budget.js.map +1 -0
  186. package/dist/runtime/frame-lease.d.ts +10 -0
  187. package/dist/runtime/frame-lease.d.ts.map +1 -0
  188. package/dist/runtime/frame-lease.js +17 -0
  189. package/dist/runtime/frame-lease.js.map +1 -0
  190. package/dist/runtime/frame-normalization.d.ts +13 -0
  191. package/dist/runtime/frame-normalization.d.ts.map +1 -0
  192. package/dist/runtime/frame-normalization.js +21 -0
  193. package/dist/runtime/frame-normalization.js.map +1 -0
  194. package/dist/runtime/memory-budget.d.ts +32 -0
  195. package/dist/runtime/memory-budget.d.ts.map +1 -0
  196. package/dist/runtime/memory-budget.js +109 -0
  197. package/dist/runtime/memory-budget.js.map +1 -0
  198. package/dist/runtime/operator-registry.d.ts +11 -0
  199. package/dist/runtime/operator-registry.d.ts.map +1 -0
  200. package/dist/runtime/operator-registry.js +19 -0
  201. package/dist/runtime/operator-registry.js.map +1 -0
  202. package/dist/runtime/result-policies.d.ts +21 -0
  203. package/dist/runtime/result-policies.d.ts.map +1 -0
  204. package/dist/runtime/result-policies.js +62 -0
  205. package/dist/runtime/result-policies.js.map +1 -0
  206. package/dist/runtime/router.d.ts +45 -0
  207. package/dist/runtime/router.d.ts.map +1 -0
  208. package/dist/runtime/router.js +202 -0
  209. package/dist/runtime/router.js.map +1 -0
  210. package/dist/runtime/scenario-compiler.d.ts +32 -0
  211. package/dist/runtime/scenario-compiler.d.ts.map +1 -0
  212. package/dist/runtime/scenario-compiler.js +131 -0
  213. package/dist/runtime/scenario-compiler.js.map +1 -0
  214. package/dist/runtime/scenario-runtime.d.ts +4 -0
  215. package/dist/runtime/scenario-runtime.d.ts.map +1 -0
  216. package/dist/runtime/scenario-runtime.js +32 -0
  217. package/dist/runtime/scenario-runtime.js.map +1 -0
  218. package/dist/runtime/session.d.ts +40 -0
  219. package/dist/runtime/session.d.ts.map +1 -0
  220. package/dist/runtime/session.js +117 -0
  221. package/dist/runtime/session.js.map +1 -0
  222. package/dist/runtime/validator-registry.d.ts +11 -0
  223. package/dist/runtime/validator-registry.d.ts.map +1 -0
  224. package/dist/runtime/validator-registry.js +16 -0
  225. package/dist/runtime/validator-registry.js.map +1 -0
  226. package/package.json +39 -0
@@ -0,0 +1,129 @@
1
+ const PADDING_RATIOS = {
2
+ tight: 0.05,
3
+ medium: 0.12,
4
+ expanded: 0.22,
5
+ };
6
+ /** Clamp a rectangle to image bounds. */
7
+ export function clampRect(rect, width, height) {
8
+ const x = Math.max(0, Math.min(width - 1, Math.floor(rect.x)));
9
+ const y = Math.max(0, Math.min(height - 1, Math.floor(rect.y)));
10
+ const maxW = width - x;
11
+ const maxH = height - y;
12
+ const w = Math.max(1, Math.min(maxW, Math.floor(rect.width)));
13
+ const h = Math.max(1, Math.min(maxH, Math.floor(rect.height)));
14
+ return { x, y, width: w, height: h };
15
+ }
16
+ /** Expand a rect by relative padding, then clamp to bounds (edge-safe). */
17
+ export function applyCropPadding(rect, imageWidth, imageHeight, padding) {
18
+ const ratio = PADDING_RATIOS[padding];
19
+ const padX = Math.round(rect.width * ratio);
20
+ const padY = Math.round(rect.height * ratio);
21
+ return clampRect({
22
+ x: rect.x - padX,
23
+ y: rect.y - padY,
24
+ width: rect.width + padX * 2,
25
+ height: rect.height + padY * 2,
26
+ }, imageWidth, imageHeight);
27
+ }
28
+ /** Intersection-over-union of two rects. */
29
+ export function iou(a, b) {
30
+ const x1 = Math.max(a.x, b.x);
31
+ const y1 = Math.max(a.y, b.y);
32
+ const x2 = Math.min(a.x + a.width, b.x + b.width);
33
+ const y2 = Math.min(a.y + a.height, b.y + b.height);
34
+ const iw = Math.max(0, x2 - x1);
35
+ const ih = Math.max(0, y2 - y1);
36
+ const inter = iw * ih;
37
+ if (inter <= 0)
38
+ return 0;
39
+ const union = a.width * a.height + b.width * b.height - inter;
40
+ return union <= 0 ? 0 : inter / union;
41
+ }
42
+ /** Non-maximum suppression for scored regions. */
43
+ export function nonMaximumSuppression(regions, iouThreshold = 0.45, maxKeep = 5) {
44
+ const sorted = [...regions].sort((a, b) => b.score - a.score);
45
+ const kept = [];
46
+ for (const candidate of sorted) {
47
+ if (kept.length >= maxKeep)
48
+ break;
49
+ const overlaps = kept.some((k) => iou(k, candidate) >= iouThreshold);
50
+ if (!overlaps)
51
+ kept.push(candidate);
52
+ }
53
+ return kept.map((r, index) => ({ ...r, index }));
54
+ }
55
+ /**
56
+ * Edge-density grid scan returning top-N candidate regions on the preview image.
57
+ * Coordinates are in preview pixel space.
58
+ */
59
+ export function detectCandidateRegions(image, options) {
60
+ const { data, width, height } = image;
61
+ const gridSize = options?.gridSize ?? 20;
62
+ const windowCells = options?.windowCells ?? 5;
63
+ const maxRaw = options?.maxRaw ?? 24;
64
+ const cellW = Math.max(1, Math.floor(width / gridSize));
65
+ const cellH = Math.max(1, Math.floor(height / gridSize));
66
+ const raw = [];
67
+ for (let gy = 0; gy <= gridSize - windowCells; gy++) {
68
+ options?.budget?.throwIfExceeded("region-scoring");
69
+ for (let gx = 0; gx <= gridSize - windowCells; gx++) {
70
+ let density = 0;
71
+ for (let dy = 0; dy < windowCells; dy++) {
72
+ for (let dx = 0; dx < windowCells; dx++) {
73
+ const cx = (gx + dx) * cellW;
74
+ const cy = (gy + dy) * cellH;
75
+ const px = Math.min(Math.floor(cx + cellW / 2), width - 1);
76
+ const py = Math.min(Math.floor(cy + cellH / 2), height - 1);
77
+ const idx = (py * width + px) * 4;
78
+ const gray = (data[idx] + data[idx + 1] + data[idx + 2]) / 3;
79
+ if (px < width - 1) {
80
+ const rIdx = (py * width + px + 1) * 4;
81
+ const right = (data[rIdx] + data[rIdx + 1] + data[rIdx + 2]) / 3;
82
+ density += Math.abs(gray - right);
83
+ }
84
+ if (py < height - 1) {
85
+ const dIdx = ((py + 1) * width + px) * 4;
86
+ const down = (data[dIdx] + data[dIdx + 1] + data[dIdx + 2]) / 3;
87
+ density += Math.abs(gray - down);
88
+ }
89
+ }
90
+ }
91
+ if (density > 800) {
92
+ raw.push({
93
+ x: gx * cellW,
94
+ y: gy * cellH,
95
+ width: windowCells * cellW,
96
+ height: windowCells * cellH,
97
+ score: density,
98
+ index: -1,
99
+ });
100
+ }
101
+ }
102
+ }
103
+ raw.sort((a, b) => b.score - a.score);
104
+ return nonMaximumSuppression(raw.slice(0, maxRaw), 0.45, options?.maxRaw ? Math.min(8, options.maxRaw) : 5);
105
+ }
106
+ /** Scale a preview-space rect to original image coordinates. */
107
+ export function scaleRectToOriginal(rect, previewScale) {
108
+ const inv = 1 / previewScale;
109
+ return {
110
+ x: Math.floor(rect.x * inv),
111
+ y: Math.floor(rect.y * inv),
112
+ width: Math.floor(rect.width * inv),
113
+ height: Math.floor(rect.height * inv),
114
+ };
115
+ }
116
+ /** Crop a region from a pixel buffer. */
117
+ export function cropBuffer(src, rect, budget) {
118
+ const r = clampRect(rect, src.width, src.height);
119
+ const out = new Uint8ClampedArray(r.width * r.height * 4);
120
+ for (let y = 0; y < r.height; y++) {
121
+ if ((y & 31) === 0)
122
+ budget?.throwIfExceeded("candidate-crop");
123
+ const srcStart = ((r.y + y) * src.width + r.x) * 4;
124
+ const dstStart = y * r.width * 4;
125
+ out.set(src.data.subarray(srcStart, srcStart + r.width * 4), dstStart);
126
+ }
127
+ return { data: out, width: r.width, height: r.height };
128
+ }
129
+ //# sourceMappingURL=region-detection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"region-detection.js","sourceRoot":"","sources":["../../src/qr/region-detection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { DecodedCode } from "./types.js";
2
+ export type ResultDeduplicationPolicy = "payload" | "payload-format" | "payload-format-spatial" | "tracked-instance";
3
+ /** Deduplicate semantic results while preserving geometry-proven physical instances. */
4
+ export declare function dedupeResults(results: DecodedCode[], policy?: ResultDeduplicationPolicy): DecodedCode[];
5
+ /** True if string looks like http(s) URL. */
6
+ export declare function looksLikeUrl(s: string): boolean;
7
+ /** Normalize whitespace-only payloads to empty failure candidates. */
8
+ export declare function normalizePayload(payload: string): string;
9
+ //# sourceMappingURL=result-normalizer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-normalizer.d.ts","sourceRoot":"","sources":["../../src/qr/result-normalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAG9C,MAAM,MAAM,yBAAyB,GAAG,SAAS,GAAG,gBAAgB,GAAG,wBAAwB,GAAG,kBAAkB,CAAC;AAsBrH,wFAAwF;AACxF,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,EAAE,MAAM,GAAE,yBAAoD,GAAG,WAAW,EAAE,CAmBjI;AAED,6CAA6C;AAC7C,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAO/C;AAED,sEAAsE;AACtE,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAExD"}
@@ -0,0 +1,70 @@
1
+ import { iou } from "./region-detection.js";
2
+ function bounds(result) {
3
+ if (!result.cornerPoints?.length)
4
+ return null;
5
+ const xs = result.cornerPoints.map((point) => point.x);
6
+ const ys = result.cornerPoints.map((point) => point.y);
7
+ const x = Math.min(...xs);
8
+ const y = Math.min(...ys);
9
+ return { x, y, width: Math.max(1, Math.max(...xs) - x), height: Math.max(1, Math.max(...ys) - y) };
10
+ }
11
+ function samePhysicalInstance(left, right) {
12
+ const a = bounds(left);
13
+ const b = bounds(right);
14
+ if (!a || !b)
15
+ return true;
16
+ const overlap = iou(a, b);
17
+ if (overlap >= 0.55)
18
+ return true;
19
+ const ax = a.x + a.width / 2;
20
+ const ay = a.y + a.height / 2;
21
+ const bx = b.x + b.width / 2;
22
+ const by = b.y + b.height / 2;
23
+ const areaRatio = Math.min(a.width * a.height, b.width * b.height) / Math.max(a.width * a.height, b.width * b.height);
24
+ const distance = Math.hypot(ax - bx, ay - by);
25
+ return overlap >= 0.25 && areaRatio >= 0.5 && distance <= Math.min(Math.hypot(a.width, a.height), Math.hypot(b.width, b.height)) * 0.35;
26
+ }
27
+ /** Deduplicate semantic results while preserving geometry-proven physical instances. */
28
+ export function dedupeResults(results, policy = "payload-format-spatial") {
29
+ if (policy === "tracked-instance")
30
+ throw new Error("tracked-instance requires a temporal tracking operator.");
31
+ const out = [];
32
+ for (const r of results) {
33
+ const duplicate = out.some((prior) => {
34
+ if (prior.payload !== r.payload)
35
+ return false;
36
+ if (policy !== "payload" && (prior.format ?? "qr_code") !== (r.format ?? "qr_code"))
37
+ return false;
38
+ return policy === "payload-format-spatial" ? samePhysicalInstance(prior, r) : true;
39
+ });
40
+ if (duplicate)
41
+ continue;
42
+ out.push(r);
43
+ }
44
+ return out.sort((a, b) => {
45
+ const ab = bounds(a);
46
+ const bb = bounds(b);
47
+ if (ab && bb)
48
+ return (ab.y - bb.y) || (ab.x - bb.x) || (a.attemptIndex - b.attemptIndex);
49
+ if (ab)
50
+ return -1;
51
+ if (bb)
52
+ return 1;
53
+ return a.attemptIndex - b.attemptIndex;
54
+ });
55
+ }
56
+ /** True if string looks like http(s) URL. */
57
+ export function looksLikeUrl(s) {
58
+ try {
59
+ const u = new URL(s);
60
+ return u.protocol === "http:" || u.protocol === "https:";
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ /** Normalize whitespace-only payloads to empty failure candidates. */
67
+ export function normalizePayload(payload) {
68
+ return payload.replace(/\u0000/g, "").trimEnd();
69
+ }
70
+ //# sourceMappingURL=result-normalizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"result-normalizer.js","sourceRoot":"","sources":["../../src/qr/result-normalizer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { PixelBuffer, RotationDegrees } from "./types.js";
2
+ import type { ExecutionBudget } from "../runtime/execution-budget.js";
3
+ /** Rotate RGBA buffer by 0/90/180/270 degrees clockwise. */
4
+ export declare function rotateBuffer(src: PixelBuffer, degrees: RotationDegrees, budget?: ExecutionBudget): PixelBuffer;
5
+ //# sourceMappingURL=rotate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.d.ts","sourceRoot":"","sources":["../../src/qr/rotate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,eAAe,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,WAAW,CAgD9G"}
@@ -0,0 +1,51 @@
1
+ /** Rotate RGBA buffer by 0/90/180/270 degrees clockwise. */
2
+ export function rotateBuffer(src, degrees, budget) {
3
+ if (degrees === 0) {
4
+ return { data: new Uint8ClampedArray(src.data), width: src.width, height: src.height };
5
+ }
6
+ const { width: w, height: h, data } = src;
7
+ if (degrees === 180) {
8
+ const out = new Uint8ClampedArray(data.length);
9
+ for (let y = 0; y < h; y++) {
10
+ if ((y & 31) === 0)
11
+ budget?.throwIfExceeded("rotate-180");
12
+ for (let x = 0; x < w; x++) {
13
+ const si = (y * w + x) * 4;
14
+ const di = ((h - 1 - y) * w + (w - 1 - x)) * 4;
15
+ out[di] = data[si];
16
+ out[di + 1] = data[si + 1];
17
+ out[di + 2] = data[si + 2];
18
+ out[di + 3] = data[si + 3];
19
+ }
20
+ }
21
+ return { data: out, width: w, height: h };
22
+ }
23
+ const outW = h;
24
+ const outH = w;
25
+ const out = new Uint8ClampedArray(outW * outH * 4);
26
+ for (let y = 0; y < h; y++) {
27
+ if ((y & 31) === 0)
28
+ budget?.throwIfExceeded("rotate");
29
+ for (let x = 0; x < w; x++) {
30
+ const si = (y * w + x) * 4;
31
+ let dx;
32
+ let dy;
33
+ if (degrees === 90) {
34
+ dx = h - 1 - y;
35
+ dy = x;
36
+ }
37
+ else {
38
+ // 270
39
+ dx = y;
40
+ dy = w - 1 - x;
41
+ }
42
+ const di = (dy * outW + dx) * 4;
43
+ out[di] = data[si];
44
+ out[di + 1] = data[si + 1];
45
+ out[di + 2] = data[si + 2];
46
+ out[di + 3] = data[si + 3];
47
+ }
48
+ }
49
+ return { data: out, width: outW, height: outH };
50
+ }
51
+ //# sourceMappingURL=rotate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rotate.js","sourceRoot":"","sources":["../../src/qr/rotate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import type { BarcodeFormat } from "@scanly/scenario-schema";
2
+ import type { EngineOutcome } from "../contracts/engine.js";
3
+ import type { ExecutionBudget } from "../runtime/execution-budget.js";
4
+ import type { FrameMemoryBudget } from "../runtime/memory-budget.js";
5
+ import type { EngineDiagnostic } from "../contracts/result.js";
6
+ /** Shared pixel buffer compatible with browser ImageData and Node raw buffers. */
7
+ export interface PixelBuffer {
8
+ data: Uint8ClampedArray;
9
+ width: number;
10
+ height: number;
11
+ }
12
+ export type NonEmptyArray<T> = [T, ...T[]];
13
+ export interface Rect {
14
+ x: number;
15
+ y: number;
16
+ width: number;
17
+ height: number;
18
+ }
19
+ export interface ScoredRegion extends Rect {
20
+ score: number;
21
+ index: number;
22
+ }
23
+ export type PreprocessMethod = "original" | "grayscale" | "contrast" | "gamma" | "invert" | "threshold-115" | "threshold-140" | "threshold-165" | "otsu" | "sharpen";
24
+ /** Engine ids are plugin-defined and intentionally not a closed union. */
25
+ export type DecoderName = string;
26
+ export type ScaleLabel = "original" | "downscaled" | "upscaled" | "full";
27
+ export type CropPadding = "tight" | "medium" | "expanded";
28
+ export type RotationDegrees = 0 | 90 | 180 | 270;
29
+ export type DecodeErrorReason = "invalid_file" | "invalid_image" | "invalid_configuration" | "unsupported_image" | "no_qr_found" | "timeout" | "cancelled" | "worker_error" | "worker_initialization_failure" | "empty_image" | "image_too_large" | "camera_permission_denied" | "camera_not_found" | "camera_busy" | "camera_constraint_failed" | "camera_track_ended" | "camera_capability_unsupported" | "camera_recovery_failed" | "browser_background_suspended" | "no_camera" | "unsupported_format" | "engine_initialization_failure" | "engine_execution_failure";
30
+ export interface DecodeAttempt {
31
+ candidateIndex: number;
32
+ candidateScore: number;
33
+ cropPadding: CropPadding | "full";
34
+ preprocessing: PreprocessMethod;
35
+ scale: ScaleLabel;
36
+ scaleFactor: number;
37
+ rotation: RotationDegrees;
38
+ decoder: DecoderName;
39
+ elapsedMs: number;
40
+ success: boolean;
41
+ }
42
+ export interface DecodedCode {
43
+ payload: string;
44
+ format?: BarcodeFormat;
45
+ /** Decoder-provided bytes; absent when the selected decoder cannot expose them. */
46
+ rawBytes?: Uint8Array;
47
+ decoder: DecoderName;
48
+ engineVersion?: string;
49
+ engineMetadata?: import("../contracts/engine.js").EngineExecutionMetadata;
50
+ cornerPoints?: Array<{
51
+ x: number;
52
+ y: number;
53
+ }>;
54
+ symbologyIdentifier?: string;
55
+ isGs1?: boolean;
56
+ metadata?: Record<string, unknown>;
57
+ preprocessing: PreprocessMethod;
58
+ candidateIndex: number;
59
+ scale: ScaleLabel;
60
+ rotation: RotationDegrees;
61
+ /** Engine-provided symbol orientation normalized to the original frame. */
62
+ symbolOrientation?: number;
63
+ cropPadding: CropPadding | "full";
64
+ attemptIndex: number;
65
+ /** Internal wall-clock offset used to report time to first result. */
66
+ foundAtMs?: number;
67
+ }
68
+ export interface DecodeSuccess {
69
+ ok: true;
70
+ results: NonEmptyArray<DecodedCode>;
71
+ /** Primary result — first unique successful decode. */
72
+ primary: DecodedCode;
73
+ attempts: DecodeAttempt[];
74
+ attemptCount: number;
75
+ elapsedMs: number;
76
+ timeToFirstResultMs?: number;
77
+ cancelled: boolean;
78
+ engineDiagnostics?: EngineDiagnostic[];
79
+ phaseTiming?: PhaseTiming;
80
+ }
81
+ export interface DecodeFailure {
82
+ ok: false;
83
+ reason: DecodeErrorReason;
84
+ message: string;
85
+ attempts: DecodeAttempt[];
86
+ attemptCount: number;
87
+ elapsedMs: number;
88
+ cancelled: boolean;
89
+ engineDiagnostics?: EngineDiagnostic[];
90
+ phaseTiming?: PhaseTiming;
91
+ }
92
+ export type DecodeOutcome = DecodeSuccess | DecodeFailure;
93
+ export interface DecoderConfig {
94
+ /** Plugin ids, in deterministic aggregation order. */
95
+ order: DecoderName[];
96
+ execution: "sequential" | "parallel";
97
+ failurePolicy?: "success-wins" | "required-engine-fails" | "any-engine-fails";
98
+ }
99
+ export interface PhaseTiming {
100
+ frameNormalizationMs?: number;
101
+ roiMs?: number;
102
+ localizationMs?: number;
103
+ candidateGenerationMs: number;
104
+ candidateDeduplicationMs?: number;
105
+ preprocessMs: number;
106
+ rotationMs: number;
107
+ validationMs?: number;
108
+ semanticParsingMs?: number;
109
+ workerTransferMs?: number;
110
+ workerSetupMs?: number;
111
+ cancellationLatencyMs?: number;
112
+ engineMs?: Record<string, number>;
113
+ }
114
+ export interface DecodeProgress {
115
+ attemptCount: number;
116
+ }
117
+ export interface PipelineConfig {
118
+ /** Explicit public formats passed to every engine attempt. Defaults to QR-only. */
119
+ formats: BarcodeFormat[];
120
+ maxCandidates: number;
121
+ maxAttempts: number;
122
+ timeoutMs: number;
123
+ maxPixels: number;
124
+ previewSize: number;
125
+ findMultiple: boolean;
126
+ maxMultipleResults: number;
127
+ resultDeduplication: "payload" | "payload-format" | "payload-format-spatial" | "tracked-instance";
128
+ scales: number[];
129
+ paddings: CropPadding[];
130
+ rotations: RotationDegrees[];
131
+ /** Ordered preprocess methods tried per candidate/scale/rotation combo (subset). */
132
+ preprocessOrder: PreprocessMethod[];
133
+ decoders: DecoderConfig;
134
+ /** When native fallbacks enter the graph. Fast uses final; richer profiles use after-cheap. */
135
+ fallbackTiming?: "after-cheap" | "final";
136
+ /** Benchmark: all payloads that must appear for a full pass. */
137
+ requiredPayloads?: string[];
138
+ /** Benchmark: stop once this many unique payloads are found. */
139
+ expectedResultCount?: number;
140
+ /** Stop after this many consecutive candidates without a new payload (multiple mode). */
141
+ stallCandidateLimit?: number;
142
+ multiCodeStallPolicy?: MultiCodeStallPolicy;
143
+ /** After this many failed attempts with no decode, skip heavy phases. */
144
+ failFastAfterAttempts?: number;
145
+ enableLocalization?: boolean;
146
+ enableFullImageFallback?: boolean;
147
+ enableSplitImageFallback?: boolean;
148
+ enableGridImageFallback?: boolean;
149
+ /** Bounded per-frame retained preprocessing cache; never global. */
150
+ maxIntermediateAllocations?: number;
151
+ maxIntermediateBytes?: number;
152
+ }
153
+ export interface DecodePipelineOptions {
154
+ signal?: AbortSignal;
155
+ config?: Partial<PipelineConfig>;
156
+ onStage?: (stage: string) => void;
157
+ onProgress?: (progress: DecodeProgress) => void;
158
+ /** If true, run on main thread (Node/tests). Browser upload uses Worker. */
159
+ forceMainThread?: boolean;
160
+ /** Required dependency-inverted engine boundary. */
161
+ engineExecutor?: PipelineEngineExecutor;
162
+ /** Internal graph path: candidates generated by upstream operators. */
163
+ candidates?: import("./candidate-generation.js").CandidateImage[];
164
+ /** Shared Router deadline/cancellation context. */
165
+ executionBudget?: ExecutionBudget;
166
+ /** Shared logical retained-buffer accounting for this frame. */
167
+ memoryBudget?: FrameMemoryBudget;
168
+ }
169
+ export interface MultiCodeStallPolicy {
170
+ maximumAttemptsWithoutNewResult: number;
171
+ minimumCandidateCoverageBeforeStop: number;
172
+ requireAllPrimaryCandidatesVisited: boolean;
173
+ }
174
+ export interface PipelineEngineExecutor {
175
+ readonly engineIds: readonly string[];
176
+ readonly versions?: Readonly<Record<string, string>>;
177
+ decode(engineId: string, image: PixelBuffer, options: {
178
+ formats: readonly BarcodeFormat[];
179
+ signal?: AbortSignal;
180
+ findMultiple: boolean;
181
+ inversion?: "unknown" | "original" | "inverted";
182
+ }): Promise<EngineOutcome>;
183
+ }
184
+ export declare const DEFAULT_PIPELINE_CONFIG: PipelineConfig;
185
+ export declare function validatePipelineConfig(config: PipelineConfig): string[];
186
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/qr/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ export const DEFAULT_PIPELINE_CONFIG = {
2
+ formats: ["qr_code"],
3
+ maxCandidates: 5,
4
+ maxAttempts: 96,
5
+ timeoutMs: 12_000,
6
+ maxPixels: 4_000_000,
7
+ previewSize: 400,
8
+ findMultiple: true,
9
+ maxMultipleResults: 8,
10
+ resultDeduplication: "payload-format-spatial",
11
+ scales: [1, 0.7, 1.35],
12
+ paddings: ["medium", "expanded", "tight"],
13
+ rotations: [0, 90, 180, 270],
14
+ preprocessOrder: [
15
+ "original",
16
+ "contrast",
17
+ "invert",
18
+ "otsu",
19
+ "threshold-140",
20
+ "gamma",
21
+ "sharpen",
22
+ "threshold-115",
23
+ "threshold-165",
24
+ ],
25
+ decoders: { order: [], execution: "sequential", failurePolicy: "success-wins" },
26
+ fallbackTiming: "final",
27
+ stallCandidateLimit: 12,
28
+ failFastAfterAttempts: 48,
29
+ enableLocalization: true,
30
+ enableFullImageFallback: true,
31
+ enableSplitImageFallback: true,
32
+ enableGridImageFallback: true,
33
+ maxIntermediateAllocations: 24,
34
+ maxIntermediateBytes: 64 * 1024 * 1024,
35
+ };
36
+ export function validatePipelineConfig(config) {
37
+ const issues = [];
38
+ if (!Array.isArray(config.formats) || config.formats.length === 0)
39
+ issues.push("formats must contain at least one public barcode format.");
40
+ for (const key of ["maxCandidates", "maxAttempts", "timeoutMs", "maxPixels", "previewSize", "maxMultipleResults", "maxIntermediateAllocations", "maxIntermediateBytes"]) {
41
+ const value = config[key];
42
+ if (typeof value !== "number" || !Number.isFinite(value) || !Number.isInteger(value) || value < 1)
43
+ issues.push(`${key} must be a positive integer.`);
44
+ }
45
+ if (config.scales.length === 0 || config.scales.some((scale) => !Number.isFinite(scale) || scale <= 0 || scale > 4))
46
+ issues.push("scales must contain finite values greater than 0 and at most 4.");
47
+ if (config.paddings.length === 0)
48
+ issues.push("paddings must not be empty.");
49
+ if (config.rotations.length === 0)
50
+ issues.push("rotations must not be empty.");
51
+ if (config.preprocessOrder.length === 0)
52
+ issues.push("preprocessOrder must not be empty.");
53
+ if (!Array.isArray(config.decoders.order) || config.decoders.order.length === 0)
54
+ issues.push("decoders.order must contain at least one registered engine id.");
55
+ if (config.decoders.execution !== "sequential" && config.decoders.execution !== "parallel")
56
+ issues.push("decoders.execution must be sequential or parallel.");
57
+ if (config.multiCodeStallPolicy) {
58
+ if (!Number.isInteger(config.multiCodeStallPolicy.maximumAttemptsWithoutNewResult) || config.multiCodeStallPolicy.maximumAttemptsWithoutNewResult < 1)
59
+ issues.push("multiCodeStallPolicy.maximumAttemptsWithoutNewResult must be a positive integer.");
60
+ if (!Number.isFinite(config.multiCodeStallPolicy.minimumCandidateCoverageBeforeStop) || config.multiCodeStallPolicy.minimumCandidateCoverageBeforeStop < 0 || config.multiCodeStallPolicy.minimumCandidateCoverageBeforeStop > 1)
61
+ issues.push("multiCodeStallPolicy.minimumCandidateCoverageBeforeStop must be between 0 and 1.");
62
+ if (typeof config.multiCodeStallPolicy.requireAllPrimaryCandidatesVisited !== "boolean")
63
+ issues.push("multiCodeStallPolicy.requireAllPrimaryCandidatesVisited must be boolean.");
64
+ }
65
+ return issues;
66
+ }
67
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/qr/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { PixelBuffer } from "./types.js";
2
+ export interface ZXingDecodeResult {
3
+ payload: string;
4
+ rawBytes?: Uint8Array;
5
+ }
6
+ /** Decode QR from RGBA pixel buffer using ZXing library (works in Node and browser). */
7
+ export declare function decodeWithZXing(buffer: PixelBuffer): ZXingDecodeResult | null;
8
+ //# sourceMappingURL=zxing-decoder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zxing-decoder.d.ts","sourceRoot":"","sources":["../../src/qr/zxing-decoder.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,UAAU,CAAC;CACvB;AASD,wFAAwF;AACxF,wBAAgB,eAAe,CAAC,MAAM,EAAE,WAAW,GAAG,iBAAiB,GAAG,IAAI,CAoB7E"}
@@ -0,0 +1,33 @@
1
+ import { BinaryBitmap, HybridBinarizer, RGBLuminanceSource, DecodeHintType, BarcodeFormat, QRCodeReader, } from "@zxing/library";
2
+ let reader = null;
3
+ function getReader() {
4
+ if (!reader)
5
+ reader = new QRCodeReader();
6
+ return reader;
7
+ }
8
+ /** Decode QR from RGBA pixel buffer using ZXing library (works in Node and browser). */
9
+ export function decodeWithZXing(buffer) {
10
+ if (buffer.width < 1 || buffer.height < 1)
11
+ return null;
12
+ try {
13
+ const luminance = new Uint8ClampedArray(buffer.width * buffer.height);
14
+ for (let i = 0, j = 0; i < buffer.data.length; i += 4, j++) {
15
+ luminance[j] = (buffer.data[i] * 0.299 + buffer.data[i + 1] * 0.587 + buffer.data[i + 2] * 0.114) | 0;
16
+ }
17
+ const source = new RGBLuminanceSource(luminance, buffer.width, buffer.height);
18
+ const bitmap = new BinaryBitmap(new HybridBinarizer(source));
19
+ const hints = new Map();
20
+ hints.set(DecodeHintType.POSSIBLE_FORMATS, [BarcodeFormat.QR_CODE]);
21
+ hints.set(DecodeHintType.TRY_HARDER, true);
22
+ const result = getReader().decode(bitmap, hints);
23
+ const text = result?.getText();
24
+ if (!text)
25
+ return null;
26
+ const rawBytes = result.getRawBytes();
27
+ return { payload: text, ...(rawBytes?.byteLength ? { rawBytes } : {}) };
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ }
33
+ //# sourceMappingURL=zxing-decoder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zxing-decoder.js","sourceRoot":"","sources":["../../src/qr/zxing-decoder.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,YAAY,GACb,MAAM,gBAAgB,CAAC;AAQxB,IAAI,MAAM,GAAwB,IAAI,CAAC;AAEvC,SAAS,SAAS;IAChB,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;IACzC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,wFAAwF;AACxF,MAAM,UAAU,eAAe,CAAC,MAAmB;IACjD,IAAI,MAAM,CAAC,KAAK,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,IAAI,iBAAiB,CAAC,MAAM,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACtE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3D,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;QACxG,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,SAAS,EAAE,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9E,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;QAC7D,MAAM,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;QACxB,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,gBAAgB,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;QACpE,KAAK,CAAC,GAAG,CAAC,cAAc,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC3C,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,EAAE,CAAC;QACtC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}