@embedpdf/engines 2.0.0-next.2 → 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 (82) hide show
  1. package/README.md +15 -9
  2. package/dist/browser-C6QEa8uk.cjs +2 -0
  3. package/dist/browser-C6QEa8uk.cjs.map +1 -0
  4. package/dist/browser-awZxztMA.js +76 -0
  5. package/dist/browser-awZxztMA.js.map +1 -0
  6. package/dist/{engine-B-RaFU77.js → direct-engine-DuLFAbiv.js} +211 -520
  7. package/dist/direct-engine-DuLFAbiv.js.map +1 -0
  8. package/dist/direct-engine-JeNRkc7w.cjs +2 -0
  9. package/dist/direct-engine-JeNRkc7w.cjs.map +1 -0
  10. package/dist/index.cjs +1 -1
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.js +301 -10
  13. package/dist/index.js.map +1 -1
  14. package/dist/lib/converters/browser.d.ts +33 -0
  15. package/dist/lib/converters/index.cjs +1 -1
  16. package/dist/lib/converters/index.cjs.map +1 -1
  17. package/dist/lib/converters/index.d.ts +3 -51
  18. package/dist/lib/converters/index.js +6 -1
  19. package/dist/lib/converters/index.js.map +1 -1
  20. package/dist/lib/converters/node.d.ts +51 -0
  21. package/dist/lib/converters/types.d.ts +6 -3
  22. package/dist/lib/image-encoder/image-encoder-worker.d.ts +24 -0
  23. package/dist/lib/image-encoder/index.d.ts +2 -0
  24. package/dist/lib/image-encoder/worker-pool.d.ts +61 -0
  25. package/dist/lib/orchestrator/index.d.ts +16 -0
  26. package/dist/lib/orchestrator/pdf-engine.d.ts +99 -0
  27. package/dist/lib/orchestrator/pdfium-native-runner.d.ts +65 -0
  28. package/dist/lib/orchestrator/remote-executor.d.ts +93 -0
  29. package/dist/lib/orchestrator/task-queue.d.ts +87 -0
  30. package/dist/lib/pdfium/engine.d.ts +52 -93
  31. package/dist/lib/pdfium/index.cjs +1 -1
  32. package/dist/lib/pdfium/index.cjs.map +1 -1
  33. package/dist/lib/pdfium/index.d.ts +6 -1
  34. package/dist/lib/pdfium/index.js +15 -8
  35. package/dist/lib/pdfium/index.js.map +1 -1
  36. package/dist/lib/pdfium/runner.d.ts +2 -2
  37. package/dist/lib/pdfium/web/direct-engine.cjs +1 -1
  38. package/dist/lib/pdfium/web/direct-engine.cjs.map +1 -1
  39. package/dist/lib/pdfium/web/direct-engine.d.ts +33 -2
  40. package/dist/lib/pdfium/web/direct-engine.js +5 -9
  41. package/dist/lib/pdfium/web/direct-engine.js.map +1 -1
  42. package/dist/lib/pdfium/web/worker-engine.cjs +1 -1
  43. package/dist/lib/pdfium/web/worker-engine.cjs.map +1 -1
  44. package/dist/lib/pdfium/web/worker-engine.d.ts +40 -4
  45. package/dist/lib/pdfium/web/worker-engine.js +412 -9
  46. package/dist/lib/pdfium/web/worker-engine.js.map +1 -1
  47. package/dist/lib/webworker/engine.cjs +1 -1
  48. package/dist/lib/webworker/engine.cjs.map +1 -1
  49. package/dist/lib/webworker/engine.d.ts +0 -6
  50. package/dist/lib/webworker/engine.js +0 -13
  51. package/dist/lib/webworker/engine.js.map +1 -1
  52. package/dist/lib/webworker/runner.d.ts +0 -12
  53. package/dist/pdf-engine-BVNF_Yo9.js +790 -0
  54. package/dist/pdf-engine-BVNF_Yo9.js.map +1 -0
  55. package/dist/pdf-engine-C3JeKij1.cjs +2 -0
  56. package/dist/pdf-engine-C3JeKij1.cjs.map +1 -0
  57. package/dist/preact/index.cjs +1 -1
  58. package/dist/preact/index.cjs.map +1 -1
  59. package/dist/preact/index.js +5 -13
  60. package/dist/preact/index.js.map +1 -1
  61. package/dist/react/index.cjs +1 -1
  62. package/dist/react/index.cjs.map +1 -1
  63. package/dist/react/index.js +5 -13
  64. package/dist/react/index.js.map +1 -1
  65. package/dist/shared-preact/hooks/use-pdfium-engine.d.ts +1 -0
  66. package/dist/shared-react/hooks/use-pdfium-engine.d.ts +1 -0
  67. package/dist/svelte/index.cjs +1 -1
  68. package/dist/svelte/index.cjs.map +1 -1
  69. package/dist/svelte/index.js +3 -11
  70. package/dist/svelte/index.js.map +1 -1
  71. package/dist/vue/index.cjs +1 -1
  72. package/dist/vue/index.cjs.map +1 -1
  73. package/dist/vue/index.js +3 -12
  74. package/dist/vue/index.js.map +1 -1
  75. package/package.json +3 -3
  76. package/dist/engine-B-RaFU77.js.map +0 -1
  77. package/dist/engine-CXnLqg_9.cjs +0 -2
  78. package/dist/engine-CXnLqg_9.cjs.map +0 -1
  79. package/dist/index-Cp8_nZYM.js +0 -342
  80. package/dist/index-Cp8_nZYM.js.map +0 -1
  81. package/dist/index-DuHK0qLu.cjs +0 -2
  82. package/dist/index-DuHK0qLu.cjs.map +0 -1
