@saeris/hanko 0.0.0 → 0.2.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 (57) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +605 -0
  4. package/dist/approve/index.d.mts +318 -0
  5. package/dist/approve/index.d.mts.map +1 -0
  6. package/dist/approve/index.mjs +393 -0
  7. package/dist/approve/index.mjs.map +1 -0
  8. package/dist/client/index.d.mts +101 -0
  9. package/dist/client/index.d.mts.map +1 -0
  10. package/dist/client/index.mjs +215 -0
  11. package/dist/client/index.mjs.map +1 -0
  12. package/dist/codes-Ba_qYH6u.mjs +93 -0
  13. package/dist/codes-Ba_qYH6u.mjs.map +1 -0
  14. package/dist/handlers.d.mts +113 -0
  15. package/dist/handlers.d.mts.map +1 -0
  16. package/dist/handlers.mjs +194 -0
  17. package/dist/handlers.mjs.map +1 -0
  18. package/dist/index.d.mts +5 -0
  19. package/dist/index.mjs +345 -0
  20. package/dist/index.mjs.map +1 -0
  21. package/dist/linking-DcQSMgem.mjs +177 -0
  22. package/dist/linking-DcQSMgem.mjs.map +1 -0
  23. package/dist/linking-nKoayyHf.d.mts +133 -0
  24. package/dist/linking-nKoayyHf.d.mts.map +1 -0
  25. package/dist/machine-CRHKjtoP.d.mts +223 -0
  26. package/dist/machine-CRHKjtoP.d.mts.map +1 -0
  27. package/dist/machine-D_5DAFxi.mjs +155 -0
  28. package/dist/machine-D_5DAFxi.mjs.map +1 -0
  29. package/dist/qr.d.mts +58 -0
  30. package/dist/qr.d.mts.map +1 -0
  31. package/dist/qr.mjs +27 -0
  32. package/dist/qr.mjs.map +1 -0
  33. package/dist/scan/index.d.mts +381 -0
  34. package/dist/scan/index.d.mts.map +1 -0
  35. package/dist/scan/index.mjs +409 -0
  36. package/dist/scan/index.mjs.map +1 -0
  37. package/dist/scan/worker.d.mts +2 -0
  38. package/dist/scan/worker.mjs +2 -0
  39. package/dist/server-BhoYRkCm.d.mts +257 -0
  40. package/dist/server-BhoYRkCm.d.mts.map +1 -0
  41. package/dist/stores/kv.d.mts +64 -0
  42. package/dist/stores/kv.d.mts.map +1 -0
  43. package/dist/stores/kv.mjs +87 -0
  44. package/dist/stores/kv.mjs.map +1 -0
  45. package/dist/stores/memory.d.mts +22 -0
  46. package/dist/stores/memory.d.mts.map +1 -0
  47. package/dist/stores/memory.mjs +42 -0
  48. package/dist/stores/memory.mjs.map +1 -0
  49. package/dist/types-BvBIFPH6.mjs +7 -0
  50. package/dist/types-BvBIFPH6.mjs.map +1 -0
  51. package/dist/types-C82lb-zX.d.mts +82 -0
  52. package/dist/types-C82lb-zX.d.mts.map +1 -0
  53. package/dist/worker-BdwaK1uX.mjs +5291 -0
  54. package/dist/worker-BdwaK1uX.mjs.map +1 -0
  55. package/dist/worker-DxbdBA2z.d.mts +164 -0
  56. package/dist/worker-DxbdBA2z.d.mts.map +1 -0
  57. package/package.json +116 -3
