@pixerate/editor 0.112.0 → 0.114.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.
- package/THIRD_PARTY_NOTICES.md +11 -0
- package/dist/animation-editor/index.cjs +60 -54
- package/dist/animation-editor/index.cjs.map +1 -1
- package/dist/animation-editor/index.d.cts +3 -3
- package/dist/animation-editor/index.d.ts +3 -3
- package/dist/animation-editor/index.js +14 -8
- package/dist/animation-editor/index.js.map +1 -1
- package/dist/builtin-CY97ppKM.d.cts +354 -0
- package/dist/builtin-CY97ppKM.d.ts +354 -0
- package/dist/canvas/index.cjs +3 -3
- package/dist/canvas/index.cjs.map +1 -1
- package/dist/canvas/index.js +9 -9
- package/dist/chunk-26PGXHY7.cjs +753 -0
- package/dist/chunk-26PGXHY7.cjs.map +1 -0
- package/dist/chunk-2OJACTPR.cjs +929 -0
- package/dist/chunk-2OJACTPR.cjs.map +1 -0
- package/dist/chunk-3UFGNHSP.js +929 -0
- package/dist/chunk-3UFGNHSP.js.map +1 -0
- package/dist/{chunk-YGIMK4NX.cjs → chunk-5OVJHMZQ.cjs} +757 -825
- package/dist/chunk-5OVJHMZQ.cjs.map +1 -0
- package/dist/chunk-643B2HKC.cjs +534 -0
- package/dist/chunk-643B2HKC.cjs.map +1 -0
- package/dist/chunk-6FCKOS2B.js +534 -0
- package/dist/chunk-6FCKOS2B.js.map +1 -0
- package/dist/chunk-BRLYOPLT.js +2574 -0
- package/dist/chunk-BRLYOPLT.js.map +1 -0
- package/dist/{chunk-LQEEDHOP.js → chunk-C6C5PDKU.js} +759 -761
- package/dist/chunk-C6C5PDKU.js.map +1 -0
- package/dist/chunk-DFQEX3AM.cjs +781 -0
- package/dist/chunk-DFQEX3AM.cjs.map +1 -0
- package/dist/{chunk-CZOXTEMN.js → chunk-EUVSQ25B.js} +336 -404
- package/dist/chunk-EUVSQ25B.js.map +1 -0
- package/dist/chunk-G5NMLUVF.cjs +2574 -0
- package/dist/chunk-G5NMLUVF.cjs.map +1 -0
- package/dist/chunk-LKCYANMW.js +781 -0
- package/dist/chunk-LKCYANMW.js.map +1 -0
- package/dist/{chunk-W3GXSUSQ.cjs → chunk-LPLCWZTM.cjs} +5087 -1283
- package/dist/chunk-LPLCWZTM.cjs.map +1 -0
- package/dist/chunk-MMVHBKMM.js +753 -0
- package/dist/chunk-MMVHBKMM.js.map +1 -0
- package/dist/{chunk-POGBUYWE.cjs → chunk-ST7E3NEE.cjs} +857 -859
- package/dist/chunk-ST7E3NEE.cjs.map +1 -0
- package/dist/{chunk-7VOHOPLW.cjs → chunk-TCKIXI46.cjs} +59 -59
- package/dist/{chunk-7VOHOPLW.cjs.map → chunk-TCKIXI46.cjs.map} +1 -1
- package/dist/{chunk-XIOMMGPD.cjs → chunk-TFOPHZ3U.cjs} +1 -1
- package/dist/chunk-TFOPHZ3U.cjs.map +1 -0
- package/dist/{chunk-Z4BC6M74.js → chunk-UBIXVXPR.js} +2 -2
- package/dist/{chunk-BLWCAQCW.js → chunk-VXR7XWMF.js} +4574 -770
- package/dist/chunk-VXR7XWMF.js.map +1 -0
- package/dist/{chunk-HNS7UHCM.js → chunk-XK5LZKBD.js} +1 -1
- package/dist/chunk-XK5LZKBD.js.map +1 -0
- package/dist/cms/index.cjs +146 -0
- package/dist/cms/index.cjs.map +1 -0
- package/dist/cms/index.d.cts +51 -0
- package/dist/cms/index.d.ts +51 -0
- package/dist/cms/index.js +146 -0
- package/dist/{export-DNu_Jr8p.d.ts → export-_1dUKwpF.d.ts} +326 -195
- package/dist/{export-DBba-buV.d.cts → export-b6NjCZ5-.d.cts} +326 -195
- package/dist/image-editor/index.cjs +2377 -1291
- package/dist/image-editor/index.cjs.map +1 -1
- package/dist/image-editor/index.d.cts +149 -97
- package/dist/image-editor/index.d.ts +149 -97
- package/dist/image-editor/index.js +1343 -257
- package/dist/image-editor/index.js.map +1 -1
- package/dist/opentype-BZEOSOX3.d.ts +188 -0
- package/dist/opentype-Dpe75vL5.d.cts +188 -0
- package/dist/paint/index.cjs +63 -4
- package/dist/paint/index.cjs.map +1 -1
- package/dist/paint/index.d.cts +30 -3
- package/dist/paint/index.d.ts +30 -3
- package/dist/paint/index.js +62 -3
- package/dist/paint-editor/index.cjs +146 -145
- package/dist/paint-editor/index.cjs.map +1 -1
- package/dist/paint-editor/index.d.cts +9 -8
- package/dist/paint-editor/index.d.ts +9 -8
- package/dist/paint-editor/index.js +6 -5
- package/dist/paint-editor/index.js.map +1 -1
- package/dist/raster/index.cjs +53 -3
- package/dist/raster/index.cjs.map +1 -1
- package/dist/raster/index.d.cts +62 -91
- package/dist/raster/index.d.ts +62 -91
- package/dist/raster/index.js +59 -9
- package/dist/{render-BEriFuqK.d.cts → render-B1K_OoLy.d.cts} +87 -2
- package/dist/{render-tjzKaik-.d.ts → render-CrmHOgpo.d.ts} +87 -2
- package/dist/{blending-aOE6Y3UE.d.cts → retouch-Bxkuc0KH.d.cts} +219 -2
- package/dist/{blending-DXl06NSx.d.ts → retouch-Do6tBs2H.d.ts} +219 -2
- package/dist/{surface-C8RRg_Bh.d.ts → surface-Cn30xIV6.d.cts} +6 -1
- package/dist/{surface-C8RRg_Bh.d.cts → surface-Cn30xIV6.d.ts} +6 -1
- package/dist/{svg-D_cfkhlB.d.cts → svg-BnRj0q8i.d.cts} +16 -4
- package/dist/{svg-wIaKLrU0.d.ts → svg-CmmBFfGT.d.ts} +16 -4
- package/dist/{types-DtL_qLFz.d.ts → types-1SUQKDAw.d.ts} +273 -4
- package/dist/{types-DyQq-WPY.d.cts → types-yINF17Ta.d.cts} +273 -4
- package/dist/vector/index.cjs +12170 -7343
- package/dist/vector/index.cjs.map +1 -1
- package/dist/vector/index.d.cts +1579 -16
- package/dist/vector/index.d.ts +1579 -16
- package/dist/vector/index.js +6303 -1476
- package/dist/vector/index.js.map +1 -1
- package/dist/warp-B39VsOtd.d.cts +348 -0
- package/dist/warp-DMN30aY6.d.ts +348 -0
- package/dist/zlib-dxQdgHyN.d.cts +95 -0
- package/dist/zlib-dxQdgHyN.d.ts +95 -0
- package/package.json +6 -1
- package/skills/pixerate-image-editor/SKILL.md +34 -34
- package/skills/pixerate-image-editor/references/color-management.md +37 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +39 -0
- package/skills/pixerate-image-editor/references/retouching.md +36 -0
- package/skills/pixerate-vector/SKILL.md +154 -5
- package/dist/chunk-BLWCAQCW.js.map +0 -1
- package/dist/chunk-CZOXTEMN.js.map +0 -1
- package/dist/chunk-FTBZPI77.cjs +0 -1
- package/dist/chunk-FTBZPI77.cjs.map +0 -1
- package/dist/chunk-HNS7UHCM.js.map +0 -1
- package/dist/chunk-JLYX4V57.cjs +0 -2001
- package/dist/chunk-JLYX4V57.cjs.map +0 -1
- package/dist/chunk-KB2YBCVS.js +0 -2001
- package/dist/chunk-KB2YBCVS.js.map +0 -1
- package/dist/chunk-LQEEDHOP.js.map +0 -1
- package/dist/chunk-POGBUYWE.cjs.map +0 -1
- package/dist/chunk-VKK5VS2T.js +0 -1
- package/dist/chunk-W3GXSUSQ.cjs.map +0 -1
- package/dist/chunk-XIOMMGPD.cjs.map +0 -1
- package/dist/chunk-YGIMK4NX.cjs.map +0 -1
- package/dist/homography-CZ-tFjay.d.cts +0 -50
- package/dist/homography-Ctfjoc1b.d.ts +0 -50
- package/dist/warp-CWHZzE3x.d.ts +0 -118
- package/dist/warp-D5jz_tN7.d.cts +0 -118
- /package/dist/{chunk-Z4BC6M74.js.map → chunk-UBIXVXPR.js.map} +0 -0
- /package/dist/{chunk-VKK5VS2T.js.map → cms/index.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/editor/editor/packages/core/dist/chunk-G5NMLUVF.cjs","../src/cms/math.ts","../src/cms/curve.ts","../src/cms/clut.ts","../src/cms/pipeline.ts","../src/cms/profile.ts","../src/cms/write.ts","../src/cms/transform.ts","../src/cms/synth.ts","../src/cms/builtin.ts","../src/cms/embed.ts"],"names":["v","i","KAPPA","blackPoint"],"mappings":"AAAA;AACE;AACA;AACF,wDAA6B;AAC7B;AACA;ACIO,IAAM,IAAA,EAAyC,CAAC,MAAA,EAAQ,CAAA,EAAK,MAAM,CAAA;AAGnE,IAAM,OAAA,EAAoC,CAAC,MAAA,EAAQ,KAAK,CAAA;AAMxD,IAAM,SAAA,EAAiB;AAAA,EAC5B,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,EACR,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,EACR,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC;AACV,CAAA;AAEO,SAAS,GAAA,CAAI,CAAA,EAAS,CAAA,EAAe;AAC1C,EAAA,MAAM,EAAA,EAAU;AAAA,IACd,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,IACR,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,IACR,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC;AAAA,EACV,CAAA;AACA,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,EAAK,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA;AAC1H,EAAA,OAAO,CAAA;AACT;AAEO,SAAS,KAAA,CAAM,CAAA,EAAS,CAAA,EAA4B;AACzD,EAAA,OAAO,CAAC,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AAC9J;AAEO,SAAS,GAAA,CAAI,CAAA,EAAiB;AACnC,EAAA,OAAO,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAA,CAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAA,CAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAA,CAAK,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,CAAA;AAChK;AAGO,SAAS,MAAA,CAAO,CAAA,EAAsB;AAC3C,EAAA,MAAM,EAAA,EAAI,GAAA,CAAI,CAAC,CAAA;AACf,EAAA,GAAA,CAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,EAAI,KAAA,EAAO,OAAO,IAAA;AACvD,EAAA,MAAM,EAAA,EAAI,EAAA,EAAI,CAAA;AACd,EAAA,OAAO;AAAA,IACL,CAAA,CAAE,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA;AAAA,IACtI,CAAA,CAAE,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA;AAAA,IACtI,CAAA,CAAE,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA,EAAA,CAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAC;AAAA,EACxI,CAAA;AACF;AAGO,SAAS,OAAA,CAAQ,EAAA,EAA6B;AACnD,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA;AACf,EAAA,OAAO,CAAC,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,CAAI,EAAA,EAAI,EAAA,EAAI,CAAA,EAAA,EAAK,CAAC,CAAA;AACnC;AAEA,IAAM,SAAA,EAAiB;AAAA,EACrB,CAAC,MAAA,EAAQ,MAAA,EAAQ,CAAA,MAAO,CAAA;AAAA,EACxB,CAAC,CAAA,MAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAAA,EACxB,CAAC,MAAA,EAAQ,CAAA,MAAA,EAAS,MAAM;AAC1B,CAAA;AAGO,SAAS,QAAA,CAAS,GAAA,EAAwB,GAAA,EAA8B;AAC7E,EAAA,MAAM,IAAA,EAAM,MAAA,CAAO,QAAQ,CAAA;AAC3B,EAAA,MAAM,EAAA,EAAI,KAAA,CAAM,QAAA,EAAU,GAAG,CAAA;AAC7B,EAAA,MAAM,EAAA,EAAI,KAAA,CAAM,QAAA,EAAU,GAAG,CAAA;AAC7B,EAAA,MAAM,MAAA,EAAc;AAAA,IAClB,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA;AAAA,IAClB,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAC,CAAA;AAAA,IAClB,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC;AAAA,EACpB,CAAA;AACA,EAAA,OAAO,GAAA,CAAI,GAAA,EAAK,GAAA,CAAI,KAAA,EAAO,QAAQ,CAAC,CAAA;AACtC;AAGO,SAAS,cAAA,CAAe,CAAA,EAAsB,CAAA,EAAsB,CAAA,EAAsB,KAAA,EAAuC;AACtI,EAAA,MAAM,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAA;AACpB,EAAA,MAAM,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAA;AACpB,EAAA,MAAM,GAAA,EAAK,OAAA,CAAQ,CAAC,CAAA;AACpB,EAAA,MAAM,EAAA,EAAU;AAAA,IACd,CAAC,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAC,CAAA;AAAA,IACpB,CAAC,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAC,CAAA;AAAA,IACpB,CAAC,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAA,EAAG,EAAA,CAAG,CAAC,CAAC;AAAA,EACtB,CAAA;AACA,EAAA,MAAM,IAAA,EAAM,MAAA,CAAO,CAAC,CAAA;AACpB,EAAA,GAAA,CAAI,CAAC,GAAA,EAAK,OAAO,IAAA;AACjB,EAAA,MAAM,EAAA,EAAI,KAAA,CAAM,GAAA,EAAK,KAAK,CAAA;AAC1B,EAAA,OAAO;AAAA,IACL,CAAC,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IAC/C,CAAC,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AAAA,IAC/C,CAAC,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC;AAAA,EACjD,CAAA;AACF;AAEA,IAAM,IAAA,EAAM,IAAA,EAAM,KAAA;AAClB,IAAM,MAAA,EAAQ,MAAA,EAAQ,EAAA;AAEtB,IAAM,KAAA,EAAO,CAAC,CAAA,EAAA,GAAe,EAAA,EAAI,IAAA,EAAM,IAAA,CAAK,IAAA,CAAK,CAAC,EAAA,EAAA,CAAK,MAAA,EAAQ,EAAA,EAAI,EAAA,EAAA,EAAM,GAAA;AACzE,IAAM,QAAA,EAAU,CAAC,CAAA,EAAA,GAAc;AAC7B,EAAA,MAAM,GAAA,EAAK,EAAA,EAAI,EAAA,EAAI,CAAA;AACnB,EAAA,OAAO,GAAA,EAAK,IAAA,EAAM,GAAA,EAAA,CAAM,IAAA,EAAM,EAAA,EAAI,EAAA,EAAA,EAAM,KAAA;AAC1C,CAAA;AAGO,SAAS,QAAA,CAAS,GAAA,EAAwB,MAAA,EAA2B,GAAA,EAAW;AACrF,EAAA,MAAM,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,EAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AACjC,EAAA,MAAM,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,EAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AACjC,EAAA,MAAM,GAAA,EAAK,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,EAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AACjC,EAAA,OAAO,CAAC,IAAA,EAAM,GAAA,EAAK,EAAA,EAAI,IAAA,EAAA,CAAO,GAAA,EAAK,EAAA,CAAA,EAAK,IAAA,EAAA,CAAO,GAAA,EAAK,EAAA,CAAG,CAAA;AACzD;AAGO,SAAS,QAAA,CAAS,GAAA,EAAwB,MAAA,EAA2B,GAAA,EAAW;AACrF,EAAA,MAAM,GAAA,EAAA,CAAM,GAAA,CAAI,CAAC,EAAA,EAAI,EAAA,EAAA,EAAM,GAAA;AAC3B,EAAA,MAAM,GAAA,EAAK,GAAA,EAAK,GAAA,CAAI,CAAC,EAAA,EAAI,GAAA;AACzB,EAAA,MAAM,GAAA,EAAK,GAAA,EAAK,GAAA,CAAI,CAAC,EAAA,EAAI,GAAA;AACzB,EAAA,OAAO,CAAC,OAAA,CAAQ,EAAE,EAAA,EAAI,KAAA,CAAM,CAAC,CAAA,EAAG,OAAA,CAAQ,EAAE,EAAA,EAAI,KAAA,CAAM,CAAC,CAAA,EAAG,OAAA,CAAQ,EAAE,EAAA,EAAI,KAAA,CAAM,CAAC,CAAC,CAAA;AAChF;AAGO,SAAS,QAAA,CAAS,CAAA,EAAsB,CAAA,EAA8B;AAC3E,EAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAG,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAC,CAAA;AACzD;AAGO,IAAM,YAAA,EAAc,CAAC,CAAA,EAAA,GAAc,IAAA,CAAK,KAAA,CAAM,EAAA,EAAI,KAAK,EAAA,EAAI,KAAA;AAG3D,IAAM,aAAA,EAAe,CAAA,EAAA,GAAY,CAAC,WAAA,CAAY,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,WAAA,CAAY,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,WAAA,CAAY,GAAA,CAAI,CAAC,CAAC,CAAC,CAAA;ADjCtG;AACA;AErFO,IAAM,eAAA,EAAwB,EAAE,IAAA,EAAM,WAAW,CAAA;AAGjD,SAAS,OAAA,CAAA,EAAiB;AAC/B,EAAA,OAAO,EAAE,IAAA,EAAM,YAAA,EAAc,IAAA,EAAM,CAAA,EAAG,CAAA,EAAG,CAAC,GAAA,EAAK,EAAA,EAAI,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,EAAA,EAAI,KAAA,EAAO,OAAA,EAAS,CAAA,EAAG,CAAC,EAAE,CAAA;AACrG;AAEO,IAAM,WAAA,EAAa,CAAC,CAAA,EAAA,GAAA,CAAsB,EAAE,IAAA,EAAM,OAAA,EAAS,KAAA,EAAO,EAAE,CAAA,CAAA;AAGpE,SAAS,UAAA,CAAW,IAAA,EAAsB;AAC/C,EAAA,OAAO,KAAA,IAAS,EAAA,EAAI,EAAA,EAAI,KAAA,IAAS,EAAA,EAAI,EAAA,EAAI,KAAA,IAAS,EAAA,EAAI,EAAA,EAAI,KAAA,IAAS,EAAA,EAAI,EAAA,EAAI,CAAA;AAC7E;AAEO,SAAS,eAAA,CAAgB,CAAA,EAAmB;AACjD,EAAA,OAAA,CAAQ,CAAA,CAAE,IAAA,EAAM;AAAA,IACd,KAAK,UAAA;AACH,MAAA,OAAO,IAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,MAAA,EAAQ,CAAC,EAAA,EAAI,IAAA;AAAA,IACjC,KAAK,YAAA;AACH,MAAA,OAAO,CAAA,CAAE,KAAA,IAAS,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,CAAA,CAAE,CAAC,EAAA,EAAI,CAAC,EAAA,EAAI,IAAA;AAAA,IAChD,KAAK,OAAA,EAAS;AACZ,MAAA,MAAM,EAAA,EAAI,CAAA,CAAE,KAAA,CAAM,MAAA;AAClB,MAAA,GAAA,CAAI,EAAA,EAAI,CAAA,EAAG,OAAO,IAAA;AAClB,MAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,EAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAA,CAAM,CAAC,EAAA,EAAI,EAAA,EAAA,CAAK,EAAA,EAAI,CAAA,CAAE,EAAA,GAAK,EAAA,EAAI,KAAA,EAAO,OAAO,KAAA;AACxF,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AACF;AAEA,IAAM,OAAA,EAAS,CAAC,CAAA,EAAW,CAAA,EAAA,GAA8B,EAAA,EAAI,EAAA,EAAI,CAAC,CAAA,CAAE,CAAC,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA;AAC7E,IAAM,GAAA,EAAK,CAAC,IAAA,EAAc,CAAA,EAAA,GAAe,KAAA,GAAQ,EAAA,EAAI,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAC,CAAA;AAEzE,SAAS,IAAA,CAAK,IAAA,EAAc,CAAA,EAAsB,CAAA,EAAmB;AACnE,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,EAAA,EAAI,CAAA;AAC9B,EAAA,OAAA,CAAQ,IAAA,EAAM;AAAA,IACZ,KAAK,CAAA;AACH,MAAA,OAAO,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAC,CAAC,CAAA;AAAA,IACxC,KAAK,CAAA;AACH,MAAA,OAAO,EAAA,IAAM,EAAA,GAAK,EAAA,GAAK,CAAC,EAAA,EAAI,EAAA,EAAI,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,EAAA,EAAI,CAAA;AAAA,IACrD,KAAK,CAAA;AACH,MAAA,OAAO,EAAA,IAAM,EAAA,GAAK,EAAA,GAAK,CAAC,EAAA,EAAI,EAAA,EAAI,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA,EAAI,CAAA;AAAA,IACzD,KAAK,CAAA;AACH,MAAA,GAAA,CAAI,EAAA,EAAI,EAAA,GAAK,EAAA,IAAM,EAAA,GAAK,EAAA,IAAM,CAAA,EAAG,OAAO,CAAC,IAAA,CAAK,IAAA,EAAM,CAAA,EAAG,CAAC,CAAC,CAAA;AACzD,MAAA,OAAO,EAAA,GAAK,EAAA,EAAI,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA,EAAI,CAAA;AAAA,IACzC,OAAA;AACE,MAAA,OAAO,EAAA,GAAK,EAAA,EAAI,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,EAAA,EAAI,EAAA,EAAI,EAAA,EAAI,EAAA,EAAI,CAAA;AAAA,EACnD;AACF;AAEA,SAAS,WAAA,CAAY,IAAA,EAAc,CAAA,EAAsB,CAAA,EAA0B;AACjF,EAAA,MAAM,CAAC,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAC,EAAA,EAAI,CAAA;AAC9B,EAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAC,EAAA,EAAI,KAAA,EAAO,OAAO,IAAA;AAChC,EAAA,MAAM,KAAA,EAAO,CAAC,CAAA,EAAA,GAAe,EAAA,GAAK,EAAA,EAAI,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAA,EAAI,CAAC,CAAA;AAC3D,EAAA,OAAA,CAAQ,IAAA,EAAM;AAAA,IACZ,KAAK,CAAA;AACH,MAAA,OAAO,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAA,EAAI,CAAC,CAAC,CAAA;AAAA,IAC5C,KAAK,CAAA;AACH,MAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,IAAA;AACpB,MAAA,OAAO,EAAA,GAAK,EAAA,EAAI,CAAC,EAAA,EAAI,EAAA,EAAA,CAAK,IAAA,CAAK,CAAC,EAAA,EAAI,CAAA,EAAA,EAAK,CAAA;AAAA,IAC3C,KAAK,CAAA;AACH,MAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,IAAA;AACpB,MAAA,OAAO,EAAA,GAAK,EAAA,EAAI,CAAC,EAAA,EAAI,EAAA,EAAA,CAAK,IAAA,CAAK,EAAA,EAAI,CAAC,EAAA,EAAI,CAAA,EAAA,EAAK,CAAA;AAAA,IAC/C,KAAK,CAAA,EAAG;AACN,MAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,IAAA;AACpB,MAAA,GAAA,CAAI,EAAA,EAAI,EAAA,GAAK,EAAA,IAAM,EAAA,GAAK,EAAA,IAAM,CAAA,EAAG;AAC/B,QAAA,MAAM,EAAA,EAAI,WAAA,CAAY,IAAA,EAAM,CAAA,EAAG,CAAC,CAAC,CAAA;AACjC,QAAA,OAAO,EAAA,IAAM,KAAA,EAAO,KAAA,EAAO,CAAC,CAAA;AAAA,MAC9B;AACA,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,CAAA;AAC1B,MAAA,GAAA,CAAI,EAAA,GAAK,EAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,CAAC,EAAA,EAAI,CAAA,EAAA,EAAK,CAAA;AACpC,MAAA,OAAO,EAAA,IAAM,EAAA,EAAI,EAAA,EAAI,EAAA,EAAI,CAAA;AAAA,IAC3B;AAAA,IACA,OAAA,EAAS;AACP,MAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,IAAA;AACpB,MAAA,MAAM,GAAA,EAAK,EAAA,CAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,CAAC,EAAA,EAAI,CAAA;AAC9B,MAAA,GAAA,CAAI,EAAA,GAAK,EAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,EAAA,EAAI,CAAC,EAAA,EAAI,CAAA,EAAA,EAAK,CAAA;AACxC,MAAA,OAAO,EAAA,IAAM,EAAA,EAAA,CAAK,EAAA,EAAI,CAAA,EAAA,EAAK,EAAA,EAAI,CAAA;AAAA,IACjC;AAAA,EACF;AACF;AAGA,SAAS,cAAA,CAAe,CAAA,EAA0B,CAAA,EAAmB;AACnE,EAAA,MAAM,WAAA,EAAa,CAAA,CAAE,CAAC,EAAA,GAAK,CAAA,CAAE,CAAC,CAAA;AAC9B,EAAA,IAAI,GAAA,EAAK,CAAA;AACT,EAAA,IAAI,GAAA,EAAK,CAAA;AACT,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,EAAA,EAAI,CAAA,EAAA,EAAK;AAC3B,IAAA,MAAM,IAAA,EAAM,IAAA,EAAA,CAAO,GAAA,EAAK,EAAA,CAAA;AACxB,IAAA,GAAA,CAAI,CAAA,CAAE,GAAG,EAAA,EAAI,EAAA,IAAM,UAAA,EAAY,GAAA,EAAK,GAAA;AAAA,IAAA,KAC/B,GAAA,EAAK,GAAA;AAAA,EACZ;AACA,EAAA,OAAO,IAAA,EAAA,CAAO,GAAA,EAAK,EAAA,CAAA;AACrB;AAEA,SAAS,KAAA,CAAM,CAAA,EAAiB,CAAA,EAAmB;AACjD,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,MAAA;AACZ,EAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,CAAA;AACpB,EAAA,GAAA,CAAI,EAAA,IAAM,CAAA,EAAG,OAAO,CAAA,CAAE,CAAC,CAAA;AACvB,EAAA,MAAM,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAC,CAAC,EAAA,EAAA,CAAK,EAAA,EAAI,CAAA,CAAA;AAC/C,EAAA,MAAM,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,GAAG,CAAC,CAAA;AACzC,EAAA,MAAM,EAAA,EAAI,IAAA,EAAM,CAAA;AAChB,EAAA,OAAO,CAAA,CAAE,CAAC,EAAA,EAAA,CAAK,CAAA,CAAE,EAAA,EAAI,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA,EAAA,EAAK,CAAA;AACpC;AAEA,SAAS,SAAA,CAAU,CAAA,EAAiB,KAAA,EAAwB;AAC1D,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,MAAA;AACZ,EAAA,GAAA,CAAI,KAAA,EAAO;AACT,IAAA,MAAMA,GAAAA,EAAI,CAAA,CAAE,CAAC,CAAA;AACb,IAAA,IAAIC,GAAAA,EAAI,EAAA,EAAI,CAAA;AACZ,IAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,EAAK;AAC1B,MAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,CAAC,EAAA,EAAID,EAAC,EAAA,EAAI,IAAA,EAAM;AAC7B,QAAAC,GAAAA,EAAI,EAAA,EAAI,CAAA;AACR,QAAA,KAAA;AAAA,MACF;AAAA,IACF;AACA,IAAA,OAAOA,GAAAA,EAAAA,CAAK,EAAA,EAAI,CAAA,CAAA;AAAA,EAClB;AACA,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,CAAC,CAAA;AACjB,EAAA,IAAI,EAAA,EAAI,CAAA;AACR,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,EAAA,EAAI,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AAC/B,IAAA,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,CAAC,EAAA,EAAI,CAAC,EAAA,EAAI,IAAA,EAAM;AAC7B,MAAA,EAAA,EAAI,EAAA,EAAI,CAAA;AACR,MAAA,KAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,EAAA,EAAA,CAAK,EAAA,EAAI,CAAA,CAAA;AAClB;AAGA,SAAS,YAAA,CAAa,CAAA,EAAiB,CAAA,EAAmB;AACxD,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,MAAA;AACZ,EAAA,GAAA,CAAI,EAAA,EAAI,CAAA,EAAG,OAAO,CAAA;AAClB,EAAA,MAAM,WAAA,EAAa,CAAA,CAAE,EAAA,EAAI,CAAC,EAAA,GAAK,CAAA,CAAE,CAAC,CAAA;AAClC,EAAA,MAAM,IAAA,EAAM,WAAA,EAAa,CAAA,CAAE,CAAC,EAAA,EAAI,CAAA,CAAE,EAAA,EAAI,CAAC,CAAA;AACvC,EAAA,MAAM,IAAA,EAAM,WAAA,EAAa,CAAA,CAAE,EAAA,EAAI,CAAC,EAAA,EAAI,CAAA,CAAE,CAAC,CAAA;AACvC,EAAA,GAAA,CAAI,EAAA,GAAK,GAAA,EAAK,OAAO,SAAA,CAAU,CAAA,EAAG,UAAU,CAAA;AAC5C,EAAA,GAAA,CAAI,EAAA,GAAK,GAAA,EAAK,OAAO,SAAA,CAAU,CAAA,EAAG,CAAC,UAAU,CAAA;AAC7C,EAAA,IAAI,GAAA,EAAK,CAAA;AACT,EAAA,IAAI,GAAA,EAAK,EAAA,EAAI,CAAA;AACb,EAAA,MAAA,CAAO,GAAA,EAAK,GAAA,EAAK,CAAA,EAAG;AAClB,IAAA,MAAM,IAAA,EAAO,GAAA,EAAK,GAAA,GAAO,CAAA;AACzB,IAAA,GAAA,CAAI,CAAA,CAAE,GAAG,EAAA,EAAI,EAAA,IAAM,UAAA,EAAY,GAAA,EAAK,GAAA;AAAA,IAAA,KAC/B,GAAA,EAAK,GAAA;AAAA,EACZ;AACA,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,EAAE,CAAA;AACd,EAAA,MAAM,EAAA,EAAI,CAAA,CAAE,EAAE,CAAA;AACd,EAAA,MAAM,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,CAAC,EAAA,EAAI,MAAA,EAAA,CAAS,EAAA,EAAI,CAAA,EAAA,EAAA,CAAM,EAAA,EAAI,CAAA,EAAA,EAAK,GAAA;AACxD,EAAA,OAAA,CAAQ,GAAA,EAAK,CAAA,EAAA,EAAA,CAAM,EAAA,EAAI,CAAA,CAAA;AACzB;AAGO,SAAS,SAAA,CAAU,CAAA,EAAU,CAAA,EAAmB;AACrD,EAAA,OAAA,CAAQ,CAAA,CAAE,IAAA,EAAM;AAAA,IACd,KAAK,UAAA;AACH,MAAA,OAAO,CAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAC9C,KAAK,YAAA;AACH,MAAA,OAAO,IAAA,CAAK,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,CAAA,EAAG,CAAC,CAAA;AAAA,IAC5B,KAAK,OAAA;AACH,MAAA,OAAO,KAAA,CAAM,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA;AAAA,EAC3B;AACF;AAGO,SAAS,gBAAA,CAAiB,CAAA,EAAU,CAAA,EAAmB;AAC5D,EAAA,OAAA,CAAQ,CAAA,CAAE,IAAA,EAAM;AAAA,IACd,KAAK,UAAA;AACH,MAAA,OAAO,CAAA;AAAA,IACT,KAAK,OAAA;AACH,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,KAAK,EAAA,EAAI,MAAA,EAAQ,EAAA,EAAI,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAA,EAAI,CAAA,CAAE,KAAK,CAAC,CAAA;AAAA,IAClF,KAAK,YAAA;AACH,MAAA,wBAAO,WAAA,CAAY,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,CAAA,EAAG,CAAC,CAAA,UAAK,cAAA,CAAe,CAAC,CAAA,EAAA,GAAM,IAAA,CAAK,CAAA,CAAE,IAAA,EAAM,CAAA,CAAE,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,GAAA;AAAA,IACrF,KAAK,OAAA;AACH,MAAA,OAAO,YAAA,CAAa,CAAA,CAAE,KAAA,EAAO,CAAC,CAAA;AAAA,EAClC;AACF;AAGO,SAAS,WAAA,CAAY,CAAA,EAAU,CAAA,EAAyB;AAC7D,EAAA,MAAM,IAAA,EAAM,IAAI,YAAA,CAAa,CAAC,CAAA;AAC9B,EAAA,IAAA,CAAA,IAAS,EAAA,EAAI,CAAA,EAAG,EAAA,EAAI,CAAA,EAAG,CAAA,EAAA,EAAK,GAAA,CAAI,CAAC,EAAA,EAAI,SAAA,CAAU,CAAA,EAAG,EAAA,EAAA,CAAK,EAAA,EAAI,CAAA,CAAE,CAAA;AAC7D,EAAA,OAAO,GAAA;AACT;AFkEA;AACA;AGpQO,IAAM,aAAA,EAAe,EAAA;AAErB,IAAM,KAAA,YAAN,MAAM,MAAK;AAAA,EAIhB,WAAA,CACW,IAAA,EACA,OAAA,EACA,IAAA,EACT;AAHS,IAAA,IAAA,CAAA,KAAA,EAAA,IAAA;AACA,IAAA,IAAA,CAAA,QAAA,EAAA,OAAA;AACA,IAAA,IAAA,CAAA,KAAA,EAAA,IAAA;AAET,IAAA,MAAM,OAAA,EAAS,IAAA,CAAK,MAAA;AACpB,IAAA,GAAA,CAAI,OAAA,EAAS,EAAA,GAAK,OAAA,EAAS,aAAA,GAAgB,QAAA,EAAU,EAAA,GAAK,QAAA,EAAU,YAAA,EAAc,MAAM,IAAI,UAAA,CAAW,qBAAqB,CAAA;AAC5H,IAAA,IAAA,CAAK,OAAA,EAAS,MAAA;AACd,IAAA,IAAA,CAAK,QAAA,EAAU,IAAI,KAAA,CAAM,MAAM,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA;AACvC,IAAA,IAAI,EAAA,EAAI,OAAA;AACR,IAAA,IAAA,CAAA,IAAS,EAAA,EAAI,OAAA,EAAS,CAAA,EAAG,EAAA,GAAK,CAAA,EAAG,CAAA,EAAA,EAAK;AACpC,MAAA,IAAA,CAAK,OAAA,CAAQ,CAAC,EAAA,EAAI,CAAA;AAClB,MAAA,EAAA,GAAK,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,CAAC,CAAC,CAAA;AAAA,IAC1B;AACA,IAAA,GAAA,CAAI,IAAA,CAAK,OAAA,IAAW,CAAA,EAAG,MAAM,IAAI,UAAA,CAAW,CAAA,iBAAA,EAAoB,IAAA,CAAK,MAAM,CAAA,WAAA,EAAc,CAAC,CAAA,CAAA;AAC5F,EAAA;AAdW,EAAA;AACA,EAAA;AACA,EAAA;AANF,EAAA;AACA,EAAA;AAmBW,EAAA;AACa,IAAA;AACjC,EAAA;AAAA;AAG0G,EAAA;AACpF,IAAA;AACwB,IAAA;AACC,IAAA;AACT,IAAA;AACD,IAAA;AACM,IAAA;AAC7B,MAAA;AAC4B,MAAA;AACf,QAAA;AACS,QAAA;AAChC,MAAA;AACiF,MAAA;AACvB,MAAA;AAC5D,IAAA;AACmC,IAAA;AACrC,EAAA;AAAA;AAG6D,EAAA;AACtC,IAAA;AACV,IAAA;AACA,MAAA;AACI,MAAA;AACA,MAAA;AACb,MAAA;AACF,IAAA;AAC6C,IAAA;AACN,IAAA;AACZ,IAAA;AACV,IAAA;AACU,IAAA;AAC7B,EAAA;AAE0D,iBAAA;AACP,kBAAA;AACA,kBAAA;AAEgB,EAAA;AAClD,IAAA;AACM,IAAA;AACX,MAAA;AACuB,QAAA;AACX,QAAA;AACqB,QAAA;AACZ,UAAA;AACgB,UAAA;AAClB,UAAA;AACzB,QAAA;AACA,QAAA;AACF,MAAA;AACK,MAAA;AAC0B,QAAA;AACA,QAAA;AACA,QAAA;AACyC,QAAA;AACtE,QAAA;AACM,MAAA;AACuB,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACQ,QAAA;AACvB,QAAA;AACA,QAAA;AACgD,QAAA;AACxC,QAAA;AAC+C,UAAA;AACiB,UAAA;AACtB,QAAA;AAChE,QAAA;AACF,MAAA;AACA,MAAA;AACiC,QAAA;AACnC,IAAA;AACF,EAAA;AAAA;AAGgI,EAAA;AAC/G,IAAA;AACiD,IAAA;AAC/C,IAAA;AACE,IAAA;AACL,IAAA;AACE,MAAA;AACP,QAAA;AAAS,QAAA;AAAU,QAAA;AAAW,QAAA;AAAS,QAAA;AAAS,QAAA;AAClC,MAAA;AACd,QAAA;AAAc,QAAA;AAAS,QAAA;AAAW,QAAA;AAAS,QAAA;AAAS,QAAA;AACpD,MAAA;AACA,QAAA;AAAc,QAAA;AAAS,QAAA;AAAW,QAAA;AAAS,QAAA;AAAS,QAAA;AAC3D,MAAA;AACmB,IAAA;AACd,MAAA;AAAS,MAAA;AAAU,MAAA;AAAW,MAAA;AAAS,MAAA;AAAS,MAAA;AAClC,IAAA;AACd,MAAA;AAAc,MAAA;AAAS,MAAA;AAAW,MAAA;AAAS,MAAA;AAAS,MAAA;AACpD,IAAA;AACA,MAAA;AAAc,MAAA;AAAS,MAAA;AAAW,MAAA;AAAS,MAAA;AAAS,MAAA;AAC3D,IAAA;AACuC,IAAA;AAChB,MAAA;AACK,MAAA;AACA,MAAA;AACA,MAAA;AACkC,MAAA;AAC9D,IAAA;AACF,EAAA;AAE8E,EAAA;AAC7D,IAAA;AACJ,IAAA;AACU,IAAA;AACA,IAAA;AACH,IAAA;AACU,IAAA;AACG,MAAA;AAClB,MAAA;AACD,MAAA;AACA,MAAA;AACZ,IAAA;AACe,IAAA;AACsB,IAAA;AACW,IAAA;AACtC,MAAA;AACE,MAAA;AACkB,MAAA;AACH,QAAA;AACb,UAAA;AACE,UAAA;AACO,QAAA;AACrB,MAAA;AACa,MAAA;AAC8C,MAAA;AAC7D,IAAA;AACF,EAAA;AACF;AH6R+F;AACA;AI5bvE;AAsBE;AACG;AACC;AAC0B;AAEhB;AACuD,EAAA;AAC/F;AAG0D;AACmB,EAAA;AAC7E;AAEkB;AACI;AAEwG;AAC5G,EAAA;AACT,IAAA;AACyE,MAAA;AACrE,MAAA;AACJ,IAAA;AACgF,MAAA;AAC5E,MAAA;AACM,IAAA;AACoB,MAAA;AACX,QAAA;AAC6C,QAAA;AACxD,QAAA;AACX,MAAA;AAC6C,MAAA;AACpC,MAAA;AACX,IAAA;AACa,IAAA;AACC,MAAA;AACqC,MAAA;AAC7B,MAAA;AAC+B,MAAA;AAC1C,MAAA;AACX,IAAA;AACmB,IAAA;AACQ,MAAA;AACF,MAAA;AACA,MAAA;AACK,MAAA;AACP,QAAA;AACqBC,QAAAA;AAC1C,MAAA;AACuB,MAAA;AACA,MAAA;AACA,MAAA;AAChB,MAAA;AACT,IAAA;AACmB,IAAA;AACqD,MAAA;AAC/B,MAAA;AACA,MAAA;AACA,MAAA;AACrB,MAAA;AACC,MAAA;AACA,MAAA;AACZ,MAAA;AACT,IAAA;AACK,IAAA;AACK,MAAA;AACY,MAAA;AACA,MAAA;AACb,MAAA;AACJ,IAAA;AACsB,MAAA;AACQ,MAAA;AACA,MAAA;AAC1B,MAAA;AACJ,IAAA;AACK,MAAA;AACc,MAAA;AACA,MAAA;AACf,MAAA;AACJ,IAAA;AACuB,MAAA;AACS,MAAA;AACA,MAAA;AAC5B,MAAA;AACJ,IAAA;AACiC,MAAA;AAC7B,MAAA;AACJ,IAAA;AACwD,MAAA;AACpD,MAAA;AACJ,IAAA;AAC4C,MAAA;AACxC,MAAA;AACX,EAAA;AACF;AAGsB;AAUlB,EAAA;AAFS,IAAA;AACF,IAAA;AAE0D,IAAA;AACnE,EAAA;AAJW,EAAA;AACF,EAAA;AART,EAAA;AAC8C,kBAAA;AACE,kBAAA;AACE,kBAAA;AACC,kBAAA;AASrB,EAAA;AACJ,IAAA;AACqB,MAAA;AACzB,MAAA;AACpB,IAAA;AACF,EAAA;AAAA;AAGkF,EAAA;AACjE,IAAA;AACqC,IAAA;AACvC,IAAA;AACuE,IAAA;AACjC,IAAA;AACrD,EAAA;AAAA;AAGiB,EAAA;AACO,IAAA;AACO,IAAA;AAE2C,MAAA;AAE5D,MAAA;AACqB,MAAA;AACgB,MAAA;AAC/B,MAAA;AACd,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACa,MAAA;AACF,MAAA;AACH,QAAA;AACR,QAAA;AACF,MAAA;AACqF,MAAA;AACpE,QAAA;AACH,QAAA;AACiB,QAAA;AACT,QAAA;AACQ,QAAA;AACyD,UAAA;AACC,UAAA;AACtF,QAAA;AACQ,QAAA;AACqD,QAAA;AAC7D,QAAA;AACF,MAAA;AACU,MAAA;AACZ,IAAA;AACc,IAAA;AACqD,IAAA;AACrE,EAAA;AACF;AJ6Z+F;AACA;AKzlBF;AAES;AAE/C;AACmB;AAGtC;AACL,EAAA;AACd,IAAA;AACD,IAAA;AACd,EAAA;AACF;AAIuH;AAEN;AAKlE;AACrC,EAAA;AACA,EAAA;AACA,EAAA;AACF,EAAA;AACE,EAAA;AACA,EAAA;AACF,EAAA;AACE,EAAA;AACA,EAAA;AACF,EAAA;AACE,EAAA;AACV;AAE6C;AACL,EAAA;AACJ,EAAA;AACC,EAAA;AAC5B,EAAA;AACT;AAEgD;AACgB,EAAA;AACzC,EAAA;AACQ,EAAA;AAC2B,EAAA;AACjD,EAAA;AACT;AAGqD;AAC1B,EAAA;AACA,EAAA;AACG,EAAA;AACC,EAAA;AACH,EAAA;AAC5B;AA0CoD;AACjB,EAAA;AACnC;AAGuC;AAMM;AACyC,EAAA;AAC3E,EAAA;AACX;AAGoD;AACuC,EAAA;AAC3F;AAEkG;AAEhC;AACzB,EAAA;AACzC;AAGoF;AACnD,EAAA;AAC+B,EAAA;AAChE;AAEmD;AACF,EAAA;AAC+B,EAAA;AAChF;AAEmD;AACF,EAAA;AAC+B,EAAA;AAChF;AAGuF;AACvD,EAAA;AAC8C,EAAA;AACtD,EAAA;AACf,IAAA;AACsF,MAAA;AACA,MAAA;AAC9E,IAAA;AACmD,MAAA;AAC0B,MAAA;AACF,MAAA;AACxF,IAAA;AACK,IAAA;AACsD,MAAA;AACtD,IAAA;AACmD,MAAA;AACxD,IAAA;AACgE,MAAA;AAClE,EAAA;AACF;AAGuF;AACvD,EAAA;AAC8C,EAAA;AACtD,EAAA;AACR,IAAA;AAC+E,MAAA;AAC9D,MAAA;AAC4B,MAAA;AACiC,MAAA;AAC1F,IAAA;AACa,IAAA;AACmD,MAAA;AAC2B,MAAA;AACJ,MAAA;AACvF,IAAA;AACK,IAAA;AACsD,MAAA;AACtD,IAAA;AACmD,MAAA;AACxD,IAAA;AACgE,MAAA;AAClE,EAAA;AACF;AAGsD;AAChD,EAAA;AACiF,IAAA;AAC5E,IAAA;AACD,EAAA;AACC,IAAA;AACT,EAAA;AACF;AAMsD;AACV,EAAA;AAChC,EAAA;AACE,EAAA;AACL,EAAA;AACF,IAAA;AACS,IAAA;AACiB,IAAA;AACrB,IAAA;AACuB,MAAA;AACA,MAAA;AACA,MAAA;AAC/B,IAAA;AACa,IAAA;AACJ,IAAA;AACa,IAAA;AACA,IAAA;AACf,IAAA;AACT,EAAA;AACF;AAMa;AACyB,EAAA;AAAf,IAAA;AAAgB,EAAA;AAAhB,EAAA;AACiB,EAAA;AACoC,IAAA;AAC1E,EAAA;AAC4C,EAAA;AACvB,IAAA;AACkB,IAAA;AACvC,EAAA;AACwB,EAAA;AACL,IAAA;AACA,IAAA;AACnB,EAAA;AACyB,EAAA;AACN,IAAA;AACyB,IAAA;AAC5C,EAAA;AACyB,EAAA;AACN,IAAA;AAC8E,IAAA;AACjG,EAAA;AAC4B,EAAA;AACG,IAAA;AAC/B,EAAA;AACuB,EAAA;AAC+C,IAAA;AACtE,EAAA;AACwC,EAAA;AACY,IAAA;AACpD,EAAA;AACF;AAGoC;AAGqB;AACc,EAAA;AACxC,EAAA;AACwB,EAAA;AAC1B,EAAA;AAEgD,EAAA;AAChC,EAAA;AACQ,EAAA;AACA,EAAA;AACL,EAAA;AAClB,EAAA;AACiB,EAAA;AACiB,EAAA;AACvC,EAAA;AACkD,EAAA;AAC1B,EAAA;AACf,EAAA;AACV,IAAA;AACI,IAAA;AACsC,IAAA;AAChE,EAAA;AACoD,EAAA;AAC5B,IAAA;AACW,IAAA;AACnC,EAAA;AAC6C,EAAA;AACtB,IAAA;AACN,IAAA;AACQ,IAAA;AAC4C,IAAA;AACpD,IAAA;AACjB,EAAA;AACgD,EAAA;AACzB,IAAA;AACS,IAAA;AAChC,EAAA;AAC4D,EAAA;AAC9B,EAAA;AAC1B,EAAA;AACwB,IAAA;AACpB,EAAA;AACO,IAAA;AACf,EAAA;AACwB,EAAA;AACC,EAAA;AAC2C,EAAA;AAC1C,IAAA;AACjB,IAAA;AACsC,MAAA;AACC,MAAA;AACA,MAAA;AAC9C,IAAA;AACF,EAAA;AACwB,EAAA;AACA,EAAA;AACA,EAAA;AAGlB,EAAA;AACsB,IAAA;AACA,IAAA;AACA,IAAA;AAEtB,EAAA;AACoB,EAAA;AACA,EAAA;AACA,EAAA;AACgD,EAAA;AAC3C,EAAA;AACwB,EAAA;AAChC,IAAA;AACS,IAAA;AAChC,EAAA;AACoF,EAAA;AACG,EAAA;AAC5D,EAAA;AACA,EAAA;AACR,EAAA;AACjB,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACsC,IAAA;AACF,IAAA;AACpC,IAAA;AACAC,IAAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACmB,IAAA;AACrB,EAAA;AAEoC,EAAA;AACyC,EAAA;AACkB,EAAA;AACC,EAAA;AACzF,EAAA;AACT;AAGoD;AAC5B,EAAA;AACG,EAAA;AACJ,EAAA;AACF,IAAA;AACI,IAAA;AACmB,IAAA;AACa,IAAA;AACoB,IAAA;AACxD,IAAA;AACW,IAAA;AAC2B,IAAA;AACf,IAAA;AAC1C,EAAA;AACqB,EAAA;AACC,IAAA;AACqE,IAAA;AAChE,IAAA;AACK,IAAA;AACwB,IAAA;AAC6B,IAAA;AACrF,EAAA;AACkE,EAAA;AACpE;AAEuE;AAC/C,EAAA;AACd,EAAA;AACoB,EAAA;AACsC,IAAA;AACvB,IAAA;AAC/B,IAAA;AACQ,IAAA;AACpB,EAAA;AACO,EAAA;AACT;AAEoD;AAC5B,EAAA;AACC,EAAA;AACa,EAAA;AACd,IAAA;AACJ,IAAA;AACA,IAAA;AACC,IAAA;AACqD,IAAA;AACtD,IAAA;AAC2B,MAAA;AACA,MAAA;AACA,MAAA;AAC3C,IAAA;AAC+B,IAAA;AACC,IAAA;AACV,IAAA;AAC6D,IAAA;AAC5D,IAAA;AACqC,IAAA;AACnC,MAAA;AACW,MAAA;AACqC,MAAA;AACb,MAAA;AACnD,MAAA;AACT,IAAA;AACwD,IAAA;AAClC,MAAA;AACY,MAAA;AACmB,QAAA;AACpC,QAAA;AACf,MAAA;AACO,MAAA;AACT,IAAA;AAC8B,IAAA;AACH,IAAA;AAC8D,IAAA;AACvD,IAAA;AACf,IAAA;AACa,IAAA;AACP,IAAA;AAC+D,IAAA;AAEnC,IAAA;AACL,IAAA;AAC2B,IAAA;AAC1B,IAAA;AACqB,IAAA;AACxE,EAAA;AACoC,EAAA;AAClB,IAAA;AACA,IAAA;AAC2C,IAAA;AACxC,IAAA;AACA,IAAA;AACC,IAAA;AACD,IAAA;AACA,IAAA;AACmB,IAAA;AACf,MAAA;AACkC,MAAA;AACiC,MAAA;AAC1F,IAAA;AAC+D,IAAA;AACrC,MAAA;AACM,MAAA;AACN,QAAA;AACgD,QAAA;AAC1D,QAAA;AACd,MAAA;AACyB,MAAA;AACmB,MAAA;AACW,MAAA;AACjC,MAAA;AACa,MAAA;AACnB,MAAA;AACQ,QAAA;AACqC,QAAA;AACtC,MAAA;AACK,QAAA;AACyC,QAAA;AACE,MAAA;AACf,MAAA;AAC1D,IAAA;AACyB,IAAA;AACN,IAAA;AAEH,MAAA;AACqB,QAAA;AAC8B,QAAA;AACrC,QAAA;AACW,MAAA;AACzB,MAAA;AACoD,QAAA;AAC1C,QAAA;AACxB,MAAA;AACgF,MAAA;AACjB,MAAA;AAC1D,IAAA;AAE2E,MAAA;AACjB,MAAA;AACjD,MAAA;AACU,QAAA;AAC0C,QAAA;AAClE,MAAA;AACc,MAAA;AACqB,QAAA;AACP,QAAA;AACqC,QAAA;AAC1B,MAAA;AACzC,IAAA;AACmD,IAAA;AACrD,EAAA;AAC8D,EAAA;AAChE;AAG0C;AACpC,EAAA;AACoB,IAAA;AACC,IAAA;AACU,IAAA;AACV,MAAA;AAC+C,MAAA;AACtE,IAAA;AAC8E,IAAA;AACjC,IAAA;AAC1B,IAAA;AACA,MAAA;AACI,MAAA;AACe,MAAA;AACO,MAAA;AACtB,QAAA;AACM,QAAA;AACF,QAAA;AACA,QAAA;AACK,QAAA;AACV,UAAA;AACG,UAAA;AACrB,QAAA;AACF,MAAA;AACkB,MAAA;AACgB,MAAA;AACxB,MAAA;AACiF,MAAA;AACvD,MAAA;AACtC,IAAA;AACM,EAAA;AACC,IAAA;AACT,EAAA;AACO,EAAA;AACT;ALof+F;AACA;AM5iCnF;AACuB,kBAAA;AACxB,kBAAA;AACe,EAAA;AACkB,IAAA;AACZ,IAAA;AACS,IAAA;AACN,IAAA;AACW,IAAA;AAC/B,IAAA;AACb,EAAA;AACmB,EAAA;AACC,IAAA;AAC+B,IAAA;AACnD,EAAA;AACe,EAAA;AACI,IAAA;AACnB,EAAA;AACe,EAAA;AACyB,IAAA;AACxC,EAAA;AACiB,EAAA;AAC2C,IAAA;AAC5D,EAAA;AACe,EAAA;AACqB,IAAA;AACpC,EAAA;AACqB,EAAA;AACD,IAAA;AACS,IAAA;AACV,IAAA;AACnB,EAAA;AACO,EAAA;AAC4B,IAAA;AACnC,EAAA;AAC6B,EAAA;AACN,IAAA;AACW,IAAA;AACD,IAAA;AACR,IAAA;AACzB,EAAA;AACqB,EAAA;AACiB,IAAA;AACtC,EAAA;AACF;AAE0E;AAEvB;AAC7B,EAAA;AACN,EAAA;AACP,EAAA;AACmB,EAAA;AACV,EAAA;AAClB;AAEwC;AAClB,EAAA;AACN,EAAA;AACP,EAAA;AACA,EAAA;AACC,EAAA;AACM,EAAA;AACO,EAAA;AACb,EAAA;AACsD,EAAA;AAC9C,EAAA;AAClB;AAEyC;AACnB,EAAA;AACJ,EAAA;AACT,IAAA;AACW,MAAA;AACP,MAAA;AACA,MAAA;AACP,MAAA;AACG,IAAA;AACW,MAAA;AACP,MAAA;AACA,MAAA;AACM,MAAA;AACb,MAAA;AACG,IAAA;AACW,MAAA;AACP,MAAA;AACK,MAAA;AACL,MAAA;AACkD,MAAA;AACzD,MAAA;AACG,IAAA;AACW,MAAA;AACP,MAAA;AACa,MAAA;AACkB,MAAA;AACtC,MAAA;AACJ,EAAA;AACgB,EAAA;AAClB;AAEuD;AACyB,EAAA;AAChF;AAEuC;AAC7B,EAAA;AAC6E,EAAA;AACjD,EAAA;AACtC;AAEwG;AAC9F,EAAA;AACmB,EAAA;AACL,EAAA;AACgD,EAAA;AACxD,IAAA;AACR,IAAA;AACN,EAAA;AACgC,EAAA;AACyD,EAAA;AACpC,EAAA;AACvD;AAEsE;AACvC,EAAA;AACV,EAAA;AACS,EAAA;AACP,EAAA;AACwB,EAAA;AACzB,EAAA;AACU,EAAA;AACvB,EAAA;AAC6B,EAAA;AACuB,EAAA;AAC1B,EAAA;AACC,EAAA;AACxB,EAAA;AACC,IAAA;AACC,IAAA;AACZ,EAAA;AACsG,EAAA;AAC1C,EAAA;AAC5B,EAAA;AAC6B,EAAA;AAC7C,EAAA;AAClB;AAEqG;AACrE,EAAA;AACN,EAAA;AACM,EAAA;AACyB,EAAA;AACzB,EAAA;AACpB,EAAA;AACD,EAAA;AACC,IAAA;AAC8C,IAAA;AACrC,MAAA;AACH,MAAA;AACR,MAAA;AACN,IAAA;AACsB,IAAA;AACqE,IAAA;AACvE,MAAA;AAC8B,MAAA;AAC9B,MAAA;AACyD,IAAA;AACjE,IAAA;AACP,EAAA;AACG,IAAA;AACqB,IAAA;AACZ,MAAA;AACX,MAAA;AACN,IAAA;AACc,IAAA;AACI,IAAA;AACkC,IAAA;AACZ,MAAA;AACzB,MAAA;AACR,MAAA;AACP,IAAA;AACc,IAAA;AACI,IAAA;AACgC,IAAA;AACtC,MAAA;AACG,MAAA;AACR,MAAA;AACP,IAAA;AAC2B,IAAA;AAC7B,EAAA;AACqB,EAAA;AACD,EAAA;AACS,EAAA;AACtB,EAAA;AACmB,EAAA;AACS,EAAA;AACR,EAAA;AACK,EAAA;AACV,IAAA;AACE,MAAA;AACb,MAAA;AACT,IAAA;AACF,EAAA;AACY,EAAA;AACE,EAAA;AACF,EAAA;AACE,IAAA;AACqB,IAAA;AACK,IAAA;AAC1B,IAAA;AACS,IAAA;AACP,IAAA;AAChB,EAAA;AACU,EAAA;AACI,IAAA;AACkB,IAAA;AACQ,IAAA;AAC7B,IAAA;AACM,IAAA;AACyB,IAAA;AACjC,IAAA;AACK,IAAA;AACS,IAAA;AACP,IAAA;AAChB,EAAA;AAC6C,EAAA;AAC7B,EAAA;AAClB;AAEyG;AAGnD;AACT,EAAA;AACJ,EAAA;AACF,EAAA;AACI,EAAA;AACkB,EAAA;AAC/C,EAAA;AACU,IAAA;AACN,IAAA;AACP,IAAA;AAC+C,IAAA;AACxB,IAAA;AAChC,EAAA;AACc,EAAA;AACA,IAAA;AAC4C,IAAA;AACA,IAAA;AACA,IAAA;AAC1D,EAAA;AACW,EAAA;AAC8B,IAAA;AACA,IAAA;AACA,IAAA;AACzC,EAAA;AACuD,EAAA;AACtB,EAAA;AACO,IAAA;AACC,IAAA;AAC7B,EAAA;AACa,IAAA;AACb,MAAA;AAC0E,MAAA;AAC9C,MAAA;AACrC,IAAA;AACH,EAAA;AACsC,EAAA;AACf,EAAA;AAC2B,EAAA;AACG,EAAA;AACxB,EAAA;AAEsB,IAAA;AACvC,IAAA;AAC4B,MAAA;AACpC,MAAA;AACF,IAAA;AACqC,IAAA;AACzB,IAAA;AACF,IAAA;AACuB,IAAA;AACH,IAAA;AAChC,EAAA;AACsC,EAAA;AAClB,EAAA;AACV,EAAA;AACH,EAAA;AACW,EAAA;AACc,EAAA;AACF,EAAA;AACW,EAAA;AACK,EAAA;AAChC,EAAA;AACqB,EAAA;AACA,EAAA;AACP,EAAA;AACrB,EAAA;AACsB,EAAA;AACT,EAAA;AACmB,EAAA;AAC1B,IAAA;AACF,IAAA;AACA,IAAA;AACX,EAAA;AACqB,EAAA;AACL,EAAA;AAClB;ANiiC+F;AACA;AOn0C0B;AAEzG;AACA;AACC;AACC;AAGS;AAOsD;AACjD,EAAA;AACE,IAAA;AAC2B,IAAA;AAClD,IAAA;AACR,EAAA;AAC4B,EAAA;AACY,IAAA;AAC6B,IAAA;AAC7D,IAAA;AACR,EAAA;AACsF,EAAA;AACzF;AAGmD;AAC5B,EAAA;AACP,EAAA;AACsC,EAAA;AACtC,EAAA;AACoB,EAAA;AACpC;AAEsD;AACxC,EAAA;AACL,IAAA;AACY,MAAA;AACZ,IAAA;AACM,MAAA;AACN,IAAA;AACe,MAAA;AACf,IAAA;AACY,MAAA;AACZ,IAAA;AACgB,MAAA;AACrB,IAAA;AACS,MAAA;AACX,EAAA;AACF;AAGuB;AAYnB,EAAA;AAFS,IAAA;AACA,IAAA;AAES,IAAA;AACK,IAAA;AACC,IAAA;AACW,IAAA;AACF,IAAA;AAEuC,IAAA;AACnC,MAAA;AACG,QAAA;AACA,QAAA;AACP,UAAA;AACuC,UAAA;AACpE,QAAA;AACO,QAAA;AACR,MAAA;AACQ,MAAA;AAC+C,MAAA;AAC1D,IAAA;AAC+C,IAAA;AAC1B,IAAA;AAC6B,IAAA;AACjC,IAAA;AACiC,IAAA;AACsC,IAAA;AACX,IAAA;AACa,IAAA;AAC3C,IAAA;AAC1C,IAAA;AACoF,MAAA;AAClE,MAAA;AACd,QAAA;AACkD,UAAA;AACrD,UAAA;AACG,QAAA;AAC0D,UAAA;AAC7D,UAAA;AACG,QAAA;AACmE,UAAA;AACtE,UAAA;AACG,QAAA;AAC4E,UAAA;AAC/E,UAAA;AACF,QAAA;AAC8B,UAAA;AAChC,MAAA;AACF,IAAA;AACF,EAAA;AAjDW,EAAA;AACA,EAAA;AAVF,EAAA;AACA,EAAA;AACD,EAAA;AAC8B,mBAAA;AACI,mBAAA;AACA,mBAAA;AACA,mBAAA;AAAA;AAuDoD,EAAA;AACpC,IAAA;AAC6B,IAAA;AACZ,IAAA;AAClE,IAAA;AACT,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAO0H,EAAA;AACvE,IAAA;AAClB,IAAA;AACwD,IAAA;AACP,IAAA;AAClF,EAAA;AAAA;AAGyD,EAAA;AAC7B,IAAA;AACF,IAAA;AACR,IAAA;AACD,IAAA;AACwB,MAAA;AAClB,MAAA;AACrB,IAAA;AAC+B,IAAA;AACX,IAAA;AACmC,IAAA;AAC7C,IAAA;AACK,IAAA;AACyB,IAAA;AACpB,MAAA;AACO,MAAA;AACmB,MAAA;AACnB,MAAA;AACf,MAAA;AACZ,IAAA;AAC0D,IAAA;AAC5D,EAAA;AAAA;AAGmE,EAAA;AACpC,IAAA;AAC/B,EAAA;AAAA;AAGuE,EAAA;AACpD,IAAA;AACC,IAAA;AACS,IAAA;AACI,MAAA;AAC7B,MAAA;AACF,IAAA;AAC0B,IAAA;AAC6D,MAAA;AACzD,MAAA;AACvB,IAAA;AACU,MAAA;AACyE,MAAA;AAC5C,MAAA;AAC9C,IAAA;AACoB,IAAA;AACtB,EAAA;AAE0F,EAAA;AACtE,IAAA;AACP,IAAA;AAC4C,MAAA;AACrD,MAAA;AACF,IAAA;AACuC,IAAA;AACrB,MAAA;AACD,MAAA;AAC0D,MAAA;AAC1B,MAAA;AACN,MAAA;AAC3C,IAAA;AACF,EAAA;AAAA;AAAA;AAAA;AAAA;AAMoI,EAAA;AACnG,IAAA;AACyD,IAAA;AACC,IAAA;AAC1D,IAAA;AACd,IAAA;AACC,IAAA;AACsD,IAAA;AAC5C,IAAA;AACZ,MAAA;AACA,MAAA;AACc,MAAA;AACX,QAAA;AACwE,QAAA;AAC3C,QAAA;AACxB,QAAA;AACf,MAAA;AAC4D,QAAA;AACtC,QAAA;AAC7B,MAAA;AAC4D,MAAA;AACuB,MAAA;AACrF,IAAA;AACF,EAAA;AAAA;AAGkH,EAAA;AACjF,IAAA;AACyD,IAAA;AACC,IAAA;AAC1D,IAAA;AACH,IAAA;AACZ,MAAA;AACA,MAAA;AACmD,MAAA;AACtC,MAAA;AAC4D,MAAA;AACJ,MAAA;AACrF,IAAA;AACF,EAAA;AAAA;AAGsH,EAAA;AACrF,IAAA;AACyD,IAAA;AACC,IAAA;AACzB,IAAA;AACjC,IAAA;AACH,IAAA;AACZ,MAAA;AACA,MAAA;AAC+C,MAAA;AAChB,MAAA;AACb,MAAA;AACyB,MAAA;AAC0B,MAAA;AACrF,IAAA;AACF,EAAA;AAE4C,EAAA;AACsB,IAAA;AAClE,EAAA;AACF;AAE0H;AAChH,EAAA;AACkC,IAAA;AACxC,IAAA;AACF,EAAA;AACiC,EAAA;AACb,IAAA;AAC6C,IAAA;AACtD,IAAA;AACX,EAAA;AACF;AAO8F;AAChE,EAAA;AAEgE,IAAA;AACP,IAAA;AACQ,MAAA;AAC3F,IAAA;AACF,EAAA;AACiC,EAAA;AACA,EAAA;AACH,EAAA;AACiB,EAAA;AACnC,EAAA;AAC6C,IAAA;AACoC,IAAA;AACpC,IAAA;AACwB,EAAA;AACF,EAAA;AACxD,EAAA;AAChB,EAAA;AACT;AAG4H;AAC/F,EAAA;AACA,IAAA;AACA,IAAA;AACiD,IAAA;AACvB,IAAA;AACG,IAAA;AACH,IAAA;AACd,IAAA;AACvC,EAAA;AACiB,EAAA;AACgB,EAAA;AACA,EAAA;AACI,EAAA;AAEf,EAAA;AACC,EAAA;AACK,EAAA;AACN,IAAA;AACA,IAAA;AACe,IAAA;AACxB,IAAA;AACe,IAAA;AAC5B,EAAA;AACuB,EAAA;AACzB;AAG+D;AACA,EAAA;AAC1B,EAAA;AACwD,EAAA;AAChE,EAAA;AACqC,EAAA;AAC/B,IAAA;AACU,IAAA;AACoB,IAAA;AAC1B,IAAA;AACrC,EAAA;AACgC,EAAA;AAC4B,EAAA;AACkB,EAAA;AAER,EAAA;AAClE,EAAA;AACsC,IAAA;AACwD,IAAA;AACjE,IAAA;AACQ,IAAA;AACU,IAAA;AAC3C,EAAA;AAC6C,IAAA;AACrD,EAAA;AACF;AAMyC;AAC5B;AACgB;AACT,EAAA;AACT,EAAA;AACF,IAAA;AACQ,IAAA;AACf,EAAA;AACO,EAAA;AACT;AAEyC;AAGuE;AACtD,EAAA;AAC6B,EAAA;AAChE,EAAA;AACb,EAAA;AAC2B,IAAA;AACE,IAAA;AACnB,IAAA;AAClB,EAAA;AACO,EAAA;AACT;AAO0E;AACpD,EAAA;AACyE,EAAA;AAClE,EAAA;AACmC,EAAA;AAC1D,EAAA;AACA,EAAA;AACA,EAAA;AAC8D,IAAA;AACA,IAAA;AAC1D,EAAA;AACC,IAAA;AACT,EAAA;AAC4B,EAAA;AACuD,EAAA;AACnD,EAAA;AACF,EAAA;AACA,EAAA;AACC,EAAA;AACC,EAAA;AACtB,IAAA;AACoB,IAAA;AACQ,MAAA;AACV,MAAA;AAC1B,IAAA;AACiB,IAAA;AACA,IAAA;AACkC,IAAA;AACrD,EAAA;AACO,EAAA;AACT;AAGwB;AAWpB,EAAA;AADS,IAAA;AAEoB,IAAA;AACwC,IAAA;AACjB,IAAA;AACxB,IAAA;AACyB,IAAA;AACvB,IAAA;AACD,IAAA;AACA,IAAA;AACyB,IAAA;AAC/B,MAAA;AACH,MAAA;AAC6D,MAAA;AACjF,IAAA;AAC2F,IAAA;AAC7F,EAAA;AAhBW,EAAA;AATM,EAAA;AACA,EAAA;AACA,EAAA;AAAA;AA0BqB,EAAA;AACP,IAAA;AACM,IAAA;AAC9B,IAAA;AAC0B,MAAA;AACA,MAAA;AACP,MAAA;AACH,MAAA;AAC4D,MAAA;AACjF,IAAA;AACU,IAAA;AACZ,EAAA;AAE2C,EAAA;AACX,IAAA;AAChC,EAAA;AACF;AAGmB;AAMf,EAAA;AADS,IAAA;AAEwE,IAAA;AACvE,IAAA;AACgC,IAAA;AACX,IAAA;AACjB,IAAA;AACc,IAAA;AACE,MAAA;AACE,QAAA;AACO,UAAA;AACG,UAAA;AAChB,UAAA;AAC+B,UAAA;AACA,UAAA;AACrD,QAAA;AACF,MAAA;AACF,IAAA;AACF,EAAA;AAlBW,EAAA;AAJF,EAAA;AAAA;AAyBmE,EAAA;AAC3D,IAAA;AAC8B,IAAA;AACE,MAAA;AACN,MAAA;AACvB,MAAA;AAClB,IAAA;AACsB,IAAA;AACA,IAAA;AACA,IAAA;AACP,IAAA;AACmF,IAAA;AACtE,IAAA;AACoD,MAAA;AACO,MAAA;AACA,MAAA;AACG,MAAA;AACzD,MAAA;AACA,MAAA;AACL,MAAA;AAC5B,IAAA;AACF,EAAA;AAAA;AAGmD,EAAA;AAC/B,IAAA;AACuB,IAAA;AAC2B,MAAA;AACT,MAAA;AACI,MAAA;AACA,MAAA;AAC/D,IAAA;AACF,EAAA;AACF;APiwC+F;AACA;AQvyDxD;AAgBkB;AAC1C,EAAA;AACR,EAAA;AACK,EAAA;AACJ,EAAA;AACI,EAAA;AACkB,EAAA;AACnB,EAAA;AACA,EAAA;AACX;AAEW;AAGY;AAIwB,EAAA;AAAxB,IAAA;AACgD,IAAA;AAC5C,IAAA;AACF,IAAA;AACnB,MAAA;AAAA;AACgB,MAAA;AAAA;AACF,MAAA;AAAA;AACC,MAAA;AAAA;AACD,MAAA;AAAA;AACC,MAAA;AAAA;AACD,MAAA;AAAA;AACF,MAAA;AAAA;AACd,IAAA;AACsB,IAAA;AACR,IAAA;AACe,IAAA;AACP,MAAA;AAGO,MAAA;AACE,QAAA;AAC0B,QAAA;AAEjD,MAAA;AACmE,MAAA;AAC3E,IAAA;AACa,IAAA;AACf,EAAA;AA3BqB,EAAA;AAHa,mBAAA;AACzB,EAAA;AA+B0B,EAAA;AACC,IAAA;AACU,MAAA;AACuB,MAAA;AAClE,IAAA;AACuB,IAAA;AACK,IAAA;AACnB,MAAA;AACsD,MAAA;AACjD,MAAA;AACS,MAAA;AACP,MAAA;AACA,MAAA;AACA,MAAA;AACjB,IAAA;AACkE,IAAA;AACpE,EAAA;AAEmC,EAAA;AACV,IAAA;AACyE,IAAA;AAClG,EAAA;AACF;AAE2G;AACtE,EAAA;AACA,IAAA;AACF,IAAA;AACmC,MAAA;AACrC,MAAA;AACH,MAAA;AACgC,MAAA;AAChC,MAAA;AAC0B,MAAA;AACpD,IAAA;AACO,IAAA;AACT,EAAA;AAC+B,EAAA;AACY,IAAA;AACmB,IAAA;AAC9D,EAAA;AACiE,EAAA;AAClB,EAAA;AACrB,EAAA;AACJ,IAAA;AACP,IAAA;AACE,IAAA;AACF,IAAA;AACyB,IAAA;AAC1B,MAAA;AACM,MAAA;AACN,QAAA;AACA,QAAA;AACA,QAAA;AACV,MAAA;AAC4B,MAAA;AACQ,QAAA;AACzB,QAAA;AACQ,QAAA;AACsC,QAAA;AACzD,MAAA;AACgB,MAAA;AACN,QAAA;AACA,QAAA;AACA,QAAA;AACV,MAAA;AACwB,MAAA;AACI,MAAA;AAC0D,QAAA;AAC5B,QAAA;AAC1D,MAAA;AACe,MAAA;AACa,MAAA;AACT,QAAA;AACW,UAAA;AACA,UAAA;AACA,UAAA;AAC5B,QAAA;AAC4D,QAAA;AACvC,QAAA;AACX,QAAA;AACE,UAAA;AACV,UAAA;AACF,QAAA;AACyB,QAAA;AAC0C,QAAA;AAClD,QAAA;AACI,QAAA;AACP,QAAA;AACwE,UAAA;AAChF,UAAA;AACA,UAAA;AACA,UAAA;AACgC,UAAA;AACjB,UAAA;AACnB,UAAA;AACF,QAAA;AACU,QAAA;AACZ,MAAA;AAC4B,MAAA;AAC9B,IAAA;AAC6B,IAAA;AACT,IAAA;AACtB,EAAA;AACmC,EAAA;AACrC;AAEsB;AACN,EAAA;AACG,EAAA;AACH,EAAA;AACA,EAAA;AACA,EAAA;AAChB;AAGmH;AAC1C,EAAA;AACrB,EAAA;AACN,EAAA;AAC6C,EAAA;AACY,EAAA;AAC1B,EAAA;AACpC,EAAA;AACzC;AAGU;AACiB,mBAAA;AACA,mBAAA;AACR,EAAA;AACR,EAAA;AAEoC,EAAA;AAClB,IAAA;AACkB,IAAA;AACjC,IAAA;AACG,IAAA;AACkB,IAAA;AACE,MAAA;AACE,QAAA;AACE,UAAA;AAC8B,YAAA;AACb,YAAA;AACvB,YAAA;AACS,YAAA;AACG,YAAA;AAC8B,YAAA;AACmB,YAAA;AAC/B,YAAA;AACI,YAAA;AAC3D,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACuH,IAAA;AAC5E,IAAA;AACX,IAAA;AACE,MAAA;AACtB,QAAA;AAC8E,QAAA;AAC9D,QAAA;AAC1B,MAAA;AACF,IAAA;AACwC,IAAA;AACR,IAAA;AACE,MAAA;AACtB,QAAA;AAC+E,QAAA;AACxD,QAAA;AACjC,MAAA;AACF,IAAA;AACc,IAAA;AAChB,EAAA;AAEgD,EAAA;AACrB,IAAA;AAC+B,IAAA;AAC6B,IAAA;AAC7D,IAAA;AACA,IAAA;AACR,IAAA;AACA,IAAA;AACqB,IAAA;AACpB,IAAA;AACM,IAAA;AACwC,IAAA;AACZ,IAAA;AACA,IAAA;AAC9B,IAAA;AACvB,EAAA;AAAA;AAG0B,EAAA;AAC6D,IAAA;AAClD,IAAA;AACN,IAAA;AACM,IAAA;AACW,IAAA;AAC3B,IAAA;AAC+D,IAAA;AACrC,IAAA;AAC/C,EAAA;AACF;AAEoH;AAC1E;AACiB,EAAA;AACF,EAAA;AACA,EAAA;AACzD;AAE0E;AAC5D,EAAA;AAC+B,EAAA;AACZ,EAAA;AACE,IAAA;AACD,MAAA;AACG,MAAA;AACkC,QAAA;AACtB,QAAA;AACK,QAAA;AACvC,QAAA;AACoC,QAAA;AAC7C,MAAA;AACF,IAAA;AACF,EAAA;AACkC,EAAA;AACpC;AAE6E;AAE7C;AACvB,EAAA;AACC,IAAA;AACO,IAAA;AACC,IAAA;AACN,IAAA;AAC8D,MAAA;AAC/C,MAAA;AACgD,MAAA;AACvE,IAAA;AACF,EAAA;AACF;AAG0F;AACvD,EAAA;AACrB,EAAA;AACgF,EAAA;AAChE,EAAA;AACH,EAAA;AACuB,EAAA;AACG,EAAA;AAC5C,EAAA;AACY,IAAA;AACH,IAAA;AACF,IAAA;AACP,IAAA;AACY,IAAA;AACF,IAAA;AACf,IAAA;AACuC,IAAA;AAC3B,IAAA;AACN,IAAA;AACE,IAAA;AACH,IAAA;AACI,IAAA;AACU,IAAA;AACuB,IAAA;AACnC,IAAA;AACT,EAAA;AACF;AR4wD+F;AACA;AShmE9D;AAgBiF;AAC9C,EAAA;AACD,EAAA;AAC4B,EAAA;AACD,EAAA;AACd,EAAA;AACG,EAAA;AACI,EAAA;AACD,EAAA;AACQ,EAAA;AACb,EAAA;AACa,EAAA;AAC9F;AAGqE;AACjB,EAAA;AACA,EAAA;AAC1C,IAAA;AACU,IAAA;AACZ,IAAA;AACO,IAAA;AACD,IAAA;AACI,IAAA;AACE,IAAA;AACN,IAAA;AACG,IAAA;AACG,IAAA;AACJ,IAAA;AACH,IAAA;AACD,IAAA;AACF,IAAA;AACO,IAAA;AACN,IAAA;AACI,IAAA;AACM,IAAA;AACZ,IAAA;AACG,IAAA;AACF,IAAA;AACM,IAAA;AACd,EAAA;AACoF,EAAA;AACtF;AAG2G;AAClE,EAAA;AACd,EAAA;AAC2D,EAAA;AAClC,EAAA;AAC9C,EAAA;AACyB,EAAA;AACxB,EAAA;AACyB,IAAA;AAC+B,IAAA;AAC7D,EAAA;AAC+C,EAAA;AACnB,EAAA;AACX,IAAA;AAC8B,IAAA;AACrC,IAAA;AACiE,IAAA;AACxC,IAAA;AACnC,EAAA;AACuF,EAAA;AACzF;AAE4E;AAEc;AAC1B,EAAA;AAC7C,EAAA;AACE,IAAA;AACH,IAAA;AACF,IAAA;AACP,IAAA;AACY,IAAA;AACJ,IAAA;AACF,IAAA;AACc,IAAA;AACb,IAAA;AACZ,IAAA;AACQ,IAAA;AACW,IAAA;AACV,IAAA;AACa,IAAA;AACA,IAAA;AACf,IAAA;AACR,EAAA;AACH;AAEwD;AACrC,EAAA;AACE,IAAA;AACH,IAAA;AACF,IAAA;AACP,IAAA;AACY,IAAA;AACJ,IAAA;AACF,IAAA;AACc,IAAA;AACb,IAAA;AACN,IAAA;AACE,IAAA;AACH,IAAA;AACI,IAAA;AACa,IAAA;AACA,IAAA;AACf,IAAA;AACR,EAAA;AACH;AAE2C;AACsE,EAAA;AAC9F,EAAA;AACE,IAAA;AACH,IAAA;AACF,IAAA;AACP,IAAA;AACY,IAAA;AACJ,IAAA;AACF,IAAA;AACc,IAAA;AACb,IAAA;AACN,IAAA;AACE,IAAA;AACH,IAAA;AACI,IAAA;AACgB,IAAA;AACA,IAAA;AAClB,IAAA;AACR,EAAA;AACH;AAE8C;AACY,EAAA;AAC9B,EAAA;AACZ,EAAA;AACD,IAAA;AACF,IAAA;AACE,IAAA;AACb,EAAA;AACY,EAAA;AACL,IAAA;AAC0C,MAAA;AAC1C,IAAA;AACgF,MAAA;AAChF,IAAA;AACiF,MAAA;AACjF,IAAA;AACsF,MAAA;AACtF,IAAA;AAC8C,MAAA;AACnC,IAAA;AAEJ,MAAA;AAC4E,MAAA;AACxF,IAAA;AACK,IAAA;AACqC,MAAA;AACrC,IAAA;AAC+B,MAAA;AAC/B,IAAA;AACuC,MAAA;AACvC,IAAA;AACmB,MAAA;AACJ,IAAA;AACgC,MAAA;AACrB,MAAA;AAEU,MAAA;AACzC,IAAA;AACF,EAAA;AACF;AAEiD;AAGa;AACxC,EAAA;AACZ,EAAA;AACM,IAAA;AACG,IAAA;AACjB,EAAA;AACO,EAAA;AACT;AAGsD;AAGY;AACpD,EAAA;AACL,IAAA;AACyB,MAAA;AACzB,IAAA;AACuC,MAAA;AACvC,IAAA;AACgC,MAAA;AAChC,IAAA;AAC4B,MAAA;AACjC,IAAA;AACS,MAAA;AACX,EAAA;AACF;ATikE+F;AACA;AUlyE5D;AACO;AACzB,EAAA;AACiB,IAAA;AACA,IAAA;AACpB,MAAA;AAC+D,MAAA;AACnD,MAAA;AACtB,IAAA;AACF,EAAA;AACQ,EAAA;AAC2E,EAAA;AACvD,EAAA;AAC9B;AAE6G;AAC7D;AACyC;AAG1B;AAChC,EAAA;AACrB,EAAA;AACqB,EAAA;AACL,IAAA;AACyD,IAAA;AAC1D,IAAA;AACsB,MAAA;AACpB,MAAA;AACyB,MAAA;AAC1C,MAAA;AAC+D,QAAA;AAC3D,MAAA;AACC,QAAA;AACT,MAAA;AACF,IAAA;AAC+C,IAAA;AACrC,IAAA;AACZ,EAAA;AACO,EAAA;AACT;AAGgG;AACvC,EAAA;AACP,EAAA;AACxC,EAAA;AACO,EAAA;AAC0D,EAAA;AACZ,EAAA;AAChB,EAAA;AAC8C,EAAA;AAC7D,EAAA;AACb,EAAA;AACmC,EAAA;AACqC,EAAA;AAC5D,EAAA;AACL,IAAA;AACyD,IAAA;AACrC,IAAA;AACkC,IAAA;AAC1C,IAAA;AACf,MAAA;AACN,MAAA;AACb,IAAA;AACU,IAAA;AACZ,EAAA;AACmE,EAAA;AAC1D,EAAA;AACe,EAAA;AACT,IAAA;AACL,IAAA;AACV,EAAA;AACO,EAAA;AACT;AAEgB;AAGiD;AACK,EAAA;AAC1B,EAAA;AAC9B,EAAA;AACJ,EAAA;AACqB,EAAA;AACL,IAAA;AACG,IAAA;AACqD,IAAA;AACvE,MAAA;AACL,MAAA;AACF,IAAA;AACwC,IAAA;AACG,IAAA;AACT,IAAA;AACU,MAAA;AACiB,MAAA;AAC1B,QAAA;AACnB,QAAA;AACd,MAAA;AACF,IAAA;AACS,IAAA;AACX,EAAA;AACkC,EAAA;AACH,EAAA;AACE,EAAA;AACV,IAAA;AACN,IAAA;AACD,IAAA;AAChB,EAAA;AACoE,EAAA;AAC3D,EAAA;AACgB,EAAA;AACV,IAAA;AACL,IAAA;AACV,EAAA;AACO,EAAA;AACT;AAG4E;AACqB,EAAA;AACnF,EAAA;AACyC,EAAA;AACsB,EAAA;AAC3C,EAAA;AACA,EAAA;AACwC,IAAA;AAC5C,IAAA;AACM,IAAA;AACO,IAAA;AACqB,IAAA;AAChD,IAAA;AACJ,IAAA;AACM,IAAA;AACC,IAAA;AACjB,EAAA;AAC+C,EAAA;AACvC,EAAA;AACO,EAAA;AACkC,EAAA;AACtB,IAAA;AACe,IAAA;AACG,IAAA;AACH,IAAA;AACyC,IAAA;AAC5B,IAAA;AAC9B,MAAA;AACV,MAAA;AACb,IAAA;AACyB,IAAA;AAChB,IAAA;AACX,EAAA;AACoC,EAAA;AACV,EAAA;AACuC,EAAA;AACxD,EAAA;AACa,EAAA;AACP,IAAA;AACL,IAAA;AACV,EAAA;AACO,EAAA;AACT;AV0xE+F;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/editor/editor/packages/core/dist/chunk-G5NMLUVF.cjs","sourcesContent":[null,"// Portions ported from photocraft/crates/cms/src/math.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Small colour-science helpers: 3×3 matrices, CIE XYZ ↔ L*a*b*, chromatic adaptation. All from\n * public standards: CIE 15 (L*a*b*), ICC.1:2010 Annex A (PCS, D50) and the Bradford matrix\n * (Lam 1985).\n */\n\n/** The ICC PCS illuminant (D50) as the header stores it: X 0.9642, Y 1, Z 0.8249. */\nexport const D50: readonly [number, number, number] = [0.9642, 1.0, 0.8249];\n\n/** CIE D65 chromaticity (sRGB, Display P3, Adobe RGB). */\nexport const D65_XY: readonly [number, number] = [0.3127, 0.329];\n\n/** Row-major 3×3 matrix. */\nexport type Mat3 = [[number, number, number], [number, number, number], [number, number, number]];\nexport type Vec3 = [number, number, number];\n\nexport const IDENTITY: Mat3 = [\n [1, 0, 0],\n [0, 1, 0],\n [0, 0, 1],\n];\n\nexport function mul(a: Mat3, b: Mat3): Mat3 {\n const o: Mat3 = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0],\n ];\n for (let i = 0; i < 3; i++) for (let j = 0; j < 3; j++) o[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];\n return o;\n}\n\nexport function apply(m: Mat3, v: readonly number[]): Vec3 {\n return [m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2], m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2], m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]];\n}\n\nexport function det(m: Mat3): number {\n return m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1]) - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);\n}\n\n/** Inverse, or `null` when (nearly) singular. */\nexport function invert(m: Mat3): Mat3 | null {\n const d = det(m);\n if (!Number.isFinite(d) || Math.abs(d) < 1e-12) return null;\n const k = 1 / d;\n return [\n [(m[1][1] * m[2][2] - m[1][2] * m[2][1]) * k, (m[0][2] * m[2][1] - m[0][1] * m[2][2]) * k, (m[0][1] * m[1][2] - m[0][2] * m[1][1]) * k],\n [(m[1][2] * m[2][0] - m[1][0] * m[2][2]) * k, (m[0][0] * m[2][2] - m[0][2] * m[2][0]) * k, (m[0][2] * m[1][0] - m[0][0] * m[1][2]) * k],\n [(m[1][0] * m[2][1] - m[1][1] * m[2][0]) * k, (m[0][1] * m[2][0] - m[0][0] * m[2][1]) * k, (m[0][0] * m[1][1] - m[0][1] * m[1][0]) * k],\n ];\n}\n\n/** XYZ (Y = 1) of a chromaticity. */\nexport function xyToXyz(xy: readonly number[]): Vec3 {\n const [x, y] = xy;\n return [x / y, 1, (1 - x - y) / y];\n}\n\nconst BRADFORD: Mat3 = [\n [0.8951, 0.2664, -0.1614],\n [-0.7502, 1.7135, 0.0367],\n [0.0389, -0.0685, 1.0296],\n];\n\n/** Bradford chromatic adaptation from white `src` to white `dst` (XYZ). */\nexport function bradford(src: readonly number[], dst: readonly number[]): Mat3 {\n const inv = invert(BRADFORD)!;\n const s = apply(BRADFORD, src);\n const d = apply(BRADFORD, dst);\n const scale: Mat3 = [\n [d[0] / s[0], 0, 0],\n [0, d[1] / s[1], 0],\n [0, 0, d[2] / s[2]],\n ];\n return mul(inv, mul(scale, BRADFORD));\n}\n\n/** RGB → XYZ matrix (relative to `white`) from primaries' chromaticities, or `null` when they are dependent. */\nexport function rgbToXyzMatrix(r: readonly number[], g: readonly number[], b: readonly number[], white: readonly number[]): Mat3 | null {\n const xr = xyToXyz(r);\n const xg = xyToXyz(g);\n const xb = xyToXyz(b);\n const m: Mat3 = [\n [xr[0], xg[0], xb[0]],\n [xr[1], xg[1], xb[1]],\n [xr[2], xg[2], xb[2]],\n ];\n const inv = invert(m);\n if (!inv) return null;\n const s = apply(inv, white);\n return [\n [m[0][0] * s[0], m[0][1] * s[1], m[0][2] * s[2]],\n [m[1][0] * s[0], m[1][1] * s[1], m[1][2] * s[2]],\n [m[2][0] * s[0], m[2][1] * s[1], m[2][2] * s[2]],\n ];\n}\n\nconst EPS = 216 / 24389;\nconst KAPPA = 24389 / 27;\n\nconst labF = (t: number) => (t > EPS ? Math.cbrt(t) : (KAPPA * t + 16) / 116);\nconst labFinv = (f: number) => {\n const f3 = f * f * f;\n return f3 > EPS ? f3 : (116 * f - 16) / KAPPA;\n};\n\n/** CIE XYZ → L*a*b* relative to `white` (CIE 15). */\nexport function xyzToLab(xyz: readonly number[], white: readonly number[] = D50): Vec3 {\n const fx = labF(xyz[0] / white[0]);\n const fy = labF(xyz[1] / white[1]);\n const fz = labF(xyz[2] / white[2]);\n return [116 * fy - 16, 500 * (fx - fy), 200 * (fy - fz)];\n}\n\n/** CIE L*a*b* → XYZ relative to `white`. */\nexport function labToXyz(lab: readonly number[], white: readonly number[] = D50): Vec3 {\n const fy = (lab[0] + 16) / 116;\n const fx = fy + lab[1] / 500;\n const fz = fy - lab[2] / 200;\n return [labFinv(fx) * white[0], labFinv(fy) * white[1], labFinv(fz) * white[2]];\n}\n\n/** CIE 1976 colour difference. */\nexport function deltaE76(a: readonly number[], b: readonly number[]): number {\n return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2]);\n}\n\n/** Rounds to ICC s15Fixed16 (what a profile can store). */\nexport const s15f16Round = (v: number) => Math.round(v * 65536) / 65536;\n\n/** D50 exactly as an ICC header stores it. */\nexport const d50Quantized = (): Vec3 => [s15f16Round(D50[0]), s15f16Round(D50[1]), s15f16Round(D50[2])];\n","// Portions ported from photocraft/crates/cms/src/curve.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * One-dimensional tone curves (ICC `curv` and `para`) and their inverses. Gamma and parametric\n * curves evaluate analytically, also outside 0..1 (negatives mirror, values above 1 extend the\n * formula), so float transforms keep HDR values. Tables clamp their input to 0..1.\n */\n\nexport type Curve =\n | { type: 'identity' }\n | { type: 'gamma'; gamma: number }\n /** ICC `parametricCurveType` function `kind` (0–4), parameters `[g, a, b, c, d, e, f]`. */\n | { type: 'parametric'; kind: number; p: number[] }\n /** Samples at evenly spaced inputs over 0..1. */\n | { type: 'table'; table: Float32Array };\n\nexport const IDENTITY_CURVE: Curve = { type: 'identity' };\n\n/** The sRGB transfer function (IEC 61966-2.1) as ICC parametric type 3. */\nexport function srgbTrc(): Curve {\n return { type: 'parametric', kind: 3, p: [2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045, 0, 0] };\n}\n\nexport const gammaCurve = (g: number): Curve => ({ type: 'gamma', gamma: g });\n\n/** Parameters stored for a parametric function type. */\nexport function paramCount(kind: number): number {\n return kind === 0 ? 1 : kind === 1 ? 3 : kind === 2 ? 4 : kind === 3 ? 5 : 7;\n}\n\nexport function isIdentityCurve(c: Curve): boolean {\n switch (c.type) {\n case 'identity':\n return true;\n case 'gamma':\n return Math.abs(c.gamma - 1) < 1e-9;\n case 'parametric':\n return c.kind === 0 && Math.abs(c.p[0] - 1) < 1e-9;\n case 'table': {\n const n = c.table.length;\n if (n < 2) return true;\n for (let i = 0; i < n; i++) if (Math.abs(c.table[i] - i / (n - 1)) >= 1 / 65535) return false;\n return true;\n }\n }\n}\n\nconst mirror = (x: number, f: (v: number) => number) => (x < 0 ? -f(-x) : f(x));\nconst pw = (base: number, g: number) => (base <= 0 ? 0 : Math.pow(base, g));\n\nfunction para(kind: number, p: readonly number[], x: number): number {\n const [g, a, b, c, d, e, f] = p;\n switch (kind) {\n case 0:\n return mirror(x, (v) => Math.pow(v, g));\n case 1:\n return a !== 0 && x >= -b / a ? pw(a * x + b, g) : 0;\n case 2:\n return a !== 0 && x >= -b / a ? pw(a * x + b, g) + c : c;\n case 3:\n if (x < 0 && b === 0 && d === 0) return -para(kind, p, -x);\n return x >= d ? pw(a * x + b, g) : c * x;\n default:\n return x >= d ? pw(a * x + b, g) + e : c * x + f;\n }\n}\n\nfunction paraInverse(kind: number, p: readonly number[], y: number): number | null {\n const [g, a, b, c, d, e, f] = p;\n if (Math.abs(g) < 1e-12) return null;\n const root = (v: number) => (v <= 0 ? 0 : Math.pow(v, 1 / g));\n switch (kind) {\n case 0:\n return mirror(y, (v) => Math.pow(v, 1 / g));\n case 1:\n if (a === 0) return null;\n return y <= 0 ? -b / a : (root(y) - b) / a;\n case 2:\n if (a === 0) return null;\n return y <= c ? -b / a : (root(y - c) - b) / a;\n case 3: {\n if (a === 0) return null;\n if (y < 0 && b === 0 && d === 0) {\n const v = paraInverse(kind, p, -y);\n return v === null ? null : -v;\n }\n const yd = pw(a * d + b, g);\n if (y >= yd) return (root(y) - b) / a;\n return c !== 0 ? y / c : 0;\n }\n default: {\n if (a === 0) return null;\n const yd = pw(a * d + b, g) + e;\n if (y >= yd) return (root(y - e) - b) / a;\n return c !== 0 ? (y - f) / c : 0;\n }\n }\n}\n\n/** Bisection inverse of a monotonic function on 0..1. */\nfunction numericInverse(f: (x: number) => number, y: number): number {\n const increasing = f(1) >= f(0);\n let lo = 0;\n let hi = 1;\n for (let k = 0; k < 60; k++) {\n const mid = 0.5 * (lo + hi);\n if (f(mid) < y === increasing) lo = mid;\n else hi = mid;\n }\n return 0.5 * (lo + hi);\n}\n\nfunction table(t: Float32Array, x: number): number {\n const n = t.length;\n if (n === 0) return x;\n if (n === 1) return t[0];\n const pos = Math.min(1, Math.max(0, x)) * (n - 1);\n const i = Math.min(n - 2, Math.floor(pos));\n const f = pos - i;\n return t[i] + (t[i + 1] - t[i]) * f;\n}\n\nfunction edgeIndex(t: Float32Array, start: boolean): number {\n const n = t.length;\n if (start) {\n const v = t[0];\n let i = n - 1;\n for (let k = 0; k < n; k++) {\n if (Math.abs(t[k] - v) > 1e-7) {\n i = k - 1;\n break;\n }\n }\n return i / (n - 1);\n }\n const v = t[n - 1];\n let i = 0;\n for (let k = n - 1; k >= 0; k--) {\n if (Math.abs(t[k] - v) > 1e-7) {\n i = k + 1;\n break;\n }\n }\n return i / (n - 1);\n}\n\n/** Exact inverse of a piecewise-linear table (binary search), increasing or decreasing. */\nfunction tableInverse(t: Float32Array, y: number): number {\n const n = t.length;\n if (n < 2) return y;\n const increasing = t[n - 1] >= t[0];\n const loV = increasing ? t[0] : t[n - 1];\n const hiV = increasing ? t[n - 1] : t[0];\n if (y <= loV) return edgeIndex(t, increasing);\n if (y >= hiV) return edgeIndex(t, !increasing);\n let lo = 0;\n let hi = n - 1;\n while (hi - lo > 1) {\n const mid = (lo + hi) >> 1;\n if (t[mid] < y === increasing) lo = mid;\n else hi = mid;\n }\n const a = t[lo];\n const b = t[hi];\n const f = Math.abs(b - a) > 1e-12 ? (y - a) / (b - a) : 0.5;\n return (lo + f) / (n - 1);\n}\n\n/** Evaluates a curve at `x`. */\nexport function evalCurve(c: Curve, x: number): number {\n switch (c.type) {\n case 'identity':\n return x;\n case 'gamma':\n return mirror(x, (v) => Math.pow(v, c.gamma));\n case 'parametric':\n return para(c.kind, c.p, x);\n case 'table':\n return table(c.table, x);\n }\n}\n\n/** Evaluates the inverse curve at `y`. */\nexport function evalCurveInverse(c: Curve, y: number): number {\n switch (c.type) {\n case 'identity':\n return y;\n case 'gamma':\n return Math.abs(c.gamma) < 1e-12 ? y : mirror(y, (v) => Math.pow(v, 1 / c.gamma));\n case 'parametric':\n return paraInverse(c.kind, c.p, y) ?? numericInverse((x) => para(c.kind, c.p, x), y);\n case 'table':\n return tableInverse(c.table, y);\n }\n}\n\n/** `n` evenly spaced samples over 0..1. */\nexport function sampleCurve(c: Curve, n: number): Float32Array {\n const out = new Float32Array(n);\n for (let i = 0; i < n; i++) out[i] = evalCurve(c, i / (n - 1));\n return out;\n}\n","// Portions ported from photocraft/crates/cms/src/clut.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Multidimensional colour lookup tables (ICC CLUTs): node values normalised to 0..1, evaluated\n * with tetrahedral interpolation for 3 inputs, two tetrahedra lerped along the first input for 4,\n * and multilinear otherwise.\n */\n\nexport const MAX_CHANNELS = 15;\n\nexport class Clut {\n readonly inputs: number;\n readonly strides: number[];\n\n constructor(\n readonly grid: number[],\n readonly outputs: number,\n readonly data: Float32Array\n ) {\n const inputs = grid.length;\n if (inputs < 1 || inputs > MAX_CHANNELS || outputs < 1 || outputs > MAX_CHANNELS) throw new RangeError('bad CLUT dimensions');\n this.inputs = inputs;\n this.strides = new Array(inputs).fill(0);\n let s = outputs;\n for (let i = inputs - 1; i >= 0; i--) {\n this.strides[i] = s;\n s *= Math.max(1, grid[i]);\n }\n if (data.length !== s) throw new RangeError(`CLUT data length ${data.length}, expected ${s}`);\n }\n\n get nodes(): number {\n return this.data.length / this.outputs;\n }\n\n /** A table sampled from `f` at every node. */\n static sample(grid: number[], outputs: number, f: (input: Float32Array, out: Float32Array) => void): Clut {\n const inputs = grid.length;\n const total = grid.reduce((a, b) => a * b, 1);\n const data = new Float32Array(total * outputs);\n const idx = new Array(inputs).fill(0);\n const inp = new Float32Array(inputs);\n for (let node = 0; node < total; node++) {\n let rem = node;\n for (let d = inputs - 1; d >= 0; d--) {\n idx[d] = rem % grid[d];\n rem = Math.floor(rem / grid[d]);\n }\n for (let d = 0; d < inputs; d++) inp[d] = grid[d] > 1 ? idx[d] / (grid[d] - 1) : 0;\n f(inp, data.subarray(node * outputs, (node + 1) * outputs));\n }\n return new Clut(grid, outputs, data);\n }\n\n /** Base offset, fraction and stride along input `d` at `v`. */\n locate(d: number, v: number, out: number[], k: number): void {\n const n = this.grid[d];\n if (n < 2) {\n out[k] = 0;\n out[k + 1] = 0;\n out[k + 2] = 0;\n return;\n }\n const p = Math.min(1, Math.max(0, v)) * (n - 1);\n const i = Math.min(n - 2, Math.floor(p));\n out[k] = i * this.strides[d];\n out[k + 1] = p - i;\n out[k + 2] = this.strides[d];\n }\n\n private readonly loc = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];\n private readonly lo = new Float32Array(MAX_CHANNELS);\n private readonly hi = new Float32Array(MAX_CHANNELS);\n\n eval(input: ArrayLike<number>, out: Float32Array | number[]): void {\n const L = this.loc;\n switch (this.inputs) {\n case 1: {\n this.locate(0, input[0], L, 0);\n const [b, r, s] = L;\n for (let k = 0; k < this.outputs; k++) {\n const a = this.data[b + k];\n const c = s > 0 ? this.data[b + s + k] : a;\n out[k] = a + (c - a) * r;\n }\n return;\n }\n case 3:\n this.locate(0, input[0], L, 0);\n this.locate(1, input[1], L, 3);\n this.locate(2, input[2], L, 6);\n this.tetra(L[0] + L[3] + L[6], L[2], L[5], L[8], L[1], L[4], L[7], out);\n return;\n case 4: {\n this.locate(0, input[0], L, 0);\n this.locate(1, input[1], L, 3);\n this.locate(2, input[2], L, 6);\n this.locate(3, input[3], L, 9);\n const base = L[0] + L[3] + L[6] + L[9];\n const r0 = L[1];\n const s0 = L[2];\n this.tetra(base, L[5], L[8], L[11], L[4], L[7], L[10], this.lo);\n if (r0 > 0 && s0 > 0) {\n this.tetra(base + s0, L[5], L[8], L[11], L[4], L[7], L[10], this.hi);\n for (let k = 0; k < this.outputs; k++) out[k] = this.lo[k] + (this.hi[k] - this.lo[k]) * r0;\n } else for (let k = 0; k < this.outputs; k++) out[k] = this.lo[k];\n return;\n }\n default:\n this.evalMultilinear(input, out);\n }\n }\n\n /** Tetrahedral interpolation in one cube at `base` with strides `sx, sy, sz` and fractions `rx, ry, rz`. */\n tetra(base: number, sx: number, sy: number, sz: number, rx: number, ry: number, rz: number, out: Float32Array | number[]): void {\n const d = this.data;\n let p1: number, p2: number, p3: number, w1: number, w2: number, w3: number;\n const sxy = sx + sy;\n const sall = sxy + sz;\n if (rx >= ry) {\n if (ry >= rz) {\n p1 = sx; p2 = sxy; p3 = sall; w1 = rx; w2 = ry; w3 = rz;\n } else if (rx >= rz) {\n p1 = sx; p2 = sx + sz; p3 = sall; w1 = rx; w2 = rz; w3 = ry;\n } else {\n p1 = sz; p2 = sx + sz; p3 = sall; w1 = rz; w2 = rx; w3 = ry;\n }\n } else if (rx >= rz) {\n p1 = sy; p2 = sxy; p3 = sall; w1 = ry; w2 = rx; w3 = rz;\n } else if (ry >= rz) {\n p1 = sy; p2 = sy + sz; p3 = sall; w1 = ry; w2 = rz; w3 = rx;\n } else {\n p1 = sz; p2 = sy + sz; p3 = sall; w1 = rz; w2 = ry; w3 = rx;\n }\n for (let k = 0; k < this.outputs; k++) {\n const v0 = d[base + k];\n const v1 = d[base + p1 + k];\n const v2 = d[base + p2 + k];\n const v3 = d[base + p3 + k];\n out[k] = v0 + (v1 - v0) * w1 + (v2 - v1) * w2 + (v3 - v2) * w3;\n }\n }\n\n evalMultilinear(input: ArrayLike<number>, out: Float32Array | number[]): void {\n const n = this.inputs;\n let base = 0;\n const r = new Array(n);\n const s = new Array(n);\n const L = [0, 0, 0];\n for (let d = 0; d < n; d++) {\n this.locate(d, input[d], L, 0);\n base += L[0];\n r[d] = L[1];\n s[d] = L[2];\n }\n const o = this.outputs;\n for (let k = 0; k < o; k++) out[k] = 0;\n for (let corner = 0; corner < 1 << n; corner++) {\n let w = 1;\n let off = base;\n for (let d = 0; d < n; d++) {\n if (corner & (1 << d)) {\n w *= r[d];\n off += s[d];\n } else w *= 1 - r[d];\n }\n if (w === 0) continue;\n for (let k = 0; k < o; k++) out[k] += w * this.data[off + k];\n }\n }\n}\n","// Portions ported from photocraft/crates/cms/src/pipeline.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Float evaluation pipelines: stages mapping normalised device values to the profile connection\n * space (or back). This is the exact path; `Transform` builds faster tables from it.\n */\n\nimport { Clut } from './clut';\nimport { evalCurve, evalCurveInverse, isIdentityCurve, type Curve } from './curve';\nimport { D50, type Mat3 } from './math';\n\n/** Largest channel count flowing through a pipeline. */\nexport const MAX_PIPE = 16;\n\nexport type Stage =\n | { kind: 'curves'; curves: Curve[] }\n | { kind: 'inv-curves'; curves: Curve[] }\n /** `out[r] = Σ m[r·cols + c]·in[c] + offset[r]`. */\n | { kind: 'matrix'; rows: number; cols: number; m: number[]; offset: number[] }\n | { kind: 'clut'; clut: Clut }\n /** Float Lab (L 0–100) → XYZ (D50, Y = 1), and back. */\n | { kind: 'lab-to-xyz' }\n | { kind: 'xyz-to-lab' }\n /** ICC v4 / 8-bit Lab encoding (normalised) ↔ float Lab. */\n | { kind: 'decode-lab-v4' }\n | { kind: 'encode-lab-v4' }\n /** ICC v2 legacy 16-bit Lab encoding (`lut16Type`) ↔ float Lab. */\n | { kind: 'decode-lab-v2' }\n | { kind: 'encode-lab-v2' }\n /** u1Fixed15 XYZ encoding ↔ XYZ. */\n | { kind: 'decode-xyz' }\n | { kind: 'encode-xyz' }\n | { kind: 'clamp01' };\n\nconst XYZ_SCALE = 65535 / 32768;\nconst V2_L = (100 * 65535) / 65280;\nconst V2_AB = (255 * 65535) / 65280;\nconst clamp01 = (v: number) => (v < 0 ? 0 : v > 1 ? 1 : v);\n\nexport function matrix3(m: Mat3): Stage {\n return { kind: 'matrix', rows: 3, cols: 3, m: [...m[0], ...m[1], ...m[2]], offset: [0, 0, 0] };\n}\n\n/** Output channels of a stage given `n` inputs. */\nexport function stageOutputs(s: Stage, n: number): number {\n return s.kind === 'matrix' ? s.rows : s.kind === 'clut' ? s.clut.outputs : n;\n}\n\nconst EPS = 216 / 24389;\nconst KAPPA = 24389 / 27;\n\nfunction runStage(s: Stage, v: Float64Array, n: number, tmp: Float64Array, tmpIn: Float32Array, tmpOut: Float32Array): number {\n switch (s.kind) {\n case 'curves':\n for (let k = 0; k < s.curves.length; k++) v[k] = evalCurve(s.curves[k], v[k]);\n return n;\n case 'inv-curves':\n for (let k = 0; k < s.curves.length; k++) v[k] = evalCurveInverse(s.curves[k], v[k]);\n return n;\n case 'matrix': {\n for (let r = 0; r < s.rows; r++) {\n let acc = s.offset[r];\n for (let c = 0; c < s.cols; c++) acc += s.m[r * s.cols + c] * v[c];\n tmp[r] = acc;\n }\n for (let r = 0; r < s.rows; r++) v[r] = tmp[r];\n return s.rows;\n }\n case 'clut': {\n const c = s.clut;\n for (let k = 0; k < c.inputs; k++) tmpIn[k] = v[k];\n c.eval(tmpIn, tmpOut);\n for (let k = 0; k < c.outputs; k++) v[k] = tmpOut[k];\n return c.outputs;\n }\n case 'lab-to-xyz': {\n const fy = (v[0] + 16) / 116;\n const fx = fy + v[1] / 500;\n const fz = fy - v[2] / 200;\n const finv = (f: number) => {\n const f3 = f * f * f;\n return f3 > EPS ? f3 : (116 * f - 16) / KAPPA;\n };\n v[0] = finv(fx) * D50[0];\n v[1] = finv(fy) * D50[1];\n v[2] = finv(fz) * D50[2];\n return 3;\n }\n case 'xyz-to-lab': {\n const f = (t: number) => (t > EPS ? Math.cbrt(t) : (KAPPA * t + 16) / 116);\n const fx = f(Math.max(0, v[0]) / D50[0]);\n const fy = f(Math.max(0, v[1]) / D50[1]);\n const fz = f(Math.max(0, v[2]) / D50[2]);\n v[0] = 116 * fy - 16;\n v[1] = 500 * (fx - fy);\n v[2] = 200 * (fy - fz);\n return 3;\n }\n case 'decode-lab-v4':\n v[0] *= 100;\n v[1] = v[1] * 255 - 128;\n v[2] = v[2] * 255 - 128;\n return 3;\n case 'encode-lab-v4':\n v[0] = clamp01(v[0] / 100);\n v[1] = clamp01((v[1] + 128) / 255);\n v[2] = clamp01((v[2] + 128) / 255);\n return 3;\n case 'decode-lab-v2':\n v[0] *= V2_L;\n v[1] = v[1] * V2_AB - 128;\n v[2] = v[2] * V2_AB - 128;\n return 3;\n case 'encode-lab-v2':\n v[0] = clamp01(v[0] / V2_L);\n v[1] = clamp01((v[1] + 128) / V2_AB);\n v[2] = clamp01((v[2] + 128) / V2_AB);\n return 3;\n case 'decode-xyz':\n for (let k = 0; k < 3; k++) v[k] *= XYZ_SCALE;\n return 3;\n case 'encode-xyz':\n for (let k = 0; k < 3; k++) v[k] = clamp01(v[k] / XYZ_SCALE);\n return 3;\n case 'clamp01':\n for (let k = 0; k < n; k++) v[k] = clamp01(v[k]);\n return n;\n }\n}\n\n/** A sequence of stages with fixed input and output channel counts. */\nexport class Pipeline {\n outputs: number;\n private readonly v = new Float64Array(MAX_PIPE);\n private readonly tmp = new Float64Array(MAX_PIPE);\n private readonly tmpIn = new Float32Array(MAX_PIPE);\n private readonly tmpOut = new Float32Array(MAX_PIPE);\n\n constructor(\n readonly inputs: number,\n public stages: Stage[]\n ) {\n this.outputs = stages.reduce((n, s) => stageOutputs(s, n), inputs);\n }\n\n extend(stages: Stage[]): void {\n for (const s of stages) {\n this.outputs = stageOutputs(s, this.outputs);\n this.stages.push(s);\n }\n }\n\n /** Evaluates one colour: `input` has `inputs` values, `out` receives `outputs`. */\n eval(input: ArrayLike<number>, out: Float32Array | Float64Array | number[]): void {\n const v = this.v;\n for (let k = 0; k < this.inputs; k++) v[k] = input[k];\n let n = this.inputs;\n for (const s of this.stages) n = runStage(s, v, n, this.tmp, this.tmpIn, this.tmpOut);\n for (let k = 0; k < this.outputs; k++) out[k] = v[k];\n }\n\n /** Removes no-op stages, cancels adjacent inverse pairs and merges consecutive 3×3 matrices. */\n optimize(): void {\n const out: Stage[] = [];\n for (const s of this.stages) {\n const noop =\n ((s.kind === 'curves' || s.kind === 'inv-curves') && s.curves.every(isIdentityCurve)) ||\n (s.kind === 'matrix' && s.rows === 3 && s.cols === 3 && s.offset.every((o) => Math.abs(o) < 1e-12) && s.m.every((v, i) => Math.abs(v - (i % 4 === 0 ? 1 : 0)) < 1e-12));\n if (noop) continue;\n const last = out[out.length - 1];\n const pair = last ? `${last.kind}>${s.kind}` : '';\n const cancels = [\n 'lab-to-xyz>xyz-to-lab',\n 'xyz-to-lab>lab-to-xyz',\n 'encode-lab-v4>decode-lab-v4',\n 'encode-lab-v2>decode-lab-v2',\n 'encode-xyz>decode-xyz',\n 'decode-lab-v4>encode-lab-v4',\n 'decode-lab-v2>encode-lab-v2',\n 'decode-xyz>encode-xyz',\n ].includes(pair);\n if (cancels) {\n out.pop();\n continue;\n }\n if (last && last.kind === 'matrix' && s.kind === 'matrix' && last.rows === 3 && last.cols === 3 && s.rows === 3 && s.cols === 3) {\n const a = last.m;\n const b = s.m;\n const m = new Array(9).fill(0);\n const off = [0, 0, 0];\n for (let r = 0; r < 3; r++) {\n for (let c = 0; c < 3; c++) for (let k = 0; k < 3; k++) m[r * 3 + c] += b[r * 3 + k] * a[k * 3 + c];\n off[r] = b[r * 3] * last.offset[0] + b[r * 3 + 1] * last.offset[1] + b[r * 3 + 2] * last.offset[2] + s.offset[r];\n }\n out.pop();\n out.push({ kind: 'matrix', rows: 3, cols: 3, m, offset: off });\n continue;\n }\n out.push(s);\n }\n this.stages = out;\n this.outputs = out.reduce((n, s) => stageOutputs(s, n), this.inputs);\n }\n}\n","// Portions ported from photocraft/crates/cms/src/profile.rs and lib.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * ICC profiles: the parsed model, the reader (ICC.1:2001-04 v2 and ICC.1:2010 v4: matrix/TRC\n * RGB, grey TRC, `mft1` / `mft2` / `mAB ` / `mBA ` LUTs, `curv` / `para` curves) and the\n * connection of a profile to the PCS as evaluation stages.\n */\n\nimport { Clut } from './clut';\nimport { gammaCurve, IDENTITY_CURVE, paramCount, type Curve } from './curve';\nimport { D50, invert, type Mat3, type Vec3 } from './math';\nimport { matrix3, type Stage } from './pipeline';\n\n/** ICC rendering intent. */\nexport type Intent = 'perceptual' | 'relative' | 'saturation' | 'absolute';\n\nexport const INTENTS: readonly Intent[] = ['perceptual', 'relative', 'saturation', 'absolute'];\n\nconst INTENT_CODES: Record<Intent, number> = { perceptual: 0, relative: 1, saturation: 2, absolute: 3 };\n\nexport const intentCode = (i: Intent) => INTENT_CODES[i];\nexport const intentFromCode = (n: number): Intent | null => INTENTS[n] ?? null;\n\n/** Errors from parsing profiles or building transforms. */\nexport class CmsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'CmsError';\n }\n}\n\nexport type ProfileClass = 'input' | 'display' | 'output' | 'link' | 'colorspace' | 'abstract' | 'named' | 'unknown';\n\nconst CLASS_SIGS: Record<string, ProfileClass> = { scnr: 'input', mntr: 'display', prtr: 'output', link: 'link', spac: 'colorspace', abst: 'abstract', nmcl: 'named' };\n\nexport const classSig = (c: ProfileClass): string => Object.entries(CLASS_SIGS).find(([, v]) => v === c)?.[0] ?? 'mntr';\n\n/** Data colour space. */\nexport type ColorSpace = 'xyz' | 'lab' | 'luv' | 'ycbcr' | 'yxy' | 'rgb' | 'gray' | 'hsv' | 'hls' | 'cmyk' | 'cmy' | `${number}clr` | 'unknown';\n\nconst SPACE_SIGS: Record<string, ColorSpace> = {\n 'XYZ ': 'xyz',\n 'Lab ': 'lab',\n 'Luv ': 'luv',\n YCbr: 'ycbcr',\n 'Yxy ': 'yxy',\n 'RGB ': 'rgb',\n GRAY: 'gray',\n 'HSV ': 'hsv',\n 'HLS ': 'hls',\n CMYK: 'cmyk',\n 'CMY ': 'cmy',\n};\n\nfunction spaceFromSig(s: string): ColorSpace {\n if (SPACE_SIGS[s]) return SPACE_SIGS[s];\n const m = /^([2-9A-F])CLR$/.exec(s);\n if (m) return `${parseInt(m[1], 16)}clr` as ColorSpace;\n return 'unknown';\n}\n\nexport function spaceSig(c: ColorSpace): string {\n const hit = Object.entries(SPACE_SIGS).find(([, v]) => v === c);\n if (hit) return hit[0];\n const m = /^(\\d+)clr$/.exec(c);\n if (m) return `${Number(m[1]).toString(16).toUpperCase()}CLR`;\n return 'RGB ';\n}\n\n/** Channels of a colour space. */\nexport function spaceChannels(c: ColorSpace): number {\n if (c === 'gray') return 1;\n if (c === 'cmyk') return 4;\n if (c === 'unknown') return 0;\n const m = /^(\\d+)clr$/.exec(c);\n return m ? Number(m[1]) : 3;\n}\n\n/** The PCS a stage list ends in (XYZ with Y = 1 for the white, or Lab with L 0–100). */\nexport type Pcs = 'xyz' | 'lab';\n\n/** Encoding family of a LUT tag, which fixes how its PCS side is encoded. */\nexport type LutKind = 'lut8' | 'lut16' | 'ab';\n\n/** A parsed `AToB` / `BToA` tag: device and PCS values normalised to 0..1. */\nexport interface Lut {\n kind: LutKind;\n inputs: number;\n outputs: number;\n stages: Stage[];\n}\n\n/** A parsed ICC profile. */\nexport interface Profile {\n /** Major version and minor.bugfix byte (`[4, 0x30]` for 4.3). */\n version: [number, number];\n profileClass: ProfileClass;\n colorSpace: ColorSpace;\n pcs: Pcs;\n renderingIntent: Intent;\n description: string;\n copyright: string;\n /** `wtpt` (D50 when absent). */\n whitePoint: Vec3;\n blackPoint: Vec3 | null;\n /** `chad` chromatic adaptation. */\n chad: Mat3 | null;\n /** Colorant matrix (columns rXYZ, gXYZ, bXYZ), D50-adapted. */\n matrix: Mat3 | null;\n trc: [Curve, Curve, Curve] | null;\n grayTrc: Curve | null;\n /** AToB0/1/2 (perceptual, colorimetric, saturation). */\n a2b: [Lut | null, Lut | null, Lut | null];\n b2a: [Lut | null, Lut | null, Lut | null];\n /** The bytes it was parsed from (or encoded to), for byte-exact embedding. */\n bytes: Uint8Array | null;\n}\n\nexport function profileChannels(p: Profile): number {\n return spaceChannels(p.colorSpace);\n}\n\n/** Largest ΔE*ab at which `sameColors` treats two profiles as one colour space. */\nexport const SAME_COLORS_MAX_DELTA_E = 0.5;\n\n/**\n * Media white for ICC-absolute colorimetry: `wtpt`, except for v2 display profiles, whose\n * `wtpt` records the unadapted display white; those count as D50.\n */\nexport function mediaWhite(p: Profile): Vec3 {\n if (p.version[0] < 4 && p.profileClass === 'display') return [D50[0], D50[1], D50[2]];\n return p.whitePoint;\n}\n\n/** True for matrix/TRC RGB or grey TRC profiles without LUTs. */\nexport function isMatrixShaper(p: Profile): boolean {\n return p.a2b.every((l) => !l) && ((p.matrix !== null && p.trc !== null) || p.grayTrc !== null);\n}\n\nconst lutIndex = (intent: Intent) => (intent === 'perceptual' ? 0 : intent === 'saturation' ? 2 : 1);\n\nfunction lutFor(luts: Profile['a2b'], intent: Intent): Lut | null {\n return luts[lutIndex(intent)] ?? luts[0];\n}\n\n/** Whether the profile has its own table for `intent` (matrix profiles serve every intent). */\nexport function supportsIntent(p: Profile, intent: Intent, input: boolean): boolean {\n const luts = input ? p.a2b : p.b2a;\n return Boolean(luts[lutIndex(intent)]) || luts.every((l) => !l);\n}\n\nfunction decodePcs(pcs: Pcs, kind: LutKind): Stage {\n if (pcs === 'xyz') return { kind: 'decode-xyz' };\n return kind === 'lut16' ? { kind: 'decode-lab-v2' } : { kind: 'decode-lab-v4' };\n}\n\nfunction encodePcs(pcs: Pcs, kind: LutKind): Stage {\n if (pcs === 'xyz') return { kind: 'encode-xyz' };\n return kind === 'lut16' ? { kind: 'encode-lab-v2' } : { kind: 'encode-lab-v4' };\n}\n\n/** Stages mapping normalised device values to the float PCS. */\nexport function deviceToPcs(p: Profile, intent: Intent): { stages: Stage[]; pcs: Pcs } {\n const l = lutFor(p.a2b, intent);\n if (l) return { stages: [...l.stages, decodePcs(p.pcs, l.kind)], pcs: p.pcs };\n switch (p.colorSpace) {\n case 'rgb':\n if (!p.matrix || !p.trc) throw new CmsError('RGB profile without matrix/TRC or AToB tags');\n return { stages: [{ kind: 'curves', curves: [...p.trc] }, matrix3(p.matrix)], pcs: 'xyz' };\n case 'gray': {\n if (!p.grayTrc) throw new CmsError('gray profile without kTRC');\n if (p.pcs === 'lab') return { stages: [{ kind: 'curves', curves: [p.grayTrc] }, { kind: 'matrix', rows: 3, cols: 1, m: [100, 0, 0], offset: [0, 0, 0] }], pcs: 'lab' };\n return { stages: [{ kind: 'curves', curves: [p.grayTrc] }, { kind: 'matrix', rows: 3, cols: 1, m: [D50[0], D50[1], D50[2]], offset: [0, 0, 0] }], pcs: 'xyz' };\n }\n case 'lab':\n return { stages: [{ kind: 'decode-lab-v4' }], pcs: 'lab' };\n case 'xyz':\n return { stages: [{ kind: 'decode-xyz' }], pcs: 'xyz' };\n default:\n throw new CmsError(`${p.colorSpace} profile without AToB tags`);\n }\n}\n\n/** Stages mapping the float PCS (of the returned kind) to normalised device values. */\nexport function pcsToDevice(p: Profile, intent: Intent): { stages: Stage[]; pcs: Pcs } {\n const l = lutFor(p.b2a, intent);\n if (l) return { stages: [encodePcs(p.pcs, l.kind), ...l.stages], pcs: p.pcs };\n switch (p.colorSpace) {\n case 'rgb': {\n if (!p.matrix || !p.trc) throw new CmsError('RGB profile without matrix/TRC or BToA tags');\n const inv = invert(p.matrix);\n if (!inv) throw new CmsError('singular colorant matrix');\n return { stages: [matrix3(inv), { kind: 'inv-curves', curves: [...p.trc] }], pcs: 'xyz' };\n }\n case 'gray': {\n if (!p.grayTrc) throw new CmsError('gray profile without kTRC');\n if (p.pcs === 'lab') return { stages: [{ kind: 'matrix', rows: 1, cols: 3, m: [0.01, 0, 0], offset: [0] }, { kind: 'inv-curves', curves: [p.grayTrc] }], pcs: 'lab' };\n return { stages: [{ kind: 'matrix', rows: 1, cols: 3, m: [0, 1, 0], offset: [0] }, { kind: 'inv-curves', curves: [p.grayTrc] }], pcs: 'xyz' };\n }\n case 'lab':\n return { stages: [{ kind: 'encode-lab-v4' }], pcs: 'lab' };\n case 'xyz':\n return { stages: [{ kind: 'encode-xyz' }], pcs: 'xyz' };\n default:\n throw new CmsError(`${p.colorSpace} profile without BToA tags`);\n }\n}\n\n/** Whether colours can be converted into this profile for every intent (input-only profiles cannot). */\nexport function canBeDestination(p: Profile): boolean {\n try {\n for (const i of ['perceptual', 'relative', 'saturation'] as const) pcsToDevice(p, i);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * An RGB view of a grey TRC profile: R, G and B each carry the grey curve and a third of the\n * white, so (v, v, v) has exactly the colour of grey v.\n */\nexport function grayAsRgb(p: Profile): Profile | null {\n if (!p.grayTrc || p.pcs !== 'xyz') return null;\n const w = D50;\n const c = p.grayTrc;\n return {\n ...p,\n colorSpace: 'rgb',\n description: `${p.description} (as RGB)`,\n matrix: [\n [w[0] / 3, w[0] / 3, w[0] / 3],\n [w[1] / 3, w[1] / 3, w[1] / 3],\n [w[2] / 3, w[2] / 3, w[2] / 3],\n ],\n trc: [c, c, c],\n grayTrc: null,\n a2b: [null, null, null],\n b2a: [null, null, null],\n bytes: null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Reader\n// ---------------------------------------------------------------------------\n\nclass Reader {\n constructor(readonly b: Uint8Array) {}\n check(off: number, len: number): void {\n if (off < 0 || len < 0 || off + len > this.b.length) throw new CmsError('ICC profile is truncated');\n }\n slice(off: number, len: number): Uint8Array {\n this.check(off, len);\n return this.b.subarray(off, off + len);\n }\n u8(off: number): number {\n this.check(off, 1);\n return this.b[off];\n }\n u16(off: number): number {\n this.check(off, 2);\n return (this.b[off] << 8) | this.b[off + 1];\n }\n u32(off: number): number {\n this.check(off, 4);\n return ((this.b[off] << 24) | (this.b[off + 1] << 16) | (this.b[off + 2] << 8) | this.b[off + 3]) >>> 0;\n }\n s15f16(off: number): number {\n return (this.u32(off) | 0) / 65536;\n }\n xyz(off: number): Vec3 {\n return [this.s15f16(off), this.s15f16(off + 4), this.s15f16(off + 8)];\n }\n ascii(off: number, len: number): string {\n return String.fromCharCode(...this.slice(off, len));\n }\n}\n\n/** Upper bound on CLUT nodes × outputs, to refuse hostile files. */\nconst MAX_CLUT_VALUES = 16 * 1024 * 1024;\n\n/** Parses ICC profile bytes. Throws `CmsError` for anything that is not a usable profile. */\nexport function parseProfile(bytes: Uint8Array): Profile {\n if (bytes.length < 132) throw new CmsError('ICC profile is truncated');\n const head = new Reader(bytes);\n if (head.ascii(36, 4) !== 'acsp') throw new CmsError(\"not an ICC profile (missing 'acsp' signature)\");\n const declared = head.u32(0);\n // Some writers pad or truncate: trust the smaller of the two.\n const end = declared >= 132 && declared <= bytes.length ? declared : bytes.length;\n const r = new Reader(bytes.subarray(0, end));\n const version: [number, number] = [r.u8(8), r.u8(9)];\n const profileClass = CLASS_SIGS[r.ascii(12, 4)] ?? 'unknown';\n const colorSpace = spaceFromSig(r.ascii(16, 4));\n const pcsSig = r.ascii(20, 4);\n const pcs: Pcs = pcsSig === 'Lab ' ? 'lab' : 'xyz';\n const renderingIntent = intentFromCode(r.u32(64) & 0xffff) ?? 'perceptual';\n const count = r.u32(128);\n if (count > 1024) throw new CmsError(`invalid ICC profile: ${count} tags`);\n const tags = new Map<string, [number, number]>();\n for (let i = 0; i < count; i++) {\n const o = 132 + i * 12;\n const sig = r.ascii(o, 4);\n if (!tags.has(sig)) tags.set(sig, [r.u32(o + 4), r.u32(o + 8)]);\n }\n const tagData = (sig: string): Uint8Array | null => {\n const t = tags.get(sig);\n return t ? r.slice(t[0], t[1]) : null;\n };\n const xyzTag = (sig: string): Vec3 | null => {\n const d = tagData(sig);\n if (!d) return null;\n const dr = new Reader(d);\n if (d.length < 20 || dr.ascii(0, 4) !== 'XYZ ') throw new CmsError(`invalid ICC profile: tag ${sig} is not XYZType`);\n return dr.xyz(8);\n };\n const curveTag = (sig: string): Curve | null => {\n const d = tagData(sig);\n return d ? parseCurve(d)[0] : null;\n };\n const whitePoint = xyzTag('wtpt') ?? [D50[0], D50[1], D50[2]];\n let blackPoint: Vec3 | null = null;\n try {\n blackPoint = xyzTag('bkpt');\n } catch {\n blackPoint = null;\n }\n let chad: Mat3 | null = null;\n const cd = tagData('chad');\n if (cd && cd.length >= 44 && new Reader(cd).ascii(0, 4) === 'sf32') {\n const rd = new Reader(cd);\n chad = [\n [rd.s15f16(8), rd.s15f16(12), rd.s15f16(16)],\n [rd.s15f16(20), rd.s15f16(24), rd.s15f16(28)],\n [rd.s15f16(32), rd.s15f16(36), rd.s15f16(40)],\n ];\n }\n const rr = xyzTag('rXYZ');\n const gg = xyzTag('gXYZ');\n const bb = xyzTag('bXYZ');\n const matrix: Mat3 | null =\n rr && gg && bb\n ? [\n [rr[0], gg[0], bb[0]],\n [rr[1], gg[1], bb[1]],\n [rr[2], gg[2], bb[2]],\n ]\n : null;\n const tr = curveTag('rTRC');\n const tg = curveTag('gTRC');\n const tb = curveTag('bTRC');\n const trc: [Curve, Curve, Curve] | null = tr && tg && tb ? [tr, tg, tb] : null;\n const grayTrc = curveTag('kTRC');\n const lut = (sig: string, a2b: boolean): Lut | null => {\n const d = tagData(sig);\n return d ? parseLut(d, a2b) : null;\n };\n const a2b: Profile['a2b'] = [lut('A2B0', true), lut('A2B1', true), lut('A2B2', true)];\n const b2a: Profile['b2a'] = [lut('B2A0', false), lut('B2A1', false), lut('B2A2', false)];\n const desc = tagData('desc');\n const cprt = tagData('cprt');\n const p: Profile = {\n version,\n profileClass,\n colorSpace,\n pcs,\n renderingIntent,\n description: desc ? parseText(desc) : '',\n copyright: cprt ? parseText(cprt) : '',\n whitePoint,\n blackPoint,\n chad,\n matrix,\n trc,\n grayTrc,\n a2b,\n b2a,\n bytes: bytes.slice(),\n };\n // LUT channel counts must match the header. A DeviceLink's PCS field holds its output space.\n const dev = spaceChannels(colorSpace);\n const conn = profileClass === 'link' ? spaceChannels(spaceFromSig(pcsSig)) : 3;\n for (const l of a2b) if (l && ((dev !== 0 && l.inputs !== dev) || (conn !== 0 && l.outputs !== conn))) throw new CmsError(`invalid ICC profile: AToB tag has ${l.inputs}→${l.outputs} channels for a ${colorSpace} profile`);\n for (const l of b2a) if (l && ((conn !== 0 && l.inputs !== conn) || (dev !== 0 && l.outputs !== dev))) throw new CmsError(`invalid ICC profile: BToA tag has ${l.inputs}→${l.outputs} channels for a ${colorSpace} profile`);\n return p;\n}\n\n/** A `curv` or `para` element: the curve and its unpadded byte length. */\nfunction parseCurve(d: Uint8Array): [Curve, number] {\n const r = new Reader(d);\n const type = r.ascii(0, 4);\n if (type === 'curv') {\n const n = r.u32(8);\n const len = 12 + n * 2;\n if (n === 0) return [IDENTITY_CURVE, len];\n if (n === 1) return [gammaCurve(r.u16(12) / 256), len];\n if (n > 1 << 20) throw new CmsError('invalid ICC profile: curve too long');\n r.check(12, n * 2);\n const t = new Float32Array(n);\n for (let i = 0; i < n; i++) t[i] = r.u16(12 + i * 2) / 65535;\n return [{ type: 'table', table: t }, len];\n }\n if (type === 'para') {\n const kind = r.u16(8);\n if (kind > 4) throw new CmsError(`unsupported ICC feature: parametric curve type ${kind}`);\n const n = paramCount(kind);\n const p = [0, 0, 0, 0, 0, 0, 0];\n for (let i = 0; i < n; i++) p[i] = r.s15f16(12 + i * 4);\n return [kind === 0 ? gammaCurve(p[0]) : { type: 'parametric', kind, p }, 12 + n * 4];\n }\n throw new CmsError(`unsupported ICC feature: curve type \"${type}\"`);\n}\n\nfunction parseCurvesAt(d: Uint8Array, off: number, n: number): Curve[] {\n const out: Curve[] = [];\n let o = off;\n for (let k = 0; k < n; k++) {\n if (o >= d.length) throw new CmsError('ICC profile is truncated');\n const [c, len] = parseCurve(d.subarray(o));\n out.push(c);\n o += (len + 3) & ~3;\n }\n return out;\n}\n\nfunction parseLut(d: Uint8Array, a2b: boolean): Lut {\n const r = new Reader(d);\n const ty = r.ascii(0, 4);\n if (ty === 'mft1' || ty === 'mft2') {\n const wide = ty === 'mft2';\n const i = r.u8(8);\n const o = r.u8(9);\n const g = r.u8(10);\n if (i < 1 || i > 15 || o < 1 || o > 15 || g === 0) throw new CmsError('invalid ICC profile: bad lut dimensions');\n const m: Mat3 = [\n [r.s15f16(12), r.s15f16(16), r.s15f16(20)],\n [r.s15f16(24), r.s15f16(28), r.s15f16(32)],\n [r.s15f16(36), r.s15f16(40), r.s15f16(44)],\n ];\n const nIn = wide ? r.u16(48) : 256;\n const nOut = wide ? r.u16(50) : 256;\n let off = wide ? 52 : 48;\n if (wide && (nIn < 2 || nIn > 4096 || nOut < 2 || nOut > 4096)) throw new CmsError('invalid ICC profile: bad lut16 table size');\n const bps = wide ? 2 : 1;\n const values = (at: number, count: number): Float32Array => {\n r.check(at, count * bps);\n const out = new Float32Array(count);\n if (wide) for (let k = 0; k < count; k++) out[k] = r.u16(at + 2 * k) / 65535;\n else for (let k = 0; k < count; k++) out[k] = d[at + k] / 255;\n return out;\n };\n const tables = (count: number, len: number): Curve[] => {\n const v: Curve[] = [];\n for (let k = 0; k < count; k++) {\n v.push({ type: 'table', table: values(off, len) });\n off += len * bps;\n }\n return v;\n };\n const inCurves = tables(i, nIn);\n const nodes = Math.pow(g, i);\n if (nodes * o > MAX_CLUT_VALUES) throw new CmsError('invalid ICC profile: CLUT too large');\n const data = values(off, nodes * o);\n off += nodes * o * bps;\n const outCurves = tables(o, nOut);\n const stages: Stage[] = [];\n const ident = m.every((row, a) => row.every((v, b) => Math.abs(v - (a === b ? 1 : 0)) < 1e-6));\n // The matrix only applies to an XYZ PCS input (BToA); Lab writers must store the identity.\n if (!a2b && i === 3 && !ident) stages.push(matrix3(m));\n stages.push({ kind: 'curves', curves: inCurves });\n stages.push({ kind: 'clut', clut: new Clut(new Array(i).fill(g), o, data) });\n stages.push({ kind: 'curves', curves: outCurves });\n return { kind: wide ? 'lut16' : 'lut8', inputs: i, outputs: o, stages };\n }\n if (ty === 'mAB ' || ty === 'mBA ') {\n const i = r.u8(8);\n const o = r.u8(9);\n if (i < 1 || i > 15 || o < 1 || o > 15) throw new CmsError('invalid ICC profile: bad lutAB dimensions');\n const ob = r.u32(12);\n const om = r.u32(16);\n const omc = r.u32(20);\n const oc = r.u32(24);\n const oa = r.u32(28);\n const matrix = (at: number): Stage => {\n const m: number[] = [];\n for (let k = 0; k < 9; k++) m.push(r.s15f16(at + k * 4));\n return { kind: 'matrix', rows: 3, cols: 3, m, offset: [r.s15f16(at + 36), r.s15f16(at + 40), r.s15f16(at + 44)] };\n };\n const clut = (at: number, cin: number, cout: number): Stage => {\n const grid: number[] = [];\n for (let k = 0; k < cin; k++) {\n const gp = r.u8(at + k);\n if (gp < 1) throw new CmsError('invalid ICC profile: zero grid points');\n grid.push(gp);\n }\n const prec = r.u8(at + 16);\n const nodes = grid.reduce((a, b) => a * b, 1);\n if (nodes * cout > MAX_CLUT_VALUES) throw new CmsError('invalid ICC profile: CLUT too large');\n const total = nodes * cout;\n const data = new Float32Array(total);\n if (prec === 1) {\n r.check(at + 20, total);\n for (let k = 0; k < total; k++) data[k] = d[at + 20 + k] / 255;\n } else if (prec === 2) {\n r.check(at + 20, total * 2);\n for (let k = 0; k < total; k++) data[k] = r.u16(at + 20 + 2 * k) / 65535;\n } else throw new CmsError(`invalid ICC profile: CLUT precision ${prec}`);\n return { kind: 'clut', clut: new Clut(grid, cout, data) };\n };\n const stages: Stage[] = [];\n if (ty === 'mAB ') {\n // A curves → CLUT → M curves → matrix → B curves.\n if (oc !== 0) {\n if (oa === 0) throw new CmsError('invalid ICC profile: lutAtoB with CLUT but no A curves');\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, oa, i) });\n stages.push(clut(oc, i, o));\n } else if (i !== o) throw new CmsError('invalid ICC profile: lutAtoB without CLUT changes channel count');\n if (om !== 0) {\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, omc, o) });\n stages.push(matrix(om));\n }\n if (ob === 0) throw new CmsError('invalid ICC profile: lutAtoB without B curves');\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, ob, o) });\n } else {\n // B curves → matrix → M curves → CLUT → A curves.\n if (ob === 0) throw new CmsError('invalid ICC profile: lutBtoA without B curves');\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, ob, i) });\n if (om !== 0) {\n stages.push(matrix(om));\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, omc, i) });\n }\n if (oc !== 0) {\n if (oa === 0) throw new CmsError('invalid ICC profile: lutBtoA with CLUT but no A curves');\n stages.push(clut(oc, i, o));\n stages.push({ kind: 'curves', curves: parseCurvesAt(d, oa, o) });\n } else if (i !== o) throw new CmsError('invalid ICC profile: lutBtoA without CLUT changes channel count');\n }\n return { kind: 'ab', inputs: i, outputs: o, stages };\n }\n throw new CmsError(`unsupported ICC feature: LUT type \"${ty}\"`);\n}\n\n/** Text from `desc`, `mluc` (English, else the first record) or `text`. */\nfunction parseText(d: Uint8Array): string {\n try {\n const r = new Reader(d);\n const ty = r.ascii(0, 4);\n const ascii = (s: Uint8Array) => {\n const z = s.indexOf(0);\n return String.fromCharCode(...(z >= 0 ? s.subarray(0, z) : s)).trim();\n };\n if (ty === 'desc') return ascii(r.slice(12, Math.min(r.u32(8), d.length - 12)));\n if (ty === 'text') return ascii(d.subarray(8));\n if (ty === 'mluc') {\n const n = r.u32(8);\n const size = r.u32(12);\n let best: [number, number] | null = null;\n for (let k = 0; k < Math.min(n, 256); k++) {\n const o = 16 + k * size;\n const lang = r.ascii(o, 2);\n const len = r.u32(o + 4);\n const off = r.u32(o + 8);\n if (!best || lang === 'en') {\n best = [off, len];\n if (lang === 'en') break;\n }\n }\n if (!best) return '';\n const s = r.slice(best[0], best[1]);\n let out = '';\n for (let k = 0; k + 1 < s.length; k += 2) out += String.fromCharCode((s[k] << 8) | s[k + 1]);\n return out.replace(/\\0+$/, '').trim();\n }\n } catch {\n return '';\n }\n return '';\n}\n","// Portions ported from photocraft/crates/cms/src/write.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/** Encodes a profile model as ICC v4.3 bytes (matrix/TRC, grey TRC, `mft1` / `mft2` / `mAB ` / `mBA ` LUTs). */\n\nimport type { Clut } from './clut';\nimport { paramCount, sampleCurve, type Curve } from './curve';\nimport { D50 } from './math';\nimport type { Stage } from './pipeline';\nimport { classSig, intentCode, spaceSig, type Profile } from './profile';\n\nclass Bytes {\n private buf = new Uint8Array(1024);\n length = 0;\n private grow(n: number) {\n if (this.length + n <= this.buf.length) return;\n let cap = this.buf.length * 2;\n while (cap < this.length + n) cap *= 2;\n const next = new Uint8Array(cap);\n next.set(this.buf.subarray(0, this.length));\n this.buf = next;\n }\n u8(...v: number[]) {\n this.grow(v.length);\n for (const x of v) this.buf[this.length++] = x & 255;\n }\n u16(v: number) {\n this.u8(v >> 8, v);\n }\n u32(v: number) {\n this.u8(v >>> 24, v >>> 16, v >>> 8, v);\n }\n ascii(s: string) {\n for (let i = 0; i < s.length; i++) this.u8(s.charCodeAt(i));\n }\n s15(v: number) {\n this.u32(Math.round(v * 65536) | 0);\n }\n bytes(b: Uint8Array) {\n this.grow(b.length);\n this.buf.set(b, this.length);\n this.length += b.length;\n }\n pad4() {\n while (this.length % 4) this.u8(0);\n }\n set32(at: number, v: number) {\n this.buf[at] = v >>> 24;\n this.buf[at + 1] = (v >>> 16) & 255;\n this.buf[at + 2] = (v >>> 8) & 255;\n this.buf[at + 3] = v & 255;\n }\n result(): Uint8Array {\n return this.buf.slice(0, this.length);\n }\n}\n\nconst u16q = (v: number) => Math.round(Math.min(1, Math.max(0, v)) * 65535);\n\nfunction xyzType(v: readonly number[]): Uint8Array {\n const o = new Bytes();\n o.ascii('XYZ ');\n o.u32(0);\n for (const c of v) o.s15(c);\n return o.result();\n}\n\nfunction mluc(text: string): Uint8Array {\n const o = new Bytes();\n o.ascii('mluc');\n o.u32(0);\n o.u32(1);\n o.u32(12);\n o.ascii('enUS');\n o.u32(text.length * 2);\n o.u32(28);\n for (let i = 0; i < text.length; i++) o.u16(text.charCodeAt(i));\n return o.result();\n}\n\nfunction curveElem(c: Curve): Uint8Array {\n const o = new Bytes();\n switch (c.type) {\n case 'identity':\n o.ascii('curv');\n o.u32(0);\n o.u32(0);\n break;\n case 'gamma':\n o.ascii('para');\n o.u32(0);\n o.u32(0);\n o.s15(c.gamma);\n break;\n case 'parametric':\n o.ascii('para');\n o.u32(0);\n o.u16(c.kind);\n o.u16(0);\n for (let i = 0; i < paramCount(c.kind); i++) o.s15(c.p[i]);\n break;\n case 'table':\n o.ascii('curv');\n o.u32(0);\n o.u32(c.table.length);\n for (const v of c.table) o.u16(u16q(v));\n break;\n }\n return o.result();\n}\n\nfunction curveTable(c: Curve, n: number): Float32Array {\n return c.type === 'table' && c.table.length === n ? c.table : sampleCurve(c, n);\n}\n\nfunction tableLen(cs: Curve[]): number {\n let n = 2;\n for (const c of cs) n = Math.max(n, c.type === 'table' ? c.table.length : c.type === 'identity' ? 2 : 1024);\n return Math.min(4096, Math.max(2, n));\n}\n\nfunction lutParts(stages: Stage[]): { mat: number[] | null; a: Curve[]; clut: Clut; b: Curve[] } | null {\n let i = 0;\n let mat: number[] | null = null;\n const first = stages[0];\n if (first?.kind === 'matrix' && first.rows === 3 && first.cols === 3) {\n mat = first.m;\n i = 1;\n }\n const [a, c, b] = stages.slice(i);\n if (stages.length - i !== 3 || a?.kind !== 'curves' || c?.kind !== 'clut' || b?.kind !== 'curves') return null;\n return { mat, a: a.curves, clut: c.clut, b: b.curves };\n}\n\nfunction encodeMft(stages: Stage[], wide: boolean): Uint8Array | null {\n const parts = lutParts(stages);\n if (!parts) return null;\n const { mat, a, clut, b } = parts;\n const g = clut.grid[0];\n if (!clut.grid.every((x) => x === g)) return null;\n const o = new Bytes();\n o.ascii(wide ? 'mft2' : 'mft1');\n o.u32(0);\n o.u8(clut.inputs, clut.outputs, g, 0);\n for (const v of mat ?? [1, 0, 0, 0, 1, 0, 0, 0, 1]) o.s15(v);\n const nIn = wide ? tableLen(a) : 256;\n const nOut = wide ? tableLen(b) : 256;\n if (wide) {\n o.u16(nIn);\n o.u16(nOut);\n }\n const put = (v: number) => (wide ? o.u16(u16q(v)) : o.u8(Math.round(Math.min(1, Math.max(0, v)) * 255)));\n for (const c of a) for (const v of curveTable(c, nIn)) put(v);\n for (const v of clut.data) put(v);\n for (const c of b) for (const v of curveTable(c, nOut)) put(v);\n return o.result();\n}\n\nfunction encodeAb(stages: Stage[], a2b: boolean, inputs: number, outputs: number): Uint8Array | null {\n let aCurves: Curve[] | null = null;\n let clut: Clut | null = null;\n let mCurves: Curve[] | null = null;\n let matrix: { m: number[]; offset: number[] } | null = null;\n let bCurves: Curve[] | null = null;\n const v = stages;\n if (a2b) {\n let k = 0;\n if (v[0]?.kind === 'curves' && v[1]?.kind === 'clut') {\n aCurves = v[0].curves;\n clut = v[1].clut;\n k = 2;\n }\n const rest = v.slice(k);\n if (rest.length === 3 && rest[0].kind === 'curves' && rest[1].kind === 'matrix' && rest[2].kind === 'curves') {\n mCurves = rest[0].curves;\n matrix = { m: rest[1].m, offset: rest[1].offset };\n bCurves = rest[2].curves;\n } else if (rest.length === 1 && rest[0].kind === 'curves') bCurves = rest[0].curves;\n else return null;\n } else {\n let k = 0;\n if (v[0]?.kind === 'curves') {\n bCurves = v[0].curves;\n k = 1;\n }\n const m0 = v[k];\n const m1 = v[k + 1];\n if (m0?.kind === 'matrix' && m1?.kind === 'curves') {\n matrix = { m: m0.m, offset: m0.offset };\n mCurves = m1.curves;\n k += 2;\n }\n const c0 = v[k];\n const c1 = v[k + 1];\n if (c0?.kind === 'clut' && c1?.kind === 'curves') {\n clut = c0.clut;\n aCurves = c1.curves;\n k += 2;\n }\n if (k !== v.length) return null;\n }\n if (!bCurves) return null;\n const o = new Bytes();\n o.ascii(a2b ? 'mAB ' : 'mBA ');\n o.u32(0);\n o.u8(inputs, outputs, 0, 0);\n for (let k = 0; k < 5; k++) o.u32(0);\n const offs = [0, 0, 0, 0, 0];\n const curves = (cs: Curve[]) => {\n for (const c of cs) {\n o.bytes(curveElem(c));\n o.pad4();\n }\n };\n offs[0] = o.length;\n curves(bCurves);\n if (matrix) {\n offs[1] = o.length;\n for (const x of matrix.m) o.s15(x);\n for (const x of matrix.offset) o.s15(x);\n offs[2] = o.length;\n if (!mCurves) return null;\n curves(mCurves);\n }\n if (clut) {\n offs[3] = o.length;\n const g = new Array(16).fill(0);\n clut.grid.forEach((n, k) => (g[k] = n));\n o.u8(...g);\n o.u8(2, 0, 0, 0);\n for (const x of clut.data) o.u16(u16q(x));\n o.pad4();\n offs[4] = o.length;\n if (!aCurves) return null;\n curves(aCurves);\n }\n offs.forEach((x, k) => o.set32(12 + k * 4, x));\n return o.result();\n}\n\nconst sameBytes = (a: Uint8Array, b: Uint8Array) => a.length === b.length && a.every((v, i) => v === b[i]);\n\n/** ICC v4.3 bytes of a profile model. */\nexport function encodeProfile(p: Profile): Uint8Array {\n const tags: Array<[string, Uint8Array]> = [];\n tags.push(['desc', mluc(p.description)]);\n tags.push(['cprt', mluc(p.copyright)]);\n tags.push(['wtpt', xyzType(p.whitePoint)]);\n if (p.blackPoint) tags.push(['bkpt', xyzType(p.blackPoint)]);\n if (p.chad) {\n const o = new Bytes();\n o.ascii('sf32');\n o.u32(0);\n for (const row of p.chad) for (const v of row) o.s15(v);\n tags.push(['chad', o.result()]);\n }\n if (p.matrix) {\n const m = p.matrix;\n tags.push(['rXYZ', xyzType([m[0][0], m[1][0], m[2][0]])]);\n tags.push(['gXYZ', xyzType([m[0][1], m[1][1], m[2][1]])]);\n tags.push(['bXYZ', xyzType([m[0][2], m[1][2], m[2][2]])]);\n }\n if (p.trc) {\n tags.push(['rTRC', curveElem(p.trc[0])]);\n tags.push(['gTRC', curveElem(p.trc[1])]);\n tags.push(['bTRC', curveElem(p.trc[2])]);\n }\n if (p.grayTrc) tags.push(['kTRC', curveElem(p.grayTrc)]);\n for (const [luts, names, a2b] of [\n [p.a2b, ['A2B0', 'A2B1', 'A2B2'], true],\n [p.b2a, ['B2A0', 'B2A1', 'B2A2'], false],\n ] as const) {\n luts.forEach((l, k) => {\n if (!l) return;\n const data = l.kind === 'lut16' ? encodeMft(l.stages, true) : l.kind === 'lut8' ? encodeMft(l.stages, false) : encodeAb(l.stages, a2b, l.inputs, l.outputs);\n if (data) tags.push([names[k], data]);\n });\n }\n const tableLength = 4 + tags.length * 12;\n const data = new Bytes();\n const entries: Array<[string, number, number]> = [];\n const placed: Array<[Uint8Array, number, number]> = [];\n for (const [sig, d] of tags) {\n // Identical tag data is stored once and shared.\n const same = placed.find(([b]) => sameBytes(b, d));\n if (same) {\n entries.push([sig, same[1], same[2]]);\n continue;\n }\n const off = 128 + tableLength + data.length;\n data.bytes(d);\n data.pad4();\n entries.push([sig, off, d.length]);\n placed.push([d, off, d.length]);\n }\n const size = 128 + tableLength + data.length;\n const o = new Bytes();\n o.u32(size);\n o.u32(0);\n o.u8(4, 0x30, 0, 0);\n o.ascii(classSig(p.profileClass));\n o.ascii(spaceSig(p.colorSpace));\n o.ascii(p.pcs === 'lab' ? 'Lab ' : 'XYZ ');\n for (const v of [2026, 1, 1, 0, 0, 0]) o.u16(v);\n o.ascii('acsp');\n for (let k = 0; k < 6; k++) o.u32(0); // platform, flags, manufacturer, model, attributes\n o.u32(intentCode(p.renderingIntent));\n for (const v of D50) o.s15(v);\n o.u32(0); // creator\n while (o.length < 128) o.u8(0);\n o.u32(entries.length);\n for (const [sig, off, len] of entries) {\n o.ascii(sig);\n o.u32(off);\n o.u32(len);\n }\n o.bytes(data.result());\n return o.result();\n}\n","// Portions ported from photocraft/crates/cms/src/transform.rs, gamut.rs and lut3d.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Colour transforms between profiles through the PCS: rendering intents, black point\n * compensation (the structure of Adobe's published algorithm), soft-proofing chains, gamut\n * checks, and lookup-table evaluation of pixel buffers.\n *\n * - The exact path is a float stage pipeline; float buffers use it by default.\n * - Integer buffers use per-code input tables plus a matrix plus output tables indexed by\n * x^(1/4) (accurate near black even for pure gamma curves) for matrix/TRC chains, a device\n * link sampled at 33³ (3 inputs) or 17⁴ (4 inputs) with tetrahedral interpolation for chains\n * with a CLUT, and the exact path for purely analytic chains (e.g. Lab ↔ RGB).\n */\n\nimport { Clut } from './clut';\nimport { evalCurve, evalCurveInverse, type Curve } from './curve';\nimport { D50, deltaE76, labToXyz } from './math';\nimport { Pipeline, type Stage } from './pipeline';\nimport { CmsError, deviceToPcs, mediaWhite, pcsToDevice, profileChannels, type ColorSpace, type Intent, type Pcs, type Profile } from './profile';\n\nexport interface TransformOptions {\n intent: Intent;\n /** Black point compensation (ignored for absolute colorimetric). Default true. */\n bpc: boolean;\n /** Float buffers through the exact pipeline (default true) rather than the tables. */\n preciseFloat: boolean;\n}\n\nexport const DEFAULT_TRANSFORM_OPTIONS: Readonly<TransformOptions> = { intent: 'relative', bpc: true, preciseFloat: true };\n\nconst GRID_3D = 33;\nconst GRID_4D = 17;\nconst TABLE_1D = 4096;\nconst OUT_TABLE = 4096;\n\n/** ICC v4 perceptual reference medium black (ICC.1:2010 §6.3.4.4), Y. */\nconst PERCEPTUAL_BLACK_Y = 0.0034731;\n\ntype Core =\n | { kind: 'shaper'; curves8: Float32Array[]; curves: Float32Array[]; matrix: { rows: number; cols: number; m: Float32Array; offset: Float32Array } | null }\n | { kind: 'grid'; clut: Clut }\n | { kind: 'exact' };\n\nfunction shaper(cs: Curve[], m: Extract<Stage, { kind: 'matrix' }> | null): Core {\n const curves8 = cs.map((c) => {\n const t = new Float32Array(256);\n for (let i = 0; i < 256; i++) t[i] = evalCurve(c, i / 255);\n return t;\n });\n const curves = cs.map((c) => {\n const t = new Float32Array(TABLE_1D + 1);\n for (let i = 0; i <= TABLE_1D; i++) t[i] = evalCurve(c, i / TABLE_1D);\n return t;\n });\n return { kind: 'shaper', curves8, curves, matrix: m ? { rows: m.rows, cols: m.cols, m: Float32Array.from(m.m), offset: Float32Array.from(m.offset) } : null };\n}\n\n/** Linear lookup that extrapolates from the end segments (HDR floats stay usable). */\nfunction table(t: Float32Array, x: number): number {\n const n = t.length - 1;\n const p = x * n;\n const i = Math.min(n - 1, Math.max(0, Math.floor(p)));\n const f = p - i;\n return t[i] + (t[i + 1] - t[i]) * f;\n}\n\nfunction deviceWhite(cs: ColorSpace): number[] | null {\n switch (cs) {\n case 'rgb':\n return [1, 1, 1];\n case 'gray':\n return [1];\n case 'cmyk':\n return [0, 0, 0, 0];\n case 'cmy':\n return [0, 0, 0];\n case 'lab':\n return [1, 0.5, 0.5];\n default:\n return null;\n }\n}\n\n/** A colour transform from one profile's device space to another's. Build once, apply often. */\nexport class Transform {\n readonly inputs: number;\n readonly outputs: number;\n private core: Core;\n private post: Float32Array[] | null = null;\n private readonly mid = new Float32Array(16);\n private readonly tmp = new Float32Array(16);\n private readonly inp = new Float32Array(16);\n\n constructor(\n readonly pipeline: Pipeline,\n readonly options: TransformOptions\n ) {\n pipeline.optimize();\n this.inputs = pipeline.inputs;\n this.outputs = pipeline.outputs;\n const head = pipeline.stages.slice();\n const last = head[head.length - 1];\n // Trailing inverse curves become accurate output tables.\n if (last?.kind === 'inv-curves' && last.curves.length === this.outputs) {\n this.post = last.curves.map((c) => {\n const t = new Float32Array(OUT_TABLE);\n for (let i = 0; i < OUT_TABLE; i++) {\n const u = i / (OUT_TABLE - 1);\n t[i] = Math.min(1, Math.max(0, evalCurveInverse(c, u * u * u * u)));\n }\n return t;\n });\n head.pop();\n if (head[head.length - 1]?.kind === 'clamp01') head.pop();\n }\n const headPipe = new Pipeline(this.inputs, head);\n const mid = headPipe.outputs;\n const hasClut = head.some((s) => s.kind === 'clut');\n const [h0, h1] = head;\n if (head.length === 0) this.core = shaper([], null);\n else if (head.length === 1 && h0.kind === 'curves' && h0.curves.length === this.inputs) this.core = shaper(h0.curves, null);\n else if (head.length === 1 && h0.kind === 'matrix') this.core = shaper([], h0);\n else if (head.length === 2 && h0.kind === 'curves' && h0.curves.length === this.inputs && h1.kind === 'matrix') this.core = shaper(h0.curves, h1);\n else if (!hasClut) this.core = { kind: 'exact' };\n else {\n const sample = (grid: number[]) => Clut.sample(grid, mid, (i, o) => headPipe.eval(i, o));\n switch (this.inputs) {\n case 1:\n this.core = { kind: 'grid', clut: sample([TABLE_1D]) };\n break;\n case 2:\n this.core = { kind: 'grid', clut: sample([GRID_3D, GRID_3D]) };\n break;\n case 3:\n this.core = { kind: 'grid', clut: sample([GRID_3D, GRID_3D, GRID_3D]) };\n break;\n case 4:\n this.core = { kind: 'grid', clut: sample([GRID_4D, GRID_4D, GRID_4D, GRID_4D]) };\n break;\n default:\n this.core = { kind: 'exact' };\n }\n }\n }\n\n /** From `src` to `dst` with `intent` (and black point compensation). */\n static create(src: Profile, dst: Profile, options: Partial<TransformOptions> = {}): Transform {\n const opts = { ...DEFAULT_TRANSFORM_OPTIONS, ...options };\n const t = new Transform(new Pipeline(profileChannels(src), linkStages(src, dst, opts.intent, opts.bpc)), opts);\n if (opts.intent !== 'absolute') t.fixWhite(src.colorSpace, dst.colorSpace);\n return t;\n }\n\n /**\n * Soft proof `src → proof → dst` (View › Proof Setup): `intent` / `bpc` apply to the\n * document → proof step; proof → display is relative colorimetric with BPC, or absolute\n * colorimetric without it when `simulatePaper` (paper colour and black ink simulated).\n */\n static proof(src: Profile, proof: Profile, dst: Profile, intent: Intent, bpc: boolean, simulatePaper: boolean): Transform {\n const stages = linkStages(src, proof, intent, bpc);\n stages.push({ kind: 'clamp01' });\n stages.push(...(simulatePaper ? linkStages(proof, dst, 'absolute', false) : linkStages(proof, dst, 'relative', true)));\n return new Transform(new Pipeline(profileChannels(src), stages), { intent, bpc, preciseFloat: true });\n }\n\n /** The device-link node at the source's device white gets exactly the destination's white. */\n private fixWhite(src: ColorSpace, dst: ColorSpace): void {\n const sw = deviceWhite(src);\n let dw = deviceWhite(dst);\n if (!sw || !dw) return;\n if (this.post) {\n if (dst !== 'rgb' && dst !== 'gray') return;\n dw = dw.map(() => 1);\n }\n if (this.core.kind !== 'grid') return;\n const c = this.core.clut;\n if (c.inputs !== sw.length || c.outputs !== dw.length) return;\n let off = 0;\n let stride = c.outputs;\n for (let d = c.inputs - 1; d >= 0; d--) {\n const n = c.grid[d];\n const pos = sw[d] * (n - 1);\n if (Math.abs(pos - Math.round(pos)) > 1e-6) return;\n off += Math.round(pos) * stride;\n stride *= n;\n }\n for (let k = 0; k < c.outputs; k++) c.data[off + k] = dw[k];\n }\n\n /** Exact evaluation of one colour. */\n eval(input: ArrayLike<number>, out: Float32Array | number[]): void {\n this.pipeline.eval(input, out);\n }\n\n /** Table evaluation of one colour (what integer buffers use). */\n evalFast(input: ArrayLike<number>, out: Float32Array | number[]): void {\n const mid = this.mid;\n const core = this.core;\n if (core.kind === 'exact') {\n this.pipeline.eval(input, out);\n return;\n }\n if (core.kind === 'grid') {\n for (let d = 0; d < this.inputs; d++) this.inp[d] = Math.min(1, Math.max(0, input[d]));\n core.clut.eval(this.inp, mid);\n } else {\n const v = this.tmp;\n for (let k = 0; k < this.inputs; k++) v[k] = core.curves.length ? table(core.curves[k], input[k]) : input[k];\n applyMatrix(core.matrix, v, mid, this.inputs);\n }\n this.finish(mid, out);\n }\n\n private finish(mid: Float32Array, out: Float32Array | number[] | Uint8ClampedArray): void {\n const post = this.post;\n if (!post) {\n for (let k = 0; k < this.outputs; k++) out[k] = mid[k];\n return;\n }\n for (let k = 0; k < this.outputs; k++) {\n const t = post[k];\n const x = mid[k];\n const u = Math.sqrt(Math.sqrt(x < 0 ? 0 : x > 1 ? 1 : x)) * (OUT_TABLE - 1);\n const i = Math.min(OUT_TABLE - 2, Math.floor(u));\n out[k] = t[i] + (t[i + 1] - t[i]) * (u - i);\n }\n }\n\n /**\n * Converts 8-bit interleaved pixels: `src` has `srcStride` samples per pixel (colour first),\n * `dst` `dstStride`. With `copyExtra`, trailing channels (alpha) are copied.\n */\n convert8(src: ArrayLike<number>, srcStride: number, dst: Uint8Array | Uint8ClampedArray, dstStride: number, copyExtra = true): void {\n this.check(srcStride, dstStride);\n const extra = copyExtra ? Math.min(srcStride - this.inputs, dstStride - this.outputs) : 0;\n const n = Math.min(Math.floor(src.length / srcStride), Math.floor(dst.length / dstStride));\n const out = new Float32Array(16);\n const mid = this.mid;\n const core = this.core;\n const q = (v: number) => (v <= 0 ? 0 : v >= 1 ? 255 : (v * 255 + 0.5) | 0);\n for (let p = 0; p < n; p++) {\n const s = p * srcStride;\n const d = p * dstStride;\n if (core.kind === 'shaper') {\n const v = this.tmp;\n for (let k = 0; k < this.inputs; k++) v[k] = core.curves8.length ? core.curves8[k][src[s + k]] : src[s + k] / 255;\n applyMatrix(core.matrix, v, mid, this.inputs);\n this.finish(mid, out);\n } else {\n for (let k = 0; k < this.inputs; k++) this.inp[k] = src[s + k] / 255;\n this.evalFast(this.inp, out);\n }\n for (let k = 0; k < this.outputs; k++) dst[d + k] = q(out[k]);\n for (let e = 0; e < extra; e++) dst[d + this.outputs + e] = src[s + this.inputs + e];\n }\n }\n\n /** Converts 16-bit interleaved pixels (see `convert8`). */\n convert16(src: ArrayLike<number>, srcStride: number, dst: Uint16Array, dstStride: number, copyExtra = true): void {\n this.check(srcStride, dstStride);\n const extra = copyExtra ? Math.min(srcStride - this.inputs, dstStride - this.outputs) : 0;\n const n = Math.min(Math.floor(src.length / srcStride), Math.floor(dst.length / dstStride));\n const out = new Float32Array(16);\n for (let p = 0; p < n; p++) {\n const s = p * srcStride;\n const d = p * dstStride;\n for (let k = 0; k < this.inputs; k++) this.inp[k] = src[s + k] / 65535;\n this.evalFast(this.inp, out);\n for (let k = 0; k < this.outputs; k++) dst[d + k] = Math.round(Math.min(1, Math.max(0, out[k])) * 65535);\n for (let e = 0; e < extra; e++) dst[d + this.outputs + e] = src[s + this.inputs + e];\n }\n }\n\n /** Converts float interleaved pixels (exact unless `preciseFloat` is off). */\n convertFloat(src: ArrayLike<number>, srcStride: number, dst: Float32Array, dstStride: number, copyExtra = true): void {\n this.check(srcStride, dstStride);\n const extra = copyExtra ? Math.min(srcStride - this.inputs, dstStride - this.outputs) : 0;\n const n = Math.min(Math.floor(src.length / srcStride), Math.floor(dst.length / dstStride));\n const precise = this.options.preciseFloat || this.core.kind === 'exact';\n const out = new Float32Array(16);\n for (let p = 0; p < n; p++) {\n const s = p * srcStride;\n const d = p * dstStride;\n for (let k = 0; k < this.inputs; k++) this.inp[k] = src[s + k];\n if (precise) this.pipeline.eval(this.inp, out);\n else this.evalFast(this.inp, out);\n for (let k = 0; k < this.outputs; k++) dst[d + k] = out[k];\n for (let e = 0; e < extra; e++) dst[d + this.outputs + e] = src[s + this.inputs + e];\n }\n }\n\n private check(ss: number, ds: number): void {\n if (ss < this.inputs || ds < this.outputs) throw new RangeError(`pixel stride smaller than the channel count (${this.inputs} → ${this.outputs})`);\n }\n}\n\nfunction applyMatrix(m: Extract<Core, { kind: 'shaper' }>['matrix'], v: Float32Array, out: Float32Array, n: number): void {\n if (!m) {\n for (let k = 0; k < n; k++) out[k] = v[k];\n return;\n }\n for (let r = 0; r < m.rows; r++) {\n let s = m.offset[r];\n for (let c = 0; c < m.cols; c++) s += m.m[r * m.cols + c] * v[c];\n out[r] = s;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Linking\n// ---------------------------------------------------------------------------\n\n/** Stages from `src` device values to `dst` device values. */\nexport function linkStages(src: Profile, dst: Profile, intent: Intent, bpc: boolean): Stage[] {\n for (const p of [src, dst]) {\n // A Lab DeviceLink stands in for an abstract profile only when it ends in Lab too.\n const labToLab = p.colorSpace === 'lab' && p.a2b.every((l) => !l || l.outputs === 3) && p.b2a.every((l) => !l || l.inputs === 3);\n if ((p.profileClass === 'link' || p.profileClass === 'named' || p.profileClass === 'abstract') && !labToLab) {\n throw new CmsError(`${p.profileClass} profiles cannot be used as a source or destination`);\n }\n }\n const s = deviceToPcs(src, intent);\n const d = pcsToDevice(dst, intent);\n const stages = s.stages.slice();\n const adjust = connection(src, dst, intent, bpc);\n if (adjust) {\n if (s.pcs === 'lab') stages.push({ kind: 'lab-to-xyz' });\n stages.push({ kind: 'matrix', rows: 3, cols: 3, m: [adjust.scale[0], 0, 0, 0, adjust.scale[1], 0, 0, 0, adjust.scale[2]], offset: adjust.offset });\n if (d.pcs === 'lab') stages.push({ kind: 'xyz-to-lab' });\n } else if (s.pcs === 'lab' && d.pcs === 'xyz') stages.push({ kind: 'lab-to-xyz' });\n else if (s.pcs === 'xyz' && d.pcs === 'lab') stages.push({ kind: 'xyz-to-lab' });\n stages.push(...d.stages);\n return stages;\n}\n\n/** Per-component XYZ scale and offset in the PCS (absolute media-white scaling or BPC), or null. */\nfunction connection(src: Profile, dst: Profile, intent: Intent, bpc: boolean): { scale: number[]; offset: number[] } | null {\n if (intent === 'absolute') {\n const ws = mediaWhite(src);\n const wd = mediaWhite(dst);\n const usable = (w: number[]) => w.every((v) => Number.isFinite(v) && v > 0);\n if (!usable(ws) || !usable(wd)) throw new CmsError('absolute colorimetric needs a positive media white point in both profiles');\n const s = [ws[0] / wd[0], ws[1] / wd[1], ws[2] / wd[2]];\n if (s.every((v) => Math.abs(v - 1) < 1e-6)) return null;\n return { scale: s, offset: [0, 0, 0] };\n }\n if (!bpc) return null;\n const bs = blackPoint(src, intent);\n const bd = blackPoint(dst, intent);\n if (Math.abs(bs - bd) < 1e-6) return null;\n // Neutral black points mapped linearly in XYZ: source black onto destination black, white fixed.\n const scale = [1, 1, 1];\n const offset = [0, 0, 0];\n for (let i = 0; i < 3; i++) {\n const s = bs * D50[i];\n const d = bd * D50[i];\n const a = (D50[i] - d) / (D50[i] - s);\n scale[i] = a;\n offset[i] = D50[i] * (1 - a);\n }\n return { scale, offset };\n}\n\n/** Luminance (Y, D50-relative) of a profile's black point for `intent`. */\nexport function blackPoint(p: Profile, intent: Intent): number {\n if (p.colorSpace === 'lab' || p.colorSpace === 'xyz') return 0;\n const lutBased = p.a2b.some(Boolean);\n if (lutBased && p.version[0] >= 4 && (intent === 'perceptual' || intent === 'saturation')) return PERCEPTUAL_BLACK_Y;\n const n = profileChannels(p);\n const pcsY = (st: Stage[], pcs: Pcs, dev: ArrayLike<number>) => {\n const out = new Float32Array(16);\n new Pipeline(n, st.slice()).eval(dev, out);\n const y = pcs === 'xyz' ? out[1] : labToXyz([out[0], 0, 0])[1];\n return Math.min(0.5, Math.max(0, y));\n };\n const to = deviceToPcs(p, intent);\n const additive = p.colorSpace === 'rgb' || p.colorSpace === 'gray';\n if (additive || !lutBased) return pcsY(to.stages, to.pcs, new Array(n).fill(0));\n // Subtractive LUT profile: the darkest colour it reaches.\n const colorimetric: Intent = intent === 'saturation' ? 'saturation' : 'relative';\n try {\n const from = pcsToDevice(p, colorimetric);\n const st: Stage[] = from.pcs === 'xyz' ? [{ kind: 'lab-to-xyz' }, ...from.stages] : from.stages.slice();\n const dev = new Float32Array(16);\n new Pipeline(3, st).eval([0, 0, 0], dev);\n return pcsY(to.stages, to.pcs, dev.subarray(0, n));\n } catch {\n return pcsY(to.stages, to.pcs, new Array(n).fill(1));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Cache, comparisons, gamut checks, display tables\n// ---------------------------------------------------------------------------\n\nconst ids = new WeakMap<Profile, number>();\nlet nextId = 1;\nconst idOf = (p: Profile) => {\n let id = ids.get(p);\n if (!id) {\n id = nextId++;\n ids.set(p, id);\n }\n return id;\n};\n\nconst cache = new Map<string, Transform>();\n\n/** A transform from a small cache keyed by the profile objects and the options. */\nexport function cachedTransform(src: Profile, dst: Profile, options: Partial<TransformOptions> = {}): Transform {\n const opts = { ...DEFAULT_TRANSFORM_OPTIONS, ...options };\n const key = `${idOf(src)}:${idOf(dst)}:${opts.intent}:${opts.bpc}:${opts.preciseFloat}`;\n let t = cache.get(key);\n if (!t) {\n if (cache.size > 64) cache.clear();\n t = Transform.create(src, dst, opts);\n cache.set(key, t);\n }\n return t;\n}\n\n/**\n * Whether two profiles describe the same colours: same colour space, and every sample of a\n * device grid lands within ΔE*ab 0.5 through both (relative colorimetric), whatever their\n * encodings (Photoshop's v2 sRGB and a v4 parametric sRGB are the same colours).\n */\nexport function sameColors(a: Profile, b: Profile, lab: Profile): boolean {\n if (a === b) return true;\n if (a.bytes && b.bytes && a.bytes.length === b.bytes.length && a.bytes.every((v, i) => v === b.bytes![i])) return true;\n const n = profileChannels(a);\n if (a.colorSpace !== b.colorSpace || n === 0 || n > 4) return false;\n let ta: Transform;\n let tb: Transform;\n try {\n ta = Transform.create(a, lab, { intent: 'relative', bpc: false });\n tb = Transform.create(b, lab, { intent: 'relative', bpc: false });\n } catch {\n return false;\n }\n const steps = n <= 3 ? 17 : 9;\n const decode = (o: Float32Array) => [o[0] * 100, o[1] * 255 - 128, o[2] * 255 - 128];\n const input = new Float32Array(4);\n const la = new Float32Array(16);\n const lb = new Float32Array(16);\n const total = Math.pow(steps, n);\n for (let i = 0; i < total; i++) {\n let k = i;\n for (let c = 0; c < n; c++) {\n input[c] = (k % steps) / (steps - 1);\n k = Math.floor(k / steps);\n }\n ta.eval(input, la);\n tb.eval(input, lb);\n if (deltaE76(decode(la), decode(lb)) > 0.5) return false;\n }\n return true;\n}\n\n/** Out-of-gamut test (Photoshop's Gamut Warning): ΔE between a colour and its round trip through a proof profile. */\nexport class GamutCheck {\n private readonly grid: Clut | null;\n private readonly direct: Pipeline;\n private readonly via: Pipeline;\n\n constructor(\n src: Profile,\n proof: Profile,\n lab: Profile,\n /** ΔE*ab above which a colour is out of gamut (default 4). */\n readonly threshold = 4\n ) {\n const n = profileChannels(src);\n this.direct = new Pipeline(n, linkStages(src, lab, 'relative', false));\n const via = linkStages(src, proof, 'relative', false);\n via.push({ kind: 'clamp01' });\n via.push(...linkStages(proof, lab, 'relative', false));\n this.via = new Pipeline(n, via);\n const a = new Float32Array(16);\n const b = new Float32Array(16);\n const de = (p: ArrayLike<number>, o: Float32Array) => {\n this.direct.eval(p, a);\n this.via.eval(p, b);\n o[0] = Math.hypot((a[0] - b[0]) * 100, (a[1] - b[1]) * 255, (a[2] - b[2]) * 255);\n };\n this.grid = n === 1 ? Clut.sample([256], 1, de) : n === 3 ? Clut.sample([33, 33, 33], 1, de) : n === 4 ? Clut.sample([17, 17, 17, 17], 1, de) : null;\n }\n\n /** ΔE*ab of a colour (normalised device values). */\n deltaE(px: ArrayLike<number>): number {\n const o = new Float32Array(16);\n if (this.grid) this.grid.eval(px, o);\n else {\n const a = new Float32Array(16);\n const b = new Float32Array(16);\n this.direct.eval(px, a);\n this.via.eval(px, b);\n o[0] = Math.hypot((a[0] - b[0]) * 100, (a[1] - b[1]) * 255, (a[2] - b[2]) * 255);\n }\n return o[0];\n }\n\n outOfGamut(px: ArrayLike<number>): boolean {\n return this.deltaE(px) > this.threshold;\n }\n}\n\n/** A 3D lookup table of an RGB → RGB transform (`size`³ RGB triples, red fastest), for fast display paths. */\nexport class Lut3d {\n readonly data: Float32Array;\n\n constructor(\n t: Transform,\n readonly size = 33\n ) {\n if (t.inputs !== 3 || (t.outputs !== 3 && t.outputs !== 1)) throw new RangeError('display LUTs need a 3 → 3 or 3 → 1 transform');\n const n = size;\n this.data = new Float32Array(n * n * n * 3);\n const out = new Float32Array(16);\n const s = n - 1;\n for (let b = 0; b < n; b++) {\n for (let g = 0; g < n; g++) {\n for (let r = 0; r < n; r++) {\n t.eval([r / s, g / s, b / s], out);\n const i = (r + g * n + b * n * n) * 3;\n this.data[i] = out[0];\n this.data[i + 1] = t.outputs === 1 ? out[0] : out[1];\n this.data[i + 2] = t.outputs === 1 ? out[0] : out[2];\n }\n }\n }\n }\n\n /** Trilinear sample of 0..1 RGB into `out`. */\n sample(r: number, g: number, b: number, out: number[] | Float32Array): void {\n const n = this.size;\n const loc = (v: number): [number, number] => {\n const p = Math.min(1, Math.max(0, v)) * (n - 1);\n const i = Math.min(n - 2, Math.floor(p));\n return [i, p - i];\n };\n const [r0, fr] = loc(r);\n const [g0, fg] = loc(g);\n const [b0, fb] = loc(b);\n const d = this.data;\n const at = (rr: number, gg: number, bb: number, k: number) => d[(rr + gg * n + bb * n * n) * 3 + k];\n for (let k = 0; k < 3; k++) {\n const x00 = at(r0, g0, b0, k) + (at(r0 + 1, g0, b0, k) - at(r0, g0, b0, k)) * fr;\n const x10 = at(r0, g0 + 1, b0, k) + (at(r0 + 1, g0 + 1, b0, k) - at(r0, g0 + 1, b0, k)) * fr;\n const x01 = at(r0, g0, b0 + 1, k) + (at(r0 + 1, g0, b0 + 1, k) - at(r0, g0, b0 + 1, k)) * fr;\n const x11 = at(r0, g0 + 1, b0 + 1, k) + (at(r0 + 1, g0 + 1, b0 + 1, k) - at(r0, g0 + 1, b0 + 1, k)) * fr;\n const y0 = x00 + (x10 - x00) * fg;\n const y1 = x01 + (x11 - x01) * fg;\n out[k] = y0 + (y1 - y0) * fb;\n }\n }\n\n /** Applies the table to 8-bit RGBA in place (alpha kept), through a per-code 8-bit cache of the lattice. */\n apply8(data: Uint8ClampedArray | Uint8Array): void {\n const o = [0, 0, 0];\n for (let i = 0; i < data.length; i += 4) {\n this.sample(data[i] / 255, data[i + 1] / 255, data[i + 2] / 255, o);\n data[i] = Math.round(Math.min(1, Math.max(0, o[0])) * 255);\n data[i + 1] = Math.round(Math.min(1, Math.max(0, o[1])) * 255);\n data[i + 2] = Math.round(Math.min(1, Math.max(0, o[2])) * 255);\n }\n }\n}\n","// Portions ported from photocraft/crates/cms/src/synth.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * A synthetic coated-offset CMYK profile, built from a printing model rather than shipped as\n * measured data (so it carries no licence): a Yule-Nielsen-modified Neugebauer model over 16\n * primaries with tone value increase, inverted per node by damped least squares with a total\n * ink limit and grey component replacement. The perceptual B2A compresses colour towards a\n * gamut boundary descriptor; the colorimetric one clips.\n *\n * Generating it takes about a second, so `coatedCmyk()` builds it once, on first use.\n */\n\nimport { Clut } from './clut';\nimport type { Curve } from './curve';\nimport { D50, apply, invert, labToXyz, s15f16Round, xyzToLab, type Mat3, type Vec3 } from './math';\nimport type { Lut, Profile } from './profile';\n\nexport const COATED_CMYK_DESCRIPTION = 'Pixerate Coated CMYK (synthetic, 300% TAC, medium GCR)';\n\nexport interface CmykParams {\n description: string;\n /** Total area coverage, 0..4 (3 = 300 %). */\n tac: number;\n /** Grey component replacement starts at this grey level. */\n gcrStart: number;\n kMax: number;\n gcrGamma: number;\n /** Tone value increase at 50 % per ink (C, M, Y, K). */\n tvi: [number, number, number, number];\n gridA2b: number;\n gridB2a: number;\n}\n\nexport const DEFAULT_CMYK_PARAMS: Readonly<CmykParams> = {\n description: COATED_CMYK_DESCRIPTION,\n tac: 3.0,\n gcrStart: 0.2,\n kMax: 0.95,\n gcrGamma: 1.1,\n tvi: [0.14, 0.14, 0.14, 0.17],\n gridA2b: 11,\n gridB2a: 17,\n};\n\nconst YN = 2.0;\n\n/** The printing model: CMYK (0..1) → XYZ and Lab relative to the paper. */\nexport class CmykModel {\n private readonly primN: Vec3[] = [];\n readonly paper: Vec3;\n\n constructor(readonly tvi: readonly number[]) {\n const lab = (l: number, a: number, b: number) => labToXyz([l, a, b]);\n const w = lab(95, 0, -2);\n const base: Vec3[] = [\n w, // paper\n lab(55, -37, -50), // C\n lab(48, 74, -3), // M\n lab(24, 22, -46), // C+M\n lab(89, -5, 93), // Y\n lab(50, -65, 27), // C+Y\n lab(47, 68, 48), // M+Y\n lab(23, 0, 0), // C+M+Y\n ];\n const k = lab(16, 0, 0);\n const floor = 0.006;\n for (let m = 0; m < 16; m++) {\n const p = base[m & 7];\n const prim: Vec3 =\n m & 8\n ? [0, 1, 2].map((i) => {\n const s = floor * w[i];\n return s + ((p[i] - s) * (k[i] - s)) / (w[i] - s);\n }) as Vec3\n : p;\n this.primN.push(prim.map((v) => Math.pow(Math.max(0, v), 1 / YN)) as Vec3);\n }\n this.paper = w;\n }\n\n xyz(cmyk: ArrayLike<number>): Vec3 {\n const a = [0, 1, 2, 3].map((i) => {\n const v = Math.min(1, Math.max(0, cmyk[i]));\n return Math.min(1, Math.max(0, v + 4 * this.tvi[i] * v * (1 - v)));\n });\n const s: Vec3 = [0, 0, 0];\n for (let m = 0; m < 16; m++) {\n let w = 1;\n for (let i = 0; i < 4; i++) w *= m & (1 << i) ? a[i] : 1 - a[i];\n if (w === 0) continue;\n const p = this.primN[m];\n s[0] += w * p[0];\n s[1] += w * p[1];\n s[2] += w * p[2];\n }\n return [Math.pow(s[0], YN), Math.pow(s[1], YN), Math.pow(s[2], YN)];\n }\n\n lab(cmyk: ArrayLike<number>): Vec3 {\n const x = this.xyz(cmyk);\n return xyzToLab([(x[0] * D50[0]) / this.paper[0], (x[1] * D50[1]) / this.paper[1], (x[2] * D50[2]) / this.paper[2]]);\n }\n}\n\nfunction solveCmy(model: CmykModel, target: Vec3, k: number, limit: number, seeds: Vec3[]): [Vec3, number] {\n const project = (x: Vec3): Vec3 => {\n const v: Vec3 = [x[0], x[1], x[2]];\n for (let it = 0; it < 4; it++) {\n for (let i = 0; i < 3; i++) v[i] = Math.min(1, Math.max(0, v[i]));\n const s = v[0] + v[1] + v[2];\n if (s <= limit + 1e-12) break;\n const active = Math.max(1, v.filter((x) => x > 0).length);\n const d = (s - limit) / active;\n for (let i = 0; i < 3; i++) if (v[i] > 0) v[i] -= d;\n }\n return v;\n };\n const err = (x: Vec3): Vec3 => {\n const l = model.lab([x[0], x[1], x[2], k]);\n return [l[0] - target[0], l[1] - target[1], l[2] - target[2]];\n };\n const norm2 = (e: Vec3) => e[0] * e[0] + e[1] * e[1] + e[2] * e[2];\n let best: [Vec3, number] = [[0, 0, 0], Infinity];\n for (const seed of seeds) {\n let x = project(seed);\n let e = err(x);\n let f = norm2(e);\n let lambda = 1e-3;\n for (let iter = 0; iter < 60; iter++) {\n const h = 1e-5;\n const j: Mat3 = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0],\n ];\n for (let c = 0; c < 3; c++) {\n const xp: Vec3 = [x[0], x[1], x[2]];\n xp[c] += h;\n const ep = err(xp);\n for (let r = 0; r < 3; r++) j[r][c] = (ep[r] - e[r]) / h;\n }\n const a: Mat3 = [\n [0, 0, 0],\n [0, 0, 0],\n [0, 0, 0],\n ];\n const g: Vec3 = [0, 0, 0];\n for (let r = 0; r < 3; r++) {\n for (let c = 0; c < 3; c++) a[r][c] = j[0][r] * j[0][c] + j[1][r] * j[1][c] + j[2][r] * j[2][c];\n g[r] = -(j[0][r] * e[0] + j[1][r] * e[1] + j[2][r] * e[2]);\n }\n let improved = false;\n for (let t = 0; t < 8; t++) {\n const al: Mat3 = [\n [a[0][0], a[0][1], a[0][2]],\n [a[1][0], a[1][1], a[1][2]],\n [a[2][0], a[2][1], a[2][2]],\n ];\n for (let d = 0; d < 3; d++) al[d][d] += lambda * (1 + a[d][d]);\n const inv = invert(al);\n if (!inv) {\n lambda *= 10;\n continue;\n }\n const step = apply(inv, g);\n const xn = project([x[0] + step[0], x[1] + step[1], x[2] + step[2]]);\n const en = err(xn);\n const fnew = norm2(en);\n if (fnew < f) {\n const moved = Math.max(Math.abs(xn[0] - x[0]), Math.abs(xn[1] - x[1]), Math.abs(xn[2] - x[2]));\n x = xn;\n e = en;\n f = fnew;\n lambda = Math.max(1e-9, lambda * 0.3);\n improved = moved > 1e-9;\n break;\n }\n lambda *= 10;\n }\n if (!improved || f < 1e-10) break;\n }\n if (f < best[1]) best = [x, f];\n if (best[1] < 1e-6) break;\n }\n return [best[0], Math.sqrt(best[1])];\n}\n\nconst SEEDS: Vec3[] = [\n [0.3, 0.3, 0.3],\n [0.05, 0.05, 0.05],\n [0.8, 0.8, 0.8],\n [0.9, 0.2, 0.2],\n [0.2, 0.9, 0.9],\n];\n\n/** Separates a Lab colour into CMYK with GCR under the ink limit; returns it and the ΔE left. */\nexport function separate(model: CmykModel, p: CmykParams, target: Vec3, warm: number[] | null): [number[], number] {\n const seeds: Vec3[] = warm ? [[warm[0], warm[1], warm[2]], ...SEEDS] : SEEDS;\n const [cmy0] = solveCmy(model, target, 0, 3, seeds);\n const g = Math.min(cmy0[0], cmy0[1], cmy0[2]);\n const k = g <= p.gcrStart ? 0 : p.kMax * Math.pow((g - p.gcrStart) / (1 - p.gcrStart), p.gcrGamma);\n const seeds2: Vec3[] = [[Math.max(0, cmy0[0] - k), Math.max(0, cmy0[1] - k), Math.max(0, cmy0[2] - k)], cmy0, ...seeds];\n const [cmy, de] = solveCmy(model, target, k, Math.max(0, p.tac - k), seeds2);\n return [[cmy[0], cmy[1], cmy[2], k], de];\n}\n\n/** Gamut boundary descriptor: the largest chroma per lightness and hue bin. */\nclass Gbd {\n private readonly lBins = 41;\n private readonly hBins = 72;\n private readonly cmax: Float64Array;\n readonly blackL: number;\n\n constructor(model: CmykModel, p: CmykParams) {\n const { lBins, hBins } = this;\n const cmax = new Float64Array(lBins * hBins);\n const n = 13;\n let blackL = 100;\n for (let ci = 0; ci < n; ci++) {\n for (let mi = 0; mi < n; mi++) {\n for (let yi = 0; yi < n; yi++) {\n for (let ki = 0; ki < 7; ki++) {\n const v = [ci / (n - 1), mi / (n - 1), yi / (n - 1), ki / 6];\n if (v[0] + v[1] + v[2] + v[3] > p.tac + 1e-9) continue;\n const lab = model.lab(v);\n blackL = Math.min(blackL, lab[0]);\n const c = Math.hypot(lab[1], lab[2]);\n const h = (Math.atan2(lab[2], lab[1]) + 2 * Math.PI) % (2 * Math.PI);\n const li = Math.min(lBins - 1, Math.max(0, Math.round((lab[0] / 100) * (lBins - 1))));\n const hi = Math.round((h / (2 * Math.PI)) * hBins) % hBins;\n cmax[li * hBins + hi] = Math.max(cmax[li * hBins + hi], c);\n }\n }\n }\n }\n const get = (v: Float64Array, l: number, h: number) => v[Math.min(lBins - 1, Math.max(0, l)) * hBins + (((h % hBins) + hBins) % hBins)];\n const filled = new Float64Array(cmax.length);\n for (let l = 0; l < lBins; l++) {\n for (let h = 0; h < hBins; h++) {\n let m = 0;\n for (let dl = -1; dl <= 1; dl++) for (let dh = -1; dh <= 1; dh++) m = Math.max(m, get(cmax, l + dl, h + dh));\n filled[l * hBins + h] = m;\n }\n }\n this.cmax = new Float64Array(cmax.length);\n for (let l = 0; l < lBins; l++) {\n for (let h = 0; h < hBins; h++) {\n let s = 0;\n for (let dl = -1; dl <= 1; dl++) for (let dh = -1; dh <= 1; dh++) s += get(filled, l + dl, h + dh);\n this.cmax[l * hBins + h] = s / 9;\n }\n }\n this.blackL = blackL;\n }\n\n private maxChroma(l: number, h: number): number {\n const { lBins, hBins } = this;\n const lp = Math.min(1, Math.max(0, l / 100)) * (lBins - 1);\n const hp = ((((h % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI)) / (2 * Math.PI)) * hBins;\n const l0 = Math.floor(lp);\n const h0 = Math.floor(hp);\n const fl = lp - l0;\n const fh = hp - h0;\n const l1 = Math.min(lBins - 1, l0 + 1);\n const h0m = h0 % hBins;\n const h1m = (h0 + 1) % hBins;\n const v = (ll: number, hh: number) => this.cmax[ll * hBins + hh];\n const a = v(l0, h0m) + (v(l0, h1m) - v(l0, h0m)) * fh;\n const b = v(l1, h0m) + (v(l1, h1m) - v(l1, h0m)) * fh;\n return a + (b - a) * fl;\n }\n\n /** Lightness mapped onto the printable range, chroma softly compressed above 80 % of the boundary. */\n compress(lab: Vec3): Vec3 {\n const l = this.blackL + (Math.min(100, Math.max(0, lab[0])) * (100 - this.blackL)) / 100;\n const c = Math.hypot(lab[1], lab[2]);\n if (c < 1e-9) return [l, 0, 0];\n const h = Math.atan2(lab[2], lab[1]);\n const cm = Math.max(1e-3, this.maxChroma(l, h));\n const knee = 0.8 * cm;\n const c2 = c <= knee ? c : knee + (cm - knee) * Math.tanh((c - knee) / (cm - knee));\n return [l, c2 * Math.cos(h), c2 * Math.sin(h)];\n }\n}\n\nconst decodeV2 = (v: number[]): Vec3 => [(v[0] * 100 * 65535) / 65280, (v[1] * 65535) / 256 - 128, (v[2] * 65535) / 256 - 128];\nconst encodeV2 = (lab: Vec3): number[] => [\n Math.min(1, Math.max(0, lab[0] / ((100 * 65535) / 65280))),\n Math.min(1, Math.max(0, ((lab[1] + 128) * 256) / 65535)),\n Math.min(1, Math.max(0, ((lab[2] + 128) * 256) / 65535)),\n];\n\nfunction b2aTable(model: CmykModel, p: CmykParams, gbd: Gbd | null): Clut {\n const n = p.gridB2a;\n const data = new Float32Array(n * n * n * 4);\n for (let li = 0; li < n; li++) {\n for (let ai = 0; ai < n; ai++) {\n let warm: number[] | null = null;\n for (let bi = 0; bi < n; bi++) {\n const lab = decodeV2([li / (n - 1), ai / (n - 1), bi / (n - 1)]);\n const target = gbd ? gbd.compress(lab) : lab;\n const [cmyk] = separate(model, p, target, warm);\n warm = cmyk;\n data.set(cmyk, ((li * n + ai) * n + bi) * 4);\n }\n }\n }\n return new Clut([n, n, n], 4, data);\n}\n\nconst ramp = (): Curve => ({ type: 'table', table: Float32Array.from([0, 1]) });\n\nfunction lut16(clut: Clut): Lut {\n return {\n kind: 'lut16',\n inputs: clut.inputs,\n outputs: clut.outputs,\n stages: [\n { kind: 'curves', curves: Array.from({ length: clut.inputs }, ramp) },\n { kind: 'clut', clut },\n { kind: 'curves', curves: Array.from({ length: clut.outputs }, ramp) },\n ],\n };\n}\n\n/** A synthetic CMYK profile model from `p` (bytes not encoded; see `builtin`). */\nexport function cmykProfile(p: CmykParams = DEFAULT_CMYK_PARAMS, copyright = ''): Profile {\n const model = new CmykModel(p.tvi);\n const g = p.gridA2b;\n const a2bClut = Clut.sample([g, g, g, g], 3, (inp, out) => out.set(encodeV2(model.lab(inp))));\n const gbd = new Gbd(model, p);\n const a2b = lut16(a2bClut);\n const perceptual = lut16(b2aTable(model, p, gbd));\n const colorimetric = lut16(b2aTable(model, p, null));\n return {\n version: [4, 0x30],\n profileClass: 'output',\n colorSpace: 'cmyk',\n pcs: 'lab',\n renderingIntent: 'perceptual',\n description: p.description,\n copyright,\n whitePoint: model.paper.map(s15f16Round) as Vec3,\n blackPoint: null,\n chad: null,\n matrix: null,\n trc: null,\n grayTrc: null,\n a2b: [a2b, a2b, a2b],\n b2a: [perceptual, colorimetric, perceptual],\n bytes: null,\n };\n}\n","// Portions ported from photocraft/crates/cms/src/builtin.rs (MIT OR Apache-2.0, © ArtCraft Team and contributors). See THIRD_PARTY_NOTICES.md.\n\n/**\n * Built-in profiles, generated here from published colorimetric definitions (primaries, white\n * points, transfer functions), so documents that embed them carry no licence obligations.\n */\n\nimport { gammaCurve, IDENTITY_CURVE, srgbTrc, type Curve } from './curve';\nimport { D50, D65_XY, apply, bradford, d50Quantized, mul, rgbToXyzMatrix, s15f16Round, xyToXyz, type Mat3 } from './math';\nimport { parseProfile, type ColorSpace, type Profile } from './profile';\nimport { cmykProfile } from './synth';\nimport { encodeProfile } from './write';\n\nexport const BUILTIN_COPYRIGHT = 'No copyright: CC0-1.0 public domain dedication. Generated by Pixerate.';\n\n/** Identifiers of the built-in profiles. */\nexport type BuiltinProfileId =\n | 'srgb'\n | 'display-p3'\n | 'adobe-rgb-compat'\n | 'prophoto-compat'\n | 'linear-srgb'\n | 'rec2020'\n | 'gray-gamma-2.2'\n | 'sgray'\n | 'dot-gain-20-compat'\n | 'lab-d50'\n | 'coated-cmyk';\n\nexport const BUILTIN_PROFILES: readonly { id: BuiltinProfileId; description: string; colorSpace: ColorSpace }[] = [\n { id: 'srgb', description: 'sRGB IEC61966-2.1', colorSpace: 'rgb' },\n { id: 'display-p3', description: 'Display P3', colorSpace: 'rgb' },\n { id: 'adobe-rgb-compat', description: 'Adobe RGB (1998)-compatible (Pixerate)', colorSpace: 'rgb' },\n { id: 'prophoto-compat', description: 'ProPhoto RGB-compatible (ROMM primaries, Pixerate)', colorSpace: 'rgb' },\n { id: 'linear-srgb', description: 'Linear sRGB (Pixerate)', colorSpace: 'rgb' },\n { id: 'rec2020', description: 'Rec. ITU-R BT.2020 (Pixerate)', colorSpace: 'rgb' },\n { id: 'gray-gamma-2.2', description: 'Gray Gamma 2.2 (Pixerate)', colorSpace: 'gray' },\n { id: 'sgray', description: 'sGray (sRGB tone curve, Pixerate)', colorSpace: 'gray' },\n { id: 'dot-gain-20-compat', description: 'Dot Gain 20%-compatible (gamma 1.732, Pixerate)', colorSpace: 'gray' },\n { id: 'lab-d50', description: 'Lab D50 identity (Pixerate)', colorSpace: 'lab' },\n { id: 'coated-cmyk', description: 'Pixerate Coated CMYK (synthetic, 300% TAC, medium GCR)', colorSpace: 'cmyk' },\n];\n\n/** Looks up a built-in id (case-insensitive; a few aliases and the descriptions too). */\nexport function builtinProfileId(s: string): BuiltinProfileId | null {\n const n = s.toLowerCase().replace(/[^a-z0-9]/g, '');\n const aliases: Record<string, BuiltinProfileId> = {\n srgb: 'srgb',\n srgbiec6196621: 'srgb',\n p3: 'display-p3',\n displayp3: 'display-p3',\n adobergb: 'adobe-rgb-compat',\n adobergb1998: 'adobe-rgb-compat',\n adobergbcompat: 'adobe-rgb-compat',\n prophoto: 'prophoto-compat',\n prophotorgb: 'prophoto-compat',\n prophotocompat: 'prophoto-compat',\n linearsrgb: 'linear-srgb',\n rec2020: 'rec2020',\n bt2020: 'rec2020',\n gray: 'gray-gamma-2.2',\n graygamma22: 'gray-gamma-2.2',\n sgray: 'sgray',\n dotgain20: 'dot-gain-20-compat',\n dotgain20compat: 'dot-gain-20-compat',\n lab: 'lab-d50',\n labd50: 'lab-d50',\n cmyk: 'coated-cmyk',\n coatedcmyk: 'coated-cmyk',\n };\n return aliases[n] ?? BUILTIN_PROFILES.find((b) => b.description.toLowerCase() === s.toLowerCase())?.id ?? null;\n}\n\n/** Colorants adapted to D50 and quantised, each row nudged so RGB (1, 1, 1) is exactly the stored D50 white. */\nfunction colorants(r: number[], g: number[], b: number[], white: number[]): { m: Mat3; chad: Mat3 | null } {\n const m = rgbToXyzMatrix(r, g, b, white)!;\n const d50 = d50Quantized();\n const nearD50 = Math.abs(white[0] - D50[0]) < 1e-3 && Math.abs(white[2] - D50[2]) < 1e-3;\n const adapt = nearD50 ? null : bradford(white, D50);\n let m50: Mat3;\n if (adapt) m50 = mul(adapt, m);\n else {\n const s = apply(m, [1, 1, 1]);\n m50 = m.map((row, i) => row.map((v) => (v * D50[i]) / s[i])) as Mat3;\n }\n const q = m50.map((row) => row.map(s15f16Round)) as Mat3;\n for (let i = 0; i < 3; i++) {\n const row = q[i];\n const err = d50[i] - (row[0] + row[1] + row[2]);\n let k = 0;\n for (let j = 1; j < 3; j++) if (Math.abs(row[j]) > Math.abs(row[k])) k = j;\n row[k] = s15f16Round(row[k] + err);\n }\n return { m: q, chad: adapt ? (adapt.map((row) => row.map(s15f16Round)) as Mat3) : null };\n}\n\nconst withBytes = (p: Profile): Profile => ({ ...p, bytes: encodeProfile(p) });\n\nfunction rgbProfile(desc: string, prim: number[][], white: number[], trc: Curve): Profile {\n const { m, chad } = colorants(prim[0], prim[1], prim[2], white);\n return withBytes({\n version: [4, 0x30],\n profileClass: 'display',\n colorSpace: 'rgb',\n pcs: 'xyz',\n renderingIntent: 'perceptual',\n description: desc,\n copyright: BUILTIN_COPYRIGHT,\n whitePoint: d50Quantized(),\n blackPoint: null,\n chad,\n matrix: m,\n trc: [trc, trc, trc],\n grayTrc: null,\n a2b: [null, null, null],\n b2a: [null, null, null],\n bytes: null,\n });\n}\n\nfunction grayProfile(desc: string, trc: Curve): Profile {\n return withBytes({\n version: [4, 0x30],\n profileClass: 'display',\n colorSpace: 'gray',\n pcs: 'xyz',\n renderingIntent: 'perceptual',\n description: desc,\n copyright: BUILTIN_COPYRIGHT,\n whitePoint: d50Quantized(),\n blackPoint: null,\n chad: null,\n matrix: null,\n trc: null,\n grayTrc: trc,\n a2b: [null, null, null],\n b2a: [null, null, null],\n bytes: null,\n });\n}\n\nfunction labProfile(desc: string): Profile {\n const ident = () => ({ kind: 'ab' as const, inputs: 3, outputs: 3, stages: [{ kind: 'curves' as const, curves: [IDENTITY_CURVE, IDENTITY_CURVE, IDENTITY_CURVE] }] });\n return withBytes({\n version: [4, 0x30],\n profileClass: 'colorspace',\n colorSpace: 'lab',\n pcs: 'lab',\n renderingIntent: 'perceptual',\n description: desc,\n copyright: BUILTIN_COPYRIGHT,\n whitePoint: d50Quantized(),\n blackPoint: null,\n chad: null,\n matrix: null,\n trc: null,\n grayTrc: null,\n a2b: [ident(), null, null],\n b2a: [ident(), null, null],\n bytes: null,\n });\n}\n\nfunction build(id: BuiltinProfileId): Profile {\n const desc = BUILTIN_PROFILES.find((b) => b.id === id)!.description;\n const d65 = xyToXyz(D65_XY);\n const srgbP = [\n [0.64, 0.33],\n [0.3, 0.6],\n [0.15, 0.06],\n ];\n switch (id) {\n case 'srgb':\n return rgbProfile(desc, srgbP, d65, srgbTrc());\n case 'display-p3':\n return rgbProfile(desc, [[0.68, 0.32], [0.265, 0.69], [0.15, 0.06]], d65, srgbTrc());\n case 'adobe-rgb-compat':\n return rgbProfile(desc, [[0.64, 0.33], [0.21, 0.71], [0.15, 0.06]], d65, gammaCurve(563 / 256));\n case 'prophoto-compat':\n return rgbProfile(desc, [[0.7347, 0.2653], [0.1596, 0.8404], [0.0366, 0.0001]], [D50[0], D50[1], D50[2]], gammaCurve(1.8));\n case 'linear-srgb':\n return rgbProfile(desc, srgbP, d65, gammaCurve(1));\n case 'rec2020': {\n // The inverse Rec. 709 OETF: V = 1.099 L^0.45 − 0.099 (L ≥ 0.018), 4.5 L below.\n const a = 1.099;\n return rgbProfile(desc, [[0.708, 0.292], [0.17, 0.797], [0.131, 0.046]], d65, { type: 'parametric', kind: 3, p: [1 / 0.45, 1 / a, (a - 1) / a, 1 / 4.5, 0.081, 0, 0] });\n }\n case 'gray-gamma-2.2':\n return grayProfile(desc, gammaCurve(2.2));\n case 'sgray':\n return grayProfile(desc, srgbTrc());\n case 'dot-gain-20-compat':\n return grayProfile(desc, gammaCurve(1.732));\n case 'lab-d50':\n return labProfile(desc);\n case 'coated-cmyk': {\n const p = cmykProfile(undefined, BUILTIN_COPYRIGHT);\n const bytes = encodeProfile(p);\n // Read back from its own bytes, so it evaluates exactly as an embedded copy would.\n return { ...parseProfile(bytes), bytes };\n }\n }\n}\n\nconst built = new Map<BuiltinProfileId, Profile>();\n\n/** A built-in profile (built once; the synthetic CMYK takes about a second the first time). */\nexport function builtinProfile(id: BuiltinProfileId): Profile {\n let p = built.get(id);\n if (!p) {\n p = build(id);\n built.set(id, p);\n }\n return p;\n}\n\n/** sRGB IEC 61966-2.1, the default working space. */\nexport const srgbProfile = () => builtinProfile('srgb');\n\n/** The default profile of a colour space: sRGB, Dot Gain 20 %-compatible grey, the coated CMYK, Lab D50. */\nexport function defaultProfileFor(cs: ColorSpace): Profile | null {\n switch (cs) {\n case 'rgb':\n return builtinProfile('srgb');\n case 'gray':\n return builtinProfile('dot-gain-20-compat');\n case 'cmyk':\n return builtinProfile('coated-cmyk');\n case 'lab':\n return builtinProfile('lab-d50');\n default:\n return null;\n }\n}\n","/**\n * Embedded ICC profiles in image files: PNG (`iCCP`), JPEG (APP2 `ICC_PROFILE` segments, split\n * across up to 255 markers) and PSD (image resource 1039). Reading returns the raw ICC bytes\n * (parse them with `parseProfile`); writing returns a copy of the file with the profile in it\n * (replacing any it had).\n */\n\nimport { deflate, inflate } from '../raster/zlib';\n\nlet crcTable: Uint32Array | null = null;\nfunction crc32(bytes: Uint8Array): number {\n if (!crcTable) {\n crcTable = new Uint32Array(256);\n for (let n = 0; n < 256; n++) {\n let c = n;\n for (let k = 0; k < 8; k++) c = c & 1 ? 0xedb88320 ^ (c >>> 1) : c >>> 1;\n crcTable[n] = c >>> 0;\n }\n }\n let c = 0xffffffff;\n for (let i = 0; i < bytes.length; i++) c = crcTable[(c ^ bytes[i]) & 255] ^ (c >>> 8);\n return (c ^ 0xffffffff) >>> 0;\n}\n\nconst u32 = (b: Uint8Array, o: number) => ((b[o] << 24) | (b[o + 1] << 16) | (b[o + 2] << 8) | b[o + 3]) >>> 0;\nconst PNG_SIG = [137, 80, 78, 71, 13, 10, 26, 10];\nconst isPngBytes = (b: Uint8Array) => b.length >= 8 && PNG_SIG.every((v, i) => b[i] === v);\n\n/** The ICC profile of a PNG (`iCCP`), or `null`. */\nexport function readPngIcc(png: Uint8Array): Uint8Array | null {\n if (!isPngBytes(png)) return null;\n let o = 8;\n while (o + 12 <= png.length) {\n const len = u32(png, o);\n const type = String.fromCharCode(png[o + 4], png[o + 5], png[o + 6], png[o + 7]);\n if (type === 'iCCP') {\n const d = png.subarray(o + 8, o + 8 + len);\n const z = d.indexOf(0);\n if (z < 1 || z > 79 || d[z + 1] !== 0) return null;\n try {\n return inflate(d.subarray(z + 2), { maxOutput: 64 * 1024 * 1024 });\n } catch {\n return null;\n }\n }\n if (type === 'IDAT' || type === 'IEND') return null;\n o += 12 + len;\n }\n return null;\n}\n\n/** The PNG with `icc` as its `iCCP` chunk (after IHDR; any old `iCCP`, `sRGB` or `gAMA` removed). */\nexport function writePngIcc(png: Uint8Array, icc: Uint8Array, name = 'ICC profile'): Uint8Array {\n if (!isPngBytes(png)) throw new Error('Not a PNG file.');\n const chunks: Uint8Array[] = [png.subarray(0, 8)];\n let o = 8;\n let inserted = false;\n const label = Array.from(name.slice(0, 79), (c) => c.charCodeAt(0) & 0x7f);\n const body = new Uint8Array([...label, 0, 0, ...deflate(icc)]);\n const chunk = new Uint8Array(12 + body.length);\n chunk.set([body.length >>> 24, (body.length >>> 16) & 255, (body.length >>> 8) & 255, body.length & 255]);\n chunk.set([105, 67, 67, 80], 4); // iCCP\n chunk.set(body, 8);\n const crc = crc32(chunk.subarray(4, 8 + body.length));\n chunk.set([crc >>> 24, (crc >>> 16) & 255, (crc >>> 8) & 255, crc & 255], 8 + body.length);\n while (o + 12 <= png.length) {\n const len = u32(png, o);\n const type = String.fromCharCode(png[o + 4], png[o + 5], png[o + 6], png[o + 7]);\n const whole = png.subarray(o, o + 12 + len);\n if (type !== 'iCCP' && type !== 'sRGB' && type !== 'gAMA') chunks.push(whole);\n if (type === 'IHDR' && !inserted) {\n chunks.push(chunk);\n inserted = true;\n }\n o += 12 + len;\n }\n const out = new Uint8Array(chunks.reduce((n, c) => n + c.length, 0));\n let at = 0;\n for (const c of chunks) {\n out.set(c, at);\n at += c.length;\n }\n return out;\n}\n\nconst ICC_TAG = 'ICC_PROFILE\\0';\n\n/** The ICC profile of a JPEG (its APP2 `ICC_PROFILE` segments, joined in sequence order), or `null`. */\nexport function readJpegIcc(jpeg: Uint8Array): Uint8Array | null {\n if (jpeg.length < 4 || jpeg[0] !== 0xff || jpeg[1] !== 0xd8) return null;\n const parts = new Map<number, Uint8Array>();\n let count = 0;\n let o = 2;\n while (o + 4 <= jpeg.length) {\n if (jpeg[o] !== 0xff) break;\n const marker = jpeg[o + 1];\n if (marker === 0xd8 || (marker >= 0xd0 && marker <= 0xd7) || marker === 0x01) {\n o += 2;\n continue;\n }\n if (marker === 0xda || marker === 0xd9) break; // start of scan / end\n const len = (jpeg[o + 2] << 8) | jpeg[o + 3];\n if (marker === 0xe2 && len >= 16) {\n const d = jpeg.subarray(o + 4, o + 2 + len);\n if (String.fromCharCode(...d.subarray(0, 12)) === ICC_TAG) {\n parts.set(d[12], d.subarray(14));\n count = d[13];\n }\n }\n o += 2 + len;\n }\n if (!parts.size || !count) return null;\n const ordered: Uint8Array[] = [];\n for (let i = 1; i <= count; i++) {\n const p = parts.get(i);\n if (!p) return null;\n ordered.push(p);\n }\n const out = new Uint8Array(ordered.reduce((n, p) => n + p.length, 0));\n let at = 0;\n for (const p of ordered) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n}\n\n/** The JPEG with `icc` in APP2 segments (after SOI and any APP0 / APP1; old ICC segments removed). */\nexport function writeJpegIcc(jpeg: Uint8Array, icc: Uint8Array): Uint8Array {\n if (jpeg.length < 4 || jpeg[0] !== 0xff || jpeg[1] !== 0xd8) throw new Error('Not a JPEG file.');\n const MAX = 65519;\n const count = Math.max(1, Math.ceil(icc.length / MAX));\n if (count > 255) throw new Error('The ICC profile is too large for a JPEG.');\n const segments: Uint8Array[] = [];\n for (let i = 0; i < count; i++) {\n const part = icc.subarray(i * MAX, Math.min(icc.length, (i + 1) * MAX));\n const len = 2 + 14 + part.length;\n const s = new Uint8Array(2 + len);\n s.set([0xff, 0xe2, len >> 8, len & 255]);\n for (let k = 0; k < 12; k++) s[4 + k] = ICC_TAG.charCodeAt(k);\n s[16] = i + 1;\n s[17] = count;\n s.set(part, 18);\n segments.push(s);\n }\n const keep: Uint8Array[] = [jpeg.subarray(0, 2)];\n let o = 2;\n let inserted = false;\n while (o + 4 <= jpeg.length && jpeg[o] === 0xff) {\n const marker = jpeg[o + 1];\n if (marker === 0xda || marker === 0xd9) break;\n const len = (jpeg[o + 2] << 8) | jpeg[o + 3];\n const seg = jpeg.subarray(o, o + 2 + len);\n const isIcc = marker === 0xe2 && String.fromCharCode(...seg.subarray(4, 16)) === ICC_TAG;\n if (!inserted && marker !== 0xe0 && marker !== 0xe1) {\n keep.push(...segments);\n inserted = true;\n }\n if (!isIcc) keep.push(seg);\n o += 2 + len;\n }\n if (!inserted) keep.push(...segments);\n keep.push(jpeg.subarray(o));\n const out = new Uint8Array(keep.reduce((n, p) => n + p.length, 0));\n let at = 0;\n for (const p of keep) {\n out.set(p, at);\n at += p.length;\n }\n return out;\n}\n"]}
|