package/README.md CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  # @embedpdf/engines
12
12
 
13
- Pluggable rendering engines for EmbedPDF. Ships with **`PdfiumEngine`** a highlevel, promise‑first wrapper built on top of `@embedpdf/pdfium`.
13
+ Pluggable rendering engines for EmbedPDF. Ships with **`PdfiumNative`** (low-level executor) and **`PdfEngine`** (high-level orchestrator) – a promise‑first API built on top of `@embedpdf/pdfium`.
14
14
 
15
15
  ## Documentation
16
16
 
@@ -43,7 +43,8 @@ npm install @embedpdf/engines @embedpdf/pdfium
43
43
 
44
44
  ```typescript
45
45
  import { init } from '@embedpdf/pdfium';
46
- import { PdfiumEngine } from '@embedpdf/engines/pdfium';
46
+ import { PdfiumNative, PdfEngine } from '@embedpdf/engines/pdfium';
47
+ import { browserImageDataToBlobConverter } from '@embedpdf/engines/converters';
47
48
 
48
49
  const pdfiumWasm =
49
50
  'https://cdn.jsdelivr.net/npm/@embedpdf/pdfium/dist/pdfium.wasm';
@@ -51,15 +52,20 @@ const pdfiumWasm =
51
52
  (async () => {
52
53
  const response = await fetch(pdfiumWasm);
53
54
  const wasmBinary = await response.arrayBuffer();
54
- // 1 – boot the low‑level WASM module
55
- const pdfium = await init({ wasmBinary });
56
55
 
57
- // create the high‑level engine
58
- const engine = new PdfiumEngine(pdfium);
59
- engine.initialize();
56
+ // 1 boot the low‑level WASM module
57
+ const pdfiumModule = await init({ wasmBinary });
60
58
 
61
- // open & render
62
- const document = await engine
59
+ // 2 create the native executor (initializes PDFium automatically)
60
+ const native = new PdfiumNative(pdfiumModule);
61
+
62
+ // 3 – create the orchestrator with image converter
63
+ const engine = new PdfEngine(native, {
64
+ imageConverter: browserImageDataToBlobConverter,
65
+ });
66
+
67
+ // 4 – open & render
68
+ const doc = await engine
63
69
  .openDocumentUrl({ id: 'demo', url: '/demo.pdf' })
64
70
  .toPromise();
65
71
  const page0 = doc.pages[0];
@@ -0,0 +1,2 @@
1
+ "use strict";class e extends Error{constructor(e){super(e),this.name="ImageConverterError"}}const t=(t,r="image/webp",n)=>{if("undefined"==typeof document)return Promise.reject(new e("document is not available. This converter requires a browser environment."));const a=t(),o=new ImageData(a.data,a.width,a.height);return new Promise((t,a)=>{const i=document.createElement("canvas");i.width=o.width,i.height=o.height,i.getContext("2d").putImageData(o,0,0),i.toBlob(r=>{r?t(r):a(new e("Canvas toBlob returned null"))},r,n)})};exports.ImageConverterError=e,exports.browserImageDataToBlobConverter=t,exports.createHybridImageConverter=function(e){return async(r,n="image/webp",a)=>{try{const t=r(),o=new Uint8ClampedArray(t.data);return await e.encode({data:o,width:t.width,height:t.height},n,a)}catch(o){return console.warn("Worker encoding failed, falling back to main-thread Canvas:",o),t(r,n,a)}}},exports.createWorkerPoolImageConverter=function(e){return(t,r="image/webp",n)=>{const a=t(),o=new Uint8ClampedArray(a.data);return e.encode({data:o,width:a.width,height:a.height},r,n)}};
2
+ //# sourceMappingURL=browser-C6QEa8uk.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-C6QEa8uk.cjs","sources":["../src/lib/converters/browser.ts"],"sourcesContent":["import type { ImageConversionTypes } from '@embedpdf/models';\nimport type { ImageDataConverter, LazyImageData } from './types';\nimport { ImageEncoderWorkerPool } from '../image-encoder';\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\nexport class ImageConverterError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ImageConverterError';\n }\n}\n\n// ============================================================================\n// Browser Converters\n// ============================================================================\n\n/**\n * Main-thread Canvas-based image converter\n * Simple and works everywhere, but blocks the main thread during encoding\n *\n * Use this as a fallback when worker-based encoding isn't available\n */\nexport const browserImageDataToBlobConverter: ImageDataConverter<Blob> = (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n): Promise<Blob> => {\n if (typeof document === 'undefined') {\n return Promise.reject(\n new ImageConverterError(\n 'document is not available. This converter requires a browser environment.',\n ),\n );\n }\n\n const pdfImage = getImageData();\n const imageData = new ImageData(pdfImage.data, pdfImage.width, pdfImage.height);\n\n return new Promise((resolve, reject) => {\n const canvas = document.createElement('canvas');\n canvas.width = imageData.width;\n canvas.height = imageData.height;\n canvas.getContext('2d')!.putImageData(imageData, 0, 0);\n\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new ImageConverterError('Canvas toBlob returned null'));\n }\n },\n imageType,\n quality,\n );\n });\n};\n\n/**\n * Worker pool image converter using OffscreenCanvas in dedicated workers\n * Non-blocking - encoding happens off the main thread\n *\n * This is the preferred approach for performance\n *\n * @param workerPool - Instance of ImageEncoderWorkerPool\n * @returns ImageDataConverter function\n */\nexport function createWorkerPoolImageConverter(\n workerPool: ImageEncoderWorkerPool,\n): ImageDataConverter<Blob> {\n return (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n ): Promise<Blob> => {\n const pdfImage = getImageData();\n\n // Copy the data since we'll transfer it to another worker\n const dataCopy = new Uint8ClampedArray(pdfImage.data);\n\n return workerPool.encode(\n {\n data: dataCopy,\n width: pdfImage.width,\n height: pdfImage.height,\n },\n imageType,\n quality,\n );\n };\n}\n\n/**\n * Hybrid converter: Worker pool (OffscreenCanvas) → Main thread Canvas fallback\n *\n * Best of both worlds:\n * - Primary: Non-blocking worker-based encoding with OffscreenCanvas\n * - Fallback: Main-thread Canvas for older browsers without OffscreenCanvas in workers\n *\n * @param workerPool - Instance of ImageEncoderWorkerPool\n * @returns ImageDataConverter function\n */\nexport function createHybridImageConverter(\n workerPool: ImageEncoderWorkerPool,\n): ImageDataConverter<Blob> {\n return async (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n ): Promise<Blob> => {\n try {\n // Try worker pool encoding first (OffscreenCanvas in worker)\n const pdfImage = getImageData();\n const dataCopy = new Uint8ClampedArray(pdfImage.data);\n\n return await workerPool.encode(\n {\n data: dataCopy,\n width: pdfImage.width,\n height: pdfImage.height,\n },\n imageType,\n quality,\n );\n } catch (error) {\n // Fallback to main-thread Canvas\n console.warn('Worker encoding failed, falling back to main-thread Canvas:', error);\n return browserImageDataToBlobConverter(getImageData, imageType, quality);\n }\n };\n}\n"],"names":["ImageConverterError","Error","constructor","message","super","this","name","browserImageDataToBlobConverter","getImageData","imageType","quality","document","Promise","reject","pdfImage","imageData","ImageData","data","width","height","resolve","canvas","createElement","getContext","putImageData","toBlob","blob","workerPool","async","dataCopy","Uint8ClampedArray","encode","error","console","warn"],"mappings":"aAQO,MAAMA,UAA4BC,MACvC,WAAAC,CAAYC,GACVC,MAAMD,GACNE,KAAKC,KAAO,qBACd,EAaK,MAAMC,EAA4D,CACvEC,EACAC,EAAkC,aAClCC,KAEA,GAAwB,oBAAbC,SACT,OAAOC,QAAQC,OACb,IAAIb,EACF,8EAKN,MAAMc,EAAWN,IACXO,EAAY,IAAIC,UAAUF,EAASG,KAAMH,EAASI,MAAOJ,EAASK,QAExE,OAAO,IAAIP,QAAQ,CAACQ,EAASP,KAC3B,MAAMQ,EAASV,SAASW,cAAc,UACtCD,EAAOH,MAAQH,EAAUG,MACzBG,EAAOF,OAASJ,EAAUI,OAC1BE,EAAOE,WAAW,MAAOC,aAAaT,EAAW,EAAG,GAEpDM,EAAOI,OACJC,IACKA,EACFN,EAAQM,GAERb,EAAO,IAAIb,EAAoB,iCAGnCS,EACAC,iHAiDC,SACLiB,GAEA,OAAOC,MACLpB,EACAC,EAAkC,aAClCC,KAEA,IAEE,MAAMI,EAAWN,IACXqB,EAAW,IAAIC,kBAAkBhB,EAASG,MAEhD,aAAaU,EAAWI,OACtB,CACEd,KAAMY,EACNX,MAAOJ,EAASI,MAChBC,OAAQL,EAASK,QAEnBV,EACAC,EAEJ,OAASsB,GAGP,OADAC,QAAQC,KAAK,8DAA+DF,GACrEzB,EAAgCC,EAAcC,EAAWC,EAClE,EAEJ,yCA/DO,SACLiB,GAEA,MAAO,CACLnB,EACAC,EAAkC,aAClCC,KAEA,MAAMI,EAAWN,IAGXqB,EAAW,IAAIC,kBAAkBhB,EAASG,MAEhD,OAAOU,EAAWI,OAChB,CACEd,KAAMY,EACNX,MAAOJ,EAASI,MAChBC,OAAQL,EAASK,QAEnBV,EACAC,GAGN"}
@@ -0,0 +1,76 @@
1
+ class ImageConverterError extends Error {
2
+ constructor(message) {
3
+ super(message);
4
+ this.name = "ImageConverterError";
5
+ }
6
+ }
7
+ const browserImageDataToBlobConverter = (getImageData, imageType = "image/webp", quality) => {
8
+ if (typeof document === "undefined") {
9
+ return Promise.reject(
10
+ new ImageConverterError(
11
+ "document is not available. This converter requires a browser environment."
12
+ )
13
+ );
14
+ }
15
+ const pdfImage = getImageData();
16
+ const imageData = new ImageData(pdfImage.data, pdfImage.width, pdfImage.height);
17
+ return new Promise((resolve, reject) => {
18
+ const canvas = document.createElement("canvas");
19
+ canvas.width = imageData.width;
20
+ canvas.height = imageData.height;
21
+ canvas.getContext("2d").putImageData(imageData, 0, 0);
22
+ canvas.toBlob(
23
+ (blob) => {
24
+ if (blob) {
25
+ resolve(blob);
26
+ } else {
27
+ reject(new ImageConverterError("Canvas toBlob returned null"));
28
+ }
29
+ },
30
+ imageType,
31
+ quality
32
+ );
33
+ });
34
+ };
35
+ function createWorkerPoolImageConverter(workerPool) {
36
+ return (getImageData, imageType = "image/webp", quality) => {
37
+ const pdfImage = getImageData();
38
+ const dataCopy = new Uint8ClampedArray(pdfImage.data);
39
+ return workerPool.encode(
40
+ {
41
+ data: dataCopy,
42
+ width: pdfImage.width,
43
+ height: pdfImage.height
44
+ },
45
+ imageType,
46
+ quality
47
+ );
48
+ };
49
+ }
50
+ function createHybridImageConverter(workerPool) {
51
+ return async (getImageData, imageType = "image/webp", quality) => {
52
+ try {
53
+ const pdfImage = getImageData();
54
+ const dataCopy = new Uint8ClampedArray(pdfImage.data);
55
+ return await workerPool.encode(
56
+ {
57
+ data: dataCopy,
58
+ width: pdfImage.width,
59
+ height: pdfImage.height
60
+ },
61
+ imageType,
62
+ quality
63
+ );
64
+ } catch (error) {
65
+ console.warn("Worker encoding failed, falling back to main-thread Canvas:", error);
66
+ return browserImageDataToBlobConverter(getImageData, imageType, quality);
67
+ }
68
+ };
69
+ }
70
+ export {
71
+ ImageConverterError as I,
72
+ createHybridImageConverter as a,
73
+ browserImageDataToBlobConverter as b,
74
+ createWorkerPoolImageConverter as c
75
+ };
76
+ //# sourceMappingURL=browser-awZxztMA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-awZxztMA.js","sources":["../src/lib/converters/browser.ts"],"sourcesContent":["import type { ImageConversionTypes } from '@embedpdf/models';\nimport type { ImageDataConverter, LazyImageData } from './types';\nimport { ImageEncoderWorkerPool } from '../image-encoder';\n\n// ============================================================================\n// Error Classes\n// ============================================================================\n\nexport class ImageConverterError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ImageConverterError';\n }\n}\n\n// ============================================================================\n// Browser Converters\n// ============================================================================\n\n/**\n * Main-thread Canvas-based image converter\n * Simple and works everywhere, but blocks the main thread during encoding\n *\n * Use this as a fallback when worker-based encoding isn't available\n */\nexport const browserImageDataToBlobConverter: ImageDataConverter<Blob> = (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n): Promise<Blob> => {\n if (typeof document === 'undefined') {\n return Promise.reject(\n new ImageConverterError(\n 'document is not available. This converter requires a browser environment.',\n ),\n );\n }\n\n const pdfImage = getImageData();\n const imageData = new ImageData(pdfImage.data, pdfImage.width, pdfImage.height);\n\n return new Promise((resolve, reject) => {\n const canvas = document.createElement('canvas');\n canvas.width = imageData.width;\n canvas.height = imageData.height;\n canvas.getContext('2d')!.putImageData(imageData, 0, 0);\n\n canvas.toBlob(\n (blob) => {\n if (blob) {\n resolve(blob);\n } else {\n reject(new ImageConverterError('Canvas toBlob returned null'));\n }\n },\n imageType,\n quality,\n );\n });\n};\n\n/**\n * Worker pool image converter using OffscreenCanvas in dedicated workers\n * Non-blocking - encoding happens off the main thread\n *\n * This is the preferred approach for performance\n *\n * @param workerPool - Instance of ImageEncoderWorkerPool\n * @returns ImageDataConverter function\n */\nexport function createWorkerPoolImageConverter(\n workerPool: ImageEncoderWorkerPool,\n): ImageDataConverter<Blob> {\n return (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n ): Promise<Blob> => {\n const pdfImage = getImageData();\n\n // Copy the data since we'll transfer it to another worker\n const dataCopy = new Uint8ClampedArray(pdfImage.data);\n\n return workerPool.encode(\n {\n data: dataCopy,\n width: pdfImage.width,\n height: pdfImage.height,\n },\n imageType,\n quality,\n );\n };\n}\n\n/**\n * Hybrid converter: Worker pool (OffscreenCanvas) → Main thread Canvas fallback\n *\n * Best of both worlds:\n * - Primary: Non-blocking worker-based encoding with OffscreenCanvas\n * - Fallback: Main-thread Canvas for older browsers without OffscreenCanvas in workers\n *\n * @param workerPool - Instance of ImageEncoderWorkerPool\n * @returns ImageDataConverter function\n */\nexport function createHybridImageConverter(\n workerPool: ImageEncoderWorkerPool,\n): ImageDataConverter<Blob> {\n return async (\n getImageData: LazyImageData,\n imageType: ImageConversionTypes = 'image/webp',\n quality?: number,\n ): Promise<Blob> => {\n try {\n // Try worker pool encoding first (OffscreenCanvas in worker)\n const pdfImage = getImageData();\n const dataCopy = new Uint8ClampedArray(pdfImage.data);\n\n return await workerPool.encode(\n {\n data: dataCopy,\n width: pdfImage.width,\n height: pdfImage.height,\n },\n imageType,\n quality,\n );\n } catch (error) {\n // Fallback to main-thread Canvas\n console.warn('Worker encoding failed, falling back to main-thread Canvas:', error);\n return browserImageDataToBlobConverter(getImageData, imageType, quality);\n }\n };\n}\n"],"names":[],"mappings":"AAQO,MAAM,4BAA4B,MAAM;AAAA,EAC7C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAYO,MAAM,kCAA4D,CACvE,cACA,YAAkC,cAClC,YACkB;AAClB,MAAI,OAAO,aAAa,aAAa;AACnC,WAAO,QAAQ;AAAA,MACb,IAAI;AAAA,QACF;AAAA,MAAA;AAAA,IACF;AAAA,EAEJ;AAEA,QAAM,WAAW,aAAA;AACjB,QAAM,YAAY,IAAI,UAAU,SAAS,MAAM,SAAS,OAAO,SAAS,MAAM;AAE9E,SAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,UAAM,SAAS,SAAS,cAAc,QAAQ;AAC9C,WAAO,QAAQ,UAAU;AACzB,WAAO,SAAS,UAAU;AAC1B,WAAO,WAAW,IAAI,EAAG,aAAa,WAAW,GAAG,CAAC;AAErD,WAAO;AAAA,MACL,CAAC,SAAS;AACR,YAAI,MAAM;AACR,kBAAQ,IAAI;AAAA,QACd,OAAO;AACL,iBAAO,IAAI,oBAAoB,6BAA6B,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH;AAWO,SAAS,+BACd,YAC0B;AAC1B,SAAO,CACL,cACA,YAAkC,cAClC,YACkB;AAClB,UAAM,WAAW,aAAA;AAGjB,UAAM,WAAW,IAAI,kBAAkB,SAAS,IAAI;AAEpD,WAAO,WAAW;AAAA,MAChB;AAAA,QACE,MAAM;AAAA,QACN,OAAO,SAAS;AAAA,QAChB,QAAQ,SAAS;AAAA,MAAA;AAAA,MAEnB;AAAA,MACA;AAAA,IAAA;AAAA,EAEJ;AACF;AAYO,SAAS,2BACd,YAC0B;AAC1B,SAAO,OACL,cACA,YAAkC,cAClC,YACkB;AAClB,QAAI;AAEF,YAAM,WAAW,aAAA;AACjB,YAAM,WAAW,IAAI,kBAAkB,SAAS,IAAI;AAEpD,aAAO,MAAM,WAAW;AAAA,QACtB;AAAA,UACE,MAAM;AAAA,UACN,OAAO,SAAS;AAAA,UAChB,QAAQ,SAAS;AAAA,QAAA;AAAA,QAEnB;AAAA,QACA;AAAA,MAAA;AAAA,IAEJ,SAAS,OAAO;AAEd,cAAQ,KAAK,+DAA+D,KAAK;AACjF,aAAO,gCAAgC,cAAc,WAAW,OAAO;AAAA,IACzE;AAAA,EACF;AACF;"}