@@ -0,0 +1,381 @@
1
+ import { a as createQrDecoder, c as GrayImage, i as QrDecoderOptions, l as Point, n as DecodeResponse, o as BitMatrix, r as serveDecoder, s as DecodedSymbol, t as DecodeRequest, u as SymbolDecoder } from "../worker-DxbdBA2z.mjs";
2
+ //#region src/scan/qr/progressive.d.ts
3
+ /** A scanner that improves its effort as frames arrive. */
4
+ interface ProgressiveScanner {
5
+ /**
6
+ * Offer one frame.
7
+ *
8
+ * Returns a symbol as soon as one is read, and `null` otherwise — including
9
+ * while effort is still ramping up.
10
+ */
11
+ scan(image: GrayImage): DecodedSymbol | null;
12
+ /**
13
+ * Reset the effort ramp.
14
+ *
15
+ * Call when the scene changes — a new code presented, the camera moved
16
+ * somewhere else — so the next frame starts cheap again rather than
17
+ * inheriting effort earned by a symbol that is no longer there.
18
+ */
19
+ reset(): void;
20
+ /** How much effort the next frame will receive, in milliseconds. */
21
+ readonly budgetMs: number;
22
+ }
23
+ /** Options for {@link createProgressiveScanner}. */
24
+ interface ProgressiveOptions extends Omit<QrDecoderOptions, `timeBudgetMs`> {
25
+ /**
26
+ * Budget for the first frame, in milliseconds.
27
+ *
28
+ * Deliberately small. Most frames a camera delivers contain no code at all,
29
+ * and this is what every one of them costs.
30
+ */
31
+ initialBudgetMs?: number;
32
+ /**
33
+ * Ceiling on the per-frame budget.
34
+ *
35
+ * 400ms by default: beyond that a single frame stalls the preview
36
+ * noticeably, and at 30fps the ladder has had a dozen frames to work with
37
+ * by the time the ramp reaches it.
38
+ */
39
+ maxBudgetMs?: number;
40
+ /**
41
+ * How much the budget grows per consecutive frame that shows a symbol.
42
+ *
43
+ * Growth is conditional on there being something to find: a frame with no
44
+ * finder candidate at all should not earn the next frame more time, or a
45
+ * camera pointed at a wall would ramp to its ceiling and stay there.
46
+ */
47
+ growth?: number;
48
+ }
49
+ /**
50
+ * Create a scanner that spreads decoding effort across frames.
51
+ *
52
+ * The ramp is driven by evidence rather than by a timer. A frame in which the
53
+ * decoder finds nothing resets it, because nothing is there to spend effort
54
+ * on; a frame that finds a symbol but cannot read it raises the budget,
55
+ * because that is exactly the case where more effort pays.
56
+ */
57
+ declare const createProgressiveScanner: ({ initialBudgetMs, maxBudgetMs, growth, ...decoderOptions }?: ProgressiveOptions) => ProgressiveScanner;
58
+ /**
59
+ * Drive a decoder running in a worker.
60
+ *
61
+ * Same shape as {@link createProgressiveScanner} but asynchronous, because
62
+ * the work happens elsewhere. The main thread stays free: measured on a hard
63
+ * frame, an in-thread decode blocks 208ms at a 40ms budget and 481ms at
64
+ * 400ms, which at 60fps is 12 and 28 dropped frames respectively — a visible
65
+ * freeze on exactly the frames where someone is lining up a shot.
66
+ *
67
+ * Frames offered while a decode is in flight are DROPPED rather than queued.
68
+ * A camera produces frames faster than they can be decoded, and a queue would
69
+ * grow without bound while returning increasingly stale results; the next
70
+ * frame is always a better input than a backlogged one.
71
+ */
72
+ interface WorkerScanner {
73
+ /** Offer a frame. Resolves `null` if dropped, still ramping, or unreadable. */
74
+ scan(image: GrayImage): Promise<DecodedSymbol | null>;
75
+ /** Reset the effort ramp — call when the scene changes. */
76
+ reset(): void;
77
+ /** Stop the worker and release it. */
78
+ close(): void;
79
+ /** Whether a decode is currently in flight. */
80
+ readonly busy: boolean;
81
+ }
82
+ /**
83
+ * Wrap a worker in the progressive interface.
84
+ *
85
+ * The worker is supplied rather than constructed here, because how a worker
86
+ * is created is a bundler question — `new Worker(new URL(...), { type:
87
+ * "module" })` in Vite, a blob URL elsewhere — and a library that guessed
88
+ * would be wrong for most consumers.
89
+ */
90
+ declare const createWorkerScanner: (worker: {
91
+ postMessage: (message: unknown, transfer?: ArrayBufferLike[]) => void;
92
+ addEventListener?: (type: string, listener: (event: {
93
+ data: unknown;
94
+ }) => void) => void;
95
+ on?: (type: string, listener: (message: unknown) => void) => void;
96
+ terminate?: () => void;
97
+ }, { initialBudgetMs, maxBudgetMs, growth }?: ProgressiveOptions) => WorkerScanner;
98
+ //#endregion
99
+ //#region src/scan/qr/locate.d.ts
100
+ /** A located finder pattern. */
101
+ interface FinderPattern {
102
+ readonly center: Point;
103
+ /** Estimated module size in pixels, from the pattern's own width. */
104
+ readonly moduleSize: number;
105
+ }
106
+ /**
107
+ * Drop candidates that have no clear space around them.
108
+ *
109
+ * Returns the original list when filtering would leave fewer than three, so a
110
+ * symbol photographed without its full quiet zone — against a dark table
111
+ * edge, say — is never made undecodable by this check.
112
+ */
113
+ declare const withClearance: (matrix: BitMatrix, patterns: readonly FinderPattern[]) => FinderPattern[];
114
+ //#endregion
115
+ //#region src/scan/binarize.d.ts
116
+ /** Convert RGBA pixels to greyscale using perceptual luminance weights. */
117
+ declare const toGray: (rgba: Uint8ClampedArray, width: number, height: number) => GrayImage;
118
+ /**
119
+ * Binarize against one threshold chosen from the whole image's histogram.
120
+ *
121
+ * The opposite trade to {@link binarize}. A single threshold cannot follow a
122
+ * shadow across a page — which is why local thresholding exists and why it
123
+ * takes the `brightness` and `monitor` categories from nothing to something.
124
+ * But local thresholding invents structure in flat regions, and on a clean,
125
+ * evenly-lit image a global threshold is both more faithful and less prone to
126
+ * that.
127
+ *
128
+ * Neither dominates, so this is a retry rather than a replacement. zxing-cpp
129
+ * reached the same conclusion from the other direction: its issue #809 is an
130
+ * image its local binarizer cannot read and its global one can, and its
131
+ * issue #500 is a prototype for supporting several binarizers for exactly
132
+ * this reason.
133
+ *
134
+ * The threshold is the midpoint between the two dominant peaks of the
135
+ * histogram rather than the mean. A QR is mostly two tones, so the histogram
136
+ * is bimodal, and the mean of a symbol with more light area than dark sits
137
+ * inside the light peak and thresholds half the modules away.
138
+ */
139
+ declare const binarizeGlobal: (image: GrayImage, { invert }?: {
140
+ invert?: boolean;
141
+ }) => BitMatrix;
142
+ /**
143
+ * Morphological closing on a bit matrix — dilate, then erode.
144
+ *
145
+ * Fills small light specks inside dark regions while leaving real structure
146
+ * intact, because dilation closes a gap smaller than the kernel and the
147
+ * following erosion restores every boundary the dilation moved.
148
+ *
149
+ * The failure this targets is specific: zxing-cpp issue #951 diagnoses an
150
+ * undetected symbol as "white pixels inside the black square that disrupt
151
+ * their detection" of the finder patterns, and its remedy is exactly this
152
+ * operation. Speckle inside a finder breaks the run-length signature — a
153
+ * single light pixel splits one dark run into two — so the pattern stops
154
+ * matching 1:1:3:1:1 even though a human sees it perfectly well.
155
+ *
156
+ * A 3x3 kernel: large enough for sensor speckle and dust, small enough that
157
+ * it cannot close a real one-module gap at any usable resolution.
158
+ */
159
+ declare const close: (matrix: BitMatrix) => BitMatrix;
160
+ /**
161
+ * Downscale by box-averaging whole blocks of pixels.
162
+ *
163
+ * Not for speed — for signal. A symbol photographed from a distance on a
164
+ * 12-megapixel sensor has modules two or three pixels wide, and at that scale
165
+ * neither run-length scanning nor shape detection produces reliable
166
+ * structure: measured on the corpus, both detectors return module-size
167
+ * estimates spanning 1.1 to 137.9 pixels within a single image, which is
168
+ * noise rather than measurement.
169
+ *
170
+ * Averaging blocks of pixels down trades resolution the symbol does not have
171
+ * for a cleaner signal it does. BoofCV builds an image pyramid for the same
172
+ * reason and scores 100% on that corpus category.
173
+ *
174
+ * Box averaging rather than nearest-neighbour sampling, because dropping
175
+ * pixels aliases a module grid badly — the very structure being looked for
176
+ * beats against the sampling lattice.
177
+ */
178
+ declare const downscale: (image: GrayImage, factor: number) => GrayImage;
179
+ /**
180
+ * Blur an image with a separable box filter, approximating a Gaussian.
181
+ *
182
+ * Two passes of a box filter — one horizontal, one vertical — is a standard
183
+ * cheap stand-in for a true Gaussian, and it is separable, so cost is linear
184
+ * in radius rather than quadratic.
185
+ *
186
+ * This exists for one specific failure: photographing a screen. Moire banding
187
+ * is frequency ALIASING between the camera sensor grid and the display's
188
+ * sub-pixel grid, so the interference sits at a much higher spatial frequency
189
+ * than the modules do. Low-pass filtering suppresses the banding and leaves
190
+ * the modules — measured on the benchmark corpus, it takes the `monitor`
191
+ * category from 0 of 25 to 10 of 25.
192
+ *
193
+ * It is NOT a free win and must not be applied by default: the same filter
194
+ * takes `blurred` from 5 of 14 down to 1, and `nominal` from 3 to 0. A blurred
195
+ * photograph blurred again is unreadable. Use it as a retry after a sharp
196
+ * pass fails.
197
+ */
198
+ declare const blur: (image: GrayImage, radius: number) => GrayImage;
199
+ /**
200
+ * Binarize a greyscale image into a bit matrix.
201
+ *
202
+ * `true` (1) means DARK, matching the QR convention where a set module is a
203
+ * dark one. Fixing polarity here — at the single boundary where pixels become
204
+ * bits — is deliberate: every stage above this one can then assume one
205
+ * orientation, and none of them has to ask which way round the image was.
206
+ *
207
+ * @param invert Treat light modules as set. Needed for symbols rendered
208
+ * light-on-dark, which decoders that assume dark-on-light read as nothing at
209
+ * all. Callers that do not know should try both.
210
+ */
211
+ declare const binarize: (image: GrayImage, { invert }?: {
212
+ invert?: boolean;
213
+ }) => BitMatrix;
214
+ //#endregion
215
+ //#region src/scan/qr/format.d.ts
216
+ /** Error-correction level, in the order the format field encodes them. */
217
+ type ErrorCorrectionLevel = `L` | `M` | `Q` | `H`;
218
+ //#endregion
219
+ //#region src/scan/qr/decode-matrix.d.ts
220
+ /** What a successful matrix decode yields. */
221
+ interface MatrixDecodeResult {
222
+ readonly value: string;
223
+ readonly version: number;
224
+ readonly errorCorrectionLevel: ErrorCorrectionLevel;
225
+ readonly mask: number;
226
+ }
227
+ /**
228
+ * Decode a bit matrix into the text it encodes.
229
+ *
230
+ * Returns `null` for anything unreadable. Every failure here is a normal
231
+ * outcome rather than an exception: a camera sees far more non-symbols than
232
+ * symbols, and a decoder that threw on each one would make its callers write
233
+ * try/catch around their hot loop.
234
+ */
235
+ declare const decodeMatrix: (matrix: BitMatrix,
236
+ /**
237
+ * Modules the imaging layer could not read confidently, as a mask the same
238
+ * shape as `matrix` where 1 marks "do not trust this".
239
+ *
240
+ * Reed-Solomon corrects twice as many codewords when it is told WHERE the
241
+ * damage is: the bound is `2 * errors + erasures <= check codewords`. A
242
+ * region blown out by glare or crushed by shadow is visibly untrustworthy,
243
+ * and thresholding it into a confident bit throws that away. Measured on a
244
+ * version 3 symbol at ecM, a blob covering 15% of the area decodes 0% of the
245
+ * time as errors and 100% as erasures.
246
+ *
247
+ * Optional because it costs a per-frame allocation the ordinary path does
248
+ * not need, and because a decoder handed no mask must behave exactly as it
249
+ * did before.
250
+ */
251
+ unreliable?: Uint8Array) => MatrixDecodeResult | null;
252
+ //#endregion
253
+ //#region src/scan/qr/sample.d.ts
254
+ /**
255
+ * A projective (homography) transform between two quadrilaterals.
256
+ *
257
+ * Affine is not enough. An affine transform preserves parallel lines, and
258
+ * perspective does not — the far edge of a tilted square is genuinely shorter
259
+ * than the near one. Only a projective transform models that, which is why
260
+ * this carries the two extra terms an affine matrix lacks.
261
+ */
262
+ interface Transform {
263
+ readonly a11: number;
264
+ readonly a12: number;
265
+ readonly a13: number;
266
+ readonly a21: number;
267
+ readonly a22: number;
268
+ readonly a23: number;
269
+ readonly a31: number;
270
+ readonly a32: number;
271
+ readonly a33: number;
272
+ }
273
+ //#endregion
274
+ //#region src/scan/gpu.d.ts
275
+ /** Scores many transforms against one image, on the GPU. */
276
+ interface GpuScorer {
277
+ score(image: BitMatrix, transforms: readonly Transform[], size: number, alignmentCenters: readonly number[]): Promise<Int32Array>;
278
+ destroy(): void;
279
+ }
280
+ /** Whether this runtime exposes WebGPU at all. */
281
+ declare const hasWebGpu: () => boolean;
282
+ /**
283
+ * Create a GPU scorer, or `null` where WebGPU is unavailable.
284
+ *
285
+ * Returns `null` rather than throwing: every caller must have a CPU path
286
+ * anyway, so an absent GPU is a normal condition and not an error.
287
+ */
288
+ declare const createGpuScorer: () => Promise<GpuScorer | null>;
289
+ //#endregion
290
+ //#region src/scan/machine.d.ts
291
+ /**
292
+ * A scan session, as a state machine.
293
+ *
294
+ * Modeled the way `machine.ts` models the device flow: states, events, and a
295
+ * declarative transition table, hand-rolled so this stays dependency-free.
296
+ *
297
+ * Deliberately NOT applied to the decode pipeline itself. Binarize → locate →
298
+ * extract → decode is a fallible sequential pipeline, not a machine: each
299
+ * stage runs once per frame and either produces a value or does not. Modeling
300
+ * it as states would add ceremony without making a single illegal move
301
+ * impossible, which is the only thing a transition table buys.
302
+ *
303
+ * What IS a machine is the session around it — permission, camera lifecycle,
304
+ * pause and resume — and that part is identical whether the frames are being
305
+ * searched for a QR, a DataMatrix, or an Aztec code. So it lives here,
306
+ * symbology-agnostic, and the decoders plug into it.
307
+ */
308
+ /**
309
+ * Lifecycle of one scanning session.
310
+ *
311
+ * `scanning` is the only state that consumes frames. `decoded` is terminal
312
+ * rather than a return to `scanning`: a scanner that kept reading after a
313
+ * successful decode would fire twice on the same symbol, and every consumer
314
+ * would have to debounce it. Restarting is explicit.
315
+ *
316
+ * `denied` is separate from `failed` because they are different conversations
317
+ * with the user — one asks them to change a browser setting, the other is a
318
+ * fault they cannot act on. Collapsing them is how a permission prompt ends up
319
+ * reported as "something went wrong".
320
+ */
321
+ type ScanState = `idle` | `starting` | `scanning` | `paused` | `decoded` | `denied` | `failed` | `stopped`;
322
+ /** Why a scan session ended without a result. */
323
+ type ScanFailure =
324
+ /** No camera on this device, or none matching the requested facing mode. */
325
+ `no-camera` |
326
+ /** The page is not a secure context, so `getUserMedia` is unavailable. */
327
+ `insecure-context` |
328
+ /** The camera was lost mid-session — unplugged, or claimed by another app. */
329
+ `camera-lost` |
330
+ /** The decoder itself threw. Distinct from "no code in this frame". */
331
+ `decoder-error`;
332
+ /** Events driving a scan session. */
333
+ type ScanEvent =
334
+ /** Consumer asked to begin. */
335
+ {
336
+ type: `START`;
337
+ } |
338
+ /** Camera acquired and frames are flowing. */
339
+ {
340
+ type: `READY`;
341
+ } |
342
+ /** A frame decoded successfully. Terminal — restarting is explicit. */
343
+ {
344
+ type: `DECODE`;
345
+ value: string;
346
+ } |
347
+ /** The user refused camera access. */
348
+ {
349
+ type: `DENY`;
350
+ } |
351
+ /** Something broke that the user cannot act on. */
352
+ {
353
+ type: `FAIL`;
354
+ reason: ScanFailure;
355
+ } |
356
+ /** Tab hidden, or the consumer suspended scanning. */
357
+ {
358
+ type: `PAUSE`;
359
+ } |
360
+ /** Visible again. */
361
+ {
362
+ type: `RESUME`;
363
+ } |
364
+ /** Consumer tore the session down. */
365
+ {
366
+ type: `STOP`;
367
+ };
368
+ /** Whether `event` would move `state`. */
369
+ declare const canTransitionScan: (state: ScanState, event: ScanEvent[`type`]) => boolean;
370
+ /** Apply an event. Unknown events for the current state are no-ops. */
371
+ declare const scanTransition: (state: ScanState, event: ScanEvent) => ScanState;
372
+ /**
373
+ * Terminal states accept no further events.
374
+ *
375
+ * Derived from the table rather than listed, so a new state cannot be added
376
+ * without its terminality following automatically.
377
+ */
378
+ declare const isScanSettled: (state: ScanState) => boolean;
379
+ //#endregion
380
+ export { type BitMatrix, type DecodeRequest, type DecodeResponse, type DecodedSymbol, type GpuScorer, type GrayImage, type MatrixDecodeResult, type Point, type ProgressiveOptions, type ProgressiveScanner, type QrDecoderOptions, type ScanEvent, type ScanFailure, type ScanState, type SymbolDecoder, type WorkerScanner, binarize, binarizeGlobal, blur, canTransitionScan, close, createGpuScorer, createProgressiveScanner, createQrDecoder, createWorkerScanner, decodeMatrix, downscale, hasWebGpu, isScanSettled, scanTransition, serveDecoder, toGray, withClearance };
381
+ //# sourceMappingURL=index.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/scan/qr/progressive.ts","../../src/scan/qr/locate.ts","../../src/scan/binarize.ts","../../src/scan/qr/format.ts","../../src/scan/qr/decode-matrix.ts","../../src/scan/qr/sample.ts","../../src/scan/gpu.ts","../../src/scan/machine.ts"],"mappings":";;;UA6BiB;;;;;;;EAOf,KAAK,OAAO,YAAY;;;;;;;;EASxB;;WAGS;;;UAIM,2BAA2B,KAC1C;;;;;;;EASA;;;;;;;;EASA;;;;;;;;EASA;;;;;;;;;;cAWW,6BAA4B,iBAAA,aAAA,WAAA,mBAKtC,uBAA0B;;;;;;;;;;;;;;;UA2DZ;;EAEf,KAAK,OAAO,YAAY,QAAQ;;EAEhC;;EAEA;;WAES;;;;;;;;;;cAWE,sBACX;EAIE,cAAc,kBAAkB,WAAW;EAC3C,oBACE,cACA,WAAW;IAAS;;EAEtB,MAAM,cAAc,WAAW;EAC/B;KAEF,iBAAA,aAAA,WAIG,uBACF;;;;UC7Kc;WACN,QAAQ;;WAER;;;;;;;;;cAynBE,gBACX,QAAQ,WACR,mBAAmB,oBAClB;;;;cCpmBU,SACX,MAAM,mBACN,eACA,mBACC;;;;;;;;;;;;;;;;;;;;;;cAiNU,iBACX,OAAO,aACP;EAAsB;MACrB;;;;;;;;;;;;;;;;;;cAmEU,QAAS,QAAQ,cAAY;;;;;;;;;;;;;;;;;;;cAkF7B,YAAa,OAAO,WAAW,mBAAiB;;;;;;;;;;;;;;;;;;;;cAgEhD,OAAQ,OAAO,WAAW,mBAAiB;;;;;;;;;;;;;cAmL3C,WACX,OAAO,aACP;EAAsB;MACrB;;;;KC5nBS;;;;UCKK;WACN;WACA;WACA,sBAAsB;WACtB;;;;;;;;;;cAWE,eACX,QAAQ,WAgBR;;;;;;;;;;;;;;;;AAAA,aAAa,eACZ;;;;;;;;;;;UC9Bc;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;;;UC6HM;EACf,MACE,OAAO,WACP,qBAAqB,aACrB,cACA,sCACC,QAAQ;EACX;;;cAIW;;;;;;;cASA,uBAA4B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KCxJrC;;KAWA;;;;;;;;;;KAWA;;;EAEN;;;;EAEA;;;;EAEA;EAAgB;;;;EAEhB;;;;EAEA;EAAc,QAAQ;;;;EAEtB;;;;EAEA;;;;EAEA;;;cAyCO,oBACX,OAAO,WACP,OAAO;;cAII,iBAAkB,OAAO,WAAW,OAAO,cAAY;;;;;;;cASvD,gBAAiB,OAAO"}