@u1f992/pdfdiff 0.2.1 → 0.3.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 (72) hide show
  1. package/.clang-format +3 -0
  2. package/.github/workflows/gh-pages.yml +6 -1
  3. package/LICENSE +68 -81
  4. package/dist/browser.js +1405 -3099
  5. package/dist/browser.js.map +1 -1
  6. package/dist/cli-png-worker.d.ts +13 -0
  7. package/dist/cli-png-worker.d.ts.map +1 -0
  8. package/dist/cli-png-worker.js +287 -0
  9. package/dist/cli-png-worker.js.map +1 -0
  10. package/dist/cli.js +401 -3110
  11. package/dist/cli.js.map +1 -1
  12. package/dist/core.wasm +0 -0
  13. package/dist/decode.d.ts +9 -0
  14. package/dist/decode.d.ts.map +1 -0
  15. package/dist/diff.d.ts +2 -1
  16. package/dist/diff.d.ts.map +1 -1
  17. package/dist/gs-wasm/gs.js +5821 -0
  18. package/dist/gs-wasm/gs.wasm +0 -0
  19. package/dist/gs-wasm/index.js +120 -0
  20. package/dist/gs-wasm/index.js.map +1 -0
  21. package/dist/gs-wasm/worker.js +764 -0
  22. package/dist/gs-wasm/worker.js.map +1 -0
  23. package/dist/image.d.ts.map +1 -1
  24. package/dist/index.d.ts +3 -1
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.html +6 -1
  27. package/dist/index.js +310 -3094
  28. package/dist/index.js.map +1 -1
  29. package/dist/iterable.d.ts.map +1 -1
  30. package/dist/jimp.d.ts +23 -1
  31. package/dist/jimp.d.ts.map +1 -1
  32. package/dist/pdf.d.ts +15 -4
  33. package/dist/pdf.d.ts.map +1 -1
  34. package/dist/perf.d.ts +16 -0
  35. package/dist/perf.d.ts.map +1 -0
  36. package/dist/rgba-color.d.ts.map +1 -1
  37. package/dist/squoosh_png_bg.wasm +0 -0
  38. package/dist/style.css +12 -0
  39. package/dist/transferable.d.ts +11 -0
  40. package/dist/transferable.d.ts.map +1 -0
  41. package/dist/version.d.ts +1 -1
  42. package/dist/worker.d.ts +8 -8
  43. package/dist/worker.d.ts.map +1 -1
  44. package/dist/worker.js +144 -3210
  45. package/dist/worker.js.map +1 -1
  46. package/package.json +11 -4
  47. package/rollup.config.js +83 -5
  48. package/scripts/build-wasm.sh +32 -0
  49. package/src/browser.ts +122 -9
  50. package/src/cli-png-worker.ts +42 -0
  51. package/src/cli.ts +113 -34
  52. package/src/decode.ts +15 -0
  53. package/src/diff.ts +99 -51
  54. package/src/image.ts +4 -18
  55. package/src/index.html +6 -1
  56. package/src/index.test.ts +10 -18
  57. package/src/index.ts +176 -76
  58. package/src/iterable.test.ts +0 -17
  59. package/src/iterable.ts +0 -17
  60. package/src/jimp.ts +25 -7
  61. package/src/pdf.ts +99 -62
  62. package/src/perf.ts +77 -0
  63. package/src/rgba-color.test.ts +0 -17
  64. package/src/rgba-color.ts +0 -17
  65. package/src/style.css +12 -0
  66. package/src/transferable.ts +15 -0
  67. package/src/worker.ts +106 -100
  68. package/wasm/Makefile +34 -0
  69. package/wasm/bindings.cpp +76 -0
  70. package/wasm/core.c +176 -0
  71. package/wasm/core.h +69 -0
  72. package/dist/mupdf-wasm.wasm +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"iterable.d.ts","sourceRoot":"","sources":["../src/iterable.ts"],"names":[],"mappings":"AAiBA,wBAAuB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,SAAI,8CAMpE"}
1
+ {"version":3,"file":"iterable.d.ts","sourceRoot":"","sources":["../src/iterable.ts"],"names":[],"mappings":"AAAA,wBAAuB,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,EAAE,KAAK,SAAI,8CAMpE"}
package/dist/jimp.d.ts CHANGED
@@ -1,5 +1,27 @@
1
1
  import * as jimp from "jimp";
2
- export type JimpInstance = Pick<jimp.JimpInstance, "width" | "height" | "bitmap" | "getPixelColor" | "setPixelColor" | "resize" | "composite"> & {
2
+ /**
3
+ * Narrowed view of `jimp.JimpInstance` used throughout the project.
4
+ *
5
+ * Two constraints are tightened relative to the upstream type:
6
+ *
7
+ * 1. `bitmap.data` is asserted to be `Uint8Array<ArrayBuffer>` (never
8
+ * SAB-backed). jimp allocates pixels via `Buffer`, which is always
9
+ * backed by a real ArrayBuffer in practice. Pinning the generic
10
+ * parameter here lets `sliceBackingBuffer` (and `postMessage` transfer
11
+ * lists) infer ArrayBuffer instead of ArrayBufferLike.
12
+ *
13
+ * 2. `resize` and `composite` return `JimpInstance` (this narrowed type)
14
+ * rather than upstream `jimp.JimpInstance`, so chaining preserves the
15
+ * bitmap-backing constraint above.
16
+ */
17
+ export type JimpInstance = Pick<jimp.JimpInstance, "width" | "height" | "getPixelColor" | "setPixelColor"> & {
18
+ bitmap: {
19
+ data: Uint8Array<ArrayBuffer>;
20
+ width: number;
21
+ height: number;
22
+ };
23
+ resize: (options: Parameters<jimp.JimpInstance["resize"]>[0]) => JimpInstance;
24
+ composite: (...args: Parameters<jimp.JimpInstance["composite"]>) => JimpInstance;
3
25
  getBuffer: (mime: "image/png") => ReturnType<jimp.JimpInstance["getBuffer"]>;
4
26
  getBase64: (mime: "image/png") => ReturnType<jimp.JimpInstance["getBase64"]>;
5
27
  };
@@ -1 +1 @@
1
- {"version":3,"file":"jimp.d.ts","sourceRoot":"","sources":["../src/jimp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,IAAI,CAAC,YAAY,EACf,OAAO,GACP,QAAQ,GACR,QAAQ,GACR,eAAe,GACf,eAAe,GACf,QAAQ,GACR,WAAW,CACd,GAAG;IACF,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7E,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;CAC9E,CAAC"}
1
+ {"version":3,"file":"jimp.d.ts","sourceRoot":"","sources":["../src/jimp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,IAAI,CAC7B,IAAI,CAAC,YAAY,EACjB,OAAO,GAAG,QAAQ,GAAG,eAAe,GAAG,eAAe,CACvD,GAAG;IACF,MAAM,EAAE;QACN,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC;QAC9B,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,YAAY,CAAC;IAC9E,SAAS,EAAE,CACT,GAAG,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,KAChD,YAAY,CAAC;IAClB,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAC7E,SAAS,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,UAAU,CAAC,IAAI,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;CAC9E,CAAC"}
package/dist/pdf.d.ts CHANGED
@@ -1,5 +1,16 @@
1
- import * as mupdf from "mupdf";
2
- import type { JimpInstance } from "./jimp.ts";
3
- export declare function loadPages(pdf: mupdf.Document): Generator<mupdf.PDFPage | mupdf.Page, void, unknown>;
4
- export declare function pageToImage(page: mupdf.Page, dpi: number, alpha: boolean): Promise<JimpInstance>;
1
+ /**
2
+ * Count the pages of a PDF using Ghostscript's `pdfpagecount`. Runs with
3
+ * `-dNODISPLAY` (no rendering) so it is cheap relative to a page render.
4
+ */
5
+ export declare function countPages(pdf: Uint8Array): Promise<number>;
6
+ /**
7
+ * Render an inclusive range of (0-based) pages of a PDF to PNG bytes in a single
8
+ * Ghostscript invocation, returning a map keyed by 0-based page index. Batching
9
+ * several pages per call amortizes Ghostscript's startup and PDF parsing, which
10
+ * dominate a single-page render. `alpha` selects the device: `pngalpha` keeps
11
+ * the page background transparent (so the diff can tell "no content" from
12
+ * "content" via the alpha channel), while `png16m` renders opaque. Decoding to
13
+ * RGBA is left to the caller (the diff workers) so it can run off this thread.
14
+ */
15
+ export declare function renderPageRangePng(pdf: Uint8Array, firstIndex: number, lastIndex: number, dpi: number, alpha: boolean): Promise<Map<number, Uint8Array<ArrayBuffer>>>;
5
16
  //# sourceMappingURL=pdf.d.ts.map
package/dist/pdf.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,wBAAiB,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,wDAI7C;AA8BD,wBAAsB,WAAW,CAC/B,IAAI,EAAE,KAAK,CAAC,IAAI,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,yBAcf"}
1
+ {"version":3,"file":"pdf.d.ts","sourceRoot":"","sources":["../src/pdf.ts"],"names":[],"mappings":"AAkBA;;;GAGG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CA0BjE;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,UAAU,EACf,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,WAAW,CAAC,CAAC,CAAC,CA6C/C"}
package/dist/perf.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ export type Counters = Readonly<Record<string, number>>;
2
+ export type Span = {
3
+ stop(): void;
4
+ };
5
+ type Perf = {
6
+ readonly enabled: boolean;
7
+ span(key: string): Span;
8
+ incr(key: string, delta?: number): void;
9
+ setMax(key: string, value: number): void;
10
+ merge(other: Counters): void;
11
+ dump(): Counters;
12
+ reset(): void;
13
+ };
14
+ export declare const perf: Perf;
15
+ export {};
16
+ //# sourceMappingURL=perf.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"perf.d.ts","sourceRoot":"","sources":["../src/perf.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAExD,MAAM,MAAM,IAAI,GAAG;IAAE,IAAI,IAAI,IAAI,CAAA;CAAE,CAAC;AAEpC,KAAK,IAAI,GAAG;IACV,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,KAAK,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC7B,IAAI,IAAI,QAAQ,CAAC;IACjB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAgDF,eAAO,MAAM,IAAI,EAAE,IAAuC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"rgba-color.d.ts","sourceRoot":"","sources":["../src/rgba-color.ts"],"names":[],"mappings":"AAiBA,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,qBAkCnC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,cAAc,SAAS,WAOpC,CAAC"}
1
+ {"version":3,"file":"rgba-color.d.ts","sourceRoot":"","sources":["../src/rgba-color.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzD,eAAO,MAAM,QAAQ,GAAI,KAAK,MAAM,qBAkCnC,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,cAAc,SAAS,WAOpC,CAAC"}
Binary file
package/dist/style.css CHANGED
@@ -11,9 +11,21 @@
11
11
  .diff-table {
12
12
  border: 1px solid black;
13
13
  border-collapse: collapse;
14
+ width: 100%;
15
+ table-layout: fixed;
14
16
  }
15
17
 
16
18
  .diff-table th,
17
19
  .diff-table td {
18
20
  border: 1px solid black;
19
21
  }
22
+
23
+ .diff-table img {
24
+ display: block;
25
+ max-width: 100%;
26
+ height: auto;
27
+ }
28
+
29
+ body.hide-no-diff .diff-details.no-diff {
30
+ display: none;
31
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Slice an ArrayBufferView into a standalone backing buffer of the same kind
3
+ * (ArrayBuffer in, ArrayBuffer out; SharedArrayBuffer in, SharedArrayBuffer
4
+ * out). The buffer kind is preserved through the generic parameter.
5
+ */
6
+ export declare function sliceBackingBuffer<TArrayBuffer extends ArrayBufferLike>(src: {
7
+ buffer: TArrayBuffer;
8
+ byteOffset: number;
9
+ byteLength: number;
10
+ }): TArrayBuffer;
11
+ //# sourceMappingURL=transferable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transferable.d.ts","sourceRoot":"","sources":["../src/transferable.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,YAAY,SAAS,eAAe,EAAE,GAAG,EAAE;IAC5E,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,YAAY,CAKf"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const VERSION = "0.2.1";
1
+ export declare const VERSION = "0.3.0";
2
2
  //# sourceMappingURL=version.d.ts.map
package/dist/worker.d.ts CHANGED
@@ -1,18 +1,17 @@
1
1
  import { type Pallet } from "./diff.ts";
2
2
  import { type AlignStrategy } from "./image.ts";
3
+ import { type Counters } from "./perf.ts";
3
4
  export type InitMessage = {
4
5
  type: "init";
5
- aBytes: Uint8Array;
6
- bBytes: Uint8Array;
7
- maskBytes: Uint8Array | null;
8
- dpi: number;
9
- alpha: boolean;
10
6
  pallet: Pallet;
11
7
  align: AlignStrategy;
12
8
  };
13
9
  export type PageMessage = {
14
10
  type: "page";
15
11
  index: number;
12
+ a: ArrayBuffer | null;
13
+ b: ArrayBuffer | null;
14
+ mask: ArrayBuffer | null;
16
15
  };
17
16
  export type LoadedMessage = {
18
17
  type: "loaded";
@@ -38,9 +37,10 @@ export type PageResultMessage = {
38
37
  height: number;
39
38
  data: ArrayBuffer;
40
39
  };
41
- addition: [number, number][];
42
- deletion: [number, number][];
43
- modification: [number, number][];
40
+ addition: ArrayBuffer;
41
+ deletion: ArrayBuffer;
42
+ modification: ArrayBuffer;
43
+ perf?: Counters | undefined;
44
44
  };
45
45
  export type ErrorMessage = {
46
46
  type: "error";
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AAmBA,OAAO,EAAkB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACxD,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAIpB,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,UAAU,GAAG,IAAI,CAAC;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IACxD,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IACxD,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IAC3D,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IAC7B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../src/worker.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAA+B,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7E,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAKhD,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,aAAa,CAAC;CACtB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IAGd,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACtB,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACtB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,YAAY,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IACxD,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IACxD,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC;IAC3D,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,YAAY,EAAE,WAAW,CAAC;IAC1B,IAAI,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC"}