diff --git a/LUPMIS2_Improvements_Mar_to_Jun_2026.docx b/LUPMIS2_Improvements_Mar_to_Jun_2026.docx new file mode 100644 index 0000000..37dc5e9 Binary files /dev/null and b/LUPMIS2_Improvements_Mar_to_Jun_2026.docx differ diff --git a/LUPMIS2_Staged_Upload_Flow.png b/LUPMIS2_Staged_Upload_Flow.png new file mode 100644 index 0000000..dcc3581 Binary files /dev/null and b/LUPMIS2_Staged_Upload_Flow.png differ diff --git a/LUPMIS2_Staged_Upload_Flow.svg b/LUPMIS2_Staged_Upload_Flow.svg new file mode 100644 index 0000000..05dd1e3 --- /dev/null +++ b/LUPMIS2_Staged_Upload_Flow.svg @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Staged Upload to the Remote Database + + + Client QA → Server staging in lu_parcels_upload_tmp → Supervisor review → Promotion to live lu_parcels + + + Idempotent on client_uuid · per-row results · no silent overwrites + + + + + + + + + STAGE 1 + CLIENT + (PWA) + browser session + SSO authenticated + + + + + + 1 · Drop file + .shp · .geojson · .kml + on the map surface + + + + + + + + 2 · Parse + stage locally + shpjs / OL KML / native parser + external_imports + + external_import_features + + + + + + + 3 · Mapping modal + user confirms target type + + field map · status = mapped + + + + + + + 4 · User clicks Upload + "Upload N" badge on the + LayerSwitcher row + + + + + + + + + + + CLIENT QA GATE · applied before the request leaves the browser + + + + + ✓ Every feature has a geometry → converted to WKT in EPSG:4326 + ✓ Target type explicitly confirmed (no silent 'other') + ✓ Field map applied — only mapped fields included; unmapped dropped + + ✓ client_uuid generated per feature (SHA1 of filename + index) + ✓ user_id_upload taken from SSO session (window.LUPMIS_SESSION) + ✓ district_id + api_token auto-attached by remotePost() + + + Only imports in status 'mapped' can be uploaded. The badge is disabled in any other state. + + + + + + + + POST /api/spatial_planning/upload_<target_type>.php + + + + + + + STAGE 2 + SERVER + PHP + PostgreSQL + SSO-scoped + per-district + + + + + 1 · Auth check + token + district scope + vs SSO session + + + + + + + 2 · Per-feature validate + geom valid · UPN policy + required fields present + + + + + + + 3 · Stage in tmp table + INSERT … ON CONFLICT + (client_uuid) DO UPDATE + → spatial.lu_parcels_upload_tmp + + + + + + + 4 · Row created + migrated = 0 + user_id_upload, created_at, + districtid (server-derived) + + + + + + + 5 · Per-row JSON + inserted / updated + / failed (with reason) + + + + + PWA badge → ✓ submitted + (failed rows stay marked locally for retry) + + + + + + Awaiting supervisor review · rows remain with migrated = 0 + + + + + + + STAGE 3 + SUPERVISOR + Review UI + (future · Laravel) + + + + + 1 · List pending rows + WHERE migrated = 0 + filter by uploader / date / district + + + + + + + 2 · Side-by-side diff + vs existing lu_parcels by UPN + map preview + attributes + + + + + + + 3 · Approve · Reject · Edit + per-row or batch action + comment captured + + + + + + + 4 · Promote to LIVE + migrated = 1 + review_at + user_id_review + → spatial.lu_parcels + + + + + PWA polls GET /import_status.php + → badge flips: ✓ submitted → ✓ live + + + + + Audit trail is intrinsic to the model: every row in lu_parcels_upload_tmp records user_id_upload + user_id_review + timestamps — no separate audit table required. + + + LUPMIS2 · Import & Upload Design Rev. 2 + + diff --git a/LUPMIS2_Workshop_Mar_to_Jun_2026.pptx b/LUPMIS2_Workshop_Mar_to_Jun_2026.pptx new file mode 100644 index 0000000..7f49bd2 Binary files /dev/null and b/LUPMIS2_Workshop_Mar_to_Jun_2026.pptx differ diff --git a/dist/.htaccess b/dist/.htaccess index d2e1dad..5169852 100644 --- a/dist/.htaccess +++ b/dist/.htaccess @@ -28,3 +28,20 @@ DirectoryIndex index.php index.html RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^ index.php [L] + +# Iframe-policy override for the embed endpoint. Some Apache deployments set +# `X-Frame-Options: SAMEORIGIN` as a default security header for every +# response — that prevents `permits.lupmis4luspa.org` from framing +# `pwa.lupmis4luspa.org/embed`, even though our Content-Security-Policy +# `frame-ancestors` directive explicitly allows it. Safari prefers +# `X-Frame-Options` when both are present, so we have to remove it. +# +# We unset it ONLY for embed.php (so index.php still inherits the +# site-wide SAMEORIGIN protection against clickjacking). embed.php's own +# `Content-Security-Policy: frame-ancestors` header (set in PHP) is then +# the sole iframe-policy header and permits the configured embedder. + + + Header always unset X-Frame-Options + + diff --git a/dist/assets/index-DR_U08k-.js.map b/dist/assets/index-DR_U08k-.js.map deleted file mode 100644 index 21e373f..0000000 --- a/dist/assets/index-DR_U08k-.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"mappings":";suCAGO,MAAMA,GAAY,WCFZC,GAAU,uCCGVC,GAA+B,MAG/BC,GAA+B,MAI/BC,GAA+B,MCHtC,CAAC,QAAAC,EAAO,EAAI,MAElB,GAAI,CAAC,kBAAAC,GAAiB,OAAEC,EAAM,EAAI,WAC9B,CAAC,OAAAC,GAAQ,KAAAC,GAAM,UAAAC,EAAS,EAAI,QAC5BC,GAAc,KAGbD,KACHA,GAAYE,IAAW,CACrB,MAAO,IAAI,QAAQC,GAAa,CAE9B,IAAIC,EAAI,IAAI,OAAO,sGAAsG,EACzHA,EAAE,UAAYD,EACdC,EAAE,YAAYF,CAAM,CACtB,CAAC,CACL,IAIA,GAAI,CACF,IAAIN,GAAkB,CAAC,CACzB,MACU,CACRA,GAAoB,YAEpB,MAAMS,EAAM,IAAI,QAEhB,GAAIR,GAAQ,CACV,MAAMS,EAAY,IAAI,IAChB,CAAC,UAAW,CAAC,YAAAC,CAAW,CAAC,EAAI,OAE7BC,EAAWC,GAAS,CACxB,MAAMC,EAAUD,EAAM,OAAOlB,EAAO,EACpC,GAAI,CAACI,GAAQe,CAAO,EAAG,CACrBD,EAAM,yBAAwB,EAC9B,KAAM,CAAE,GAAAE,EAAI,GAAAC,CAAE,EAAKF,EACnBJ,EAAU,IAAIK,CAAE,EAAEC,CAAE,CACtB,CACF,EAEAX,GAAc,SAAUY,KAASC,EAAM,CACrC,MAAMJ,EAAUG,IAAOtB,EAAO,EAC9B,GAAII,GAAQe,CAAO,EAAG,CACpB,KAAM,CAACC,EAAIC,CAAE,EAAIF,EACjBL,EAAI,IAAIO,EAAID,CAAE,EACd,KAAK,iBAAiB,UAAWH,CAAQ,CAC3C,CACA,OAAOD,EAAY,KAAK,KAAMM,EAAM,GAAGC,CAAI,CAC7C,EAEAd,GAAYY,IAAO,CACjB,MAAO,IAAI,QAAQG,GAAW,CAC5BT,EAAU,IAAID,EAAI,IAAIO,CAAE,EAAGG,CAAO,CACpC,CAAC,EAAE,KAAKC,GAAQ,CACdV,EAAU,OAAOD,EAAI,IAAIO,CAAE,CAAC,EAC5BP,EAAI,OAAOO,CAAE,EACb,QAASK,EAAI,EAAGA,EAAID,EAAK,OAAQC,IAAKL,EAAGK,CAAC,EAAID,EAAKC,CAAC,EACpD,MAAO,IACT,CAAC,CACP,EACE,KACK,CACH,MAAMC,EAAK,CAACP,EAAIC,KAAQ,CAAC,CAACrB,EAAO,EAAG,CAAE,GAAAoB,EAAI,GAAAC,CAAE,CAAE,GAE9Cd,GAASc,GAAM,CACb,YAAYM,EAAGb,EAAI,IAAIO,CAAE,EAAGA,CAAE,CAAC,CACjC,EAEA,iBAAiB,UAAWH,GAAS,CACnC,MAAMC,EAAUD,EAAM,OAAOlB,EAAO,EACpC,GAAII,GAAQe,CAAO,EAAG,CACpB,KAAM,CAACC,EAAIC,CAAE,EAAIF,EACjBL,EAAI,IAAIO,EAAID,CAAE,CAChB,CACF,CAAC,CACH,CACF,CCpFA,kCAUA,KAAM,CAAC,WAAAQ,GAAU,IAAEC,GAAK,YAAAC,EAAW,EAAI,WAGjC,CAAC,kBAAmBC,EAAS,EAAIH,GACjC,CAAC,kBAAmBI,EAAU,EAAIF,GAElCG,GAAgB,CAACZ,EAAIa,EAAOC,IAAY,CAC5C,KAAO3B,GAAKa,EAAI,EAAG,EAAGa,CAAK,IAAM,aAC/BC,EAAO,CACX,EAGMC,GAAU,IAAI,QAGdC,GAAU,IAAI,QAEdC,GAAa,CAAC,MAAO,CAAC,KAAMC,GAAMA,EAAE,CAAE,CAAC,EAG7C,IAAIC,GAAM,EAcV,MAAMC,GAAa,CAACC,EAAM,CAAC,MAAAC,EAAQ,KAAK,MAAO,UAAAC,EAAY,KAAK,UAAW,UAAAC,EAAW,UAAAC,CAAS,EAAI,OAAS,CAE1G,GAAI,CAACT,GAAQ,IAAIK,CAAI,EAAG,CAEtB,MAAMK,EAAcrC,IAAegC,EAAK,YAElCM,EAAO,CAACC,KAAaC,IAASH,EAAY,KAAKL,EAAM,CAAC,CAAC1C,EAAO,EAAGkD,CAAI,EAAG,CAAC,SAAAD,CAAQ,CAAC,EAElFd,EAAU,OAAOW,IAAc/C,GAAW+C,EAAYA,GAAW,QACjEZ,EAAQY,GAAW,OAAS,GAC5BK,EAAU,IAAI,YAAY,QAAQ,EAIlCC,EAAU,CAACC,EAAShC,IAAOgC,EAC/B5C,GAAUY,EAAI,CAAC,GACbc,EAAUF,GAAcZ,EAAIa,EAAOC,CAAO,EAAI3B,GAAKa,EAAI,CAAC,EAAIiB,IAGhE,IAAIgB,EAAU,GAEdjB,GAAQ,IAAIK,EAAM,IAAI,MAAM,IAAIb,GAAK,CAOnC,CAAC3B,EAAG,EAAG,CAACqD,EAAGC,IAAW,OAAOA,GAAW,UAAY,CAACA,EAAO,WAAW,GAAG,EAG1E,CAACvD,EAAG,EAAG,CAACsD,EAAGC,IAAWA,IAAW,OAAS,MAAQ,IAAIN,IAAS,CAE7D,MAAM9B,EAAKoB,KAIX,IAAInB,EAAK,IAAIO,GAAW,IAAIvB,GAAkB0B,GAAY,CAAC,CAAC,EAGxDkB,EAAW,GACXb,GAAQ,IAAIc,EAAK,GAAG,EAAE,GAAKD,CAAQ,GACrCb,GAAQ,OAAOa,EAAWC,EAAK,IAAG,CAAE,EAGtCF,EAAKC,EAAU7B,EAAIC,EAAImC,EAAQX,EAAYK,EAAK,IAAIL,CAAS,EAAIK,CAAI,EAGrE,MAAMG,EAAUX,IAAS,WAIzB,IAAIe,EAAW,EACf,OAAIH,GAAWD,IACbI,EAAW,WAAW,QAAQ,KAAM,IAAM,qCAAqCD,CAAM,sBAAsB,GAEtGJ,EAAQC,EAAShC,CAAE,EAAE,MAAM,KAAK,IAAM,CAC3C,aAAaoC,CAAQ,EAGrB,MAAMC,EAASrC,EAAG,CAAC,EAGnB,GAAI,CAACqC,EAAQ,OAGb,MAAMC,EAAQ3B,GAAa0B,EAG3B,OAAArC,EAAK,IAAIO,GAAW,IAAIvB,GAAkBsD,EAASA,EAAQ5B,EAAU,CAAC,EAGtEiB,EAAK,GAAI5B,EAAIC,CAAE,EACR+B,EAAQC,EAAShC,CAAE,EAAE,MAAM,KAAK,IAAMsB,EAC3CQ,EAAQ,OAAO,IAAIrB,GAAYT,EAAG,MAAM,EAAE,MAAM,EAAGqC,CAAM,CAAC,CAAC,CACvE,CACQ,CAAC,CACH,GAGA,CAACvD,EAAG,EAAEyD,EAASJ,EAAQK,EAAU,CAC/B,MAAMC,EAAO,OAAOD,EACpB,GAAIC,IAAS/D,GACX,MAAM,IAAI,MAAM,oBAAoByD,CAAM,OAAOM,CAAI,EAAE,EAEzD,GAAI,CAACF,EAAQ,KAAM,CAEjB,MAAMG,EAAU,IAAIlC,GAEpBa,EAAK,iBAAiB,UAAW,MAAOxB,GAAU,CAEhD,MAAMC,EAAUD,EAAM,OAAOlB,EAAO,EACpC,GAAII,GAAQe,CAAO,EAAG,CAEpBD,EAAM,yBAAwB,EAC9B,KAAM,CAACE,EAAIC,EAAI,GAAGE,CAAI,EAAIJ,EAC1B,IAAI6C,EAEJ,GAAIzC,EAAK,OAAQ,CACf,KAAM,CAACiC,EAAQN,CAAI,EAAI3B,EACvB,GAAIqC,EAAQ,IAAIJ,CAAM,EAAG,CACvBF,EAAU,GACV,GAAI,CAEF,MAAMW,EAAS,MAAML,EAAQ,IAAIJ,CAAM,EAAE,GAAGN,CAAI,EAChD,GAAIe,IAAW,OAAQ,CACrB,MAAMC,EAAatB,EAAUC,EAAYA,EAAUoB,CAAM,EAAIA,CAAM,EAEnEF,EAAQ,IAAI3C,EAAI8C,CAAU,EAG1B7C,EAAG,CAAC,EAAI6C,EAAW,MACrB,CACF,OACOX,EAAG,CACRS,EAAQT,CACV,QAClB,CACoBD,EAAU,EACZ,CACF,MAGEU,EAAQ,IAAI,MAAM,uBAAuBR,CAAM,EAAE,EAGnDnC,EAAG,CAAC,EAAI,CACV,KAIK,CACH,MAAM4C,EAASF,EAAQ,IAAI3C,CAAE,EAC7B2C,EAAQ,OAAO3C,CAAE,EAEjB,QAAS+C,EAAQ,IAAIrC,GAAYT,EAAG,MAAM,EAAGK,EAAI,EAAGA,EAAIuC,EAAO,OAAQvC,IACrEyC,EAAMzC,CAAC,EAAIuC,EAAO,WAAWvC,CAAC,CAClC,CAGA,GADAnB,GAAOc,EAAI,CAAC,EACR2C,EAAO,MAAMA,CACnB,CACF,CAAC,CACH,CAEA,MAAO,CAAC,CAACJ,EAAQ,IAAIJ,EAAQK,CAAQ,CACvC,CACN,CAAK,CAAC,CACJ,CACA,OAAOxB,GAAQ,IAAIK,CAAI,CACzB,EAEAD,GAAW,SAAW,IAAIS,KAAUd,GAAQ,IAAIc,CAAI,EAAGA,GCpMhD,SAASkB,IAAc,CAC1B,IAAIC,EACA7C,EAeJ,MAAO,CAAE,KAdI,SAAY,CACrB,KAAO6C,GACH,MAAMA,EAEVA,EAAU,IAAI,QAASC,GAAQ,CAC3B9C,EAAU8C,CACd,CAAC,CACL,EAOe,OANA,SAAY,CACvB,MAAMA,EAAM9C,EACZ6C,EAAU,OACV7C,EAAU,OACV8C,IAAG,CACP,CACqB,CACzB,CClBO,eAAeC,GAAsBC,EAAQC,EAAiB,CACjE,IAAIC,EAOJ,GANIF,aAAkB,KAClBE,EAAiBF,EAAO,OAAM,EAG9BE,EAAiBF,EAEjBE,aAA0B,gBAAkBD,EAAiB,CAE7D,MAAME,EADSD,EACO,UAAS,EAC/B,OAAQD,EAAe,CACnB,IAAK,WACD,MAAO,WACW,MAAME,EAAO,KAAI,GAClB,MAErB,IAAK,SACD,MAAMC,EAAS,GACf,IAAIC,EAAa,GACjB,KAAO,CAACA,GAAY,CAChB,MAAMC,EAAQ,MAAMH,EAAO,KAAI,EAC3BG,EAAM,OACNF,EAAO,KAAKE,EAAM,KAAK,EAC3BD,EAAaC,EAAM,IACvB,CACA,MAAMC,EAAcH,EAAO,OAAO,CAAClB,EAAQoB,IAChCpB,EAASoB,EAAM,OACvB,CAAC,EACEnE,EAAS,IAAI,WAAWoE,CAAW,EACzC,IAAIC,EAAS,EACb,OAAAJ,EAAO,QAASE,GAAU,CACtBnE,EAAO,IAAImE,EAAOE,CAAM,EACxBA,GAAUF,EAAM,MACpB,CAAC,EACMnE,EAAO,MAC9B,CACI,KAEI,QAAO+D,CAEf,CCxCO,MAAMO,EAAmB,CAC5B,YAAYC,EAAmB,CAC3B,OAAO,eAAe,KAAM,oBAAqB,CAC7C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAOA,CACnB,CAAS,EACD,OAAO,eAAe,KAAM,UAAW,CACnC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,KAAM,CAC9B,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,SAAU,CAClC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,WAAY,CACpC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,EACnB,CAAS,EACD,OAAO,eAAe,KAAM,iBAAkB,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAI,GACvB,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,QACnB,CAAS,CACL,CACA,MAAM,KAAKC,EAAQ,CACf,KAAM,CAAE,aAAAC,CAAY,EAAKD,EACnBE,EAAQ,KAAK,SAASF,CAAM,EAClC,GAAI,CAAC,KAAK,kBAAmB,CACzB,KAAM,CAAE,QAASD,GAAsB,MAAKI,GAAA,wBAAAJ,CAAA,OAAC,QAAO,qBAAyB,iBAAAA,CAAA,OAC7E,KAAK,kBAAoBA,CAC7B,CACK,KAAK,UACN,KAAK,QAAU,MAAM,KAAK,kBAAiB,GAE3C,KAAK,IACL,MAAM,KAAK,QAAO,EAEtB,KAAK,GAAK,IAAI,KAAK,QAAQ,IAAI,GAAGE,EAAcC,CAAK,EACrD,KAAK,OAASF,EACd,KAAK,cAAa,CACtB,CACA,QAAQtB,EAAU,CACd,YAAK,eAAe,IAAIA,CAAQ,EACzB,IAAM,CACT,KAAK,eAAe,OAAOA,CAAQ,CACvC,CACJ,CACA,MAAM,KAAK0B,EAAW,CAClB,GAAI,CAAC,KAAK,GACN,MAAM,IAAI,MAAM,wBAAwB,EAC5C,OAAO,KAAK,SAAS,KAAK,GAAIA,CAAS,CAC3C,CACA,MAAM,UAAUC,EAAY,CACxB,GAAI,CAAC,KAAK,GACN,MAAM,IAAI,MAAM,wBAAwB,EAC5C,MAAMzB,EAAU,GAChB,YAAK,GAAG,YAAa0B,GAAO,CACxB,MAAMC,EAAW,IAAI,IACrB,GAAI,CACA,QAASH,KAAaC,EAAY,CAC9B,IAAIG,EAAOD,EAAS,IAAIH,EAAU,GAAG,EACrC,GAAI,CAACI,EAAM,CACP,MAAMC,EAAUH,EAAG,QAAQF,EAAU,GAAG,EACxCG,EAAS,IAAIH,EAAU,IAAKK,CAAO,EACnCD,EAAOC,CACX,CACIL,EAAU,QAAQ,QAClBI,EAAK,KAAKJ,EAAU,MAAM,EAE9B,IAAIM,EAAU,GACVC,EAAO,GACX,KAAOH,EAAK,QACRE,EAAUF,EAAK,eAAe,EAAE,EAChCG,EAAK,KAAKH,EAAK,IAAI,EAAE,CAAC,EAE1B5B,EAAQ,KAAK,CAAE,QAAA8B,EAAS,KAAAC,CAAI,CAAE,EAC9BH,EAAK,MAAK,CACd,CACJ,QACZ,CACgBD,EAAS,QAASC,GAAS,CACvBA,EAAK,SAAQ,CACjB,CAAC,CACL,CACJ,CAAC,EACM5B,CACX,CACA,MAAM,qBAAsB,CACxB,MAAO,EACX,CACA,MAAM,sBAAuB,CAMzB,MAAMgC,GALa,MAAM,KAAK,KAAK,CAC/B,IAAK;AAAA,kDAEL,OAAQ,KACpB,CAAS,IACwB,OAAO,CAAC,EACjC,GAAI,OAAOA,GAAS,SAChB,MAAM,IAAI,MAAM,+BAA+B,EAEnD,OAAOA,CACX,CACA,MAAM,eAAexD,EAAI,CACrB,GAAI,CAAC,KAAK,GACN,MAAM,IAAI,MAAM,wBAAwB,EAC5C,OAAQA,EAAG,KAAI,CACX,IAAK,WACL,IAAK,SACD,KAAK,GAAG,eAAe,CACnB,KAAMA,EAAG,KACT,MAAO,CAACgB,KAAML,IAASX,EAAG,KAAK,GAAGW,CAAI,EACtC,MAAO,EAC3B,CAAiB,EACD,MACJ,IAAK,YACD,KAAK,GAAG,eAAe,CACnB,KAAMX,EAAG,KACT,MAAO,CAACgB,KAAML,IAASX,EAAG,KAAK,KAAK,GAAGW,CAAI,EAC3C,OAAQ,CAACK,KAAML,IAASX,EAAG,KAAK,MAAM,GAAGW,CAAI,EAC7C,MAAO,EAC3B,CAAiB,EACD,KAChB,CACI,CACA,MAAM,OAAO8C,EAAU,CACnB,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,IAAM,CAAC,KAAK,OACnC,MAAM,IAAI,MAAM,wBAAwB,EAE5C,MAAM1E,EAAO,MAAMiD,GAAsByB,EAAU,QAAQ,EACrDC,EAAc,KAAK,QAAQ,KAAK,oBAAoB3E,CAAI,EAC9D,KAAK,SAAS,KAAK2E,CAAW,EAC9B,MAAMC,EAAa,KAAK,QAAQ,KAAK,oBAAoB,KAAK,GAAI,OAAQD,EAAa3E,EAAK,WAAYA,EAAK,WAAY,KAAK,OAAO,SAC/H,KAAK,QAAQ,KAAK,4BAClB,KAAK,QAAQ,KAAK,6BAA6B,EACrD,KAAK,GAAG,QAAQ4E,CAAU,CAC9B,CACA,MAAM,QAAS,CACX,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,GACvB,MAAM,IAAI,MAAM,wBAAwB,EAE5C,MAAO,CACH,KAAM,mBACN,KAAM,KAAK,QAAQ,KAAK,qBAAqB,KAAK,EAAE,CAChE,CACI,CACA,MAAM,OAAQ,CAAE,CAChB,MAAM,SAAU,CACZ,KAAK,QAAO,EACZ,KAAK,SAAS,QAASC,GAAY,KAAK,SAAS,KAAK,QAAQA,CAAO,CAAC,EACtE,KAAK,SAAW,GAChB,KAAK,eAAe,MAAK,CAC7B,CACA,SAAShB,EAAQ,CACb,KAAM,CAAE,SAAAiB,EAAU,QAAAC,CAAO,EAAKlB,EAE9B,MADc,CAACiB,IAAa,GAAO,IAAM,KAAMC,IAAY,GAAO,IAAM,EAAE,EAC7D,KAAK,EAAE,CACxB,CACA,SAASC,EAAIf,EAAW,CACpB,MAAMgB,EAAgB,CAClB,KAAM,GACN,QAAS,EACrB,EACcT,EAAOQ,EAAG,KAAK,CACjB,IAAKf,EAAU,IACf,KAAMA,EAAU,OAChB,YAAa,aACb,QAAS,QACT,YAAagB,EAAc,OACvC,CAAS,EACD,OAAQhB,EAAU,OAAM,CACpB,IAAK,MACD,MACJ,IAAK,MACDgB,EAAc,KAAOT,EAAK,CAAC,GAAK,GAChC,MACJ,IAAK,MACL,QACIS,EAAc,KAAOT,EACrB,KAChB,CACQ,OAAOS,CACX,CACA,eAAgB,CACZ,GAAI,CAAC,KAAK,QAAQ,SACd,OACJ,GAAI,CAAC,KAAK,SAAW,CAAC,KAAK,GACvB,MAAM,IAAI,MAAM,wBAAwB,EAE5C,MAAMC,EAAQ,CACV,CAAC,KAAK,QAAQ,KAAK,aAAa,EAAG,SACnC,CAAC,KAAK,QAAQ,KAAK,aAAa,EAAG,SACnC,CAAC,KAAK,QAAQ,KAAK,aAAa,EAAG,QAC/C,EACQ,KAAK,QAAQ,KAAK,oBAAoB,KAAK,GAAI,CAACC,EAAMC,EAAMC,EAAKC,EAAOC,IAAU,CAC9E,KAAK,eAAe,QAASC,GAAO,CAChCA,EAAG,CAAE,MAAAF,EAAO,MAAAC,EAAO,UAAWL,EAAME,CAAI,EAAG,CAC/C,CAAC,CACL,EAAG,CAAC,CACR,CACA,SAAU,CACF,KAAK,KACL,KAAK,GAAG,MAAK,EACb,KAAK,GAAK,OAElB,CACJ,CC3NO,SAASK,GAASC,EAAMxG,EAAMyG,EAAS,CAC1C,IAAIC,EACAC,EACAC,EACAnD,EACAoD,EACAC,EACAC,EAAiB,EACjBC,EAAU,GACVC,EAAS,GACTC,EAAW,GACf,GAAI,OAAOV,GAAS,WAChB,MAAM,IAAI,UAAU,qBAAqB,EAE7CxG,EAAO,OAAOA,CAAI,GAAK,EACnB,OAAOyG,GAAY,UAAYA,IAAY,OAC3CO,EAAU,CAAC,CAACP,EAAQ,QACpBQ,EAAS,YAAaR,EACtBG,EAAUK,EAAS,KAAK,IAAI,OAAOR,EAAQ,OAAO,GAAK,EAAGzG,CAAI,EAAI,EAClEkH,EAAW,aAAcT,EAAU,CAAC,CAACA,EAAQ,SAAWS,GAE5D,SAASC,EAAWC,EAAM,CACtB,MAAM1E,EAAOgE,EACPW,EAAUV,EAChB,OAAAD,EAAWC,EAAW,OACtBI,EAAiBK,EACjB3D,EAAS+C,EAAK,MAAMa,EAAS3E,CAAI,EAC1Be,CACX,CACA,SAAS6D,EAAYF,EAAM,CACvB,OAAAL,EAAiBK,EACjBP,EAAU,WAAWU,EAAcvH,CAAI,EAChCgH,EAAUG,EAAWC,CAAI,EAAI3D,CACxC,CACA,SAAS+D,EAAcJ,EAAM,CACzB,MAAMK,EAAoBL,GAAQN,GAAgB,GAC5CY,EAAsBN,EAAOL,EAC7BY,EAAc3H,EAAOyH,EAC3B,OAAOR,EACD,KAAK,IAAIU,EAAaf,EAAUc,CAAmB,EACnDC,CACV,CACA,SAASC,EAAaR,EAAM,CACxB,MAAMK,EAAoBL,GAAQN,GAAgB,GAC5CY,EAAsBN,EAAOL,EACnC,OAAQD,IAAiB,QACrBW,GAAqBzH,GACrByH,EAAoB,GACnBR,GAAUS,GAAuBd,CAC1C,CACA,SAASW,GAAe,CACpB,MAAMH,EAAO,KAAK,IAAG,EACrB,GAAIQ,EAAaR,CAAI,EACjB,OAAOS,EAAaT,CAAI,EAE5BP,EAAU,WAAWU,EAAcC,EAAcJ,CAAI,CAAC,CAC1D,CACA,SAASS,EAAaT,EAAM,CAExB,OADAP,EAAU,OACNK,GAAYR,EACLS,EAAWC,CAAI,GAE1BV,EAAWC,EAAW,OACflD,EACX,CACA,SAASqE,GAAS,CACVjB,IAAY,QACZ,aAAaA,CAAO,EAExBE,EAAiB,EACjBL,EAAWI,EAAeH,EAAWE,EAAU,MACnD,CACA,SAASkB,GAAQ,CACb,OAAOlB,IAAY,OAAYpD,EAASoE,EAAa,KAAK,KAAK,CACnE,CACA,SAASG,GAAY,CACjB,MAAMZ,EAAO,KAAK,IAAG,EACfa,EAAaL,EAAaR,CAAI,EAMpC,GAJAV,EAAW,UAEXC,EAAW,KACXG,EAAeM,EACXa,EAAY,CACZ,GAAIpB,IAAY,OACZ,OAAOS,EAAYR,CAAY,EAEnC,GAAIG,EACA,OAAAJ,EAAU,WAAWU,EAAcvH,CAAI,EAChCmH,EAAWL,CAAY,CAEtC,CACA,OAAID,IAAY,SACZA,EAAU,WAAWU,EAAcvH,CAAI,GAEpCyD,CACX,CACA,OAAAuE,EAAU,OAASF,EACnBE,EAAU,MAAQD,EACXC,CACX,CC5GO,SAASE,IAAc,CAC1B,OAAO,OAAO,WAAU,CAC5B,CCDO,SAASC,GAAevD,EAAcwD,EAAW,CACpD,OAAQxD,EAAY,CAChB,IAAK,UACL,IAAK,mBAED,IAAIyD,EAAa,eAAe,qBAChC,OAAKA,IACDA,EAAaH,GAAW,EACxB,eAAe,qBAAuBG,GAEnC,WAAWA,CAAU,GAChC,IAAK,QACL,IAAK,iBAED,MAAO,QACX,IAAK,WAED,MAAO,UAAUD,CAAS,GAC9B,QAEI,MAAO,QAAQxD,CAAY,EACvC,CACA,CClBO,MAAM0D,EAAiB,CAC1B,YAAYC,EAAQ,CAChB,OAAO,eAAe,KAAM,SAAU,CAClC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,SAAU,CAClC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,EACnB,CAAS,EACD,OAAO,eAAe,KAAM,gBAAiB,CACzC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAI,GACvB,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO3E,GAAW,CAC9B,CAAS,EACD,OAAO,eAAe,KAAM,mBAAoB,CAC5C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAOA,GAAW,CAC9B,CAAS,EACD,OAAO,eAAe,KAAM,iBAAkB,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IACnB,CAAS,EACD,OAAO,eAAe,KAAM,QAAS,CACjC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAI,GACvB,CAAS,EACD,OAAO,eAAe,KAAM,iBAAkB,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,gBAAiB,CACzC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,OAAQ,CAChC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAO4E,GAAW,CACrB,GAAI,GAAC,KAAK,OAAO,cAAgB,CAAC,KAAK,OAAO,WAE9C,OAAM,KAAK,UAAU,KAAI,EACzB,GAAI,CACA,GAAI,CACA,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,CACtC,MACM,CACF,QAAQ,KAAK,0BAA0B,KAAK,OAAO,YAAY,gNAAgN,EAC/Q,KAAK,OAAO,aAAe,WAC3B,KAAK,OAAS,IAAI/D,GAClB,MAAM,KAAK,OAAO,KAAK,KAAK,MAAM,CACtC,CACA,MAAMgE,EAAQN,GAAe,KAAK,OAAO,aAAc,KAAK,OAAO,SAAS,EAC5E,KAAK,cAAgB,IAAI,iBAAiB,oBAAoBM,CAAK,GAAG,EACtE,KAAK,cAAc,UAAa/H,GAAU,CACtC,MAAMgI,EAAUhI,EAAM,KACtB,GAAI,KAAK,OAAO,YAAcgI,EAAQ,UAEtC,OAAQA,EAAQ,KAAI,CAChB,IAAK,SACD,KAAK,KAAKA,EAAQ,MAAM,EACxB,MACJ,IAAK,QACD,KAAK,OAAO,QAAO,EACnB,KAChC,CACoB,EACI,KAAK,OAAO,WACZ,KAAK,eAAiB,IAAI,iBAAiB,qBAAqBD,CAAK,GAAG,EACxE,KAAK,OAAO,QAAQ,MAAOE,GAAW,CAClC,KAAK,YAAY,IAAIA,EAAO,KAAK,EACjC,MAAM,KAAK,iBAAiB,KAAI,EAChC,KAAK,qBAAoB,EACzB,MAAM,KAAK,iBAAiB,OAAM,CACtC,CAAC,GAEL,MAAM,QAAQ,IAAI,MAAM,KAAK,KAAK,cAAc,OAAM,CAAE,EAAE,IAAK5G,GACpD,KAAK,iBAAiBA,CAAE,CAClC,CAAC,EACF,MAAM,KAAK,mBAAkB,EAC7B,KAAK,YAAY,CAAE,KAAM,QAAS,MAAO,UAAW,OAAAyG,EAAQ,CAChE,OACOhF,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAU,IAClC,CAAqB,EACD,MAAM,KAAK,QAAO,CACtB,QAChB,CACoB,MAAM,KAAK,UAAU,OAAM,CAC/B,EACJ,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAO9C,EAAOkI,IAAc,CAC/B,MAAMF,EAAUhI,aAAiB,aAAeA,EAAM,KAAOA,EAE7D,OADA,MAAM,KAAK,UAAU,KAAI,EACjBgI,EAAQ,KAAI,CAChB,IAAK,SACD,KAAK,WAAWA,CAAO,EACvB,MACJ,IAAK,QACL,IAAK,QACL,IAAK,cACD,KAAK,KAAKA,CAAO,EACjB,MACJ,IAAK,WACD,KAAK,mBAAmBA,CAAO,EAC/B,MACJ,IAAK,UACD,KAAK,gBAAgBA,CAAO,EAC5B,MACJ,IAAK,SACD,KAAK,SAASA,CAAO,EACrB,MACJ,IAAK,SACD,KAAK,SAASA,CAAO,EACrB,MACJ,IAAK,SACD,KAAK,SAASA,CAAO,EACrB,MACJ,IAAK,UACD,KAAK,QAAQA,CAAO,EACpB,KACxB,CACgB,MAAM,KAAK,UAAU,OAAM,CAC/B,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,CAACA,EAASjG,EAAW,KAAO,CAC3B,KAAK,WACL,KAAK,UAAUiG,EAASjG,CAAQ,CAExC,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAM,CACL,CAAC,KAAK,gBAAkB,KAAK,YAAY,OAAS,IAEtD,KAAK,eAAe,YAAY,CAC5B,KAAM,UACN,OAAQ,CAAC,GAAG,KAAK,WAAW,CAChD,CAAiB,EACD,KAAK,YAAY,MAAK,EAC1B,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,uBAAwB,CAChD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO8D,GAAS,IAAM,KAAK,YAAW,EAAI,GAAI,CAC1C,QAAS,GACzB,CAAa,CACb,CAAS,EACD,OAAO,eAAe,KAAM,aAAc,CACtC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAQmC,GAAY,CAChB,KAAK,OAASA,EAAQ,OACtB,KAAK,KAAK,SAAS,CACvB,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,OAAQ,CAChC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOA,GAAY,CACtB,GAAI,CACA,MAAMG,EAAW,CACb,KAAM,OACN,SAAUH,EAAQ,SAClB,KAAM,EAC9B,EACoB,OAAQA,EAAQ,KAAI,CAChB,IAAK,QACD,MAAMI,EAAoB,KAAK,iBAAmB,MAC9C,KAAK,iBAAmBJ,EAAQ,eACpC,GAAI,CACKI,GACD,MAAM,KAAK,iBAAiB,KAAI,EAEpC,MAAM/C,EAAgB,MAAM,KAAK,OAAO,KAAK2C,CAAO,EACpDG,EAAS,KAAK,KAAK9C,CAAa,CACpC,QAC5B,CACqC+C,GACD,MAAM,KAAK,iBAAiB,OAAM,CAE1C,CACA,MACJ,IAAK,QACD,GAAI,CACA,MAAM,KAAK,iBAAiB,KAAI,EAChC,MAAMvF,EAAU,MAAM,KAAK,OAAO,UAAUmF,EAAQ,UAAU,EAC9DG,EAAS,KAAK,KAAK,GAAGtF,CAAO,CACjC,QAC5B,CACgC,MAAM,KAAK,iBAAiB,OAAM,CACtC,CACA,MACJ,IAAK,cAMD,GALImF,EAAQ,SAAW,UACnB,MAAM,KAAK,iBAAiB,KAAI,EAChC,KAAK,eAAiBA,EAAQ,eAC9B,MAAM,KAAK,OAAO,KAAK,CAAE,IAAK,OAAO,CAAE,IAEtCA,EAAQ,SAAW,UAAYA,EAAQ,SAAW,aACnD,KAAK,iBAAmB,MACxB,KAAK,iBAAmBA,EAAQ,eAAgB,CAChD,MAAMK,EAAML,EAAQ,SAAW,SAAW,SAAW,WACrD,MAAM,KAAK,OAAO,KAAK,CAAE,IAAAK,CAAG,CAAE,EAC9B,KAAK,eAAiB,KACtB,MAAM,KAAK,iBAAiB,OAAM,CACtC,CACA,KAC5B,CACoB,KAAK,YAAYF,CAAQ,CAC7B,OACOrF,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAUkF,EAAQ,QAC1C,CAAqB,CACL,CACJ,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,qBAAsB,CAC9C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,GAAI,KAAK,OAAO,iBACZ,QAAS3D,KAAa,KAAK,OAAO,iBAC9B,MAAM,KAAK,OAAO,KAAKA,CAAS,CAG5C,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,kBAAmB,CAC3C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAO2D,GAAY,CACtB,GAAI,CACA,KAAK,YAAY,CACb,KAAM,OACN,SAAUA,EAAQ,SAClB,KAAM,CACF,aAAc,KAAK,OAAO,aAC1B,YAAa,KAAK,OAAO,YACzB,kBAAmB,MAAM,KAAK,OAAO,qBAAoB,EACzD,UAAW,MAAM,KAAK,OAAO,oBAAmB,CAC5E,CACA,CAAqB,CACL,OACOlF,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,SAAUkF,EAAQ,SAClB,MAAAlF,CACxB,CAAqB,CACL,CACJ,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,qBAAsB,CAC9C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOkF,GAAY,CACtB,KAAM,CAAE,aAAcM,EAAM,aAAc1F,EAAM,SAAA2F,CAAQ,EAAKP,EAC7D,IAAI3G,EACJ,GAAI,KAAK,cAAc,IAAIiH,CAAI,EAAG,CAC9B,KAAK,YAAY,CACb,KAAM,QACN,MAAO,IAAI,MAAM,0CAA0CA,CAAI,uDAAuD,EACtH,SAAAC,CACxB,CAAqB,EACD,MACJ,CACA,OAAQ3F,EAAI,CACR,IAAK,WACDvB,EAAK,CACD,KAAAuB,EACA,KAAA0F,EACA,KAAM,IAAItG,IAAS,CACf,KAAK,YAAY,CAAE,KAAM,WAAY,KAAAsG,EAAM,KAAAtG,EAAM,CACrD,CAC5B,EACwB,MACJ,IAAK,SACDX,EAAK,CACD,KAAAuB,EACA,KAAA0F,EACA,KAAM,KAAK,MAAM,iBAAiBA,CAAI,EAAE,CACpE,EACwB,MACJ,IAAK,YACDjH,EAAK,CACD,KAAAuB,EACA,KAAA0F,EACA,KAAM,CACF,KAAM,KAAK,MAAM,iBAAiBA,CAAI,OAAO,EAC7C,MAAO,KAAK,MAAM,iBAAiBA,CAAI,QAAQ,CAC/E,CACA,EACwB,KACxB,CACgB,GAAI,CACA,MAAM,KAAK,iBAAiBjH,CAAE,EAC9B,KAAK,YAAY,CACb,KAAM,UACN,SAAAkH,CACxB,CAAqB,CACL,OACOzF,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAAyF,CACxB,CAAqB,CACL,CACJ,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,mBAAoB,CAC5C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOlH,GAAO,CACjB,MAAM,KAAK,OAAO,eAAeA,CAAE,EACnC,KAAK,cAAc,IAAIA,EAAG,KAAMA,CAAE,CACtC,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,WAAY,CACpC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAO2G,GAAY,CACtB,KAAM,CAAE,SAAAO,EAAU,SAAAzD,CAAQ,EAAKkD,EAC/B,IAAIQ,EAAU,GACd,GAAI,CACA,MAAM,KAAK,OAAO,OAAO1D,CAAQ,EAC7B,KAAK,OAAO,cAAgB,UAC5B,MAAM,KAAK,mBAAkB,CAErC,OACOhC,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAAyF,CACxB,CAAqB,EACDC,EAAU,EACd,QAChB,CACwB,KAAK,OAAO,cAAgB,UAC5B,MAAM,KAAK,KAAK,WAAW,CAEnC,CACKA,GACD,KAAK,YAAY,CACb,KAAM,UACN,SAAAD,CACxB,CAAqB,CAET,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,WAAY,CACpC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOP,GAAY,CACtB,KAAM,CAAE,SAAAO,CAAQ,EAAKP,EACrB,GAAI,CACA,KAAM,CAAE,KAAAM,EAAM,KAAAlI,CAAI,EAAK,MAAM,KAAK,OAAO,OAAM,EAC/C,KAAK,YAAY,CACb,KAAM,SACN,SAAAmI,EACA,WAAYD,EACZ,OAAQlI,CAChC,EAAuB,CAACA,CAAI,CAAC,CACb,OACO0C,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAAyF,CACxB,CAAqB,CACL,CACJ,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,WAAY,CACpC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOP,GAAY,CACtB,KAAM,CAAE,SAAAO,CAAQ,EAAKP,EACrB,IAAIQ,EAAU,GACd,GAAI,CACA,MAAM,KAAK,OAAO,MAAK,CAC3B,OACO1F,EAAO,CACV,KAAK,YAAY,CACb,KAAM,QACN,MAAAA,EACA,SAAAyF,CACxB,CAAqB,EACDC,EAAU,EACd,QAChB,CACoB,MAAM,KAAK,KAAK,QAAQ,CAC5B,CACKA,GACD,KAAK,YAAY,CACb,KAAM,UACN,SAAAD,CACxB,CAAqB,CAET,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,UAAW,CACnC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOP,GAAY,CACtB,MAAM,KAAK,OAAO,KAAK,CAAE,IAAK,iBAAiB,CAAE,EACjD,MAAM,KAAK,OAAO,QAAO,EACrB,KAAK,iBACL,KAAK,qBAAqB,MAAK,EAC/B,KAAK,eAAe,MAAK,EACzB,KAAK,eAAiB,QAEtB,KAAK,gBACL,KAAK,cAAc,MAAK,EACxB,KAAK,cAAgB,QAErBA,GACA,KAAK,YAAY,CACb,KAAM,UACN,SAAUA,EAAQ,QAC1C,CAAqB,CAET,CACZ,CAAS,EAGD,MAAMS,EAFa,OAAO,kBAAsB,KAC5C,sBAAsB,kBACClH,GAAW,UAAU,EAAI,WACpD,KAAK,MAAQkH,EACb,KAAK,OAASZ,CAClB,CACJ,CCrfO,SAASa,GAAOC,KAAkBC,EAAQ,CAC7C,MAAO,CACH,IAAKD,EAAc,KAAK,GAAG,EAC3B,OAAAC,CACR,CACA,CCLA,SAASC,GAAgBjE,EAAM,CAC3B,MAAO,CAACA,EAAK,KAAMkE,GAAQ,CAAC,MAAM,QAAQA,CAAG,CAAC,CAClD,CACO,SAASC,GAAqBnE,EAAMD,EAAS,CAChD,IAAIqE,EACJ,OAAIH,GAAgBjE,CAAI,EACpBoE,EAAcpE,EAGdoE,EAAc,CAACpE,CAAI,EAEhBoE,EAAY,IAAKF,GAAQ,CAC5B,MAAMG,EAAS,GACf,OAAAtE,EAAQ,QAAQ,CAACuE,EAAQC,IAAgB,CACrCF,EAAOC,CAAM,EAAIJ,EAAIK,CAAW,CACpC,CAAC,EACMF,CACX,CAAC,CACL,CCjBA,SAASG,GAAmB/E,EAAW,CACnC,OAAQ,OAAOA,GAAc,UACzBA,IAAc,MACd,WAAYA,GACZ,OAAOA,EAAU,QAAW,UACpC,CACA,SAASgF,GAAYhF,EAAW,CAC5B,OAAQ,OAAOA,GAAc,UACzBA,IAAc,MACd,QAASA,GACT,OAAOA,EAAU,KAAQ,UACzB,WAAYA,CACpB,CACO,SAASiF,GAAmBjF,EAAW,CAI1C,GAHI,OAAOA,GAAc,aACrBA,EAAYA,EAAUqE,EAAM,GAE5BU,GAAmB/E,CAAS,EAC5B,GAAI,CACA,GAAI,EAAE,UAAWA,GAAa,OAAOA,EAAU,OAAU,YACrD,KAAM,GAEV,MAAMkF,EAAmBlF,EAAU,MAAK,EACxC,GAAI,CAACgF,GAAYE,CAAgB,EAC7B,KAAM,GAEV,MAAMC,EAAO,QAASnF,GAAa,OAAOA,EAAU,KAAQ,WACtDA,EAAU,IACV,OACN,MAAO,CACH,GAAGkF,EACH,KAAMC,EAAO,IAAMA,EAAI,EAAK,MAC5C,CACQ,MACM,CACF,MAAM,IAAI,MAAM,2CAA2C,CAC/D,CAEJ,MAAMnB,EAAMhE,EAAU,IACtB,IAAIuE,EAAS,GACb,MAAI,WAAYvE,EACZuE,EAASvE,EAAU,OAEd,eAAgBA,IACrBuE,EAASvE,EAAU,YAEhB,CAAE,IAAAgE,EAAK,OAAAO,CAAM,CACxB,CC/CO,SAASa,GAAaC,EAAoBd,EAAQ,CACrD,IAAIvE,EACJ,OAAI,OAAOqF,GAAuB,SAC9BrF,EAAY,CAAE,IAAKqF,EAAoB,OAAAd,CAAM,EAG7CvE,EAAYqE,GAAOgB,EAAoB,GAAGd,CAAM,EAE7CvE,CACX,CCVO,eAAesF,GAAaC,EAAMC,EAAQ5F,EAAQ6F,EAAU,CAC/D,MAAI,CAACD,GAAU,UAAW,UACf,UAAU,MAAM,QAAQ,sBAAsB5F,EAAO,YAAY,IAAK,CAAE,KAAA2F,CAAI,EAAIE,CAAQ,EAGxFA,EAAQ,CAEvB,CCNO,MAAMC,WAA0BhG,EAAmB,CACtD,YAAYiG,EAAahG,EAAmB,CACxC,MAAMA,CAAiB,EACvB,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAOgG,CACnB,CAAS,CACL,CACA,MAAM,KAAK/F,EAAQ,CACf,MAAME,EAAQ,KAAK,SAASF,CAAM,EAClC,GAAIA,EAAO,SACP,MAAM,IAAI,MAAM,wBAAwB,KAAK,WAAW,oCAAoC,EAEhG,GAAI,CAAC,KAAK,kBAAmB,CACzB,KAAM,CAAE,QAASD,GAAsB,MAAKI,GAAA,wBAAAJ,CAAA,OAAC,QAAO,qBAAyB,iBAAAA,CAAA,OAC7E,KAAK,kBAAoBA,CAC7B,CACK,KAAK,UACN,KAAK,QAAU,MAAM,KAAK,kBAAiB,GAE3C,KAAK,IACL,MAAM,KAAK,QAAO,EAEtB,KAAK,GAAK,IAAI,KAAK,QAAQ,IAAI,YAAY,CACvC,SAAU,KAAK,YACf,MAAAG,CACZ,CAAS,EACD,KAAK,OAASF,EACd,KAAK,cAAa,CACtB,CACA,MAAM,qBAAsB,CACxB,OAAO,UAAU,SAAS,UAAS,CACvC,CACA,MAAM,sBAAuB,CACzB,GAAI,CAAC,KAAK,GACN,MAAM,IAAI,MAAM,wBAAwB,EAC5C,OAAO,KAAK,GAAG,YAAW,CAC9B,CACA,MAAM,OAAOa,EAAU,CACnB,MAAMmF,EAAQ,IAAIlG,GAClB,MAAMkG,EAAM,KAAK,EAAE,EACnB,MAAMA,EAAM,OAAOnF,CAAQ,EAC3B,MAAM,KAAK,MAAK,EAChB,MAAMmF,EAAM,KAAK,CACb,IAAK,qBAAqB,KAAK,WAAW,aACtD,CAAS,EACD,MAAMA,EAAM,QAAO,CACvB,CACA,MAAM,OAAQ,CACV,GAAI,CAAC,KAAK,GACN,MAAM,IAAI,MAAM,wBAAwB,EAC5C,KAAK,GAAG,aAAY,CACxB,CACA,MAAM,SAAU,CACZ,KAAK,QAAO,EACZ,KAAK,eAAe,MAAK,CAC7B,CACJ,CC5DA,IAAIC,GAAIC,GAaD,MAAMC,EAAQ,CACjB,YAAYnG,EAAQ,CAChB,OAAO,eAAe,KAAM,SAAU,CAClC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,EACnB,CAAS,EACD,OAAO,eAAe,KAAM,qBAAsB,CAC9C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,EACnB,CAAS,EACD,OAAO,eAAe,KAAM,2BAA4B,CACpD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,EACnB,CAAS,EACD,OAAO,eAAe,KAAM,gBAAiB,CACzC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAI,GACvB,CAAS,EACD,OAAO,eAAe,KAAM,oBAAqB,CAC7C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAI,GACvB,CAAS,EACD,OAAO,eAAe,KAAM,QAAS,CACjC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,gBAAiB,CACzC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,iBAAkB,CAC1C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MACnB,CAAS,EACD,OAAO,eAAe,KAAM,sBAAuB,CAC/C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAQjE,GAAU,CACd,MAAMgI,EAAUhI,aAAiB,aAAeA,EAAM,KAAOA,EACvDqK,EAAU,KAAK,kBACrB,OAAQrC,EAAQ,KAAI,CAChB,IAAK,UACL,IAAK,OACL,IAAK,SACL,IAAK,OACL,IAAK,QACD,GAAIA,EAAQ,UAAYqC,EAAQ,IAAIrC,EAAQ,QAAQ,EAAG,CACnD,KAAM,CAAC1H,EAASgK,CAAM,EAAID,EAAQ,IAAIrC,EAAQ,QAAQ,EAClDA,EAAQ,OAAS,QACjBsC,EAAOtC,EAAQ,KAAK,EAGpB1H,EAAQ0H,CAAO,EAEnBqC,EAAQ,OAAOrC,EAAQ,QAAQ,CACnC,SACSA,EAAQ,OAAS,QACtB,MAAMA,EAAQ,MAElB,MACJ,IAAK,WACD,MAAMuC,EAAe,KAAK,cAAc,IAAIvC,EAAQ,IAAI,EACpDuC,GACAA,EAAa,GAAIvC,EAAQ,MAAQ,EAAG,EAExC,MACJ,IAAK,QACD,KAAK,OAAO,YAAYA,EAAQ,MAAM,EACtC,KACxB,CACY,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOA,GACH2B,GAAa,SAAU,KAAK,oBAC/B3B,EAAQ,OAAS,UACjBA,EAAQ,OAAS,SAAU,KAAK,OAAQ,SAAY,CACpD,GAAI,KAAK,cAAgB,GACrB,MAAM,IAAI,MAAM,oHAAoH,EAExI,MAAMO,EAAWf,GAAW,EAC5B,OAAQQ,EAAQ,KAAI,CAChB,IAAK,SACD,KAAK,UAAU,YAAY,CACvB,GAAGA,EACH,SAAAO,CAChC,EAA+B,CAACP,EAAQ,QAAQ,CAAC,EACrB,MACJ,QACI,KAAK,UAAU,YAAY,CACvB,GAAGA,EACH,SAAAO,CAChC,CAA6B,EACD,KAC5B,CACoB,OAAO,IAAI,QAAQ,CAACjI,EAASgK,IAAW,CACpC,KAAK,kBAAkB,IAAI/B,EAAU,CAACjI,EAASgK,CAAM,CAAC,CAC1D,CAAC,CACL,CAAC,CAEjB,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAQtC,GAAY,CAChB,KAAK,cAAc,YAAYA,CAAO,CAC1C,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,OAAQ,CAChC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOK,EAAKO,EAAQ4B,EAAS,MAAOC,IAAmB,CAC1D,MAAMzC,EAAU,MAAM,KAAK,YAAY,CACnC,KAAM,QACN,eAAAyC,EACA,IAAApC,EACA,OAAAO,EACA,OAAA4B,CACpB,CAAiB,EACKpK,EAAO,CACT,KAAM,GACN,QAAS,EAC7B,EACgB,OAAI4H,EAAQ,OAAS,SACjB5H,EAAK,KAAO4H,EAAQ,KAAK,CAAC,GAAG,MAAQ,GACrC5H,EAAK,QAAU4H,EAAQ,KAAK,CAAC,GAAG,SAAW,IAExC5H,CACX,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,YAAa,CACrC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOkE,GAAe,CACzB,MAAM0D,EAAU,MAAM,KAAK,YAAY,CACnC,KAAM,QACN,WAAA1D,CACpB,CAAiB,EACKlE,EAAO,IAAI,MAAMkE,EAAW,MAAM,EAAE,KAAK,CAC3C,KAAM,GACN,QAAS,EAC7B,CAAiB,EACD,OAAI0D,EAAQ,OAAS,QACjBA,EAAQ,KAAK,QAAQ,CAACjF,EAAQ2H,IAAgB,CAC1CtK,EAAKsK,CAAW,EAAI3H,CACxB,CAAC,EAEE3C,CACX,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,MAAO,CAC/B,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOuI,KAAkBC,IAAW,CACvC,MAAMvE,EAAYoF,GAAad,EAAeC,CAAM,EAC9C,CAAE,KAAAhE,EAAM,QAAAD,CAAO,EAAK,MAAM,KAAK,KAAKN,EAAU,IAAKA,EAAU,OAAQ,KAAK,EAEhF,OADsB0E,GAAqBnE,EAAMD,CAAO,CAE5D,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,QAAS,CACjC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOgG,GAAmB,CAC7B,MAAMrG,EAAaqG,EAAejC,EAAM,EAExC,OADa,MAAM,KAAK,UAAUpE,CAAU,GAChC,IAAI,CAAC,CAAE,KAAAM,EAAM,QAAAD,CAAO,IACNoE,GAAqBnE,EAAMD,CAAO,CAE3D,CACL,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,mBAAoB,CAC5C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,MAAM8F,EAAiBjD,GAAW,EAClC,MAAM,KAAK,YAAY,CACnB,KAAM,cACN,eAAAiD,EACA,OAAQ,OAC5B,CAAiB,EACD,MAAMG,EAAQ,MAAOC,GAAkB,CACnC,MAAMxG,EAAYiF,GAAmBuB,CAAa,EAClD,GAAIxG,EAAU,KACV,YAAK,yBAAyB,KAAKoG,CAAc,EAC1CpG,EAAU,KAAI,EAEzB,KAAM,CAAE,KAAAO,EAAM,QAAAD,CAAO,EAAK,MAAM,KAAK,KAAKN,EAAU,IAAKA,EAAU,OAAQ,MAAOoG,CAAc,EAEhG,OADsB1B,GAAqBnE,EAAMD,CAAO,CAE5D,EAoBA,MAAO,CACH,MAAAiG,EACA,IArBQ,MAAOjC,KAAkBC,IAAW,CAC5C,MAAMvE,EAAYoF,GAAad,EAAeC,CAAM,EAEpD,OADsB,MAAMgC,EAAMvG,CAAS,CAE/C,EAkBI,OAjBW,SAAY,CACvB,MAAM,KAAK,YAAY,CACnB,KAAM,cACN,eAAAoG,EACA,OAAQ,QAChC,CAAqB,CACL,EAYI,SAXa,SAAY,CACzB,MAAM,KAAK,YAAY,CACnB,KAAM,cACN,eAAAA,EACA,OAAQ,UAChC,CAAqB,CACL,CAMhB,CACY,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,cAAe,CACvC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOK,GACHnB,GAAa,YAAa,GAAO,KAAK,OAAQ,SAAY,CAC7D,IAAIpF,EACJ,KAAK,mBAAqB,GAC1B,GAAI,CACAA,EAAK,MAAM,KAAK,iBAAgB,EAChC,MAAMxB,EAAS,MAAM+H,EAAY,CAC7B,IAAKvG,EAAG,IACR,MAAOA,EAAG,KACtC,CAAyB,EACD,aAAMA,EAAG,OAAM,EACRxB,CACX,OACOgI,EAAK,CACR,YAAMxG,GAAI,SAAQ,EACZwG,CACV,QACpB,CACwB,KAAK,mBAAqB,EAC9B,CACJ,CAAC,CAEjB,CAAS,EACD,OAAO,eAAe,KAAM,gBAAiB,CACzC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAQF,GAAkB,CACtB,IAAIG,EAAQ,GACRC,EAAgB,GAChBC,EAAc,GACdC,EAAc,EAClB,MAAM9G,EAAYiF,GAAmBuB,CAAa,EAC5CO,EAAgB,IAAI,IACpBC,EAAe,IAAI,IACnBC,EAAe,IAAI,IACnBC,EAAe,SAAY,CAC7B,GAAI,CACA,MAAMC,EAAc,EAAEL,EACtB,GAAIC,EAAc,OAAS,EAAG,CAC1B,MAAMK,EAAa,MAAM,KAAK,IAAI,2DAA4DpH,EAAU,GAAG,EACrGqH,EAAa,IAAI,IACjBC,EAAgB,IAAI,IAQ1B,GAPAF,EAAW,QAAS/F,GAAU,CACtB,OAAOA,EAAM,MAAS,WAE1BA,EAAM,GACAiG,EAAc,IAAIjG,EAAM,IAAI,EAC5BgG,EAAW,IAAIhG,EAAM,IAAI,EACnC,CAAC,EACGgG,EAAW,OAAS,EACpB,MAAM,IAAI,MAAM,0CAA0C,EAE9D,GAAI,MAAM,KAAKC,CAAa,EAAE,KAAMjG,GAAUgG,EAAW,IAAIhG,CAAK,CAAC,EAC/D,MAAM,IAAI,MAAM,oIAAoI,EAExJgG,EAAW,QAASpD,GAAS8C,EAAc,IAAI9C,CAAI,CAAC,CACxD,CACA,MAAMzF,EAAUwB,EAAU,KACpB,MAAMA,EAAU,KAAI,EACpB,MAAM,KAAK,IAAIA,EAAU,IAAK,GAAGA,EAAU,MAAM,EACnDmH,IAAgBL,IAChBH,EAAQnI,EACRoI,EAAgB,GAChBI,EAAa,QAASO,GAAaA,EAASZ,CAAK,CAAC,EAE1D,OACOD,EAAK,CACRO,EAAa,QAASM,GAAa,CAC/BA,EAASb,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,CAAC,CAChE,CAAC,CACL,CACJ,EACMc,EAAY7D,GAAY,CACtBA,EAAQ,KAAK,OAAO,KAAMtC,GAAU0F,EAAc,IAAI1F,CAAK,CAAC,GAC5D6F,EAAY,CAEpB,EACA,MAAO,CACH,IAAI,OAAQ,CACR,OAAOP,CACX,EACA,UAAW,CAACc,EAAQC,IAAY,CAC5B,GAAI,CAAC,KAAK,eACN,MAAM,IAAI,MAAM,yGAAyG,EAE7H,OAAKA,IACDA,EAAWhB,GAAQ,CACf,MAAMA,CACV,GAEJM,EAAa,IAAIS,CAAM,EACvBR,EAAa,IAAIS,CAAO,EACnBb,EAKID,GACLa,EAAOd,CAAK,GALZ,KAAK,eAAe,iBAAiB,UAAWa,CAAQ,EACxDX,EAAc,GACdK,EAAY,GAKT,CACH,YAAa,IAAM,CACfF,EAAa,OAAOS,CAAM,EAC1BR,EAAa,OAAOS,CAAO,EACvBV,EAAa,OAAS,IAE1B,KAAK,gBAAgB,oBAAoB,UAAWQ,CAAQ,EAC5DX,EAAc,GAClB,CAC5B,CACoB,CACpB,CACY,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,yBAA0B,CAClD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOc,EAAUlG,IAAS,CAC7B,MAAM,KAAK,YAAY,CACnB,KAAM,WACN,aAAckG,EACd,aAAc,UAClC,CAAiB,EACD,KAAK,cAAc,IAAIA,EAAUlG,CAAI,CACzC,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,uBAAwB,CAChD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOkG,EAAUlG,IAAS,CAC7B,MAAMmG,EAAM,iBAAiBD,CAAQ,GAC/BE,EAAiB,IAAM,CACzB,KAAK,MAAMD,CAAG,EAAInG,CACtB,EACI,KAAK,QAAU,YACfoG,EAAc,EAElB,MAAM,KAAK,YAAY,CACnB,KAAM,WACN,aAAcF,EACd,aAAc,QAClC,CAAiB,EACG,KAAK,QAAU,YACfE,EAAc,CAEtB,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,0BAA2B,CACnD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOF,EAAUlG,IAAS,CAC7B,MAAMmG,EAAM,iBAAiBD,CAAQ,GAC/BE,EAAiB,IAAM,CACzB,KAAK,MAAM,GAAGD,CAAG,OAAO,EAAInG,EAAK,KACjC,KAAK,MAAM,GAAGmG,CAAG,QAAQ,EAAInG,EAAK,KACtC,EACI,KAAK,QAAU,YACfoG,EAAc,EAElB,MAAM,KAAK,YAAY,CACnB,KAAM,WACN,aAAcF,EACd,aAAc,WAClC,CAAiB,EACG,KAAK,QAAU,YACfE,EAAc,CAEtB,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,kBAAmB,CAC3C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,MAAMlE,EAAU,MAAM,KAAK,YAAY,CAAE,KAAM,UAAW,EAC1D,GAAIA,EAAQ,OAAS,OACjB,OAAOA,EAAQ,KAGf,MAAM,IAAI,MAAM,kDAAkD,CAE1E,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,kBAAmB,CAC3C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,MAAMA,EAAU,MAAM,KAAK,YAAY,CAAE,KAAM,SAAU,EACzD,GAAIA,EAAQ,OAAS,SACjB,OAAO,IAAI,KAAK,CAACA,EAAQ,MAAM,EAAGA,EAAQ,WAAY,CAClD,KAAM,uBAC9B,CAAqB,EAGD,MAAM,IAAI,MAAM,gCAAgC,CAExD,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,wBAAyB,CACjD,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOmE,EAAcC,IAAiB,CACzC,MAAMzC,GAAa,YAAa,GAAO,KAAK,OAAQ,SAAY,CAC5D,GAAI,CACA,KAAK,UAAU,CACX,KAAM,QACN,UAAW,KAAK,SAC5C,CAAyB,EACD,MAAM7E,EAAW,MAAMzB,GAAsB8I,EAAc,QAAQ,EACnE,MAAM,KAAK,YAAY,CACnB,KAAM,SACN,SAAArH,CAC5B,CAAyB,EACG,OAAOsH,GAAiB,aACxB,KAAK,mBAAqB,GAC1B,MAAMA,EAAY,GAEtB,KAAK,UAAU,CACX,KAAM,SACN,UAAW,KAAK,UAChB,OAAQ,WACpC,CAAyB,CACL,QACpB,CACwB,KAAK,mBAAqB,EAC9B,CACJ,CAAC,CACL,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,qBAAsB,CAC9C,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,MAAOA,GAAiB,CAC3B,MAAMzC,GAAa,YAAa,GAAO,KAAK,OAAQ,SAAY,CAC5D,GAAI,CACA,KAAK,UAAU,CACX,KAAM,QACN,UAAW,KAAK,SAC5C,CAAyB,EACD,MAAM,KAAK,YAAY,CACnB,KAAM,QAClC,CAAyB,EACG,OAAOyC,GAAiB,aACxB,KAAK,mBAAqB,GAC1B,MAAMA,EAAY,GAEtB,KAAK,UAAU,CACX,KAAM,SACN,UAAW,KAAK,UAChB,OAAQ,QACpC,CAAyB,CACL,QACpB,CACwB,KAAK,mBAAqB,EAC9B,CACJ,CAAC,CACL,CACZ,CAAS,EACD,OAAO,eAAe,KAAM,UAAW,CACnC,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,MAAM,KAAK,YAAY,CAAE,KAAM,SAAS,CAAE,EACtC,OAAO,WAAW,OAAW,KAC7B,KAAK,qBAAqB,SAC1B,KAAK,UAAU,oBAAoB,UAAW,KAAK,mBAAmB,EACtE,KAAK,UAAU,UAAS,GAE5B,KAAK,kBAAkB,MAAK,EAC5B,KAAK,cAAc,MAAK,EACxB,KAAK,cAAc,MAAK,EACxB,KAAK,gBAAgB,MAAK,EAC1B,KAAK,YAAc,EACvB,CACZ,CAAS,EACD,OAAO,eAAe,KAAMlC,GAAI,CAC5B,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,IAAM,CACT,KAAK,QAAO,CAChB,CACZ,CAAS,EACD,OAAO,eAAe,KAAMC,GAAI,CAC5B,WAAY,GACZ,aAAc,GACd,SAAU,GACV,MAAO,SAAY,CACf,MAAM,KAAK,QAAO,CACtB,CACZ,CAAS,EACD,MAAMkC,EAAe,OAAOpI,GAAW,SAAW,CAAE,aAAcA,CAAM,EAAKA,EACvE,CAAE,OAAAqI,EAAQ,UAAAC,EAAW,UAAAC,EAAW,GAAGC,CAAY,EAAKJ,EACpD,CAAE,aAAAnI,CAAY,EAAKuI,EACzB,KAAK,OAASJ,EACd,KAAK,UAAY7E,GAAW,EAC5B,MAAMO,EAAQN,GAAevD,EAAc,KAAK,SAAS,EAKzD,GAJA,KAAK,cAAgB,IAAI,iBAAiB,oBAAoB6D,CAAK,GAAG,EAClE0E,EAAa,WACb,KAAK,eAAiB,IAAI,iBAAiB,qBAAqB1E,CAAK,GAAG,GAExE,OAAOyE,EAAc,IACrB,KAAK,UAAYA,UAEZtI,IAAiB,SAAWA,IAAiB,iBAAkB,CACpE,MAAM2D,EAAS,IAAIkC,GAAkB,OAAO,EAC5C,KAAK,UAAY,IAAInC,GAAiBC,CAAM,CAChD,SACS3D,IAAiB,WACtBA,IAAiB,mBAAoB,CACrC,MAAM2D,EAAS,IAAIkC,GAAkB,SAAS,EAC9C,KAAK,UAAY,IAAInC,GAAiBC,CAAM,CAChD,SACS,OAAO,WAAW,OAAW,KAClC3D,IAAiB,WACjB,KAAK,UAAY,IAAI,OAAO,sDAAsC,CAC9D,KAAM,QACtB,CAAa,MAEA,CACD,MAAM2D,EAAS,IAAI9D,GACnB,KAAK,UAAY,IAAI6D,GAAiBC,CAAM,CAChD,CACI,KAAK,qBAAqBD,IAC1B,KAAK,UAAU,UAAaI,GAAY,KAAK,oBAAoBA,CAAO,EACxE,KAAK,MAAQ,aAGb,KAAK,UAAU,iBAAiB,UAAW,KAAK,mBAAmB,EACnE,KAAK,MAAQzG,GAAW,KAAK,SAAS,GAE1C,KAAK,UAAU,YAAY,CACvB,KAAM,SACN,OAAQ,CACJ,GAAGkL,EACH,UAAW,KAAK,UAChB,iBAAkBH,IAAS5D,EAAM,GAAK,EACtD,CACA,CAAS,CACL,CACJ,CACAwB,GAAK,OAAO,QAASC,GAAK,OAAO,aC/lBjC,MAAMuC,GAAgB,aAChBC,GAAoB,iBAGpBvH,GAAK,IAAIgF,GAAQsC,EAAa,EAG9B,CAAE,IAAArE,CAAG,EAAKjD,GAEhB,QAAQ,IAAI,2CAA4CsH,EAAa,EAMrE,MAAME,GAAU,IAAI,iBAAiBD,EAAiB,EAGtD,IAAIE,GAAU,GACVC,GACAC,GAEG,MAAMC,GAAU,IAAI,QAAQ,CAAC1M,EAASgK,IAAW,CACtDwC,GAAexM,EACfyM,GAAczC,CAChB,CAAC,EAGK2C,GAAkB,IAAI,IAOrB,SAASC,GAAiBnN,EAAU,CACzC,OAAAkN,GAAgB,IAAIlN,CAAQ,EACrB,IAAMkN,GAAgB,OAAOlN,CAAQ,CAC9C,CAGA6M,GAAQ,UAAa5M,GAAU,CAC7B,KAAM,CAAE,KAAA4C,EAAM,QAAAuK,CAAO,EAAKnN,EAAM,KAChC,GAAI4C,IAAS,YAEX,UAAW7C,KAAYkN,GACrB,GAAI,CACFlN,EAASoN,CAAO,CAClB,OAASC,EAAG,CACV,QAAQ,MAAM,oCAAqCA,CAAC,CACtD,CAGN,EAKA,SAASC,GAAgB3H,EAAOpD,EAAQpC,EAAK,KAAM,CACjD0M,GAAQ,YAAY,CAClB,KAAM,YACN,QAAS,CAAE,MAAAlH,EAAO,OAAApD,EAAQ,GAAApC,EAAI,UAAW,KAAK,IAAG,CAAE,CACvD,CAAG,EAGD,UAAWH,KAAYkN,GACrB,GAAI,CACFlN,EAAS,CAAE,MAAA2F,EAAO,OAAApD,EAAQ,GAAApC,EAAI,UAAW,KAAK,IAAG,EAAI,MAAO,GAAM,CACpE,OAASkN,EAAG,CACV,QAAQ,MAAM,oCAAqCA,CAAC,CACtD,CAEJ,CASO,eAAeE,IAAa,CACjC,GAAI,CACF,QAAQ,IAAI,mCAAmC,EAG/C,MAAMC,EAAa,MAAMlF,sCACzB,QAAQ,IAAI,6BAA8BkF,EAAW,CAAC,GAAG,OAAO,EAGhE,QAAQ,IAAI,wCAAwC,EACpD,MAAMlF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeN,MAAMmF,EAAuB,MAAMnF,0EACnC,QAAQ,IAAI,qCAAsCmF,EAAqB,OAAS,CAAC,EAGjF,QAAQ,IAAI,uCAAuC,EACnD,MAAMnF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYN,QAAQ,IAAI,0CAA0C,EACtD,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MASN,QAAQ,IAAI,8CAA8C,EAC1D,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAoBN,QAAQ,IAAI,sCAAsC,EAClD,GAAI,CACF,MAAMoF,EAAO,MAAMpF,8BACfoF,EAAK,OAAS,GAAK,CAACA,EAAK,KAAMC,GAAMA,EAAE,OAAS,KAAK,IACvD,QAAQ,IAAI,oFAAoF,EAChG,MAAMrF,sBAEV,OAAS+E,EAAG,CACV,QAAQ,KAAK,6CAA8CA,CAAC,CAC9D,CACA,MAAM/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiCN,QAAQ,IAAI,kDAAkD,EAC9D,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUN,QAAQ,IAAI,wCAAwC,EACpD,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAaN,QAAQ,IAAI,uCAAuC,EACnD,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeN,QAAQ,IAAI,yCAAyC,EACrD,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBN,QAAQ,IAAI,+CAA+C,EAC3D,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkCN,QAAQ,IAAI,+CAA+C,EAC3D,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAeN,QAAQ,IAAI,uDAAuD,EACnE,MAAMA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAcN,MAAMA,4EACN,MAAMA,wEACN,MAAMA,kFACN,MAAMA,4FACN,MAAMA,sFACN,MAAMA,wHAGN,MAAMsF,EAAY,MAAMtF,kFACxB,QAAQ,IAAI,yBAA0BsF,EAAU,IAAIC,GAAKA,EAAE,IAAI,CAAC,EAEhEf,GAAU,GACVC,GAAa,EAAI,EACjB,QAAQ,IAAI,iCAAiC,CAE/C,OAAShK,EAAO,CACd,cAAQ,MAAM,mCAAoCA,CAAK,EACvDiK,GAAYjK,CAAK,EACXA,CACR,CACF,CASO,eAAe+K,GAAYvF,EAAMwF,EAAWC,EAAUhI,EAAU,GAAI,CACzE,KAAM,CAAE,YAAAiI,EAAc,KAAM,SAAAC,EAAW,SAAS,EAAKlI,EAErD,QAAQ,IAAI,8BAA+BuC,EAAMwF,EAAWC,EAAUE,CAAQ,EAE9E,GAAI,CAEF,MAAMC,EAAa,MAAM7F,0EAGzB,GAFA,QAAQ,IAAI,wCAAyC6F,CAAU,EAE3DA,EAAW,SAAW,EACxB,cAAQ,MAAM,8CAA8C,EACtD,IAAI,MAAM,gCAAgC,EAIlD,QAAQ,IAAI,gCAAgC,EAC5C,MAAM7F;AAAA;AAAA,cAEIC,CAAI,KAAKwF,CAAS,KAAKC,CAAQ,KAAKC,CAAW,KAAKC,CAAQ;AAAA,IAEtE,QAAQ,IAAI,6BAA6B,EAIzC,MAAME,GADW,MAAM9F,qCACA,CAAC,GAAG,GAC3B,QAAQ,IAAI,qBAAsB8F,CAAK,EAGvC,MAAMC,EAAe,MAAM/F,uCAAyC8F,CAAK,GAGzE,GAFA,QAAQ,IAAI,4BAA6BC,CAAY,EAEjDA,EAAa,SAAW,EAC1B,cAAQ,MAAM,0DAA0D,EAClE,IAAI,MAAM,4BAA4B,EAI9C,aAAM/F;AAAA;AAAA,6BAEmB8F,CAAK;AAAA,MAIhCd,GAAgB,YAAa,SAAUc,CAAK,EAE1C,QAAQ,IAAI,+BAAgCA,CAAK,EAC5C,CAAE,GAAIA,CAAK,CAElB,OAASrL,EAAO,CACd,cAAQ,MAAM,uCAAwCA,CAAK,EACrDA,CACV,CACA,CAKO,eAAeuL,GAAatI,EAAU,GAAI,CAC/C,KAAM,CAAE,SAAAkI,EAAW,KAAM,MAAAK,EAAQ,GAAI,EAAKvI,EAE1C,GAAI,CAEF,MAAMmI,EAAa,MAAM7F,0EAGzB,GAFA,QAAQ,IAAI,0CAA2C6F,EAAW,OAAS,CAAC,EAExEA,EAAW,SAAW,EACxB,eAAQ,KAAK,+CAA+C,EACrD,GAGT,IAAIrL,EACN,OAAIoL,EACApL,EAAU,MAAMwF;AAAA;AAAA,yBAEG4F,CAAQ;AAAA;AAAA,cAEnBK,CAAK;AAAA,MAGbzL,EAAU,MAAMwF;AAAA;AAAA;AAAA,YAGViG,CAAK;AAAA,IAIb,QAAQ,IAAI,mCAAoCzL,EAAQ,OAAQ,MAAM,EAC/DA,CAET,OAASC,EAAO,CACd,eAAQ,MAAM,iCAAkCA,CAAK,EAC9C,EACT,CACF,CA8EO,eAAeyL,IAAmB,CACvC,GAAI,CAEJ,OADe,MAAMlG,4CACP,CAAC,GAAG,OAAS,CAC3B,OAASvF,EAAO,CACd,eAAQ,MAAM,qCAAsCA,CAAK,EAClD,CACX,CACA,CAmDO,eAAe0L,GAAevC,EAAK7L,EAAM,CAC9C,GAAI,CACF,MAAMqO,EAAO,KAAK,UAAUrO,CAAI,EAChC,MAAMiI;AAAA;AAAA,gBAEM4D,CAAG,KAAKwC,CAAI;AAAA,MAExB,QAAQ,IAAI,mCAAoCxC,CAAG,CACrD,OAASnJ,EAAO,CACd,cAAQ,MAAM,4CAA6CmJ,EAAKnJ,CAAK,EAC/DA,CACR,CACF,CAQO,eAAe4L,GAAczC,EAAK,CACvC,GAAI,CACF,MAAMrH,EAAO,MAAMyD,yDAA2D4D,CAAG,GACjF,GAAIrH,EAAK,SAAW,EAAG,OAAO,KAC9B,MAAM+J,EAAS,KAAK,MAAM/J,EAAK,CAAC,EAAE,IAAI,EACtC,eAAQ,IAAI,8CAA+CqH,EAAK,WAAYrH,EAAK,CAAC,EAAE,WAAa,GAAG,EAC7F+J,CACT,OAAS7L,EAAO,CACd,eAAQ,MAAM,kDAAmDmJ,EAAKnJ,CAAK,EACpE,IACT,CACF,CAYO,eAAe8L,GAAmBC,EAAO,CAC9C,GAAI,CACF,MAAMxG,+BACN,UAAWyG,KAAKD,EAAO,CACrB,MAAME,EAAQ,KAAK,UAAUD,CAAC,EAC9B,MAAMzG;AAAA;AAAA,kBAEMyG,EAAE,WAAaA,EAAE,EAAE,KAAKA,EAAE,aAAeA,EAAE,WAAa,EAAE,KAAKA,EAAE,SAAWA,EAAE,UAAY,EAAE,KAAKC,CAAK;AAAA,OAEpH,CACA,QAAQ,IAAI,qBAAsBF,EAAM,OAAQ,iBAAiB,CACnE,OAAS/L,EAAO,CACd,cAAQ,MAAM,+CAAgDA,CAAK,EAC7DA,CACR,CACF,CAMO,eAAekM,IAAyB,CAC7C,GAAI,CACF,MAAMpK,EAAO,MAAMyD,sDACnB,OAAIzD,EAAK,SAAW,EAAU,KACvBA,EAAK,IAAIqK,GAAK,KAAK,MAAMA,EAAE,UAAU,CAAC,CAC/C,OAASnM,EAAO,CACd,eAAQ,MAAM,qDAAsDA,CAAK,EAClE,IACT,CACF,CAgBO,eAAeoM,GAAYtK,EAAMuK,EAAY,CAClD,GAAI,CACF,MAAM9G,SACN,MAAMA,wBACN,IAAI+G,EAAQ,EACZ,UAAW,KAAKxK,EAAM,CACpB,MAAMyK,EAAM,EAAE,SAAW,EAAE,cAAgB,EAAE,MAAQ,GACrD,MAAMhH;AAAA;AAAA,kBAEMiH,EAAUH,CAAU,CAAC,KAAK,EAAE,YAAc,IAAI,KAAKE,CAAG;AAAA,QAElED,GACF,CACA,MAAM/G,UACN,QAAQ,IAAI,qBAAsB+G,EAAO,2BAA4BD,EAAY,GAAG,CACtF,OAASrM,EAAO,CACd,GAAI,CAAE,MAAMuF,WAAe,MAAQ,CAAsB,CACzD,cAAQ,MAAM,wCAAyCvF,CAAK,EACtDA,CACR,CACF,CAUO,eAAeyM,GAAgBJ,EAAY,CAChD,GAAI,CACF,MAAMvK,EAAO,MAAMyD;AAAA;AAAA;AAAA,2BAGIiH,EAAUH,CAAU,CAAC;AAAA;AAAA,MAG5C,OAAIvK,EAAK,SAAW,EAAU,KACvBA,CACT,OAAS9B,EAAO,CACd,eAAQ,MAAM,wCAAyCA,CAAK,EACrD,IACT,CACF,CAQA,SAAS0M,IAAS,CAChB,OAAI,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,WACzD,OAAO,WAAU,EAGnB,uCAAuC,QAAQ,QAAU9B,GAAM,CACpE,MAAMuB,EAAK,KAAK,OAAM,EAAK,GAAM,EACjC,OAAQvB,IAAM,IAAMuB,EAAKA,EAAI,EAAO,GAAK,SAAS,EAAE,CACtD,CAAC,CACH,CAWO,eAAeQ,GAAqBC,EAAM,CAC/C,KAAM,CAAE,SAAAC,EAAU,WAAAC,EAAa,QAAS,aAAAC,EAAe,CAAC,EAAKH,EACvDI,EAAiBN,GAAM,EAC7B,GAAI,CACF,MAAMnH;AAAA;AAAA;AAAA;AAAA,WAICsH,CAAQ,KAAKC,CAAU;AAAA,WACvBA,IAAe,QAAU,QAAU,UAAU;AAAA,WAC7CC,CAAY,KAAKC,CAAc;AAAA,MAGtC,MAAM5P,GADQ,MAAMmI,qCACH,CAAC,GAAG,GACrB,OAAAgF,GAAgB,mBAAoB,SAAUnN,CAAE,EACzC,CAAE,GAAAA,EAAI,iBAAkB4P,CAAc,CAC/C,OAAShN,EAAO,CACd,cAAQ,MAAM,iDAAkDA,CAAK,EAC/DA,CACR,CACF,CASO,eAAeiN,GAA0BC,EAAUC,EAAU,CAClE,GAAI,CAAC,MAAM,QAAQA,CAAQ,GAAKA,EAAS,SAAW,EAAG,MAAO,GAC9D,GAAI,CACF,MAAM5H,SACN,IAAI6H,EAAW,EACf,UAAWC,KAAKF,EAAU,CACxB,MAAMZ,EAAMc,EAAE,cAAgB,GAC9B,GAAI,CAACd,EAAK,SACV,MAAMe,EAAY,KAAK,UAAUD,EAAE,YAAc,EAAE,EAC7CE,EAAQF,EAAE,aAAeX,GAAM,EACrC,MAAMnH;AAAA;AAAA;AAAA;AAAA,aAIC2H,CAAQ,KAAKK,CAAK,KAAKhB,CAAG,KAAKe,CAAS;AAAA,QAE/CF,GACF,CACA,aAAM7H,UACNgF,GAAgB,2BAA4B,SAAU2C,CAAQ,EACvDE,CACT,OAASpN,EAAO,CACd,GAAI,CAAE,MAAMuF,WAAe,MAAQ,CAAsB,CACzD,cAAQ,MAAM,8CAA+CvF,CAAK,EAC5DA,CACR,CACF,CAQO,eAAewN,GAAqBN,EAAUO,EAAQ,GAAI,CAC/D,GAAI,CACF,MAAMC,EAAM,MAAMnI,8CAAgD2H,CAAQ,GAC1E,GAAIQ,EAAI,SAAW,EAAG,MAAM,IAAI,MAAM,UAAUR,CAAQ,YAAY,EACpE,MAAMlH,EAAM0H,EAAI,CAAC,EAEXZ,EAAcW,EAAM,YAAezH,EAAI,YACvC2H,EAAcF,EAAM,UAAY,OACjCA,EAAM,QAAU,KAAK,UAAUA,EAAM,OAAO,EAAI,KACjDzH,EAAI,aACF4H,EAAcH,EAAM,QAAezH,EAAI,OACvC6H,EAAcJ,EAAM,YAAezH,EAAI,YACvC8H,EAAiBL,EAAM,gBAAkBzH,EAAI,iBAEnD,MAAMT;AAAA;AAAA,wBAEcuH,CAAU;AAAA,yBACTa,CAAW;AAAA,mBACjBC,CAAM;AAAA,wBACDC,CAAU;AAAA,6BACLC,CAAc;AAAA,mBACxBZ,CAAQ;AAAA,MAEvB3C,GAAgB,mBAAoB,SAAU2C,CAAQ,CACxD,OAASlN,EAAO,CACd,cAAQ,MAAM,iDAAkDA,CAAK,EAC/DA,CACR,CACF,CAGO,eAAe+N,GAAkBb,EAAU,CAChD,GAAI,CACF,MAAMpL,EAAO,MAAMyD,8CAAgD2H,CAAQ,GAC3E,GAAIpL,EAAK,SAAW,EAAG,OAAO,KAC9B,MAAMkE,EAAMlE,EAAK,CAAC,EAClB,MAAO,CAAE,GAAGkE,EAAK,QAASA,EAAI,aAAe,KAAK,MAAMA,EAAI,YAAY,EAAI,IAAI,CAClF,OAAShG,EAAO,CACd,eAAQ,MAAM,+CAAgDA,CAAK,EAC5D,IACT,CACF,CAaO,eAAegO,GAA0Bd,EAAU,CACxD,GAAI,CAQF,OAPa,MAAM3H;AAAA;AAAA;AAAA;AAAA,0BAIG2H,CAAQ;AAAA;AAAA,OAGlB,IAAKf,IAAO,CACtB,GAAGA,EACH,WAAYA,EAAE,gBAAkB,KAAK,MAAMA,EAAE,eAAe,EAAI,EACtE,EAAM,CACJ,OAASnM,EAAO,CACd,eAAQ,MAAM,+CAAgDA,CAAK,EAC5D,EACT,CACF,CAWO,eAAeiO,GAA+Bf,EAAUgB,EAAO,CACpE,GAAI,CACF,MAAMpM,EAAO,MAAMyD;AAAA;AAAA;AAAA,0BAGG2H,CAAQ;AAAA,MAE9B,GAAIpL,EAAK,SAAW,EAAG,MAAO,GAE9B,MAAMyD,SACN,IAAI4I,EAAI,EACR,UAAWhC,KAAKrK,EAAM,CACpB,MAAMsM,EAASjC,EAAE,gBAAkB,KAAK,MAAMA,EAAE,eAAe,EAAI,GAC7DkC,EAASH,EAAME,CAAM,GAAK,GAChC,MAAM7I;AAAA;AAAA,gCAEoB,KAAK,UAAU8I,CAAK,CAAC;AAAA,qBAChClC,EAAE,EAAE;AAAA,QAEnBgC,GACF,CACA,aAAM5I,UACNgF,GAAgB,2BAA4B,SAAU2C,CAAQ,EACvDiB,CACT,OAASnO,EAAO,CACd,GAAI,CAAE,MAAMuF,WAAe,MAAQ,CAAQ,CAC3C,cAAQ,MAAM,gDAAiDvF,CAAK,EAC9DA,CACR,CACF,CAkBA,SAASwM,EAAU8B,EAAG,CACpB,GAAIA,IAAM,IAAMA,IAAM,MAAQA,IAAM,OAAW,OAAO,KACtD,MAAMH,EAAI,OAAOG,CAAC,EAClB,OAAO,OAAO,MAAMH,CAAC,EAAI,KAAOA,CAClC,CASO,eAAeI,GAAYC,EAAS,CACzC,GAAI,CAGF,MAAMjJ,SACN,MAAMA,uBACN,IAAI+G,EAAQ,EACZ,UAAWmC,KAAKD,EAAS,CACvB,MAAMpR,EAAKqR,EAAE,IAAMA,EAAE,UAAYA,EAAE,WAAa,KAChD,GAAIrR,GAAM,KAAM,SAIhB,MAAMmP,EAAMkC,EAAE,UAAYA,EAAE,cAAgBA,EAAE,SAAWA,EAAE,MACrD,OAAOA,EAAE,MAAS,SAAWA,EAAE,KAAO,IAC5C,MAAMlJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAOAnI,CAAE,KAAKqR,EAAE,KAAO,IAAI,KAAKjC,EAAUiC,EAAE,KAAK,CAAC,KAAKA,EAAE,SAAW,IAAI;AAAA,YACjEA,EAAE,WAAa,IAAI,KAAKA,EAAE,WAAa,IAAI,KAAKA,EAAE,QAAU,IAAI;AAAA,YAChEA,EAAE,OAAS,IAAI,KAAKA,EAAE,WAAa,IAAI,KAAKA,EAAE,SAAW,IAAI;AAAA,YAC7DA,EAAE,SAAW,IAAI,KAAKA,EAAE,UAAY,IAAI,KAAKA,EAAE,UAAY,IAAI;AAAA,YAC/DjC,EAAUiC,EAAE,UAAU,CAAC,KAAKjC,EAAUiC,EAAE,UAAU,CAAC,KAAKA,EAAE,UAAY,IAAI;AAAA,YAC1EA,EAAE,SAAW,IAAI,KAAKA,EAAE,UAAY,IAAI,KAAKA,EAAE,MAAQ,IAAI;AAAA,YAC3DA,EAAE,aAAe,IAAI,KAAKA,EAAE,SAAW,IAAI,KAAKlC,CAAG;AAAA,YACnDkC,EAAE,YAAc,IAAI,KAAKA,EAAE,YAAc,IAAI,KAAKjC,EAAUiC,EAAE,UAAU,CAAC;AAAA;AAAA;AAAA,QAI/EnC,GACF,CACA,MAAM/G,UACN,QAAQ,IAAI,qBAAsB+G,EAAO,gBAAiBkC,EAAQ,OAAQ,QAASA,EAAQ,OAASlC,EAAO,mBAAmB,CAChI,OAAStM,EAAO,CACd,GAAI,CAAE,MAAMuF,WAAe,MAAQ,CAAsB,CACzD,cAAQ,MAAM,uCAAwCvF,CAAK,EACrDA,CACR,CACF,CAOO,eAAe0O,IAAkB,CACtC,GAAI,CACF,MAAM5M,EAAO,MAAMyD,qCACnB,OAAIzD,EAAK,SAAW,EAAU,KACvBA,CACT,OAAS9B,EAAO,CACd,eAAQ,MAAM,6CAA8CA,CAAK,EAC1D,IACT,CACF,CASO,eAAe2O,GAAaC,EAAUH,EAAG,CAC9C,GAAI,CACF,MAAMlJ;AAAA;AAAA,gBAEMkJ,EAAE,KAAO,IAAI;AAAA,kBACXjC,EAAUiC,EAAE,KAAK,CAAC;AAAA,oBAChBA,EAAE,SAAW,IAAI;AAAA,sBACfA,EAAE,WAAa,IAAI;AAAA,sBACnBA,EAAE,WAAa,IAAI;AAAA,mBACtBA,EAAE,QAAU,IAAI;AAAA,kBACjBA,EAAE,OAAS,IAAI;AAAA,sBACXA,EAAE,WAAa,IAAI;AAAA,oBACrBA,EAAE,SAAW,IAAI;AAAA,oBACjBA,EAAE,SAAW,IAAI;AAAA,qBAChBA,EAAE,UAAY,IAAI;AAAA,qBAClBA,EAAE,UAAY,IAAI;AAAA,uBAChBjC,EAAUiC,EAAE,UAAU,CAAC;AAAA,uBACvBjC,EAAUiC,EAAE,UAAU,CAAC;AAAA,qBACzBA,EAAE,UAAY,IAAI;AAAA,oBACnBA,EAAE,SAAW,IAAI;AAAA,qBAChBA,EAAE,UAAY,IAAI;AAAA,iBACtBA,EAAE,MAAQ,IAAI;AAAA,wBACPA,EAAE,aAAe,IAAI;AAAA,oBACzBA,EAAE,SAAW,IAAI;AAAA,uBACdjC,EAAUiC,EAAE,UAAU,CAAC;AAAA;AAAA,mBAE3BG,CAAQ;AAAA,MAEvB,QAAQ,IAAI,+BAAgCA,CAAQ,EACpDrE,GAAgB,UAAW,SAAUqE,CAAQ,CAC/C,OAAS5O,EAAO,CACd,cAAQ,MAAM,wCAAyC4O,EAAU5O,CAAK,EAChEA,CACR,CACF,CAUO,eAAe6O,GAAgBC,EAAaL,EAAI,GAAI,CACzD,GAAI,CACF,MAAMlJ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAOMkJ,EAAE,KAAO,IAAI,KAAKjC,EAAUiC,EAAE,KAAK,CAAC,KAAKA,EAAE,SAAW,IAAI;AAAA,UAChEA,EAAE,WAAa,IAAI,KAAKA,EAAE,WAAa,IAAI,KAAKA,EAAE,QAAU,IAAI;AAAA,UAChEA,EAAE,OAAS,IAAI,KAAKA,EAAE,WAAa,IAAI,KAAKA,EAAE,SAAW,IAAI;AAAA,UAC7DA,EAAE,SAAW,IAAI,KAAKA,EAAE,UAAY,IAAI,KAAKA,EAAE,UAAY,IAAI;AAAA,UAC/DjC,EAAUiC,EAAE,UAAU,CAAC,KAAKjC,EAAUiC,EAAE,UAAU,CAAC,KAAKA,EAAE,UAAY,IAAI;AAAA,UAC1EA,EAAE,SAAW,IAAI,KAAKA,EAAE,UAAY,IAAI,KAAKA,EAAE,MAAQ,IAAI;AAAA,UAC3DA,EAAE,aAAe,IAAI,KAAKA,EAAE,SAAW,IAAI,KAAKK,CAAW;AAAA,gDACrBtC,EAAUiC,EAAE,UAAU,CAAC;AAAA;AAAA;AAAA,MAKnE,MAAMpD,GADW,MAAM9F,qCACA,CAAC,GAAG,GAC3B,eAAQ,IAAI,oCAAqC8F,EAAO,eAAe,EACvEd,GAAgB,UAAW,SAAUc,CAAK,EACnC,CAAE,GAAIA,CAAK,CACpB,OAASrL,EAAO,CACd,cAAQ,MAAM,4CAA6CA,CAAK,EAC1DA,CACR,CACF,CAYO,eAAe+O,GAAuBC,EAAY,CACvD,GAAI,CAEF,GAAIA,EAAW,OAAS,EAAG,CACzB,MAAMC,EAAQD,EAAW,CAAC,EACpBE,EAAQ,GACd,SAAW,CAACC,EAAGb,CAAC,IAAK,OAAO,QAAQW,CAAK,EACvCC,EAAMC,CAAC,EAAIb,IAAM,KAAO,OAAS,OAAOA,EAE1C,QAAQ,IAAI,0CAA2CY,CAAK,CAC9D,CAEA,MAAM3J,mCACN,UAAW8H,KAAK2B,EAAY,CAC1B,MAAM/C,EAAQ,KAAK,UAAUoB,CAAC,EAI9B,IAAI+B,EAAS/B,EAAE,SAAWA,EAAE,UAAYA,EAAE,MAAQA,EAAE,KAAOA,EAAE,WAAa,GAC1E,MAAMd,EAAM,OAAO6C,GAAW,SAAW,KAAK,UAAUA,CAAM,EAAI,OAAOA,CAAM,EAG/E,IAAIC,EAAQhC,EAAE,IAAMA,EAAE,cAAgBA,EAAE,aAAe,KAGvD,MAAM9H;AAAA;AAAA,kBAFM8J,IAAU,MAAQ,OAAOA,GAAU,SAAY,KAAOA,CAIpD,KAAK9C,CAAG,KAAKN,CAAK;AAAA,OAElC,CACA,QAAQ,IAAI,qBAAsB+C,EAAW,OAAQ,qBAAqB,CAC5E,OAAShP,EAAO,CACd,cAAQ,MAAM,mDAAoDA,CAAK,EACjEA,CACR,CACF,CAMO,eAAesP,IAA6B,CACjD,GAAI,CACF,MAAMxN,EAAO,MAAMyD,0DACnB,OAAIzD,EAAK,SAAW,EAAU,KACvBA,EAAK,IAAIqK,GAAK,KAAK,MAAMA,EAAE,UAAU,CAAC,CAC/C,OAASnM,EAAO,CACd,eAAQ,MAAM,yDAA0DA,CAAK,EACtE,IACT,CACF,CAQO,eAAeuP,GAAaC,EAAO,CACxC,GAAI,CACF,GAAIA,EAAM,OAAS,EAAG,CACpB,MAAMP,EAAQO,EAAM,CAAC,EACfN,EAAQ,GACd,SAAW,CAACC,EAAGb,CAAC,IAAK,OAAO,QAAQW,CAAK,EACvCC,EAAMC,CAAC,EAAIb,IAAM,KAAO,OAAS,OAAOA,EAE1C,QAAQ,IAAI,qCAAsCY,CAAK,CACzD,CAEA,MAAM3J,yBACN,UAAW4G,KAAKqD,EAAO,CACrB,MAAMvD,EAAQ,KAAK,UAAUE,CAAC,EAG9B,IAAIiD,EAASjD,EAAE,MAAQA,EAAE,UAAYA,EAAE,KAAOA,EAAE,MAAQA,EAAE,MAAQ,GAClE,MAAMI,EAAM,OAAO6C,GAAW,SAAW,KAAK,UAAUA,CAAM,EAAI,OAAOA,CAAM,EAG/E,IAAIC,EAAQlD,EAAE,QAAUA,EAAE,OAASA,EAAE,IAAM,KAG3C,MAAM5G;AAAA;AAAA,kBAFS8J,IAAU,MAAQ,OAAOA,GAAU,SAAY,KAAOA,CAIpD,KAAK9C,CAAG,KAAKN,CAAK;AAAA,OAErC,CACA,QAAQ,IAAI,qBAAsBuD,EAAM,OAAQ,WAAW,CAC7D,OAASxP,EAAO,CACd,cAAQ,MAAM,yCAA0CA,CAAK,EACvDA,CACR,CACF,CAMO,eAAeyP,IAAmB,CACvC,GAAI,CACF,MAAM3N,EAAO,MAAMyD,oDACnB,OAAIzD,EAAK,SAAW,EAAU,KACvBA,EAAK,IAAIqK,GAAK,KAAK,MAAMA,EAAE,UAAU,CAAC,CAC/C,OAASnM,EAAO,CACd,eAAQ,MAAM,+CAAgDA,CAAK,EAC5D,IACT,CACF,CASO,eAAe0P,IAAiB,CACrC,OAAOpN,GAAG,gBAAe,CAC3B,CAaO,eAAeqN,GAAiB9C,EAAW,wBAAyB,CACzE,MAAMvP,EAAO,MAAMoS,GAAc,EAC3BE,EAAO,IAAI,KAAK,CAACtS,CAAI,EAAG,CAAE,KAAM,wBAAyB,EACzDuS,EAAM,IAAI,gBAAgBD,CAAI,EAE9BE,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAWjD,EACbiD,EAAE,MAAK,EAEP,IAAI,gBAAgBD,CAAG,CACzB,CAGO,eAAeE,IAAkB,CAGtC,MAAO,CACL,KAAM,oBACN,UAJgB,MAAMxE,GAAY,GAId,IAAKyE,IAAS,CAChC,KAAM,UACN,WAAY,CACV,GAAIA,EAAI,GACR,KAAMA,EAAI,KACV,SAAUA,EAAI,SACd,MAAOA,EAAI,MACX,WAAYA,EAAI,UACxB,EACM,SAAU,CACR,KAAM,QACN,YAAa,CAACA,EAAI,IAAKA,EAAI,GAAG,CACtC,CACA,EAAM,CACN,CACA,CASO,eAAeC,IAAoB,CACxC,GAAI,CACJ,MAAMC,EAAS,MAAM3K;AAAA;AAAA;AAAA;AAAA,IAMf4K,EAAgB,MAAM1E,GAAgB,EAE5C,MAAO,CACL,MAAO1B,GACP,aAAcH,GACd,OAAQsG,EAAO,IAAI,GAAK,EAAE,IAAI,EAC9B,cAAAC,CACJ,CACE,OAASnQ,EAAO,CACd,MAAO,CACL,MAAO,GACP,MAAOA,EAAM,OACnB,CACA,CACA,CAgBO,MAAMoQ,GAAsB,OAAO,OAAO,CAC/C,UACA,sBACA,YACA,kBACA,WACA,aACF,CAAC,EAOM,SAASC,GAAmBC,EAAW,CAC5C,OAAOF,GAAoB,SAASE,CAAS,CAC/C,CASO,eAAeC,GAAWD,EAAW,CAC1C,GAAI,CAACD,GAAmBC,CAAS,EAC/B,MAAM,IAAI,MAAM,sBAAsBA,CAAS,oCAAoC,EAIrF,MAAME,GADS,MAAMjL,EAAI,8BAA8B+K,CAAS,GAAG,GAC9C,CAAC,GAAG,GAAK,EAE9B,aAAM/K,EAAI,gBAAgB+K,CAAS,GAAG,EACtC,QAAQ,IAAI,yBAAyBA,CAAS,MAAME,CAAK,QAAQ,EACjEjG,GAAgB+F,EAAW,QAAS,IAAI,EACjCE,CACT,CAQO,eAAeC,IAAuB,CAC3C,MAAMC,EAAW,MAAMnL;AAAA;AAAA;AAAA;AAAA;AAAA,IAMjBoL,EAAgB,IAAI,IAAID,EAAS,IAAKvE,GAAMA,EAAE,IAAI,CAAC,EAEnDpM,EAAU,GAChB,UAAWuQ,KAAaF,GACtB,GAAKO,EAAc,IAAIL,CAAS,EAChC,GAAI,CACF,MAAME,EAAQ,MAAMD,GAAWD,CAAS,EACxCvQ,EAAQ,KAAK,CAAE,MAAOuQ,EAAW,MAAAE,CAAK,CAAE,CAC1C,OAASvI,EAAK,CACZ,QAAQ,MAAM,8BAA8BqI,CAAS,IAAKrI,CAAG,EAC7DlI,EAAQ,KAAK,CAAE,MAAOuQ,EAAW,MAAO,EAAG,MAAOrI,EAAI,QAAS,CACjE,CAGF,MAAM2I,EAAQ7Q,EAAQ,OAAO,CAAC8Q,EAAG1E,IAAM0E,EAAI1E,EAAE,MAAO,CAAC,EACrD,eAAQ,IAAI,2CAA2CyE,CAAK,gBAAgB7Q,EAAQ,MAAM,SAAS,EAC5FA,CACT,CAMO,eAAe+Q,IAAgB,CACpC,MAAMZ,EAAS,MAAM3K;AAAA;AAAA;AAAA;AAAA,IAMrB,GAAI2K,EAAO,SAAW,EAAG,MAAO,GAIhC,MAAMpI,EAAQoI,EACX,IAAI,GAAK,WAAW,EAAE,IAAI,sCAAsC,EAAE,IAAI,GAAG,EACzE,KAAK,aAAa,EAErB,OAAO3K,EAAIuC,CAAK,CAClB,CASO,eAAeiJ,GAAgBT,EAAW9E,EAAQ,IAAK,CAM5D,IAJc,MAAMjG;AAAA;AAAA,oCAEc+K,CAAS;AAAA,KAEjC,SAAW,EACnB,MAAM,IAAI,MAAM,UAAUA,CAAS,kBAAkB,EAGvD,MAAMxO,EAAO,MAAMyD,EAAI,kBAAkB+K,CAAS,WAAW9E,CAAK,EAAE,EAKpE,MAAO,CAAE,QAFO1J,EAAK,OAAS,EAAI,OAAO,KAAKA,EAAK,CAAC,CAAC,EAAI,GAEvC,KAAAA,CAAI,CACxB,CAGO,eAAekP,IAAe,CACnC,QAAQ,IAAI,uBAAuB,EAEnC,GAAI,CAEF,MAAMC,EAAU,MAAM1L,gCACtB,QAAQ,IAAI,qBAAsB0L,EAAQ,CAAC,EAAE,CAAC,EAG9C,MAAMf,EAAS,MAAM3K,qDACrB,QAAQ,IAAI,aAAc2K,EAAO,IAAIpF,GAAKA,EAAE,IAAI,CAAC,EAGjD,QAAQ,IAAI,0BAA0B,EACtC,MAAMvF,kGAGN,MAAMzD,EAAO,MAAMyD,+CACnB,QAAQ,IAAI,eAAgBzD,CAAI,EAGhC,MAAM0O,EAAQ,MAAMjL,uCACpB,eAAQ,IAAI,iBAAkBiL,EAAM,CAAC,EAAE,CAAC,EAGxC,MAAMjL,6CACN,QAAQ,IAAI,qBAAqB,EAEjC,QAAQ,IAAI,qBAAqB,EAC1B,EACT,OAASvF,EAAO,CACd,eAAQ,MAAM,sBAAuBA,CAAK,EACnC,EACX,CACA,CAGI,OAAO,OAAW,MACpB,OAAO,aAAegR,GACtB,OAAO,SAAWf,IAuBb,eAAeiB,GAAeC,EAAM,CACzC,KAAM,CAAE,KAAAC,EAAM,KAAA5L,EAAO,KAAM,UAAA6L,EAAW,WAAAhF,EAAa,IAAI,EAAK8E,EAC5D,MAAM5L;AAAA;AAAA,cAEM6L,CAAI,KAAK5L,CAAI,KAAK6G,CAAU,KAAKgF,CAAS;AAAA,IAGtD,MAAMjU,GADW,MAAMmI,qCACH,CAAC,GAAG,GACxB,OAAAgF,GAAgB,aAAc,SAAUnN,CAAE,EACnCA,CACT,CAOO,eAAekU,GAAiBC,EAASC,EAAO,CACrD,KAAM,CACJ,IAAAC,EAAK,IAAAC,EAAK,IAAAC,EACV,SAAAC,EAAW,KAAM,SAAAC,EAAW,KAAM,iBAAAC,EAAmB,KACrD,QAAAC,EAAU,KAAM,MAAAC,EAAQ,KAAM,WAAAC,EAAa,KAAM,UAAAC,CACrD,EAAMV,EACEW,EAAa,OAAOD,GAAc,SAAW,IAAI,KAAKA,CAAS,EAAE,YAAW,EAAMA,GAAa,IAAI,KAAI,EAAG,YAAW,EAC3H,MAAM3M;AAAA;AAAA;AAAA;AAAA,SAICgM,CAAO,KAAKE,CAAG,KAAKC,CAAG,KAAKC,CAAG,KAAKC,CAAQ,KAAKC,CAAQ,KAAKC,CAAgB,KAAKC,CAAO,KAAKC,CAAK,KAAKC,CAAU,KAAKE,CAAU;AAAA,GAE3I,CAOO,eAAeC,GAAeb,EAASc,EAAS,CACrD,KAAM,CAAE,QAAAC,EAAS,WAAAC,EAAa,EAAG,UAAAC,EAAY,CAAC,EAAKH,EACnD,MAAM9M;AAAA;AAAA,wBAEgB+M,CAAO,mBAAmBC,CAAU,kBAAkBC,CAAS;AAAA,kBACrEjB,CAAO;AAAA,IAEvBhH,GAAgB,aAAc,SAAUgH,CAAO,CACjD,CAMO,eAAekB,IAAuB,CAC3C,OAAOlN,6FACT,CAOO,eAAemN,GAAkBnB,EAAS,CAC/C,OAAOhM,oDAAsDgM,CAAO,mBACtE,CAOO,eAAeoB,GAAmBpB,EAASqB,EAAW,KAAM,CACjE,MAAMrN,kDAAoDqN,CAAQ,eAAerB,CAAO,GACxFhH,GAAgB,aAAc,SAAUgH,CAAO,CACjD,CCviDA,MAAMsB,GAAY,QACZC,GAAY,UACZC,GAAc,QACdC,GAAc,UACdC,GAAc,SAKb,SAASC,IAAY,CAC1B,OAAO,aAAa,QAAQ,oBAAoB,GAAK,QACvD,CASO,SAASC,GAAaC,EAAQ,CACnC,GAAIF,GAAS,IAAO,WAAY,CAC9B,MAAMG,EAAKD,EAASP,GACpB,OAAIQ,GAAM,KACA,KAAK,MAAMD,EAASN,GAAU,GAAG,EAAI,IAAO,MAE/C,KAAK,MAAMO,CAAE,EAAI,KAC1B,CAEA,OAAID,EAAS,IACH,KAAK,MAAMA,EAAS,IAAO,GAAG,EAAI,IAAO,MAE3C,KAAK,MAAMA,EAAS,GAAG,EAAI,IAAO,IAC5C,CAOO,SAASE,GAAiBF,EAAQ,CACvC,GAAIF,GAAS,IAAO,WAAY,CAC9B,MAAMG,EAAKD,EAASP,GACdU,EAAKH,EAASN,GACpB,OAAIO,GAAM,KACD,GAAGE,EAAG,QAAQ,CAAC,CAAC,SAASF,EAAG,eAAe,KAAM,CAAE,sBAAuB,CAAC,CAAE,CAAC,OAEhF,GAAGA,EAAG,eAAe,KAAM,CAAE,sBAAuB,EAAG,CAAC,KACjE,CACA,OAAID,GAAU,IACL,IAAIA,EAAS,KAAM,QAAQ,CAAC,CAAC,SAASA,EAAO,eAAe,KAAM,CAAE,sBAAuB,CAAC,CAAE,CAAC,MAEjG,GAAGA,EAAO,eAAe,KAAM,CAAE,sBAAuB,EAAG,CAAC,IACrE,CASO,SAASI,GAAWC,EAAU,CACnC,GAAIP,GAAS,IAAO,WAAY,CAC9B,MAAMQ,EAAQD,EAAWT,GACzB,OAAIU,GAAS,IACH,KAAK,MAAMD,EAAWR,GAAc,GAAG,EAAI,IAAO,OAExDS,GAAS,EACH,KAAK,MAAMA,EAAQ,GAAG,EAAI,IAAO,SAEpC,KAAK,MAAMD,EAAWV,EAAW,EAAE,eAAe,IAAI,EAAI,MACnE,CAEA,OAAIU,EAAW,IACL,KAAK,MAAMA,EAAW,IAAU,GAAG,EAAI,IAAO,OAEhD,KAAK,MAAMA,EAAW,GAAG,EAAI,IAAO,KAC9C,CAOO,SAASE,GAAeF,EAAU,CACvC,GAAIP,GAAS,IAAO,WAAY,CAC9B,MAAMU,EAAOH,EAAWV,GAClBW,EAAQD,EAAWT,GACnBa,EAAOJ,EAAWR,GACxB,OAAIS,GAAS,IACJ,GAAGG,EAAK,QAAQ,CAAC,CAAC,UAAUH,EAAM,eAAe,KAAM,CAAE,sBAAuB,CAAC,CAAE,CAAC,UAEzFA,GAAS,EACJ,GAAGA,EAAM,eAAe,KAAM,CAAE,sBAAuB,EAAG,CAAC,YAAYE,EAAK,eAAe,KAAM,CAAE,sBAAuB,CAAC,CAAE,CAAC,QAEhI,GAAGA,EAAK,eAAe,KAAM,CAAE,sBAAuB,EAAG,CAAC,MACnE,CACA,OAAIH,EAAW,IACN,IAAIA,EAAW,KAAS,QAAQ,CAAC,CAAC,UAAUA,EAAS,eAAe,KAAM,CAAE,sBAAuB,CAAC,CAAE,CAAC,OAEzG,GAAGA,EAAS,eAAe,KAAM,CAAE,sBAAuB,EAAG,CAAC,KACvE,CAOO,SAASK,GAAmBC,EAAc,CAC/C,OAAOP,GAAW,KAAK,GAAKO,EAAeA,CAAY,CACzD,CCvGA,SAASC,GAAoBC,EAAIC,EAAIC,EAAIC,EAAIC,EAAM,MAAO,CACxD,MAAMC,EAAMJ,EAAG,CAAC,EAAID,EAAG,CAAC,EAClBM,EAAML,EAAG,CAAC,EAAID,EAAG,CAAC,EAClBO,EAAMJ,EAAG,CAAC,EAAID,EAAG,CAAC,EAClBM,EAAML,EAAG,CAAC,EAAID,EAAG,CAAC,EAElBO,EAAQJ,EAAMG,EAAMF,EAAMC,EAChC,GAAI,KAAK,IAAIE,CAAK,EAAIL,EAAK,OAAO,KAElC,MAAMM,EAAMR,EAAG,CAAC,EAAIF,EAAG,CAAC,EAClBW,EAAMT,EAAG,CAAC,EAAIF,EAAG,CAAC,EAElBnJ,GAAK6J,EAAMF,EAAMG,EAAMJ,GAAOE,EAC9BG,GAAKF,EAAMJ,EAAMK,EAAMN,GAAOI,EAEpC,OAAI5J,EAAI,CAACuJ,GAAOvJ,EAAI,EAAIuJ,GAAOQ,EAAI,CAACR,GAAOQ,EAAI,EAAIR,EAAY,KAExD,CACL,MAAO,CAACJ,EAAG,CAAC,EAAInJ,EAAIwJ,EAAKL,EAAG,CAAC,EAAInJ,EAAIyJ,CAAG,EACxC,EAAG,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGzJ,CAAC,CAAC,EAC7B,EAAG,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG+J,CAAC,CAAC,CACjC,CACA,CAMA,SAASC,GAAWC,EAAM,CACxB,IAAIC,EAAO,EACX,QAAStX,EAAI,EAAGyQ,EAAI4G,EAAK,OAAQrX,EAAIyQ,EAAI,EAAGzQ,IAC1CsX,GAASD,EAAKrX,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAMqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,CAAC,EAAE,CAAC,EAErE,OAAOsX,EAAO,CAChB,CAKA,SAASC,GAAYC,EAAIH,EAAM,CAC7B,IAAII,EAAS,GACb,QAASzX,EAAI,EAAG0X,EAAIL,EAAK,OAAS,EAAGrX,EAAIqX,EAAK,OAAS,EAAGK,EAAI1X,IAAK,CACjE,MAAM2X,EAAKN,EAAKrX,CAAC,EAAE,CAAC,EAAG4X,EAAKP,EAAKrX,CAAC,EAAE,CAAC,EAC/B6X,EAAKR,EAAKK,CAAC,EAAE,CAAC,EAAGI,EAAKT,EAAKK,CAAC,EAAE,CAAC,EAC/BE,EAAKJ,EAAG,CAAC,GAAQM,EAAKN,EAAG,CAAC,GAC3BA,EAAG,CAAC,GAAKK,EAAKF,IAAOH,EAAG,CAAC,EAAII,IAAOE,EAAKF,GAAMD,IAClDF,EAAS,CAACA,EAEd,CACA,OAAOA,CACT,CAKA,SAASM,GAAM3F,EAAG4F,EAAG,CACnB,OAAQ5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,GAAK5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,CAC/C,CASA,SAASC,GAAkBZ,EAAMa,EAAM,CACrC,MAAMC,EAAO,GAGb,QAASC,EAAK,EAAGA,EAAKF,EAAK,OAAS,EAAGE,IACrC,QAASC,EAAK,EAAGA,EAAKhB,EAAK,OAAS,EAAGgB,IAAM,CAC3C,MAAMC,EAAKhC,GAAoBe,EAAKgB,CAAE,EAAGhB,EAAKgB,EAAK,CAAC,EAAGH,EAAKE,CAAE,EAAGF,EAAKE,EAAK,CAAC,EAAG,KAAG,EAClF,GAAI,CAACE,EAAI,SAIT,MAAMd,EAAKc,EAAG,MAGd,IAAIC,EAAQ,GACZ,UAAWC,KAAKL,EACd,GAAIJ,GAAMS,EAAE,MAAOhB,CAAE,EAAI,KAAM,CAC7Be,EAAQ,GACR,KACF,CAEEA,GAEJJ,EAAK,KAAK,CACR,MAAOX,EACP,WAAYa,EACZ,MAAOC,EAAG,EACV,WAAYF,EACZ,MAAOE,EAAG,CAClB,CAAO,CACH,CAIF,OAAAH,EAAK,KAAK,CAAC/F,EAAG4F,IACR5F,EAAE,aAAe4F,EAAE,WAAmB5F,EAAE,WAAa4F,EAAE,WACpD5F,EAAE,MAAQ4F,EAAE,KACpB,EAEMG,CACT,CAWA,SAASM,GAAqBpB,EAAMc,EAAM,CAGxC,MAAMO,EAASP,EAAK,IAAI,CAACK,EAAG,KAAO,CAAE,GAAGA,EAAG,UAAW,CAAC,EAAG,EAC1DE,EAAO,KAAK,CAAC,EAAGV,IACV,EAAE,aAAeA,EAAE,WAAmB,EAAE,WAAaA,EAAE,WACpD,EAAE,MAAQA,EAAE,KACpB,EAED,MAAMW,EAAWtB,EAAK,QAChBuB,EAAU,IAAI,MAAMF,EAAO,MAAM,EAGvC,QAASjH,EAAIiH,EAAO,OAAS,EAAGjH,GAAK,EAAGA,IAAK,CAC3C,MAAM+G,EAAIE,EAAOjH,CAAC,EACZoH,EAAYL,EAAE,WAAa,EAG3BM,EAAW,KACjB,GAAIf,GAAMS,EAAE,MAAOG,EAASH,EAAE,UAAU,CAAC,EAAIM,EAAU,CACrDF,EAAQJ,EAAE,SAAS,EAAIA,EAAE,WACzB,QACF,CACA,GAAIT,GAAMS,EAAE,MAAOG,EAASH,EAAE,WAAa,CAAC,CAAC,EAAIM,EAAU,CACzDF,EAAQJ,EAAE,SAAS,EAAIA,EAAE,WAAa,EACtC,QACF,CAGAG,EAAS,OAAOE,EAAW,EAAGL,EAAE,KAAK,EACrCI,EAAQJ,EAAE,SAAS,EAAIK,EAIvB,QAASnB,EAAIjG,EAAI,EAAGiG,EAAIgB,EAAO,OAAQhB,IACjCkB,EAAQF,EAAOhB,CAAC,EAAE,SAAS,GAAKmB,GAClCD,EAAQF,EAAOhB,CAAC,EAAE,SAAS,GAGjC,CAEA,MAAO,CAAE,KAAMiB,EAAU,QAAAC,CAAO,CAClC,CAWA,SAASG,GAAU1B,EAAM2B,EAAIC,EAAI,CAC/B,MAAMxI,EAAI4G,EAAK,OAAS,EAElB6B,GAAUF,EAAKvI,EAAKA,GAAKA,EACzB0I,GAAQF,EAAKxI,EAAKA,GAAKA,EACvBlO,EAAS,GACf,IAAI6W,EAAMF,EACV,KACE3W,EAAO,KAAK8U,EAAK+B,CAAG,CAAC,EACjBA,IAAQD,GACZC,GAAOA,EAAM,GAAK3I,EAEpB,OAAOlO,CACT,CAUA,SAAS8W,GAAiBnB,EAAMoB,EAAMC,EAAM,CAC1C,MAAMhX,EAAS,CAAC+W,EAAK,KAAK,EAGpBE,EAAWF,EAAK,WAChBG,EAASF,EAAK,WAEpB,QAAS,EAAIC,EAAW,EAAG,GAAKC,EAAQ,IACtClX,EAAO,KAAK2V,EAAK,CAAC,CAAC,EAIrB,OAAIH,GAAMxV,EAAOA,EAAO,OAAS,CAAC,EAAGgX,EAAK,KAAK,EAAI,OACjDhX,EAAO,KAAKgX,EAAK,KAAK,EAGjBhX,CACT,CAQA,SAASmX,GAAcrC,EAAMsC,EAAK,CAChC,MAAMrC,EAAOF,GAAWC,CAAI,EAC5B,OAAKsC,GAAOrC,EAAO,GAAO,CAACqC,GAAOrC,EAAO,EAChCD,EAAK,MAAK,EAAG,QAAO,EAEtBA,CACT,CAKA,SAASuC,GAAUC,EAAQ,CACzB,GAAIA,EAAO,OAAS,EAAG,OAAOA,EAC9B,MAAMtI,EAAQsI,EAAO,CAAC,EAChBC,EAAOD,EAAOA,EAAO,OAAS,CAAC,EACrC,OAAI9B,GAAMxG,EAAOuI,CAAI,EAAI,MAChB,CAAC,GAAGD,EAAQtI,EAAM,MAAK,CAAE,EAE3BsI,CACT,CAWA,SAASE,GAAsB7B,EAAMb,EAAM,CAEzC,IAAI2C,EAAO,IAAUC,EAAO,IAAUC,EAAO,KAAWC,EAAO,KAC/D,UAAW3C,KAAMH,EACXG,EAAG,CAAC,EAAIwC,IAAMA,EAAOxC,EAAG,CAAC,GACzBA,EAAG,CAAC,EAAIyC,IAAMA,EAAOzC,EAAG,CAAC,GACzBA,EAAG,CAAC,EAAI0C,IAAMA,EAAO1C,EAAG,CAAC,GACzBA,EAAG,CAAC,EAAI2C,IAAMA,EAAO3C,EAAG,CAAC,GAE/B,MAAM4C,EAAO,KAAK,MAAMF,EAAOF,IAAS,GAAKG,EAAOF,IAAS,CAAC,GAAK,EAE7D1X,EAAS2V,EAAK,MAAK,EAGzB,GAAIX,GAAYhV,EAAO,CAAC,EAAG8U,CAAI,EAAG,CAChC,MAAMgD,EAAK9X,EAAO,CAAC,EACbgU,EAAKhU,EAAO,CAAC,EACb+X,EAAKD,EAAG,CAAC,EAAI9D,EAAG,CAAC,EACjBgE,EAAKF,EAAG,CAAC,EAAI9D,EAAG,CAAC,EACjBiE,EAAM,KAAK,KAAKF,EAAKA,EAAKC,EAAKA,CAAE,GAAK,EACtCE,EAAQL,EAAO,EAAII,EACzBjY,EAAO,CAAC,EAAI,CAAC8X,EAAG,CAAC,EAAIC,EAAKG,EAAOJ,EAAG,CAAC,EAAIE,EAAKE,CAAK,CACrD,CAGA,MAAMX,EAAOvX,EAAO,OAAS,EAC7B,GAAIgV,GAAYhV,EAAOuX,CAAI,EAAGzC,CAAI,EAAG,CACnC,MAAMqD,EAAKnY,EAAOuX,CAAI,EAChBa,EAAMpY,EAAOuX,EAAO,CAAC,EACrBQ,EAAKI,EAAG,CAAC,EAAIC,EAAI,CAAC,EAClBJ,EAAKG,EAAG,CAAC,EAAIC,EAAI,CAAC,EAClBH,EAAM,KAAK,KAAKF,EAAKA,EAAKC,EAAKA,CAAE,GAAK,EACtCE,EAAQL,EAAO,EAAII,EACzBjY,EAAOuX,CAAI,EAAI,CAACY,EAAG,CAAC,EAAIJ,EAAKG,EAAOC,EAAG,CAAC,EAAIH,EAAKE,CAAK,CACxD,CAEA,OAAOlY,CACT,CAeO,SAASqY,GAAmBC,EAAeC,EAAY,CAC5D,MAAMC,EAAeF,EAAc,CAAC,EAC9BG,EAAQH,EAAc,MAAM,CAAC,EAG7BI,EAAelB,GAAsBe,EAAYC,CAAY,EAG7D5C,EAAOF,GAAkB8C,EAAcE,CAAY,EAGzD,GAAI9C,EAAK,SAAW,EAClB,eAAQ,KAAK,gDAAgDA,EAAK,MAAM,EAAE,EACnE,KAGT,KAAM,CAACmB,EAAMC,CAAI,EAAIpB,EAGf,CAAE,KAAM+C,EAAc,QAAAtC,CAAO,EAAKH,GAAqBsC,EAAc5C,CAAI,EACzEgD,EAAOvC,EAAQ,CAAC,EAChBwC,EAAOxC,EAAQ,CAAC,EAGhB,CAACyC,EAAIC,CAAE,EAAIH,EAAOC,EAAO,CAACD,EAAMC,CAAI,EAAI,CAACA,EAAMD,CAAI,EAInDI,EAAaJ,EAAOC,EACtB/B,GAAiB4B,EAAc3B,EAAMC,CAAI,EACzCF,GAAiB4B,EAAc1B,EAAMD,CAAI,EACvCkC,EAAaD,EAAW,MAAK,EAAG,QAAO,EAIvCE,EAAU1C,GAAUmC,EAAcG,EAAIC,CAAE,EACxCI,EAAQ9B,GAAU,CAAC,GAAG6B,EAAS,GAAGD,EAAW,MAAM,CAAC,CAAC,CAAC,EAGtDG,EAAU5C,GAAUmC,EAAcI,EAAID,CAAE,EACxCO,EAAQhC,GAAU,CAAC,GAAG+B,EAAS,GAAGJ,EAAW,MAAM,CAAC,CAAC,CAAC,EAGtDM,EAAczE,GAAW2D,CAAY,EAAI,EACzCe,EAASpC,GAAcgC,EAAOG,CAAW,EACzCE,EAASrC,GAAckC,EAAOC,CAAW,EAGzCG,EAAQ,CAACF,CAAM,EACfG,EAAQ,CAACF,CAAM,EAErB,UAAWG,KAAQlB,EAAO,CAExB,MAAMmB,EAAWC,GAAaF,CAAI,EAC9B3E,GAAY4E,EAAUL,CAAM,EAC9BE,EAAM,KAAKE,CAAI,EAEfD,EAAM,KAAKC,CAAI,CAEnB,CAEA,MAAO,CAACF,EAAOC,CAAK,CACtB,CAKA,SAASG,GAAa/E,EAAM,CAC1B,IAAIgF,EAAK,EAAGC,EAAK,EACjB,MAAM7L,EAAI4G,EAAK,OAAS,EACxB,QAASrX,EAAI,EAAGA,EAAIyQ,EAAGzQ,IACrBqc,GAAMhF,EAAKrX,CAAC,EAAE,CAAC,EACfsc,GAAMjF,EAAKrX,CAAC,EAAE,CAAC,EAEjB,MAAO,CAACqc,EAAK5L,EAAG6L,EAAK7L,CAAC,CACxB,CC7XA,MAAM8L,GAAS,CACb,QAAS,CAAE,GAAI,UAAW,KAAM,GAAQ,EACxC,MAAS,CAAE,GAAI,UAAW,KAAM,GAAQ,EACxC,QAAS,CAAE,GAAI,UAAW,KAAM,IAAc,EAC9C,KAAS,CAAE,GAAI,UAAW,KAAM,IAAc,CAChD,EAIA,IAAIC,GAAY,KAEhB,SAASC,IAAkB,CACzB,OAAID,KACJA,GAAY,SAAS,cAAc,KAAK,EACxCA,GAAU,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAY1B,SAAS,KAAK,YAAYA,EAAS,EAC5BA,GACT,CAWO,SAASE,EAAUlV,EAASpF,EAAO,OAAQua,EAAW,IAAM,CACjE,MAAMC,EAASH,GAAe,EACxBI,EAAQN,GAAOna,CAAI,GAAKma,GAAO,KAE/BO,EAAK,SAAS,cAAc,KAAK,EACvCA,EAAG,MAAM,QAAU;AAAA,kBACHD,EAAM,EAAE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAiBxBC,EAAG,YAAc,GAAGD,EAAM,IAAI,KAAKrV,CAAO,GAE1CoV,EAAO,YAAYE,CAAE,EAGrB,sBAAsB,IAAM,CAC1BA,EAAG,MAAM,QAAU,IACnBA,EAAG,MAAM,UAAY,eACvB,CAAC,EAGD,MAAMC,EAAU,IAAM,CACpBD,EAAG,MAAM,QAAU,IACnBA,EAAG,MAAM,UAAY,mBACrB,WAAW,IAAMA,EAAG,OAAM,EAAI,GAAG,CACnC,EAGAA,EAAG,iBAAiB,QAASC,CAAO,EAGpC,WAAWA,EAASJ,CAAQ,CAC9B,CCzEA,MAAMK,GAAe,CACnB,CAAE,OAAQ,UAAW,KAAM,sBAAsB,EACjD,CAAE,OAAQ,UAAW,KAAM,uBAAuB,CACpD,EAGMC,GAAkB,IAAIC,EAAM,CAChC,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CACnD,CAAC,EAGKC,GAAe,IAAIH,EAAM,CAC7B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,SAAU,CAAC,EAAG,CAAC,CAAC,CAAE,EACnE,MAAO,IAAIG,GAAY,CACrB,OAAQ,EACR,KAAM,IAAIF,EAAK,CAAE,MAAO,SAAS,CAAE,EACnC,OAAQ,IAAID,EAAO,CAAE,MAAO,OAAQ,MAAO,IAAK,CACpD,CAAG,CACH,CAAC,EAEM,MAAMI,WAAgCC,EAA2B,CAQtE,YAAYjY,EAAU,GAAI,CACxB,MAAM,CACJ,YAAcqH,GAAM,KAAK,aAAaA,CAAC,CAC7C,CAAK,EAED,KAAK,cAAgBrH,EAAQ,cAAgB,GAC7C,KAAK,SAAWA,EAAQ,QACnB,MAAM,QAAQA,EAAQ,OAAO,EAAIA,EAAQ,QAAU,CAACA,EAAQ,OAAO,EACpE,KAGJ,KAAK,OAAS,SACd,KAAK,iBAAmB,KACxB,KAAK,gBAAkB,KACvB,KAAK,iBAAmB,KACxB,KAAK,eAAiB,KAGtB,KAAK,eAAiB,IAAIkY,EAAa,CAAE,gBAAiB,EAAK,CAAE,EACjE,KAAK,cAAgB,IAAIC,EAAY,CACnC,OAAQ,KAAK,eACb,uBAAwB,GACxB,MAAOT,EACb,CAAK,CACH,CAMA,OAAOU,EAAK,CACN,KAAK,WACP,KAAK,OAAM,EAAG,YAAY,KAAK,aAAa,EAC5C,KAAK,uBAAsB,GAE7B,MAAM,OAAOA,CAAG,EACZA,GACF,KAAK,cAAc,OAAOA,CAAG,CAEjC,CAEA,UAAUC,EAAQ,CAChB,MAAM,UAAUA,CAAM,EACjBA,GACH,KAAK,OAAM,CAEf,CAMA,aAAc,CACZ,GAAI,KAAK,SAAU,OAAO,KAAK,SAC/B,GAAI,CAAC,KAAK,OAAM,EAAI,MAAO,GAC3B,MAAMC,EAAU,GACVC,EAAWC,GAAW,CAC1BA,EAAO,QAASC,GAAU,CACpBA,EAAM,eACJA,EAAM,WAAaA,EAAM,UAAS,YAAcP,EAClDI,EAAQ,KAAKG,EAAM,WAAW,EACrBA,EAAM,WACfF,EAAQE,EAAM,WAAW,EAG/B,CAAC,CACH,EACA,OAAAF,EAAQ,KAAK,OAAM,EAAG,UAAS,CAAE,EAC1BD,CACT,CAMA,aAAa,EAAG,CACd,GAAI,CAAC,KAAK,UAAS,EAAI,MAAO,GAE9B,GAAI,KAAK,SAAW,SAAU,CAC5B,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,CAAC,EACzD,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,eAAe,CAAC,CAC5D,CAGA,GAAI,KAAK,SAAW,QACd,EAAE,OAAS,WAAa,EAAE,eAAe,MAAQ,SACnD,YAAK,YAAW,EACT,GAKX,GAAI,KAAK,SAAW,OAAQ,CAC1B,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,YAAY,CAAC,EACvD,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,aAAa,CAAC,EACxD,GAAI,EAAE,OAAS,WAAa,EAAE,eAAe,MAAQ,SACnD,YAAK,OAAM,EACJ,EAEX,CAEA,MAAO,EACT,CAMA,cAAc,EAAG,CACf,MAAMF,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,eAAe,MAAK,EAEzB,MAAMM,EAAM,KAAK,gBAAgB,CAAC,EAClC,GAAIA,EAAK,CAEP,MAAMC,EAAQD,EAAI,QAAQ,MAAK,EAC/B,KAAK,eAAe,WAAWC,CAAK,EACpCP,EAAI,iBAAgB,EAAG,MAAM,OAAS,SACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,eAAe,EAAG,CAChB,MAAMM,EAAM,KAAK,gBAAgB,CAAC,EAClC,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,iBAAmBA,EAAI,QAC5B,KAAK,gBAAkBA,EAAI,OAG3B,KAAK,eAAe,MAAK,EACzB,MAAMC,EAAQD,EAAI,QAAQ,MAAK,EAC/B,YAAK,eAAe,WAAWC,CAAK,EAEpC,KAAK,gBAAe,EACb,EACT,CAKA,gBAAgB,EAAG,CACjB,IAAIC,EAAO,KACPC,EAAW,KAAK,cAAgB,EAEpC,UAAWC,KAAU,KAAK,cAAe,CACvC,MAAMC,EAAOD,EAAO,8BAA8B,EAAE,UAAU,EAC9D,GAAI,CAACC,EAAM,SACX,MAAMC,EAAOD,EAAK,YAAW,EAC7B,GAAI,CAACC,EAAM,SACX,MAAMnc,EAAOmc,EAAK,QAAO,EACzB,GAAInc,IAAS,WAAaA,IAAS,eAAgB,SAEnD,MAAMoc,EAAUD,EAAK,gBAAgB,EAAE,UAAU,EAE3CE,EADO,IAAIC,GAAW,CAAC,EAAE,WAAYF,CAAO,CAAC,EAC/B,UAAS,EAAK,EAAE,WAAW,UAAU,WAErDC,EAASL,IACXA,EAAWK,EACXN,EAAO,CAAE,QAASG,EAAM,OAAAD,EAAQ,MAAOG,CAAO,EAElD,CACA,OAAOL,CACT,CAMA,iBAAkB,CAChB,KAAK,OAAS,OACd,MAAMR,EAAM,KAAK,OAAM,EAClBA,IAELA,EAAI,iBAAgB,EAAG,MAAM,OAAS,YAEtC,KAAK,iBAAmB,IAAIgB,GAAoB,CAC9C,KAAM,aACN,MAAOtB,EACb,CAAK,EAED,KAAK,iBAAiB,GAAG,UAAYuB,GAAQ,CAC3C,MAAMC,EAAcD,EAAI,QAAQ,YAAW,EAAG,eAAc,EAC5D,KAAK,cAAcC,CAAW,CAChC,CAAC,EAEDlB,EAAI,eAAe,KAAK,gBAAgB,EAC1C,CAEA,wBAAyB,CACnB,KAAK,kBAAoB,KAAK,OAAM,GACtC,KAAK,OAAM,EAAG,kBAAkB,KAAK,gBAAgB,EAEvD,KAAK,iBAAmB,IAC1B,CAEA,aAAc,CACZ,KAAK,uBAAsB,EAC3B,KAAK,OAAM,CACb,CAMA,cAAcmB,EAAmB,CAC/B,MAAMC,EAAU,KAAK,iBACfV,EAAS,KAAK,gBACdE,EAAOQ,EAAQ,YAAW,EAEhC,IAAIlE,EACA0D,EAAK,QAAO,IAAO,UACrB1D,EAAgB0D,EAAK,eAAc,EAC1BA,EAAK,QAAO,IAAO,iBAI5B1D,EAAgB0D,EAAK,eAAc,EAAG,CAAC,GAGzC,MAAMhc,EAASqY,GAAmBC,EAAeiE,CAAiB,EAElE,GAAI,CAACvc,EAAQ,CACX,QAAQ,KAAK,yFAAyF,EAEtG,KAAK,uBAAsB,EAC3B,KAAK,gBAAe,EACpB,MACF,CAEA,KAAM,CAACyc,EAASC,CAAO,EAAI1c,EAGrB2c,EAAWH,EAAQ,MAAK,EAC9BG,EAAS,YAAY,IAAIC,GAAYH,CAAO,CAAC,EAC7CE,EAAS,SAAS,IAAIhC,EAAM,CAC1B,OAAQ,IAAIC,EAAO,CAAE,MAAOH,GAAa,CAAC,EAAE,OAAQ,MAAO,IAAK,EAChE,KAAM,IAAII,EAAK,CAAE,MAAOJ,GAAa,CAAC,EAAE,KAAM,CACpD,CAAK,CAAC,EAEF,MAAMoC,EAAWL,EAAQ,MAAK,EAC9BK,EAAS,YAAY,IAAID,GAAYF,CAAO,CAAC,EAC7CG,EAAS,SAAS,IAAIlC,EAAM,CAC1B,OAAQ,IAAIC,EAAO,CAAE,MAAOH,GAAa,CAAC,EAAE,OAAQ,MAAO,IAAK,EAChE,KAAM,IAAII,EAAK,CAAE,MAAOJ,GAAa,CAAC,EAAE,KAAM,CACpD,CAAK,CAAC,EAGF,MAAMqC,EAAgB,CAACH,EAAUE,CAAQ,EAkCzC,GAjCA,KAAK,cAAc,CACjB,KAAM,cACN,SAAUL,EACV,SAAUM,CAChB,CAAK,EACDhB,EAAO,cAAc,CACnB,KAAM,cACN,SAAUU,EACV,SAAUM,CAChB,CAAK,EAGDhB,EAAO,cAAcU,CAAO,EAC5BV,EAAO,WAAWa,CAAQ,EAC1Bb,EAAO,WAAWe,CAAQ,EAG1B,KAAK,cAAc,CACjB,KAAM,aACN,SAAUL,EACV,SAAUM,CAChB,CAAK,EACDhB,EAAO,cAAc,CACnB,KAAM,aACN,SAAUU,EACV,SAAUM,CAChB,CAAK,EAGD,KAAK,uBAAsB,EAGVN,EAAQ,IAAI,YAAY,IAAM,SACjC,CACZ,KAAK,eAAiBM,EACtB,KAAK,OAAS,OACd,KAAK,eAAe,MAAK,EACzB,MAAM1B,EAAM,KAAK,OAAM,EACnBA,IAAKA,EAAI,iBAAgB,EAAG,MAAM,OAAS,IAC/CjB,EAAU,8DAA+D,OAAQ,GAAI,EAErF,KAAK,cAAc,CACjB,KAAM,cACN,SAAU2C,EACV,cAAeN,EAAQ,cAAa,EACpC,OAAAV,CACR,CAAO,CACH,MACE,KAAK,OAAM,CAEf,CAMA,YAAY,EAAG,CACb,MAAMV,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,eAAe,MAAK,EAEzB,MAAMM,EAAM,KAAK,mBAAmB,CAAC,EACrC,GAAIA,EAAK,CACP,MAAMC,EAAQD,EAAI,MAAK,EACvB,KAAK,eAAe,WAAWC,CAAK,EACpCP,EAAI,iBAAgB,EAAG,MAAM,OAAS,SACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,aAAa,EAAG,CACd,MAAMM,EAAM,KAAK,mBAAmB,CAAC,EACrC,OAAKA,GAEL,KAAK,cAAc,CACjB,KAAM,YACN,OAAQA,EACR,SAAU,KAAK,cACrB,CAAK,EAED,KAAK,OAAM,EACJ,IATU,EAUnB,CAKA,mBAAmB,EAAG,CACpB,GAAI,CAAC,KAAK,eAAgB,OAAO,KACjC,IAAIE,EAAO,KACPC,EAAW,KAAK,cAAgB,EAEpC,UAAWE,KAAQ,KAAK,eAAgB,CACtC,MAAMC,EAAOD,EAAK,YAAW,EAC7B,GAAI,CAACC,EAAM,SACX,MAAMC,EAAUD,EAAK,gBAAgB,EAAE,UAAU,EAE3CE,EADO,IAAIC,GAAW,CAAC,EAAE,WAAYF,CAAO,CAAC,EAC/B,UAAS,EAAK,EAAE,WAAW,UAAU,WACrDC,EAASL,IACXA,EAAWK,EACXN,EAAOG,EAEX,CACA,OAAOH,CACT,CAMA,QAAS,CACP,KAAK,OAAS,SACd,KAAK,iBAAmB,KACxB,KAAK,gBAAkB,KACvB,KAAK,eAAiB,KACtB,KAAK,eAAe,MAAK,EACzB,KAAK,uBAAsB,EAE3B,MAAMR,EAAM,KAAK,OAAM,EACnBA,IACFA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAE1C,CACF,CCvaA,SAAS5F,GAAM3F,EAAG4F,EAAG,CACnB,OAAQ5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,GAAK5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,CAC/C,CAMA,SAASZ,GAAWC,EAAM,CACxB,IAAIC,EAAO,EACX,QAAStX,EAAI,EAAGyQ,EAAI4G,EAAK,OAAQrX,EAAIyQ,EAAI,EAAGzQ,IAC1CsX,GAASD,EAAKrX,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAMqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,CAAC,EAAE,CAAC,EAErE,OAAOsX,EAAO,CAChB,CAKA,SAASC,GAAYC,EAAIH,EAAM,CAC7B,IAAII,EAAS,GACb,QAASzX,EAAI,EAAG0X,EAAIL,EAAK,OAAS,EAAGrX,EAAIqX,EAAK,OAAS,EAAGK,EAAI1X,IAAK,CACjE,MAAM2X,EAAKN,EAAKrX,CAAC,EAAE,CAAC,EAAG4X,EAAKP,EAAKrX,CAAC,EAAE,CAAC,EAC/B6X,EAAKR,EAAKK,CAAC,EAAE,CAAC,EAAGI,EAAKT,EAAKK,CAAC,EAAE,CAAC,EAC/BE,EAAKJ,EAAG,CAAC,GAAQM,EAAKN,EAAG,CAAC,GAC3BA,EAAG,CAAC,GAAKK,EAAKF,IAAOH,EAAG,CAAC,EAAII,IAAOE,EAAKF,GAAMD,IAClDF,EAAS,CAACA,EAEd,CACA,OAAOA,CACT,CAKA,SAASiC,GAAcrC,EAAMsC,EAAK,CAChC,MAAMrC,EAAOF,GAAWC,CAAI,EAC5B,OAAKsC,GAAOrC,EAAO,GAAO,CAACqC,GAAOrC,EAAO,EAChCD,EAAK,MAAK,EAAG,QAAO,EAEtBA,CACT,CAKA,SAASuC,GAAUC,EAAQ,CACzB,OAAIA,EAAO,OAAS,EAAUA,EAC1B9B,GAAM8B,EAAO,CAAC,EAAGA,EAAOA,EAAO,OAAS,CAAC,CAAC,EAAI,MACzC,CAAC,GAAGA,EAAQA,EAAO,CAAC,EAAE,MAAK,CAAE,EAE/BA,CACT,CAUA,SAASyF,GAAgB9H,EAAI+H,EAAMC,EAAM,CACvC,MAAMlF,EAAKkF,EAAK,CAAC,EAAID,EAAK,CAAC,EACrBhF,EAAKiF,EAAK,CAAC,EAAID,EAAK,CAAC,EACrBE,EAAQnF,EAAKA,EAAKC,EAAKA,EAE7B,GAAIkF,EAAQ,MAAO,OAAO1H,GAAMP,EAAI+H,CAAI,EAGxC,IAAInS,IAAMoK,EAAG,CAAC,EAAI+H,EAAK,CAAC,GAAKjF,GAAM9C,EAAG,CAAC,EAAI+H,EAAK,CAAC,GAAKhF,GAAMkF,EAC5DrS,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAC,CAAC,EAE9B,MAAMsS,EAAQH,EAAK,CAAC,EAAInS,EAAIkN,EACtBqF,EAAQJ,EAAK,CAAC,EAAInS,EAAImN,EAC5B,OAAQ/C,EAAG,CAAC,EAAIkI,IAAU,GAAKlI,EAAG,CAAC,EAAImI,IAAU,CACnD,CASA,SAASC,GAAgBvI,EAAMwI,EAAY,CACzC,IAAIC,EAAU,EACV1B,EAAW,IACf,MAAM3N,EAAI4G,EAAK,OAAS,EAExB,QAASrX,EAAI,EAAGA,EAAIyQ,EAAGzQ,IAAK,CAC1B,MAAM+f,EAAIT,GAAgBO,EAAYxI,EAAKrX,CAAC,EAAGqX,GAAMrX,EAAI,GAAKyQ,IAAM,EAAIA,EAAIzQ,EAAI,CAAC,CAAC,EAC9E+f,EAAI3B,IACNA,EAAW2B,EACXD,EAAU9f,EAEd,CACA,MAAO,CAAE,OAAQ8f,EAAS,OAAQ1B,CAAQ,CAC5C,CAKA,SAAS4B,GAAY5N,EAAG4F,EAAGiI,EAAO,CAChC,OAAOlI,GAAM3F,EAAG4F,CAAC,EAAIiI,CACvB,CAeA,SAASC,GAAiB1I,EAAIH,EAAM4I,EAAO,CACzC,MAAMxP,EAAI4G,EAAK,OAAS,EACxB,QAASrX,EAAI,EAAGA,EAAIyQ,EAAGzQ,IACrB,GAAIsf,GAAgB9H,EAAIH,EAAKrX,CAAC,EAAGqX,EAAKrX,EAAI,CAAC,CAAC,EAAIigB,EAC9C,MAAO,GAGX,MAAO,EACT,CAiCA,SAASE,GAAmBzE,EAAOE,EAAOwE,EAAUC,EAAUC,EAAW,CACvE,MAAMC,EAAK7E,EAAM,OAAS,EACpB8E,EAAK5E,EAAM,OAAS,EACpBqE,EAAQK,EAAYA,EAMpBG,EAAK/E,EAAM0E,CAAQ,EACnBM,EAAKhF,GAAO0E,EAAW,GAAKG,CAAE,EAC9BI,EAAK/E,EAAMyE,CAAQ,EACnBO,EAAKhF,GAAOyE,EAAW,GAAKG,CAAE,EAE9BK,EAAUX,GAAiBO,EAAI7E,EAAOqE,CAAK,EAC3Ca,EAAUZ,GAAiBQ,EAAI9E,EAAOqE,CAAK,EAC3Cc,EAAUb,GAAiBS,EAAIjF,EAAOuE,CAAK,EAC3Ce,EAAUd,GAAiBU,EAAIlF,EAAOuE,CAAK,EAEjD,GAAI,EAAEY,GAAWC,IAAY,EAAEC,GAAWC,GACxC,eAAQ,KAAK,0DAA0D,EAChE,KAKT,IAAIC,EACAjB,GAAYS,EAAIG,EAAIX,CAAK,GAAKD,GAAYU,EAAIC,EAAIV,CAAK,EACzDgB,EAAW,GACFjB,GAAYS,EAAIE,EAAIV,CAAK,GAAKD,GAAYU,EAAIE,EAAIX,CAAK,EAChEgB,EAAW,GAGXA,EAAWlJ,GAAM0I,EAAIG,CAAE,EAAI7I,GAAM0I,EAAIE,CAAE,EAIzC,IAAIO,EAASd,EACTe,GAAQf,EAAW,GAAKG,EACxBa,EAAQC,EAERJ,GAEFG,GAAUf,EAAW,GAAKG,EAC1Ba,EAAOhB,IAEPe,EAASf,EACTgB,GAAQhB,EAAW,GAAKG,GAQ1B,IAAIc,EAASf,EAAKC,EAClB,KAAOc,KAAW,GAAG,CACnB,MAAMC,GAASJ,EAAO,GAAKZ,EACrBiB,EAAQP,GAAYI,EAAO,EAAIb,GAAMA,GAAMa,EAAO,GAAKb,EAC7D,GAAIe,IAAUL,GAAUM,IAAUJ,EAAQ,MAG1C,GAAIpB,GAAYtE,EAAM6F,CAAK,EAAG3F,EAAM4F,CAAK,EAAGvB,CAAK,EAAG,CAClDkB,EAAOI,EACPF,EAAOG,EACP,QACF,CAGA,GAAIlC,GAAgB5D,EAAM6F,CAAK,EAAG3F,EAAMyF,CAAI,EAAGzF,EAAM4F,CAAK,CAAC,EAAIvB,EAAO,CACpEkB,EAAOI,EACP,QACF,CAGA,GAAIjC,GAAgB1D,EAAM4F,CAAK,EAAG9F,EAAMyF,CAAI,EAAGzF,EAAM6F,CAAK,CAAC,EAAItB,EAAO,CACpEoB,EAAOG,EACP,QACF,CAEA,KACF,CAIA,IADAF,EAASf,EAAKC,EACPc,KAAW,GAAG,CACnB,MAAMG,GAASP,EAAS,EAAIX,GAAMA,EAC5BmB,EAAQT,GAAYG,EAAS,GAAKZ,GAAMY,EAAS,EAAIZ,GAAMA,EACjE,GAAIiB,IAAUN,GAAQO,IAAUL,EAAM,MAGtC,GAAIrB,GAAYtE,EAAM+F,CAAK,EAAG7F,EAAM8F,CAAK,EAAGzB,CAAK,EAAG,CAClDiB,EAASO,EACTL,EAASM,EACT,QACF,CAGA,GAAIpC,GAAgB5D,EAAM+F,CAAK,EAAG7F,EAAMwF,CAAM,EAAGxF,EAAM8F,CAAK,CAAC,EAAIzB,EAAO,CACtEiB,EAASO,EACT,QACF,CAGA,GAAInC,GAAgB1D,EAAM8F,CAAK,EAAGhG,EAAMwF,CAAM,EAAGxF,EAAM+F,CAAK,CAAC,EAAIxB,EAAO,CACtEmB,EAASM,EACT,QACF,CAEA,KACF,CAEA,MAAO,CAAE,OAAAR,EAAQ,KAAAC,EAAM,OAAAC,EAAQ,KAAAC,EAAM,SAAAJ,CAAQ,CAC/C,CAYA,SAASU,GAAStK,EAAMuK,EAASC,EAAO,CACtC,MAAMpR,EAAI4G,EAAK,OAAS,EAClB9U,EAAS,GACf,IAAI6W,EAAMwI,EACV,KACErf,EAAO,KAAK8U,EAAK+B,CAAG,CAAC,EACjB,EAAAA,IAAQyI,IACZzI,GAAOA,EAAM,GAAK3I,EAEdlO,EAAO,OAASkO,EAAI,KAAxB,CAEF,OAAOlO,CACT,CAeO,SAASuf,GAAcC,EAAgBC,EAAgBC,EAAaC,EAAa5B,EAAY,EAAG,CACrG,MAAM5E,EAAQqG,EAAe,CAAC,EACxBnG,EAAQoG,EAAe,CAAC,EACxBG,EAASJ,EAAe,MAAM,CAAC,EAC/BK,EAASJ,EAAe,MAAM,CAAC,EAG/BK,EAAQzC,GAAgBlE,EAAOuG,CAAW,EAC1CK,EAAQ1C,GAAgBhE,EAAOsG,CAAW,EAG1CK,EAASpC,GAAmBzE,EAAOE,EAAOyG,EAAM,OAAQC,EAAM,OAAQhC,CAAS,EACrF,GAAI,CAACiC,EACH,eAAQ,KAAK,yGAAyG,EAC/G,CAAE,OAAQ,KAAM,MAAO,sHAAsH,EAGtJ,KAAM,CAAE,OAAArB,EAAQ,KAAAC,EAAM,OAAAC,EAAQ,KAAAC,EAAM,SAAAJ,CAAQ,EAAKsB,EACtC7G,EAAM,OAAS,EACfE,EAAM,OAAS,EAY1B,MAAM4G,EAAQb,GAASjG,EAAOyF,EAAMD,CAAM,EAE1C,IAAIuB,EACAxB,EAGFwB,EAAQd,GAAS/F,EAAOwF,EAAQC,CAAI,EAGpCoB,EAAQd,GAAS/F,EAAOyF,EAAMD,CAAM,EAKtC,MAAMsB,EAAS,CAAC,GAAGF,EAAO,GAAGC,EAAM,MAAM,CAAC,CAAC,EAMrCxC,EAAQK,EAAYA,EACtBoC,EAAO,OAAS,GAAK3K,GAAM2K,EAAOA,EAAO,OAAS,CAAC,EAAGA,EAAO,CAAC,CAAC,EAAIzC,IACrEyC,EAAOA,EAAO,OAAS,CAAC,EAAIA,EAAO,CAAC,EAAE,MAAK,GAG7C,MAAMC,EAAa/I,GAAU8I,CAAM,EAG7BE,EAAQ,KAAK,IAAIxL,GAAWsE,CAAK,CAAC,EAClCmH,EAAQ,KAAK,IAAIzL,GAAWwE,CAAK,CAAC,EAClCkH,EAAa,KAAK,IAAI1L,GAAWuL,CAAU,CAAC,EAC5CI,EAAeH,EAAQC,EAG7B,GAAIC,EAAaC,EAAe,IAAOD,EAAaC,EAAe,IACjE,eAAQ,KAAK,mCAAmCH,EAAM,QAAQ,CAAC,CAAC,OAAOC,EAAM,QAAQ,CAAC,CAAC,YAAYC,EAAW,QAAQ,CAAC,CAAC,cAAcC,EAAa,QAAQ,CAAC,CAAC,EAAE,EACxJ,CAAE,OAAQ,KAAM,MAAO,yIAAyI,EAIzK,MAAMlH,EAAczE,GAAWsE,CAAK,EAAI,EAClCsH,EAAYtJ,GAAciJ,EAAY9G,CAAW,EAKjDoH,EAFW,CAAC,GAAGd,EAAQ,GAAGC,CAAM,EAEV,OAAOlG,IAAQ,CACzC,MAAMG,EAAKH,GAAK,OAAO,CAAC/I,EAAGpC,KAAMoC,EAAIpC,GAAE,CAAC,EAAG,CAAC,GAAKmL,GAAK,OAAS,GACzDI,GAAKJ,GAAK,OAAO,CAAC/I,EAAGpC,KAAMoC,EAAIpC,GAAE,CAAC,EAAG,CAAC,GAAKmL,GAAK,OAAS,GAC/D,OAAO3E,GAAY,CAAC8E,EAAIC,EAAE,EAAG0G,CAAS,CACxC,CAAC,EAED,MAAO,CAAE,OAAQ,CAACA,EAAW,GAAGC,CAAU,CAAC,CAC7C,CC7XA,MAAMC,GAAc,IAAIhG,EAAM,CAC5B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CACnD,CAAC,EAEK+F,GAAc,IAAIjG,EAAM,CAC5B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CACnD,CAAC,EAGKgG,GAAU,IAAIlG,EAAM,CACxB,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,EACjD,KAAM,IAAIiG,GAAK,CACb,KAAM,IACN,KAAM,4BACN,KAAM,IAAIjG,EAAK,CAAE,MAAO,SAAS,CAAE,EACnC,OAAQ,IAAID,EAAO,CAAE,MAAO,OAAQ,MAAO,EAAG,EAC9C,SAAU,EACd,CAAG,CACH,CAAC,EAEKmG,GAAU,IAAIpG,EAAM,CACxB,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,EACjD,KAAM,IAAIiG,GAAK,CACb,KAAM,IACN,KAAM,4BACN,KAAM,IAAIjG,EAAK,CAAE,MAAO,SAAS,CAAE,EACnC,OAAQ,IAAID,EAAO,CAAE,MAAO,OAAQ,MAAO,EAAG,EAC9C,SAAU,EACd,CAAG,CACH,CAAC,EAEKoG,GAAa,IAAIrG,EAAM,CAC3B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,SAAU,CAAC,GAAI,CAAC,CAAC,CAAE,CACtE,CAAC,EAEKqG,GAAc,IAAItG,EAAM,CAC5B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,IAAK,EACnD,KAAM,IAAIC,EAAK,CAAE,MAAO,sBAAsB,CAAE,CAClD,CAAC,EAIM,MAAMqG,WAAgCjG,EAA2B,CAMtE,YAAYjY,EAAU,GAAI,CACxB,MAAM,CACJ,YAAcqH,GAAM,KAAK,aAAaA,CAAC,CAC7C,CAAK,EAED,KAAK,cAAgBrH,EAAQ,cAAgB,GAC7C,KAAK,WAAaA,EAAQ,WAAa,EAGvC,KAAK,OAAS,WAGd,KAAK,UAAY,KACjB,KAAK,SAAW,KAChB,KAAK,UAAY,KACjB,KAAK,SAAW,KAGhB,KAAK,YAAc,KACnB,KAAK,YAAc,KAGnB,KAAK,iBAAmB,IAAIkY,EAAa,CAAE,gBAAiB,EAAK,CAAE,EACnE,KAAK,gBAAkB,IAAIC,EAAY,CACrC,OAAQ,KAAK,iBACb,uBAAwB,GACxB,MAAQ/N,GAAMA,EAAE,IAAI,iBAAiB,GAAKuT,EAChD,CAAK,EAGD,KAAK,YAAc,IAAIzF,EAAa,CAAE,gBAAiB,EAAK,CAAE,EAC9D,KAAK,WAAa,IAAIC,EAAY,CAChC,OAAQ,KAAK,YACb,uBAAwB,GACxB,MAAO6F,EACb,CAAK,CACH,CAMA,OAAO5F,EAAK,CACN,KAAK,WACP,KAAK,OAAM,EAAG,YAAY,KAAK,eAAe,EAC9C,KAAK,OAAM,EAAG,YAAY,KAAK,UAAU,GAE3C,MAAM,OAAOA,CAAG,EACZA,IACF,KAAK,gBAAgB,OAAOA,CAAG,EAC/B,KAAK,WAAW,OAAOA,CAAG,EAE9B,CAEA,UAAUC,EAAQ,CAChB,MAAM,UAAUA,CAAM,EACjBA,GAAQ,KAAK,OAAM,CAC1B,CAMA,aAAc,CACZ,GAAI,CAAC,KAAK,OAAM,EAAI,MAAO,GAC3B,MAAMC,EAAU,GACVC,EAAWC,GAAW,CAC1BA,EAAO,QAASC,GAAU,CACpBA,EAAM,eACJA,EAAM,WAAaA,EAAM,UAAS,YAAcP,EAClDI,EAAQ,KAAKG,EAAM,WAAW,EACrBA,EAAM,WACfF,EAAQE,EAAM,WAAW,EAG/B,CAAC,CACH,EACA,OAAAF,EAAQ,KAAK,OAAM,EAAG,UAAS,CAAE,EAC1BD,CACT,CAMA,aAAa,EAAG,CACd,GAAI,CAAC,KAAK,UAAS,EAAI,MAAO,GAG9B,GAAI,EAAE,OAAS,WAAa,EAAE,eAAe,MAAQ,SACnD,YAAK,OAAM,EACJ,GAGT,OAAQ,KAAK,OAAM,CACjB,IAAK,WACH,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,EAAG,IAAI,EAC/D,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,gBAAgB,CAAC,EAC3D,MACF,IAAK,WACH,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,EAAG,KAAK,SAAS,EACzE,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,gBAAgB,CAAC,EAC3D,MACF,IAAK,eACH,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,YAAY,EAAG,KAAK,SAAS,EACvE,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,CAAC,EACzD,MACF,IAAK,eACH,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,YAAY,EAAG,KAAK,SAAS,EACvE,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,CAAC,EACzD,KACR,CACI,MAAO,EACT,CAMA,cAAc,EAAG6F,EAAa,CAC5B,MAAM/F,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAGjB,KAAK,iBAAiB,MAAK,EAC3B,KAAK,YAAY,MAAK,EACtB,KAAK,mBAAkB,EAEvB,MAAMM,EAAM,KAAK,gBAAgB,EAAGyF,CAAW,EAC/C,GAAIzF,EAAK,CACP,MAAM0F,EAAQ,KAAK,SAAW,WAAaT,GAAcC,GACnDjF,EAAQD,EAAI,QAAQ,MAAK,EAC/BC,EAAM,IAAI,kBAAmByF,CAAK,EAClC,KAAK,iBAAiB,WAAWzF,CAAK,EACtCP,EAAI,iBAAgB,EAAG,MAAM,OAAS,SACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,gBAAgB,EAAG,CACjB,MAAMM,EAAM,KAAK,gBAAgB,EAAG,IAAI,EACxC,OAAKA,GAEL,KAAK,UAAYA,EAAI,QACrB,KAAK,SAAWA,EAAI,OACpB,KAAK,OAAS,WAEd,KAAK,mBAAkB,EAChB,IAPU,EAQnB,CAEA,gBAAgB,EAAG,CACjB,MAAMA,EAAM,KAAK,gBAAgB,EAAG,KAAK,SAAS,EAClD,OAAKA,GAEL,KAAK,UAAYA,EAAI,QACrB,KAAK,SAAWA,EAAI,OACpB,KAAK,OAAS,eAEd,KAAK,mBAAkB,EACvB,KAAK,OAAM,EAAG,iBAAgB,EAAG,MAAM,OAAS,YACzC,IARU,EASnB,CAMA,gBAAgB,EAAGyF,EAAa,CAC9B,IAAIvF,EAAO,KACPC,EAAW,KAAK,cAAgB,EAEpC,UAAWC,KAAU,KAAK,cAAe,CACvC,MAAMC,EAAOD,EAAO,8BAA8B,EAAE,UAAU,EAE9D,GADI,CAACC,GACDoF,GAAepF,IAASoF,EAAa,SACzC,MAAMnF,EAAOD,EAAK,YAAW,EAC7B,GAAI,CAACC,EAAM,SACX,MAAMnc,EAAOmc,EAAK,QAAO,EACzB,GAAInc,IAAS,WAAaA,IAAS,eAAgB,SAEnD,MAAMoc,EAAUD,EAAK,gBAAgB,EAAE,UAAU,EAE3CE,EADO,IAAIC,GAAW,CAAC,EAAE,WAAYF,CAAO,CAAC,EAC/B,UAAS,EAAK,EAAE,WAAW,UAAU,WAErDC,EAASL,IACXA,EAAWK,EACXN,EAAO,CAAE,QAASG,EAAM,OAAAD,EAAQ,MAAOG,CAAO,EAElD,CACA,OAAOL,CACT,CAMA,YAAY,EAAGY,EAAS,CACtB,MAAMpB,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,YAAY,MAAK,EAEtB,MAAMiG,EAAO,KAAK,oBAAoB7E,EAAS,CAAC,EAChD,GAAI6E,EAAM,CACR,MAAMC,EAAW,IAAIC,GAAQ,IAAIpF,GAAW,CAACkF,EAAK,SAAUA,EAAK,MAAM,CAAC,CAAC,EACzE,KAAK,YAAY,WAAWC,CAAQ,EACpClG,EAAI,iBAAgB,EAAG,MAAM,OAAS,WACxC,CACA,MAAO,EACT,CAEA,cAAc,EAAG,CACf,YAAK,YAAc,EAAE,WACrB,KAAK,OAAS,eACd,KAAK,YAAY,MAAK,EACf,EACT,CAEA,cAAc,EAAG,CACf,YAAK,YAAc,EAAE,WACrB,KAAK,cAAa,EACX,EACT,CAKA,oBAAoBoB,EAASnS,EAAG,CAC9B,MAAM2R,EAAOQ,EAAQ,YAAW,EAChC,IAAI1H,EACJ,GAAIkH,EAAK,QAAO,IAAO,UACrBlH,EAAOkH,EAAK,eAAc,EAAG,CAAC,UACrBA,EAAK,QAAO,IAAO,eAC5BlH,EAAOkH,EAAK,eAAc,EAAG,CAAC,EAAE,CAAC,MAEjC,QAAO,KAGT,MAAMwF,EAAanX,EAAE,WAAW,UAAU,WAC1C,IAAIwR,EAAW,IACX4F,EAAU,KACd,MAAMvT,EAAI4G,EAAK,OAAS,EAExB,QAASrX,EAAI,EAAGA,EAAIyQ,EAAGzQ,IAAK,CAC1B,MAAMoS,EAAIiF,EAAKrX,CAAC,EACVgY,EAAIX,EAAKrX,EAAI,CAAC,EACdsa,EAAKtC,EAAE,CAAC,EAAI5F,EAAE,CAAC,EAAGmI,EAAKvC,EAAE,CAAC,EAAI5F,EAAE,CAAC,EACjCqN,EAAQnF,EAAKA,EAAKC,EAAKA,EAC7B,GAAIkF,EAAQ,MAAO,SAEnB,IAAIrS,IAAMR,EAAE,WAAW,CAAC,EAAIwF,EAAE,CAAC,GAAKkI,GAAM1N,EAAE,WAAW,CAAC,EAAIwF,EAAE,CAAC,GAAKmI,GAAMkF,EAC1ErS,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAC,CAAC,EAC9B,MAAMsS,EAAQtN,EAAE,CAAC,EAAIhF,EAAIkN,EAAIqF,EAAQvN,EAAE,CAAC,EAAIhF,EAAImN,EAC1CkE,EAAS,KAAK,MAAM7R,EAAE,WAAW,CAAC,EAAI8S,IAAU,GAAK9S,EAAE,WAAW,CAAC,EAAI+S,IAAU,CAAC,EAAIoE,EAExFtF,EAASL,IACXA,EAAWK,EACXuF,EAAU,CAAE,SAAU5R,EAAG,OAAQ4F,CAAC,EAEtC,CACA,OAAOoG,GAAY,KAAK,cAAgB4F,EAAU,IACpD,CAMA,eAAgB,CACd,MAAM9E,EAAW,KAAK,UAChBE,EAAW,KAAK,UAChB6E,EAAU,KAAK,SACfC,EAAU,KAAK,SAGfC,EAAQjF,EAAS,YAAW,EAC5BkF,EAAQhF,EAAS,YAAW,EAC5BJ,EAAUmF,EAAM,QAAO,IAAO,UAAYA,EAAM,iBAAmBA,EAAM,eAAc,EAAG,CAAC,EAC3FlF,EAAUmF,EAAM,QAAO,IAAO,UAAYA,EAAM,iBAAmBA,EAAM,eAAc,EAAG,CAAC,EAE3F7hB,EAASuf,GAAc9C,EAASC,EAAS,KAAK,YAAa,KAAK,YAAa,KAAK,UAAU,EAElG,GAAI,CAAC1c,EAAO,OAAQ,CAClBma,EAAUna,EAAO,OAAS,sDAAuD,QAAS,GAAI,EAE9F,KAAK,YAAc,KACnB,KAAK,YAAc,KACnB,KAAK,OAAS,eACd,KAAK,YAAY,MAAK,EACtB,MACF,CAGA,MAAM8hB,EAAgBnF,EAAS,MAAK,EACpCmF,EAAc,YAAY,IAAIlF,GAAY5c,EAAO,MAAM,CAAC,EACxD8hB,EAAc,SAASb,EAAW,EAGlC,MAAMc,EAAU,CACd,KAAM,cACN,SAAU,CAACpF,EAAUE,CAAQ,EAC7B,OAAQiF,CACd,EACI,KAAK,cAAcC,CAAO,EAC1BL,EAAQ,cAAc,CAAE,GAAGK,EAAS,EAChCJ,IAAYD,GACdC,EAAQ,cAAc,CAAE,GAAGI,EAAS,EAItCL,EAAQ,cAAc/E,CAAQ,EAC9BgF,EAAQ,cAAc9E,CAAQ,EAC9B6E,EAAQ,WAAWI,CAAa,EAGhC,MAAME,EAAW,CACf,KAAM,aACN,SAAU,CAACrF,EAAUE,CAAQ,EAC7B,OAAQiF,CACd,EACI,KAAK,cAAcE,CAAQ,EAC3BN,EAAQ,cAAc,CAAE,GAAGM,EAAU,EACjCL,IAAYD,GACdC,EAAQ,cAAc,CAAE,GAAGK,EAAU,EAIvC,MAAMC,EAAYtF,EAAS,IAAI,YAAY,IAAM,SAC3CuF,EAAYrF,EAAS,IAAI,YAAY,IAAM,SAC7CoF,GAAaC,GACf,KAAK,cAAc,CACjB,KAAM,eACN,OAAQJ,EACR,OAAQnF,EAAS,cAAa,EAC9B,OAAQE,EAAS,cAAa,EAC9B,WAAY,KAAK,WACzB,CAAO,EACD1C,EAAU,qDAAsD,SAAS,GAEzEA,EAAU,gCAAiC,SAAS,EAItD,KAAK,OAAM,CACb,CASA,oBAAqB,CAEnB,MAAMgI,EAAW,GAMjB,GALA,KAAK,iBAAiB,YAAW,EAAG,QAAS/U,GAAM,CAC7CA,EAAE,IAAI,YAAY,GAAG+U,EAAS,KAAK/U,CAAC,CAC1C,CAAC,EACD+U,EAAS,QAAS/U,GAAM,KAAK,iBAAiB,cAAcA,CAAC,CAAC,EAE1D,KAAK,UAAW,CAClB,MAAMgV,EAAS,KAAK,UAAU,MAAK,EACnCA,EAAO,IAAI,kBAAmBvB,EAAO,EACrCuB,EAAO,IAAI,aAAc,EAAI,EAC7B,KAAK,iBAAiB,WAAWA,CAAM,CACzC,CACA,GAAI,KAAK,UAAW,CAClB,MAAMC,EAAS,KAAK,UAAU,MAAK,EACnCA,EAAO,IAAI,kBAAmBtB,EAAO,EACrCsB,EAAO,IAAI,aAAc,EAAI,EAC7B,KAAK,iBAAiB,WAAWA,CAAM,CACzC,CACF,CAMA,QAAS,CACP,KAAK,OAAS,WACd,KAAK,UAAY,KACjB,KAAK,SAAW,KAChB,KAAK,UAAY,KACjB,KAAK,SAAW,KAChB,KAAK,YAAc,KACnB,KAAK,YAAc,KACnB,KAAK,iBAAiB,MAAK,EAC3B,KAAK,YAAY,MAAK,EAEtB,MAAMjH,EAAM,KAAK,OAAM,EACnBA,IACFA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAE1C,CACF,CC3cA,SAAS5F,GAAM3F,EAAG4F,EAAG,CACnB,OAAQ5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,GAAK5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,IAAM,CAC/C,CAKA,SAASZ,GAAWC,EAAM,CACxB,IAAIC,EAAO,EACX,QAAStX,EAAI,EAAGyQ,EAAI4G,EAAK,OAAQrX,EAAIyQ,EAAI,EAAGzQ,IAC1CsX,GAAQD,EAAKrX,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,EAAI,CAAC,EAAE,CAAC,EAAIqX,EAAKrX,CAAC,EAAE,CAAC,EAElE,OAAOsX,EAAO,CAChB,CAKA,SAASuN,GAAYhL,EAAQ,CAC3B,IAAIvC,EAAO,KAAK,IAAIF,GAAWyC,EAAO,CAAC,CAAC,CAAC,EACzC,QAAS7Z,EAAI,EAAGA,EAAI6Z,EAAO,OAAQ7Z,IACjCsX,GAAQ,KAAK,IAAIF,GAAWyC,EAAO7Z,CAAC,CAAC,CAAC,EAExC,OAAOsX,CACT,CAUA,SAASwN,GAAYzN,EAAM,CACzB,MAAM5G,EAAI4G,EAAK,OAAS,EACxB,IAAI0N,EAAU,GACVC,EAAQ,EAEZ,QAAShlB,EAAI,EAAGA,EAAIyQ,EAAGzQ,IAAK,CAC1B,MAAM,EAAI+X,GAAMV,EAAKrX,CAAC,EAAGqX,EAAKrX,EAAI,CAAC,CAAC,EAChC,EAAI+kB,IACNA,EAAU,EACVC,EAAQhlB,EAEZ,CAEA,MAAMqa,EAAKhD,EAAK2N,CAAK,EACfzO,EAAKc,EAAK2N,EAAQ,CAAC,EACnBxK,EAAM,KAAK,KAAKuK,CAAO,EACvBE,EAAQ,EAAE1O,EAAG,CAAC,EAAI8D,EAAG,CAAC,GAAKG,GAAMjE,EAAG,CAAC,EAAI8D,EAAG,CAAC,GAAKG,CAAG,EAErD0K,EAAO,CAAC,CAACD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,EAEjC,MAAO,CAAE,GAAA5K,EAAI,GAAA9D,EAAI,MAAA0O,EAAO,KAAAC,CAAI,CAC9B,CAQA,SAASC,GAAgBC,EAAQH,EAAOC,EAAM9X,EAAGiY,EAAQ,CACvD,MAAMhJ,EAAK+I,EAAO,CAAC,EAAIhY,EAAI6X,EAAM,CAAC,EAC5B3I,EAAK8I,EAAO,CAAC,EAAIhY,EAAI6X,EAAM,CAAC,EAClC,MAAO,CACL,CAAC5I,EAAKgJ,EAASH,EAAK,CAAC,EAAG5I,EAAK+I,EAASH,EAAK,CAAC,CAAC,EAC7C,CAAC7I,EAAKgJ,EAASH,EAAK,CAAC,EAAG5I,EAAK+I,EAASH,EAAK,CAAC,CAAC,CACjD,CACA,CAMA,SAASI,GAAUzL,EAAQuL,EAAQH,EAAO,CACxC,MAAM5N,EAAOwC,EAAO,CAAC,EACfpJ,EAAI4G,EAAK,OAAS,EACxB,IAAIkO,EAAK,EAAGC,EAAK,EACjB,QAASxlB,EAAI,EAAGA,EAAIyQ,EAAGzQ,IACrBulB,GAAMlO,EAAKrX,CAAC,EAAE,CAAC,EACfwlB,GAAMnO,EAAKrX,CAAC,EAAE,CAAC,EAEjB,MAAMqc,EAAKkJ,EAAK9U,EAAI2U,EAAO,CAAC,EACtB9I,EAAKkJ,EAAK/U,EAAI2U,EAAO,CAAC,EAC5B,OAAO/I,EAAK4I,EAAM,CAAC,EAAI3I,EAAK2I,EAAM,CAAC,CACrC,CAcO,SAASQ,GAAc5K,EAAepK,EAAGiV,EAAY,CAC1D,GAAI,CAAC,OAAO,UAAUjV,CAAC,GAAKA,EAAI,EAC9B,MAAO,CAAE,OAAQ,KAAM,MAAO,iDAAiD,EAEjF,GAAIA,IAAM,EACR,MAAO,CAAE,OAAQ,CAACoK,CAAa,CAAC,EAGlC,MAAMxD,EAAOwD,EAAc,CAAC,EAG5B,GAFkBgK,GAAYhK,CAAa,EAE3B,KACd,MAAO,CAAE,OAAQ,KAAM,MAAO,iCAAiC,EAIjE,IAAIR,EAAI4K,EAAOC,EACf,GAAIQ,GAAcA,EAAW,SAAW,EAAG,CACzCrL,EAAKqL,EAAW,CAAC,EACjB,MAAMpL,EAAKoL,EAAW,CAAC,EAAE,CAAC,EAAIA,EAAW,CAAC,EAAE,CAAC,EACvCnL,EAAKmL,EAAW,CAAC,EAAE,CAAC,EAAIA,EAAW,CAAC,EAAE,CAAC,EACvClL,EAAM,KAAK,KAAKF,EAAKA,EAAKC,EAAKA,CAAE,EACvC,GAAIC,EAAM,MACR,MAAO,CAAE,OAAQ,KAAM,MAAO,gCAAgC,EAEhEyK,EAAQ,CAAC3K,EAAKE,EAAKD,EAAKC,CAAG,EAC3B0K,EAAO,CAAC,CAACD,EAAM,CAAC,EAAGA,EAAM,CAAC,CAAC,CAC7B,KAAO,CAEL,MAAMrB,EAAOkB,GAAYzN,CAAI,EAC7BgD,EAAKuJ,EAAK,GACVqB,EAAQrB,EAAK,MACbsB,EAAOtB,EAAK,IACd,CACA,MAAMwB,EAAS/K,EAGTsL,EAAStO,EAAK,OAAS,EAE7B,QAASrX,EAAI,EAAGA,EAAI2lB,EAAQ3lB,IAAK,CAC/B,MAAMsa,EAAKjD,EAAKrX,CAAC,EAAE,CAAC,EAAIolB,EAAO,CAAC,EAC1B7K,EAAKlD,EAAKrX,CAAC,EAAE,CAAC,EAAIolB,EAAO,CAAC,EACtB9K,EAAK2K,EAAM,CAAC,EAAI1K,EAAK0K,EAAM,CAAC,CAGxC,CAGA,IAAIW,EAAU,IAAUC,EAAU,KAClC,QAAS7lB,EAAI,EAAGA,EAAI2lB,EAAQ3lB,IAAK,CAC/B,MAAMsa,EAAKjD,EAAKrX,CAAC,EAAE,CAAC,EAAIolB,EAAO,CAAC,EAC1B7K,EAAKlD,EAAKrX,CAAC,EAAE,CAAC,EAAIolB,EAAO,CAAC,EAC1BrU,EAAIuJ,EAAK4K,EAAK,CAAC,EAAI3K,EAAK2K,EAAK,CAAC,EAChCnU,EAAI6U,IAASA,EAAU7U,GACvBA,EAAI8U,IAASA,EAAU9U,EAC7B,CACA,MAAMsU,GAAUQ,EAAUD,GAAW,IAG/BE,EAAS,GACf,IAAIC,EAAYlL,EACZmL,EAAiBvV,EAErB,QAASzQ,EAAI,EAAGA,EAAIyQ,EAAI,EAAGzQ,IAAK,CAC9B,MAAMimB,EAAgBpB,GAAYkB,CAAS,EACrCG,EAAaD,EAAgBD,EAG7BG,EAAUJ,EAAU,CAAC,EACrBK,EAAOD,EAAQ,OAAS,EAC9B,IAAIE,EAAO,IAAUC,EAAO,KAC5B,QAAS5O,EAAI,EAAGA,EAAI0O,EAAM1O,IAAK,CAC7B,MAAM4C,EAAK6L,EAAQzO,CAAC,EAAE,CAAC,EAAI0N,EAAO,CAAC,EAC7B7K,GAAK4L,EAAQzO,CAAC,EAAE,CAAC,EAAI0N,EAAO,CAAC,EAC7BhY,EAAIkN,EAAK2K,EAAM,CAAC,EAAI1K,GAAK0K,EAAM,CAAC,EAClC7X,EAAIiZ,IAAMA,EAAOjZ,GACjBA,EAAIkZ,IAAMA,EAAOlZ,EACvB,CAGA,IAAImZ,EAAKF,EACLG,EAAKF,EAELG,EAAY,KACZC,EAAgB,KAChBC,EAAY,IAEhB,QAASC,EAAO,EAAGA,EAAO,GAAIA,IAAQ,CACpC,MAAMC,GAAON,EAAKC,GAAM,EAClBtO,GAAOiN,GAAgBC,EAAQH,EAAOC,EAAM2B,EAAKxB,CAAM,EACvD9iB,EAASqY,GAAmBmL,EAAW7N,EAAI,EAEjD,GAAI,CAAC3V,EAAQ,CAGX,MAAMukB,GAASN,EAAKD,GAAM,IACpBQ,EAAQ5B,GAAgBC,EAAQH,EAAOC,EAAM2B,EAAMC,EAAOzB,CAAM,EAChE2B,GAAUpM,GAAmBmL,EAAWgB,CAAK,EACnD,GAAIC,GAAS,CACX,KAAM,CAACC,GAAOC,EAAK,EAAIF,GACjBG,GAAK7B,GAAU2B,GAAO7B,EAAQH,CAAK,EACnCmC,GAAK9B,GAAU4B,GAAO9B,EAAQH,CAAK,EACnCoC,GAAYF,GAAKC,GAAKH,GAAQC,GAC9BI,GAAWH,GAAKC,GAAKF,GAAQD,GAC7BM,GAAW1C,GAAYwC,EAAS,EAChC9c,GAAM,KAAK,IAAIgd,GAAWrB,CAAU,EACtC3b,GAAMoc,IACRA,EAAYpc,GAEZkc,EAAYY,GACZX,EAAgBY,GAEpB,CAEA,MAAME,GAAQrC,GAAgBC,EAAQH,EAAOC,EAAM2B,EAAMC,EAAOzB,CAAM,EAChEoC,GAAU7M,GAAmBmL,EAAWyB,EAAK,EACnD,GAAIC,GAAS,CACX,KAAM,CAACR,GAAOC,EAAK,EAAIO,GACjBN,GAAK7B,GAAU2B,GAAO7B,EAAQH,CAAK,EACnCmC,GAAK9B,GAAU4B,GAAO9B,EAAQH,CAAK,EACnCoC,GAAYF,GAAKC,GAAKH,GAAQC,GAC9BI,GAAWH,GAAKC,GAAKF,GAAQD,GAC7BM,GAAW1C,GAAYwC,EAAS,EAChC9c,GAAM,KAAK,IAAIgd,GAAWrB,CAAU,EACtC3b,GAAMoc,IACRA,EAAYpc,GAEZkc,EAAYY,GACZX,EAAgBY,GAEpB,CAEAf,EAAKM,EACL,QACF,CAEA,KAAM,CAACI,GAAOC,CAAK,EAAI3kB,EACjB4kB,GAAK7B,GAAU2B,GAAO7B,EAAQH,CAAK,EACnCmC,GAAK9B,GAAU4B,EAAO9B,EAAQH,CAAK,EACnCoC,EAAYF,GAAKC,GAAKH,GAAQC,EAC9BI,EAAWH,GAAKC,GAAKF,EAAQD,GAC7BM,EAAW1C,GAAYwC,CAAS,EAEhC9c,GAAM,KAAK,IAAIgd,EAAWrB,CAAU,EAS1C,GARI3b,GAAMoc,IACRA,EAAYpc,GAEZkc,EAAYY,EACZX,EAAgBY,GAId/c,GAAM0b,EAAgB,KAAO,MAG7BsB,EAAWrB,EACbK,EAAKM,EAELL,EAAKK,CAET,CAEA,GAAI,CAACJ,GAAa,CAACC,EACjB,MAAO,CACL,OAAQ,KACR,MAAO,wCAAwC1mB,EAAI,CAAC,OAAOyQ,CAAC,8DACpE,EAGIqV,EAAO,KAAKW,CAAS,EACrBV,EAAYW,EACZV,GACF,CAGA,OAAAF,EAAO,KAAKC,CAAS,EAEd,CAAE,OAAAD,CAAM,CACjB,CC7QA,MAAM7I,GAAkB,IAAIC,EAAM,CAChC,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CACnD,CAAC,EAGKmG,GAAa,IAAIrG,EAAM,CAC3B,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,SAAU,CAAC,GAAI,CAAC,CAAC,CAAE,CACtE,CAAC,EAKD,SAASuK,GAAY,EAAG,CACtB,MAAMC,EAAS,GACf,QAAS3nB,EAAI,EAAGA,EAAI,EAAGA,IAAK,CAC1B,MAAM4nB,EAAM,KAAK,MAAO5nB,EAAI,IAAO,CAAC,EACpC2nB,EAAO,KAAK,CACV,OAAQ,OAAOC,CAAG,cAClB,KAAM,QAAQA,CAAG,mBACvB,CAAK,CACH,CACA,OAAOD,CACT,CAEO,MAAME,WAAiCrK,EAA2B,CAOvE,YAAYjY,EAAU,GAAI,CACxB,MAAM,CACJ,YAAcqH,GAAM,KAAK,aAAaA,CAAC,CAC7C,CAAK,EAED,KAAK,cAAgBrH,EAAQ,cAAgB,GAC7C,KAAK,SAAWA,EAAQ,QACnB,MAAM,QAAQA,EAAQ,OAAO,EAAIA,EAAQ,QAAU,CAACA,EAAQ,OAAO,EACpE,KAGJ,KAAK,OAAS,SACd,KAAK,iBAAmB,KACxB,KAAK,gBAAkB,KACvB,KAAK,cAAgB,KACrB,KAAK,iBAAmB,KAGxB,KAAK,eAAiB,IAAIkY,EAAa,CAAE,gBAAiB,EAAK,CAAE,EACjE,KAAK,cAAgB,IAAIC,EAAY,CACnC,OAAQ,KAAK,eACb,uBAAwB,GACxB,MAAOT,EACb,CAAK,EAGD,KAAK,YAAc,IAAIQ,EAAa,CAAE,gBAAiB,EAAK,CAAE,EAC9D,KAAK,WAAa,IAAIC,EAAY,CAChC,OAAQ,KAAK,YACb,uBAAwB,GACxB,MAAO6F,EACb,CAAK,CACH,CAMA,OAAO5F,EAAK,CACN,KAAK,WACP,KAAK,OAAM,EAAG,YAAY,KAAK,aAAa,EAC5C,KAAK,OAAM,EAAG,YAAY,KAAK,UAAU,GAE3C,MAAM,OAAOA,CAAG,EACZA,IACF,KAAK,cAAc,OAAOA,CAAG,EAC7B,KAAK,WAAW,OAAOA,CAAG,EAE9B,CAEA,UAAUC,EAAQ,CAChB,MAAM,UAAUA,CAAM,EACjBA,GACH,KAAK,OAAM,CAEf,CAMA,aAAc,CACZ,GAAI,KAAK,SAAU,OAAO,KAAK,SAC/B,GAAI,CAAC,KAAK,OAAM,EAAI,MAAO,GAC3B,MAAMC,EAAU,GACVC,EAAWC,GAAW,CAC1BA,EAAO,QAASC,GAAU,CACpBA,EAAM,eACJA,EAAM,WAAaA,EAAM,UAAS,YAAcP,EAClDI,EAAQ,KAAKG,EAAM,WAAW,EACrBA,EAAM,WACfF,EAAQE,EAAM,WAAW,EAG/B,CAAC,CACH,EACA,OAAAF,EAAQ,KAAK,OAAM,EAAG,UAAS,CAAE,EAC1BD,CACT,CAMA,aAAa,EAAG,CACd,GAAI,CAAC,KAAK,UAAS,EAAI,MAAO,GAG9B,GAAI,EAAE,OAAS,WAAa,EAAE,eAAe,MAAQ,SACnD,OAAI,KAAK,SAAW,OAClB,KAAK,aAAY,EAEjB,KAAK,OAAM,EAEN,GAGT,GAAI,KAAK,SAAW,SAAU,CAC5B,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,cAAc,CAAC,EACzD,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,eAAe,CAAC,CAC5D,CAEA,GAAI,KAAK,SAAW,OAAQ,CAC1B,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,YAAY,CAAC,EACvD,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,aAAa,CAAC,CAC1D,CAEA,GAAI,KAAK,SAAW,OAAQ,CAC1B,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,YAAY,CAAC,EACvD,GAAI,EAAE,OAAS,cAAe,OAAO,KAAK,aAAa,CAAC,CAC1D,CAEA,MAAO,EACT,CAMA,cAAc,EAAG,CACf,MAAMF,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,eAAe,MAAK,EAEzB,MAAMM,EAAM,KAAK,gBAAgB,CAAC,EAClC,GAAIA,EAAK,CACP,MAAMC,EAAQD,EAAI,QAAQ,MAAK,EAC/B,KAAK,eAAe,WAAWC,CAAK,EACpCP,EAAI,iBAAgB,EAAG,MAAM,OAAS,SACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,eAAe,EAAG,CAChB,MAAMM,EAAM,KAAK,gBAAgB,CAAC,EAClC,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,iBAAmBA,EAAI,QAC5B,KAAK,gBAAkBA,EAAI,OAG3B,KAAK,eAAe,MAAK,EACzB,MAAMC,EAAQD,EAAI,QAAQ,MAAK,EAC/B,OAAAC,EAAM,IAAI,aAAc,EAAI,EAC5B,KAAK,eAAe,WAAWA,CAAK,EAEpC,KAAK,OAAS,OACdxB,EAAU,kCAAmC,OAAQ,GAAI,EAClD,EACT,CAEA,gBAAgB,EAAG,CACjB,IAAIyB,EAAO,KACPC,EAAW,KAAK,cAAgB,EAEpC,UAAWC,KAAU,KAAK,cAAe,CACvC,MAAMC,EAAOD,EAAO,8BAA8B,EAAE,UAAU,EAC9D,GAAI,CAACC,EAAM,SACX,MAAMC,EAAOD,EAAK,YAAW,EAC7B,GAAI,CAACC,EAAM,SACX,MAAMnc,EAAOmc,EAAK,QAAO,EACzB,GAAInc,IAAS,WAAaA,IAAS,eAAgB,SAEnD,MAAMoc,EAAUD,EAAK,gBAAgB,EAAE,UAAU,EAE3CE,EADO,IAAIC,GAAW,CAAC,EAAE,WAAYF,CAAO,CAAC,EAC/B,UAAS,EAAK,EAAE,WAAW,UAAU,WAErDC,EAASL,IACXA,EAAWK,EACXN,EAAO,CAAE,QAASG,EAAM,OAAAD,CAAM,EAElC,CACA,OAAOF,CACT,CAMA,YAAY,EAAG,CACb,MAAMR,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,YAAY,MAAK,EAEtB,MAAMiG,EAAO,KAAK,oBAAoB,KAAK,iBAAkB,CAAC,EAC9D,GAAIA,EAAM,CACR,MAAMC,EAAW,IAAIC,GAAQ,IAAIpF,GAAW,CAACkF,EAAK,SAAUA,EAAK,MAAM,CAAC,CAAC,EACzE,KAAK,YAAY,WAAWC,CAAQ,EACpClG,EAAI,iBAAgB,EAAG,MAAM,OAAS,WACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,aAAa,EAAG,CACd,MAAMiG,EAAO,KAAK,oBAAoB,KAAK,iBAAkB,CAAC,EAC9D,GAAI,CAACA,EAAM,MAAO,GAElB,KAAK,cAAgB,CAACA,EAAK,SAAUA,EAAK,MAAM,EAChD,KAAK,YAAY,MAAK,EAEtB,KAAK,OAAS,OAId,MAAMkE,EADO,KAAK,iBAAiB,YAAW,EAC7B,UAAS,EACpBC,EAAS,EAAED,EAAI,CAAC,EAAIA,EAAI,CAAC,GAAK,GAAIA,EAAI,CAAC,EAAIA,EAAI,CAAC,GAAK,CAAC,EAE5D,YAAK,cAAc,CACjB,KAAM,aACN,QAAS,KAAK,iBACd,OAAQ,KAAK,gBACb,WAAYC,CAClB,CAAK,EAEM,EACT,CAKA,oBAAoBhJ,EAASnS,EAAG,CAC9B,MAAM2R,EAAOQ,EAAQ,YAAW,EAChC,IAAI1H,EACJ,GAAIkH,EAAK,QAAO,IAAO,UACrBlH,EAAOkH,EAAK,eAAc,EAAG,CAAC,UACrBA,EAAK,QAAO,IAAO,eAC5BlH,EAAOkH,EAAK,eAAc,EAAG,CAAC,EAAE,CAAC,MAEjC,QAAO,KAGT,MAAMwF,EAAanX,EAAE,WAAW,UAAU,WAC1C,IAAIwR,EAAW,IACX4F,EAAU,KACd,MAAMvT,EAAI4G,EAAK,OAAS,EAExB,QAASrX,EAAI,EAAGA,EAAIyQ,EAAGzQ,IAAK,CAC1B,MAAMoS,EAAIiF,EAAKrX,CAAC,EACVgY,EAAIX,EAAKrX,EAAI,CAAC,EACdsa,EAAKtC,EAAE,CAAC,EAAI5F,EAAE,CAAC,EAAGmI,EAAKvC,EAAE,CAAC,EAAI5F,EAAE,CAAC,EACjCqN,EAAQnF,EAAKA,EAAKC,EAAKA,EAC7B,GAAIkF,EAAQ,MAAO,SAEnB,IAAIrS,IAAMR,EAAE,WAAW,CAAC,EAAIwF,EAAE,CAAC,GAAKkI,GAAM1N,EAAE,WAAW,CAAC,EAAIwF,EAAE,CAAC,GAAKmI,GAAMkF,EAC1ErS,EAAI,KAAK,IAAI,EAAG,KAAK,IAAI,EAAGA,CAAC,CAAC,EAC9B,MAAMsS,EAAQtN,EAAE,CAAC,EAAIhF,EAAIkN,EAAIqF,EAAQvN,EAAE,CAAC,EAAIhF,EAAImN,EAC1CkE,EAAS,KAAK,MAAM7R,EAAE,WAAW,CAAC,EAAI8S,IAAU,GAAK9S,EAAE,WAAW,CAAC,EAAI+S,IAAU,CAAC,EAAIoE,EAExFtF,EAASL,IACXA,EAAWK,EACXuF,EAAU,CAAE,SAAU5R,EAAG,OAAQ4F,CAAC,EAEtC,CACA,OAAOoG,GAAY,KAAK,cAAgB4F,EAAU,IACpD,CAYA,cAAcvT,EAAG,CACf,GAAI,KAAK,SAAW,QAAU,CAAC,KAAK,iBAAkB,OAEtD,MAAMsO,EAAU,KAAK,iBACfV,EAAS,KAAK,gBACdE,EAAOQ,EAAQ,YAAW,EAEhC,IAAIlE,EACA0D,EAAK,QAAO,IAAO,UACrB1D,EAAgB0D,EAAK,eAAc,EAC1BA,EAAK,QAAO,IAAO,iBAC5B1D,EAAgB0D,EAAK,eAAc,EAAG,CAAC,GAGzC,MAAMhc,EAASkjB,GAAc5K,EAAepK,EAAG,KAAK,aAAa,EAEjE,GAAI,CAAClO,EAAO,OAAQ,CAClBma,EAAUna,EAAO,OAAS,mBAAoB,QAAS,GAAI,EAC3D,KAAK,OAAM,EACX,MACF,CAGA,MAAMolB,EAASD,GAAYjX,CAAC,EACtBuX,EAAczlB,EAAO,OAAO,IAAI,CAACsX,EAAQ7Z,IAAM,CACnD,MAAM,EAAI+e,EAAQ,MAAK,EACvB,SAAE,YAAY,IAAII,GAAYtF,CAAM,CAAC,EACrC,EAAE,SAAS,IAAIqD,EAAM,CACnB,OAAQ,IAAIC,EAAO,CAAE,MAAOwK,EAAO3nB,CAAC,EAAE,OAAQ,MAAO,IAAK,EAC1D,KAAM,IAAIod,EAAK,CAAE,MAAOuK,EAAO3nB,CAAC,EAAE,KAAM,CAChD,CAAO,CAAC,EACK,CACT,CAAC,EAGKskB,EAAU,CACd,KAAM,eACN,SAAUvF,EACV,SAAUiJ,CAChB,EACI,KAAK,cAAc1D,CAAO,EAC1BjG,EAAO,cAAc,CAAE,GAAGiG,EAAS,EAGnCjG,EAAO,cAAcU,CAAO,EAC5B,UAAWpP,KAAKqY,EACd3J,EAAO,WAAW1O,CAAC,EAIrB,MAAM4U,EAAW,CACf,KAAM,cACN,SAAUxF,EACV,SAAUiJ,CAChB,EACI,KAAK,cAAczD,CAAQ,EAC3BlG,EAAO,cAAc,CAAE,GAAGkG,EAAU,EAGnBxF,EAAQ,IAAI,YAAY,IAAM,UAE7C,KAAK,iBAAmBiJ,EACxB,KAAK,OAAS,OACdtL,EAAU,8DAA+D,OAAQ,GAAI,EAErF,KAAK,cAAc,CACjB,KAAM,gBACN,SAAUsL,EACV,cAAejJ,EAAQ,cAAa,EACpC,OAAAV,CACR,CAAO,IAED3B,EAAU,wBAAwBjM,CAAC,iBAAkB,SAAS,EAC9D,KAAK,OAAM,EAEf,CAMA,YAAY,EAAG,CACb,MAAMkN,EAAM,KAAK,OAAM,EACvB,GAAI,CAACA,EAAK,MAAO,GAEjB,KAAK,eAAe,MAAK,EAGzB,MAAMM,EAAM,KAAK,qBAAqB,CAAC,EACvC,GAAIA,EAAK,CACP,MAAMC,EAAQD,EAAI,MAAK,EACvB,KAAK,eAAe,WAAWC,CAAK,EACpCP,EAAI,iBAAgB,EAAG,MAAM,OAAS,SACxC,MACEA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAExC,MAAO,EACT,CAEA,aAAa,EAAG,CACd,MAAMM,EAAM,KAAK,qBAAqB,CAAC,EACvC,OAAKA,GAEL,KAAK,cAAc,CACjB,KAAM,aACN,OAAQA,EACR,SAAU,KAAK,gBACrB,CAAK,EAED,KAAK,OAAM,EACJ,IATU,EAUnB,CAKA,qBAAqB,EAAG,CACtB,GAAI,CAAC,KAAK,iBAAkB,OAAO,KACnC,IAAIE,EAAO,KACPC,EAAW,KAAK,cAAgB,EAEpC,UAAWE,KAAQ,KAAK,iBAAkB,CACxC,MAAMC,EAAOD,EAAK,YAAW,EAC7B,GAAI,CAACC,EAAM,SACX,MAAMC,EAAUD,EAAK,gBAAgB,EAAE,UAAU,EAE3CE,EADO,IAAIC,GAAW,CAAC,EAAE,WAAYF,CAAO,CAAC,EAC/B,UAAS,EAAK,EAAE,WAAW,UAAU,WACrDC,EAASL,IACXA,EAAWK,EACXN,EAAOG,EAEX,CACA,OAAOH,CACT,CAMA,cAAe,CACb,KAAK,cAAc,CAAE,KAAM,cAAc,CAAE,EAC3C,KAAK,OAAM,CACb,CAMA,QAAS,CACP,KAAK,OAAS,SACd,KAAK,iBAAmB,KACxB,KAAK,gBAAkB,KACvB,KAAK,cAAgB,KACrB,KAAK,iBAAmB,KACxB,KAAK,eAAe,MAAK,EACzB,KAAK,YAAY,MAAK,EAEtB,MAAMR,EAAM,KAAK,OAAM,EACnBA,IACFA,EAAI,iBAAgB,EAAG,MAAM,OAAS,GAE1C,CACF,CCjZO,MAAMsK,EAAQ,CACnB,YAAYC,EAAU3iB,EAAU,GAAI,CAClC,KAAK,QAAUA,EACf,KAAK,aAAe,IAAIkY,EACxB,KAAK,eAAiB,GAItB,KAAK,eAAiB,CACpB,QAAW,CAAE,MAAO,KAAM,MAAO,WACjC,MAAS,CAAE,MAAO,KAAM,MAAO,eAC/B,OAAU,CAAE,MAAO,KAAM,MAAO,UAChC,OAAU,CAAE,MAAO,KAAM,MAAO,mBAChC,OAAU,CAAE,MAAO,KAAM,MAAO,UAChC,MAAS,CAAE,MAAO,KAAM,MAAO,QAAQ,EAIzC,KAAK,SAAYhQ,GAAa,CAC5B,MAAM0a,EAAM,KAAK,eAAe1a,CAAQ,EACxC,OAAO0a,EAAMA,EAAI,MAAQ,IAC3B,EAGA,KAAK,uBAAyB,IACrB,OAAO,QAAQ,KAAK,cAAc,EACtC,IAAI,CAAC,CAAC1c,EAAK,CAAE,MAAA2c,EAAO,MAAAC,CAAA,CAAO,IAC1B,kBAAkB5c,CAAG,KAAK2c,CAAK,IAAIC,CAAK,aAEzC,KAAK;AAAA,aAAgB,EAI1B,KAAK,iBAAmB,CAACD,EAAOE,EAAW,KAClC,IAAIpL,EAAM,CACf,KAAM,IAAImG,GAAK,CACb,KAAM+E,EACN,KAAM,GAAGE,CAAQ,gBACjB,aAAc,SACd,UAAW,SACX,QAAS,GACZ,EACF,EAID,KAAK,aAAe,KAAK,iBAAiB,KAAM,EAAE,EAGlD,KAAK,cAAgB,KAAK,iBAAiB,KAAM,EAAE,EAGnD,KAAK,eAAiB,GACtB,SAAW,CAAC7a,EAAU,CAAE,MAAA2a,CAAA,CAAO,IAAK,OAAO,QAAQ,KAAK,cAAc,EACpE,KAAK,eAAe3a,CAAQ,EAAI,KAAK,iBAAiB2a,EAAO,EAAE,EAIjE,MAAMG,EAAa,KAAK,iBAAiBhjB,EAAQ,SAAW,MAAM,EAIlE,KAAK,aAAe,IAAImY,EAAY,CAClC,MAAO,UACP,OAAQ,KAAK,aACb,MAAQqB,GAAY,KAAK,gBAAgBA,CAAO,EAChD,QAAS,GACV,EAGD,KAAK,aAAe,IAAIyJ,GAAW,CACjC,MAAO,WACR,EAQD,KAAK,IAAM,IAAIroB,GAAI,CACjB,OAAQ+nB,EACR,OAAQ,CACNK,EACA,KAAK,aACL,KAAK,cAEP,KAAM,IAAIE,GAAK,CACb,OAAQC,EAAWnjB,EAAQ,QAAU,CAAC,EAAG,CAAC,CAAC,EAC3C,KAAMA,EAAQ,MAAQ,EACtB,QAASA,EAAQ,SAAW,EAC5B,QAASA,EAAQ,SAAW,GAC7B,EACF,EAGD,MAAMojB,EAAgB,IAAIC,GAAc,CACtC,UAAW,GACX,UAAW,GACX,OAAQ,GACR,MAAO,GACP,OAAQ,KACT,EACD,KAAK,IAAI,WAAWD,CAAa,EAQjC,eAAe,IAAM,CACnB,MAAME,EAAMF,EAAc,SAAS,cAAc,iBAAiB,EAClE,GAAIE,EAAK,CACP,MAAMC,EAAW,IAAkC,QAAQ,OAAQ,GAAG,EACtED,EAAI,MAAM,gBAAkB,QAAQC,CAAO,6BAC7C,CACF,CAAC,EASD,IAAIC,EAAqB,GACzBJ,EAAc,GAAG,WAAa/J,GAAQ,CACpC,KAAK,uBAAuBA,EAAI,MAAOA,EAAI,EAAE,EAExCmK,IACHA,EAAqB,GACrB,eAAe,IAAM,CACnBA,EAAqB,GACrB,KAAK,4BAA4BJ,CAAa,CAChD,CAAC,EAEL,CAAC,EAID,KAAK,IAAI,YAAY,GAAG,SAAU,IAAM,CACtC,KAAK,4BAA4BA,CAAa,CAChD,CAAC,EAED,KAAK,kCAAkCA,CAAa,EAGpD,KAAK,wBAGL,KAAK,qBAGL,KAAK,SAAW,IAAIK,GAAU,CAC5B,IAAK,GACL,MAAO,EACP,KAAM,GACN,SAAU,IACX,EACD,KAAK,IAAI,WAAW,KAAK,QAAQ,EAIjC,KAAK,oBACL,KAAK,yBAGL,KAAK,uBAGL,MAAMC,EAAkB,IAAIC,GAAgB,CAC1C,YAAa,qBACb,OAAQ,IACR,UAAW,EACX,SAAU,GACV,UAAW,GAGZ,EACD,KAAK,IAAI,WAAWD,CAAe,EAGnCA,EAAgB,GAAG,SAAWzpB,GAAU,CACtC,MAAM2pB,EAAe3pB,EAAM,OAC3B,GAAI2pB,EAAc,CAEhB,MAAMnV,EAAM,WAAWmV,EAAa,GAAG,EACjClV,EAAM,WAAWkV,EAAa,GAAG,EACjCC,EAAS,CAACpV,EAAKC,CAAG,EAClBoV,EAAaX,EAAWU,CAAM,EAGpC,KAAK,WAAWpV,EAAKC,EAAK,EAAE,EAG5B,MAAM1R,EAAS,CACb,WAAA8mB,EACA,OAAAD,EACA,KAAMD,EAAa,cAAgBA,EAAa,MAAQ,UACxD,aAAAA,CAAA,EAEF,KAAK,sBAAsB,QAAQ/jB,GAAMA,EAAG7C,CAAM,CAAC,CACrD,CACF,CAAC,EAGD,KAAK,gBAAkB0mB,EACvB,KAAK,sBAAwB,GAG7B,KAAK,gBAAkB,KAGvB,KAAK,cAGL,KAAK,kBAGL,KAAK,yBAGL,KAAK,wBAGL,KAAK,0BAGL,KAAK,mBAGL,KAAK,oBAGL,KAAK,kBAAoB,GAIzB,KAAK,QAAU,KACf,KAAK,eAAiB,KACtB,KAAK,cAAgB,KACrB,KAAK,YAAc,KACnB,KAAK,eAAiB,EACxB,CAiBA,aAAc,CAEZ,KAAK,eAAiB,IAAIxL,EAC1B,KAAK,cAAgB,IAAIC,EAAY,CACnC,MAAO,WACP,OAAQ,KAAK,eACb,MAAO,IAAIR,EAAM,CACf,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,IAAK,EACnD,KAAM,IAAIC,EAAK,CAAE,MAAO,wBAAyB,EACjD,MAAO,IAAIkM,GAAO,CAChB,OAAQ,EACR,KAAM,IAAIlM,EAAK,CAAE,MAAO,UAAW,EACnC,OAAQ,IAAID,EAAO,CAAE,MAAO,OAAQ,MAAO,IAAK,EACjD,EACF,EACF,EAED,KAAK,eAAiB,IAAIqL,GAAW,CACnC,MAAO,WACP,OAAQ,CAAC,KAAK,aAAa,EAC5B,EAMD,MAAMe,EAAY,KAAK,IAAI,YACrBC,EAAaD,EAAU,WAAW,QAAQ,KAAK,YAAY,EACjEA,EAAU,SAASC,GAAc,EAAIA,EAAaD,EAAU,YAAa,KAAK,cAAc,EAI5F,KAAK,mBAAqB,IAAIE,GAAO,CACnC,UAAWC,GACX,OAAQ,CAAC3K,EAASf,IAAU,CAAC,CAACA,EAC9B,OAASA,GAAUA,aAAiBN,CAAA,CACrC,EACD,KAAK,mBAAmB,UAAU,EAAK,EACvC,KAAK,IAAI,eAAe,KAAK,kBAAkB,EAI/C,KAAK,mBAAqB,IAAIiM,GAAc,CAC1C,SAAU,KAAK,mBAAmB,aAAY,CAC/C,EACD,KAAK,mBAAmB,UAAU,EAAK,EAGvC,KAAK,UAAY,IAAIC,GACrB,KAAK,IAAI,eAAe,KAAK,SAAS,EAGtC,KAAK,QAAU,IAAIC,GAAQ,CACzB,OAAQ,KAAK,eACb,aAAc,CACZ,OAAQ,KAAK,mBACb,aAAc,KAAK,mBACnB,UAAW,GACX,SAAU,GACV,YAAa,GACb,YAAa,GACb,SAAU,GACV,OAAQ,GACR,KAAM,GACN,UAAW,GACX,MAAO,GACT,CACD,EACD,KAAK,IAAI,WAAW,KAAK,OAAO,EAOhC,KAAK,sBAIL,MAAMC,EAAW,IAAIC,GAAI,CACvB,MAAO,GAGP,UAAW,qBACX,SAAU,CACR,IAAIC,GAAO,CACT,KAAM,+CACN,UAAW,UACX,MAAO,OACP,YAAa,IAAM,CACb,KAAK,UAAU,WAAW,KAAK,UAAU,MAC/C,EACD,EACD,IAAIA,GAAO,CACT,KAAM,wCACN,UAAW,UACX,MAAO,OACP,YAAa,IAAM,CACb,KAAK,UAAU,WAAW,KAAK,UAAU,MAC/C,EACD,EACD,IAAIA,GAAO,CACT,KAAM,+BACN,UAAW,UACX,MAAO,gBACP,YAAa,IAAM,CACjB,KAAK,kBAAkB,MAAM,CAC/B,EACD,EACH,CACD,EACD,KAAK,QAAQ,WAAWF,CAAQ,EAQhC,KAAK,sBAAwB,IAAIG,GACjC,KAAK,yBAA2B,IAAI1M,GACpC,KAAK,IAAI,eAAe,KAAK,qBAAqB,EAClD,KAAK,IAAI,eAAe,KAAK,wBAAwB,EACrD,KAAK,sBAAsB,UAAU,EAAK,EAC1C,KAAK,yBAAyB,UAAU,EAAK,EAG7C,KAAK,yBAAyB,GAAG,YAAcqB,GAAQ,CACrD,MAAMsL,EAAW,CAAC,MAAO,MAAO,KAAM,WAAY,YAAa,WAAY,YAAa,IAAI,EAC5F,UAAW5L,KAAQM,EAAI,SACrB,GAAIN,IAASM,EAAI,OACjB,UAAWuL,KAASD,EACd5L,EAAK,IAAI6L,CAAK,IAAM,QACtB7L,EAAK,IAAI6L,EAAO,EAAE,CAI1B,CAAC,EAGD,KAAK,0BAA4B,IAAItC,GACrC,KAAK,IAAI,eAAe,KAAK,yBAAyB,EACtD,KAAK,0BAA0B,UAAU,EAAK,EAE9C,MAAMuC,EAAkB,IAAIC,GAAO,CACjC,KAAM,iCACN,UAAW,gBACX,MAAO,cACP,KAAM,YACN,YAAa,KAAK,sBAClB,aAAc,GACf,EACKC,EAAkB,IAAID,GAAO,CACjC,KAAM,iCACN,UAAW,mBACX,MAAO,iBACP,KAAM,eACN,YAAa,KAAK,yBACnB,EACKE,EAAoB,IAAIF,GAAO,CACnC,KAAM,qCACN,UAAW,kBACX,MAAO,iBACP,KAAM,gBACN,YAAa,KAAK,0BACnB,EAEKG,EAAc,IAAIT,GAAI,CAC1B,UAAW,GACX,eAAgB,GAChB,SAAU,CAACK,EAAiBE,EAAiBC,CAAiB,EAC/D,EAEKE,EAAoB,IAAIJ,GAAO,CACnC,UAAW,WACX,MAAO,QACP,KAAM,QACN,IAAKG,EACL,SAAW5M,GAAW,CACfA,IACH,KAAK,sBAAsB,UAAU,EAAK,EAC1C,KAAK,yBAAyB,UAAU,EAAK,EAC7C,KAAK,0BAA0B,UAAU,EAAK,EAElD,EACD,EACD,KAAK,QAAQ,WAAW6M,CAAiB,EAGzC,KAAK,0BAA0B,GAAG,aAAe7L,GAAQ,CACvD,KAAK,gBAAgBA,EAAI,QAASA,EAAI,OAAQA,EAAI,UAAU,CAC9D,CAAC,EACD,KAAK,0BAA0B,GAAG,eAAgB,IAAM,CACtD,KAAK,iBACP,CAAC,EAID,KAAK,0BAA0B,GAAG,aAAeA,GAAQ,CACvD,MAAMsL,EAAW,CAAC,MAAO,MAAO,KAAM,WAAY,YAAa,WAAY,YAAa,IAAI,EAC5F,UAAW5L,KAAQM,EAAI,SACrB,GAAIN,IAASM,EAAI,OAEjB,UAAWuL,KAASD,EACd5L,EAAK,IAAI6L,CAAK,IAAM,QACtB7L,EAAK,IAAI6L,EAAO,EAAE,CAI1B,CAAC,EAID,KAAK,yBAA2B,IAAI1G,GACpC,KAAK,IAAI,eAAe,KAAK,wBAAwB,EACrD,KAAK,yBAAyB,UAAU,EAAK,EAE7C,MAAMiH,EAAc,IAAIL,GAAO,CAC7B,KAAM,8BACN,UAAW,WACX,MAAO,iBACP,KAAM,QACN,YAAa,KAAK,yBACnB,EACD,KAAK,QAAQ,WAAWK,CAAW,EAGnC,KAAK,yBAAyB,GAAG,eAAiB9L,GAAQ,CACxD,KAAK,yBAAyBA,EAAI,OAAQA,EAAI,OAAQA,EAAI,OAAQA,EAAI,UAAU,CAClF,CAAC,EAQD,MAAM+L,EAAY,KAAK,QAAQ,QAC/B,GAAIA,GAAab,EAAS,SAAWA,EAAS,QAAQ,aAAea,EAAW,CAC9E,MAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,mBACpBD,EAAU,aAAaC,EAASd,EAAS,OAAO,CAClD,CAKA,KAAK,mBAAqB,aAAa,QAAQ,qBAAqB,IAAM,IAC1E,KAAK,YAAc,IAAIe,GAAW,CAChC,eAAgB,GAChB,YAAaC,EAAA,CACd,EACD,KAAK,IAAI,eAAe,KAAK,WAAW,EAKxC,MAAMC,EAAgB,CAAC,YAAa,WAAY,cAAe,WAAY,aAAa,EACxF,UAAWjjB,KAAQijB,EAAe,CAChC,MAAMC,EAAc,KAAK,QAAQ,eAAeljB,CAAI,EAChDkjB,GACFA,EAAY,GAAG,gBAAiB,IAAM,CAChCA,EAAY,aACd,KAAK,YAAY,mBAAmBA,CAAW,CAEnD,CAAC,CAEL,CAGI,KAAK,oBACP,KAAK,YAAY,qBAAqB,KAAK,kBAAkB,EAI/D,MAAMC,EAAgB,IAAIjB,GAAO,CAC/B,KAAM,+BACN,UAAW,kBAAoB,KAAK,mBAAqB,aAAe,IACxE,MAAO,qBACP,YAAa,IAAM,CACjB,KAAK,mBAAqB,CAAC,KAAK,mBAChC,aAAa,QAAQ,sBAAuB,KAAK,mBAAqB,IAAM,GAAG,EAE/EiB,EAAc,QAAQ,UAAU,OAAO,YAAa,KAAK,kBAAkB,EAEvE,KAAK,aACP,KAAK,YAAY,UAAU,KAAK,oBAAsB,KAAK,cAAc,EAE3E,QAAQ,IAAI,yBAA0B,KAAK,mBAAqB,KAAO,KAAK,CAC9E,EACD,EACD,KAAK,eAAiBA,EACtBnB,EAAS,WAAWmB,CAAa,EAKjC,KAAK,YAAY,EAAK,EAGtB,KAAK,eAAe,GAAG,iBAAkB,IAAM,CAC7C,MAAMC,EAAU,KAAK,eAAe,aACpC,KAAK,YAAYA,CAAO,CAC1B,CAAC,GAGsB,iBAAkB,QACtC,UAAU,eAAiB,GAC3B,UAAU,iBAAmB,KAG9B,KAAK,YAAc,IAAIC,GAAY,CACjC,UAAW,oBACZ,EACD,KAAK,IAAI,eAAe,KAAK,WAAW,EACxC,KAAK,YAAY,UAAU,EAAK,EAChC,QAAQ,IAAI,qDAAqD,GAKnE,KAAK,eAAe,GAAG,aAAevM,GAAQ,CAC5C,MAAMG,EAAUH,EAAI,QACdL,EAAOQ,EAAQ,cACrB,GAAI,CAACR,GAAQA,EAAK,YAAc,UAAW,OAE3C,MAAM8K,EAAa9K,EAAK,mBAAmB,iBAC3C,KAAK,sBAAsBQ,EAASsK,CAAU,CAChD,CAAC,EAED,QAAQ,IAAI,uFAAwF,KAAK,mBAAqB,KAAO,MAAO,GAAG,CACjJ,CAOA,kBAAkBjnB,EAAM,CACtB,GAAI,CAAC,KAAK,oBAAqB,OAC/B,MAAMgpB,EAAY,KAAK,oBAAoBhpB,CAAI,EAC3CgpB,GACFA,EAAU,QAASvqB,GAAOA,EAAA,CAAI,CAElC,CAOA,YAAYuB,EAAMD,EAAU,CACrB,KAAK,sBAAqB,KAAK,oBAAsB,IACrD,KAAK,oBAAoBC,CAAI,IAAG,KAAK,oBAAoBA,CAAI,EAAI,IACtE,KAAK,oBAAoBA,CAAI,EAAE,KAAKD,CAAQ,CAC9C,CAYA,YAAYyb,EAAQ,CAClB,KAAK,eAAiB,CAAC,CAACA,EAEpB,KAAK,UACP,KAAK,QAAQ,WAAW,KAAK,cAAc,EAEtC,KAAK,gBAGR,KAAK,QAAQ,sBAKb,KAAK,qBACF,KAAK,gBAER,KAAK,mBAAmB,cAAc,QAExC,KAAK,mBAAmB,UAAU,KAAK,cAAc,GAEnD,KAAK,oBACP,KAAK,mBAAmB,UAAU,KAAK,cAAc,EAInD,KAAK,aACP,KAAK,YAAY,UAAU,KAAK,oBAAsB,KAAK,cAAc,EAIvE,KAAK,aACP,KAAK,YAAY,UAAU,KAAK,cAAc,EAI5C,CAAC,KAAK,gBAAkB,KAAK,sBAC/B,KAAK,qBAAqB,QAG5B,QAAQ,IAAI,uBAAwB,KAAK,eAAiB,KAAO,KAAK,CACxE,CAMA,YAAa,CACX,OAAO,KAAK,cACd,CAeA,qBAAsB,CACpB,KAAK,qBAAuB,IAAIH,EAChC,KAAK,oBAAsB,IAAIC,EAAY,CACzC,MAAO,uBACP,OAAQ,KAAK,qBAEb,OAAQ,IACR,MAAO,IAAIR,EAAM,CACf,MAAO,IAAIoM,GAAO,CAChB,OAAQ,EACR,KAAM,IAAIlM,EAAK,CAAE,MAAO,wBAAyB,EACjD,OAAQ,IAAID,EAAO,CAAE,MAAO,OAAQ,MAAO,IAAK,EACjD,EACF,EACF,EAED,KAAK,oBAAoB,IAAI,yBAA0B,EAAK,EAC5D,KAAK,IAAI,SAAS,KAAK,mBAAmB,EAG1C,KAAK,6BAA+B,IAAM,KAAK,wBAG/C,KAAK,2BAA6B,IAGlC,KAAK,mBAAmB,GAAG,SAAU,IAAM,KAAK,uBAAuB,CACzE,CAMA,uBAAwB,CACtB,GAAI,CAAC,KAAK,qBAAsB,OAIhC,GAHA,KAAK,qBAAqB,QAGtB,KAAK,uBAAwB,CAC/B,UAAWxN,KAAK,KAAK,uBACnBA,EAAE,GAAG,SAAU,KAAK,4BAA4B,EAElD,KAAK,uBAAuB,OAC9B,CAEA,GAAI,CAAC,KAAK,gBAAkB,CAAC,KAAK,mBAAoB,OAEtD,MAAM0b,EAAW,KAAK,mBAAmB,cAAc,WACvD,UAAW/M,KAAQ+M,EAAU,CAC3B,MAAM9M,EAAOD,EAAK,cAClB,GAAI,CAACC,EAAM,SACX,MAAMnc,EAAOmc,EAAK,UAClB,GAAI,CAAC,CAAC,UAAW,eAAgB,aAAc,iBAAiB,EAAE,SAASnc,CAAI,EAC7E,SAEF,MAAMyX,EAAS,KAAK,oBAAoB0E,CAAI,EAC5C,UAAWrR,KAAK2M,EACd,KAAK,qBAAqB,WAAW,IAAIiK,GAAQ,IAAIwH,GAAMpe,CAAC,CAAC,CAAC,EAGhEoR,EAAK,GAAG,SAAU,KAAK,4BAA4B,EACnD,KAAK,uBAAuB,IAAIA,CAAI,CACtC,CACF,CAWA,oBAAoBC,EAAM,CACxB,MAAMgN,EAAM,GACNC,EAAW5a,GAAM,MAAM,QAAQA,CAAC,GAAK,OAAOA,EAAE,CAAC,GAAM,SAErD6a,EAAY,CAACpU,EAAMqU,IAAkB,CACzC,MAAMlR,EAAMkR,GAAiBrU,EAAK,OAAS,EAAIA,EAAK,OAAS,EAAIA,EAAK,OACtE,QAASrX,EAAI,EAAGA,EAAIwa,EAAKxa,IAAKurB,EAAI,KAAKlU,EAAKrX,CAAC,CAAC,CAChD,EAEMoC,EAAOmc,EAAK,UACZ1E,EAAS0E,EAAK,iBAEpB,OAAQnc,EAAA,CACN,IAAK,UAEH,UAAWiV,KAAQwC,EAAQ4R,EAAUpU,EAAM,EAAI,EAC/C,MACF,IAAK,eAEH,UAAWsU,KAAQ9R,EAAQ,UAAWxC,KAAQsU,EAAMF,EAAUpU,EAAM,EAAI,EACxE,MACF,IAAK,aACHoU,EAAU5R,EAAQ,EAAK,EACvB,MACF,IAAK,kBACH,UAAW3B,KAAQ2B,EAAQ4R,EAAUvT,EAAM,EAAK,EAChD,MACF,QAEE,MAAM0T,EAAQhb,GAAM,CAClB,GAAI4a,EAAQ5a,CAAC,EAAG2a,EAAI,KAAK3a,CAAC,UACjB,MAAM,QAAQA,CAAC,YAAcib,KAAOjb,IAAQib,CAAG,CAC1D,EACAD,EAAK/R,CAAM,EAEf,OAAO0R,CACT,CAMA,kBAAmB,CACjB,OAAO,KAAK,aACd,CAMA,mBAAoB,CAClB,OAAO,KAAK,cACd,CAMA,YAAa,CACX,OAAO,KAAK,OACd,CAMA,iBAAiBO,EAAQ,CACnB,KAAK,UACP,KAAK,SAAS,SAASA,IAAW,WAAa,WAAa,QAAQ,CAExE,CAKA,aAAc,CAEZ,KAAK,aAAe,SAAS,cAAc,KAAK,EAChD,KAAK,aAAa,UAAY,YAC9B,KAAK,aAAa,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBlC,KAAK,MAAQ,IAAIC,GAAQ,CACvB,QAAS,KAAK,aACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACZ,EAED,KAAK,IAAI,WAAW,KAAK,KAAK,EAG9B,KAAK,iBACP,CAKA,iBAAkB,CAChB,IAAIC,EAAiB,KAErB,KAAK,IAAI,GAAG,cAAgBpN,GAAQ,CAClC,GAAIA,EAAI,SAAU,CAChB,KAAK,YACL,MACF,CAGA,MAAMG,EAAU,KAAK,IAAI,sBAAsBH,EAAI,MAAQjP,GAErDA,EAAE,IAAI,MAAM,EACPA,EAEF,IACR,EAEGoP,GAAWA,IAAYiN,GACzBA,EAAiBjN,EACjB,KAAK,UAAUA,EAASH,EAAI,UAAU,GAC7B,CAACG,GAAWiN,IACrBA,EAAiB,KACjB,KAAK,aAIP,KAAK,IAAI,mBAAmB,MAAM,OAASjN,EAAU,UAAY,EACnE,CAAC,EAGD,KAAK,IAAI,mBAAmB,iBAAiB,aAAc,IAAM,CAC/D,KAAK,YACLiN,EAAiB,IACnB,CAAC,CACH,CAKA,UAAUjN,EAASsK,EAAY,CAC7B,MAAMvhB,EAAOiX,EAAQ,IAAI,MAAM,GAAK,UAC9BtR,EAAWsR,EAAQ,IAAI,UAAU,GAAK,UACtCvR,EAAcuR,EAAQ,IAAI,aAAa,EACvC/K,EAAM+K,EAAQ,IAAI,KAAK,EACvB9K,EAAM8K,EAAQ,IAAI,KAAK,EAI7B,IAAIkN,EAAO;AAAA;AAAA,UAHG,KAAK,SAASxe,CAAQ,CAKzB,IAAI,KAAK,WAAW3F,CAAI,CAAC;AAAA;AAAA,MAapC,MAAMokB,EARiB,CACrB,MAAS,UACT,OAAU,UACV,OAAU,UACV,OAAU,UACV,QAAW,UACX,MAAS,WAEqBze,CAAQ,GAAK,UAC7Cwe,GAAQ;AAAA;AAAA;AAAA,wBAGYC,CAAQ;AAAA,mBACbA,CAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,YAKfze,CAAQ;AAAA;AAAA,MAKZD,IACFye,GAAQ;AAAA;AAAA,YAEF,KAAK,WAAWze,CAAW,CAAC;AAAA;AAAA,SAMhCwG,IAAQ,QAAaC,IAAQ,SAC/BgY,GAAQ;AAAA;AAAA,YAEF,OAAOjY,CAAG,EAAE,QAAQ,CAAC,CAAC,KAAK,OAAOC,CAAG,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,SAKzD,KAAK,aAAa,UAAYgY,EAC9B,KAAK,MAAM,YAAY5C,CAAU,CACnC,CAKA,WAAY,CACV,KAAK,MAAM,YAAY,MAAS,CAClC,CAKA,iBAAkB,CAChB,KAAK,iBAAmB,SAAS,cAAc,KAAK,EACpD,KAAK,iBAAiB,UAAY,iBAClC,KAAK,iBAAiB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAmBtC,KAAK,UAAY,IAAI0C,GAAQ,CAC3B,QAAS,KAAK,iBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAAE,SAAU,IAAI,CACnC,EAED,KAAK,IAAI,WAAW,KAAK,SAAS,CACpC,CAUA,cAAchN,EAASsK,EAAY9jB,EAAU,GAAI,CAC/C,KAAM,CAAE,MAAA4mB,EAAQ,eAAgB,MAAAC,EAAQ,WAAc7mB,EAChD8mB,EAAatN,EAAQ,gBACrBuN,EAAWvN,EAAQ,cACnBwN,EAAWD,EAAS,UAGpBE,EAAW,CAAC,WAAY,YAAY,EAC1C,IAAIpoB,EAAO,GACX,SAAW,CAACqH,EAAKjB,CAAK,IAAK,OAAO,QAAQ6hB,CAAU,EAC9CG,EAAS,SAAS/gB,CAAG,GAAKjB,IAAU,QAAaA,IAAU,OAC/DpG,GAAQ;AAAA;AAAA,mHAEqG,KAAK,WAAWqH,CAAG,CAAC;AAAA,0EAC7D,KAAK,WAAW,OAAOjB,CAAK,CAAC,CAAC;AAAA;AAAA,SAMpG,GAAI+hB,IAAa,WAAaA,IAAa,eAAgB,CAEzD,MAAME,EAAUC,GAAQJ,EAAU,CAAE,WAAY,YAAa,EACvDK,EAAgB1W,GAAewW,CAAO,EAC5CroB,GAAQ;AAAA;AAAA;AAAA,0EAG4DuoB,CAAa;AAAA;AAAA,OAGnF,SAAWJ,IAAa,cAAgBA,IAAa,kBAAmB,CAEtE,MAAMK,EAAUC,GAAUP,EAAU,CAAE,WAAY,YAAa,EACzDQ,EAAkBlX,GAAiBgX,CAAO,EAChDxoB,GAAQ;AAAA;AAAA;AAAA,0EAG4D0oB,CAAe;AAAA;AAAA,OAGrF,SAAWP,IAAa,QAAS,CAE/B,MAAM1S,EAASkT,GAAST,EAAS,gBAAgB,EAC3CtY,EAAM6F,EAAO,CAAC,EAAE,QAAQ,CAAC,EACzB5F,EAAM4F,EAAO,CAAC,EAAE,QAAQ,CAAC,EAC/BzV,GAAQ;AAAA;AAAA;AAAA,0EAG4D4P,CAAG;AAAA;AAAA;AAAA;AAAA,0EAIHC,CAAG;AAAA;AAAA,OAGzE,CAEA,MAAMgY,EAAO;AAAA,+BACcG,CAAK;AAAA,gBACpB,KAAK,WAAWD,CAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,YAK1B/nB,CAAI;AAAA;AAAA;AAAA,MAKZ,KAAK,iBAAiB,UAAY6nB,EAClC,KAAK,UAAU,YAAY5C,CAAU,EAGrC,KAAK,iBAAiB,cAAc,mBAAmB,EAAE,iBAAiB,QAAS,IAAM,CACvF,KAAK,eACP,CAAC,CACH,CAKA,eAAgB,CACd,KAAK,UAAU,YAAY,MAAS,CACtC,CAiBA,yBAAyB2D,EAAgBC,EAAcC,EAAc,CACnE,MAAMC,EAAW,GAMjB,GAJIH,EAAe,OAAS,GAC1BG,EAAS,KAAK,CAAE,MAAO,UAAW,MAAO,OAAOH,EAAe,MAAM,EAAG,MAAO,UAAW,EAGxFC,EAAa,OAAS,EAAG,CAC3B,MAAMG,EAAQH,EAAa,IAAItd,GAC7BA,EAAE,IAAI,aAAa,GAAKA,EAAE,IAAI,WAAW,GAAKA,EAAE,IAAI,MAAM,GAAK,WAEjEwd,EAAS,KAAK,CAAE,MAAO,QAAS,MAAO,OAAOF,EAAa,MAAM,EAAG,MAAO,UAAW,EACtFE,EAAS,KAAK,CAAE,MAAO,aAAc,MAAOC,EAAM,IAAI3c,GAAK,KAAK,WAAWA,CAAC,CAAC,EAAE,KAAK,IAAI,EAAG,MAAO,UAAW,CAC/G,CAEA,SAAW,CAAC0b,EAAO1c,CAAQ,IAAK,OAAO,QAAQyd,CAAY,EACzDC,EAAS,KAAK,CAAE,MAAO,KAAK,WAAWhB,CAAK,EAAG,MAAO,GAAG1c,EAAS,MAAM,cAAe,EAGzF,OAAI0d,EAAS,SAAW,GACtBA,EAAS,KAAK,CAAE,MAAO,GAAI,MAAO,iCAAkC,MAAO,GAAM,EAG5EA,CACT,CAUA,wBAAwB/E,EAAO+D,EAAOgB,EAAU,CAC9C,IAAIE,EAAY,GAChB,UAAW/kB,KAAO6kB,EAAU,CAC1B,GAAI7kB,EAAI,MAAO,CACb+kB,GAAa;AAAA;AAAA,kGAE6E/kB,EAAI,KAAK;AAAA,iBAEnG,QACF,CACA,MAAMglB,EAAahlB,EAAI,OAAS,mCAC1BilB,EAASjlB,EAAI,OAAS,GAAK,iDACjC+kB,GAAa;AAAA,qBACEE,CAAM;AAAA,6DACkCD,CAAU,yBAAyBhlB,EAAI,KAAK;AAAA,0EAC/BA,EAAI,KAAK;AAAA,cAE/E,CAEA,MAAO;AAAA;AAAA,gBAEK8f,CAAK,IAAI+D,CAAK;AAAA;AAAA;AAAA;AAAA;AAAA,YAKlBkB,CAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,aAanB,CAgBA,mBAAmBjF,EAAO+D,EAAOgB,EAAU9D,EAAYmE,EAAgB,KAAM,CAC3E,KAAK,iBAAiB,UAAY,KAAK,wBAAwBpF,EAAO+D,EAAOgB,CAAQ,EACrF,KAAK,UAAU,YAAY9D,CAAU,EAErC,KAAK,iBAAiB,cAAc,mBAAmB,EAAE,iBAAiB,QAAS,IAAM,CACvF,KAAK,eACP,CAAC,EAGD,KAAK,iBAAiB,cAAc,wBAAwB,GAAG,iBAAiB,QAAS,IAAM,CAE7F,MAAMoE,EAAUN,EACb,OAAO1e,GAAK,CAACA,EAAE,KAAK,EACpB,IAAIA,IAAM,CAAE,MAAOA,EAAE,MAAO,MAAOA,EAAE,MAAM,QAAQ,WAAY,EAAE,GAAI,EAExE7K,GAAA,kCAAA8pB,CAAA,eAAO,0BAAkB,2BAAAA,CAAA,+BAAE,KAAK,CAAC,CAAE,kBAAAA,KAAwB,CACzDA,EAAkB,CAAE,MAAAvB,EAAO,KAAMsB,CAAA,CAAS,CAC5C,CAAC,EAAE,MAAMljB,GAAO,CACd,QAAQ,MAAM,+BAAgCA,CAAG,CACnD,CAAC,CACH,CAAC,EAID,MAAMojB,EAAS,KAAK,iBAAiB,cAAc,wBAAwB,EAC3E,GAAIA,EAAQ,CACV,MAAMza,EAAQsa,EACVA,EAAc,eAAe,OAC3BA,EAAc,aAAa,OAC3B,OAAO,OAAOA,EAAc,YAAY,EAAE,OAAO,CAACra,EAAGya,IAAQza,EAAIya,EAAI,OAAQ,CAAC,EAChF,EACA,CAACJ,GAAiBta,IAAU,GAC9Bya,EAAO,SAAW,GAClBA,EAAO,MAAM,QAAU,MACvBA,EAAO,MAAM,OAAS,cACtBA,EAAO,MAAQ,sCAEfA,EAAO,iBAAiB,QAAS,IAAM,CACrC,OAAO,cAAc,IAAI,YAAY,oBAAqB,CACxD,OAAQ,CAAE,MAAAxB,EAAO,GAAGqB,CAAA,CAAc,CACnC,CAAC,CACJ,CAAC,CAEL,CACF,CAEA,4BAA4BK,EAAexE,EAAY,CACrD,MAAMyE,EAAaD,EAAc,cACjC,GAAI,CAACC,GAAc,OAAOA,EAAW,WAAc,WAAY,OAG/D,MAAMC,EAAaC,GAAWF,EAAY,EAAE,EACtCG,EAAeF,EAAW,YAE1BG,EAASL,EAAc,IAAI,SAAS,GAAKC,EAAW,YAGpDd,EAAiB,GACjBC,EAAe,GACfC,EAAe,GAEfiB,EAAoBpP,GAAY,CACpC,MAAMR,EAAOQ,EAAQ,cACrB,GAAI,CAACR,EAAM,MAAO,GAClB,MAAM6P,EAAU7P,EAAK,YACrB,OACE6P,EAAQ,CAAC,EAAIH,EAAa,CAAC,GAC3BG,EAAQ,CAAC,EAAIH,EAAa,CAAC,GAC3BG,EAAQ,CAAC,EAAIH,EAAa,CAAC,GAC3BG,EAAQ,CAAC,EAAIH,EAAa,CAAC,EAEpB,GAEFF,EAAW,iBAAiBK,CAAO,GAAK,KAAK,qBAAqBL,EAAYxP,CAAI,CAC3F,EAEM8P,EAAY,CAACC,EAAOC,IAAe,CACvCD,EAAM,YAAY,QAAStQ,GAAU,CACnC,GAAIA,aAAiBwK,GACnB6F,EAAUrQ,EAAOA,EAAM,IAAI,OAAO,GAAKuQ,CAAU,UACxCvQ,aAAiBN,GAAeM,EAAM,aAAc,CAC7D,MAAMwQ,EAAaxQ,EAAM,IAAI,OAAO,GAAKuQ,GAAc,UACjDlQ,EAASL,EAAM,YACrB,GAAI,CAACK,EAAQ,OAEb,MAAMoQ,EAAapQ,EAAO,oBAAoB4P,CAAY,EAC1D,UAAWte,KAAK8e,EAAY,CAC1B,MAAMC,EAAQ/e,EAAE,IAAI,YAAY,EAC5B+e,IAAU,kBAAoBA,IAAU,yBAEvCP,EAAiBxe,CAAC,IAEnB+e,IAAU,SACZ1B,EAAe,KAAKrd,CAAC,EACZ+e,IAAU,iBACnBzB,EAAa,KAAKtd,CAAC,GAEdud,EAAasB,CAAU,IAAGtB,EAAasB,CAAU,EAAI,IAC1DtB,EAAasB,CAAU,EAAE,KAAK7e,CAAC,GAEnC,CACF,CACF,CAAC,CACH,EAEA0e,EAAU,KAAK,aAAc,UAAU,EAGvC,MAAMM,EAAkBlZ,GAAayY,CAAM,EACrCzB,EAAU,KAAK,GAAKyB,EAASA,EAC7BvB,EAAgB7W,GAAW2W,CAAO,EAElCU,EAAW,CACf,CAAE,MAAO,SAAU,MAAOwB,EAAiB,OAAQ,IACnD,CAAE,MAAO,OAAQ,MAAOhC,CAAA,EACxB,GAAG,KAAK,yBAAyBK,EAAgBC,EAAcC,CAAY,GAG7E,KAAK,mBAAmB,IAAK,kBAAmBC,EAAU9D,EAAY,CACpE,KAAM,SACN,aAAc0E,EACd,eAAAf,EACA,aAAAC,EACA,aAAAC,CAAA,CACD,CACH,CAUA,0BAA0B0B,EAAgBvF,EAAY,CACpD,MAAMwF,EAAWD,EAAe,cAChC,GAAI,CAACC,EAAU,OAEf,MAAMC,EAAaD,EAAS,YAGtBpC,EAAUC,GAAQmC,EAAU,CAAE,WAAY,YAAa,EACvDlC,EAAgB7W,GAAW2W,CAAO,EAGlCsC,EAAalC,GAAUgC,EAAU,CAAE,WAAY,YAAa,EAC5DG,EAAqBvZ,GAAasZ,CAAU,EAG5C/B,EAAiB,GACjBC,EAAe,GACfC,EAAe,GAEf+B,EAAkBlQ,GAAY,CAClC,MAAMR,EAAOQ,EAAQ,cACrB,GAAI,CAACR,EAAM,MAAO,GAClB,MAAM6P,EAAU7P,EAAK,YACrB,OACE6P,EAAQ,CAAC,EAAIU,EAAW,CAAC,GACzBV,EAAQ,CAAC,EAAIU,EAAW,CAAC,GACzBV,EAAQ,CAAC,EAAIU,EAAW,CAAC,GACzBV,EAAQ,CAAC,EAAIU,EAAW,CAAC,EAElB,GAEFD,EAAS,iBAAiBT,CAAO,GAAK,KAAK,qBAAqBS,EAAUtQ,CAAI,CACvF,EAEM8P,EAAY,CAACC,EAAOC,IAAe,CACvCD,EAAM,YAAY,QAAStQ,GAAU,CACnC,GAAIA,aAAiBwK,GACnB6F,EAAUrQ,EAAOA,EAAM,IAAI,OAAO,GAAKuQ,CAAU,UACxCvQ,aAAiBN,GAAeM,EAAM,aAAc,CAC7D,MAAMwQ,EAAaxQ,EAAM,IAAI,OAAO,GAAKuQ,GAAc,UACjDlQ,EAASL,EAAM,YACrB,GAAI,CAACK,EAAQ,OAEb,MAAMoQ,EAAapQ,EAAO,oBAAoByQ,CAAU,EACxD,UAAWnf,KAAK8e,EAAY,CAC1B,MAAMC,EAAQ/e,EAAE,IAAI,YAAY,EAC5B+e,IAAU,gBAAkBA,IAAU,kBAAoBA,IAAU,yBAEnEO,EAAetf,CAAC,IAEjB+e,IAAU,SACZ1B,EAAe,KAAKrd,CAAC,EACZ+e,IAAU,iBACnBzB,EAAa,KAAKtd,CAAC,GAEdud,EAAasB,CAAU,IAAGtB,EAAasB,CAAU,EAAI,IAC1DtB,EAAasB,CAAU,EAAE,KAAK7e,CAAC,GAEnC,CACF,CACF,CAAC,CACH,EAEA0e,EAAU,KAAK,aAAc,UAAU,EAGvC,MAAMlB,EAAW,CACf,CAAE,MAAO,OAAQ,MAAOR,EAAe,OAAQ,IAC/C,CAAE,MAAO,YAAa,MAAOqC,CAAA,EAC7B,GAAG,KAAK,yBAAyBhC,EAAgBC,EAAcC,CAAY,GAG7E,KAAK,mBAAmB,KAAM,gBAAiBC,EAAU9D,EAAY,CACnE,KAAM,OACN,aAAcwF,EACd,eAAA7B,EACA,aAAAC,EACA,aAAAC,CAAA,CACD,CACH,CAWA,qBAAqB/I,EAAOC,EAAO,CACjC,MAAM8K,EAAQ9K,EAAM,UAIpB,GAAI8K,IAAU,WAAaA,IAAU,eAAgB,CAEnD,MAAMC,EAAQ/K,EAAM,qBACdgL,EAAShL,EAAM,YACrB,QAASpkB,EAAI,EAAGA,EAAImvB,EAAM,OAAQnvB,GAAKovB,EACrC,GAAIjL,EAAM,qBAAqB,CAACgL,EAAMnvB,CAAC,EAAGmvB,EAAMnvB,EAAI,CAAC,CAAC,CAAC,EAAG,MAAO,GAGnE,MAAMqvB,EAAQlL,EAAM,qBACdmL,EAAUnL,EAAM,YACtB,QAASnkB,EAAI,EAAGA,EAAIqvB,EAAM,OAAQrvB,GAAKsvB,EACrC,GAAIlL,EAAM,qBAAqB,CAACiL,EAAMrvB,CAAC,EAAGqvB,EAAMrvB,EAAI,CAAC,CAAC,CAAC,EAAG,MAAO,GAEnE,MAAO,EACT,CAEA,GAAIkvB,IAAU,QACZ,OAAO/K,EAAM,qBAAqBC,EAAM,gBAAgB,EAG1D,GAAI8K,IAAU,cAAgBA,IAAU,kBAAmB,CACzD,MAAMC,EAAQ/K,EAAM,qBACdgL,EAAShL,EAAM,YACrB,QAAS,EAAI,EAAG,EAAI+K,EAAM,OAAQ,GAAKC,EACrC,GAAIjL,EAAM,qBAAqB,CAACgL,EAAM,CAAC,EAAGA,EAAM,EAAI,CAAC,CAAC,CAAC,EAAG,MAAO,GAEnE,MAAO,EACT,CAGA,MAAO,EACT,CASA,uBAAwB,CACtB,KAAK,kBAAoB,SAAS,cAAc,KAAK,EACrD,KAAK,kBAAkB,UAAY,wBACnC,KAAK,kBAAkB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAkBvC,KAAK,gBAAkB,IAAIpD,GAAQ,CACjC,QAAS,KAAK,kBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAAE,SAAU,IAAI,CACnC,EAED,KAAK,IAAI,WAAW,KAAK,eAAe,EAGxC,KAAK,qBAAuB,GAE5B,KAAK,mBAAqB,IAC5B,CASA,oBAAoBhN,EAASsK,EAAY,CACvC,KAAK,mBAAqBtK,EAC1B,MAAMsN,EAAatN,EAAQ,gBAGrByN,EAAW,CAAC,WAAY,YAAY,EAG1C,IAAI+C,EAAa,GACjB,SAAW,CAAC9jB,EAAKjB,CAAK,IAAK,OAAO,QAAQ6hB,CAAU,EAAG,CACrD,GAAIG,EAAS,SAAS/gB,CAAG,EAAG,SAC5B,MAAM+jB,EAAchlB,GAAU,KAA+B,GAAK,OAAOA,CAAK,EACxEilB,EAAa,KAAK,WAAWhkB,CAAG,EAChCikB,EAAa,KAAK,WAAWF,CAAU,EAC7CD,GAAc;AAAA;AAAA,kIAE8GE,CAAU;AAAA,qCACvGA,CAAU,YAAYC,CAAU;AAAA;AAAA;AAAA;AAAA,OAKjE,CAEA,MAAMzD,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UAMPsD,CAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYhB,KAAK,kBAAkB,UAAYtD,EACnC,KAAK,gBAAgB,YAAY5C,CAAU,EAG3C,KAAK,kBAAkB,cAAc,oBAAoB,EAAE,iBAAiB,QAAS,IAAM,CACzF,KAAK,qBACP,CAAC,EACD,KAAK,kBAAkB,cAAc,qBAAqB,EAAE,iBAAiB,QAAS,IAAM,CAC1F,KAAK,qBACP,CAAC,EAGD,MAAMsG,EAAO,KAAK,kBAAkB,cAAc,mBAAmB,EACrEA,EAAK,iBAAiB,SAAW/iB,GAAM,CACrCA,EAAE,iBAGF,MAAMgjB,EAAW,IAAI,SAASD,CAAI,EAC5BE,EAAe,GACrB,SAAW,CAACpkB,EAAKjB,CAAK,IAAKolB,EAAS,UAClCC,EAAapkB,CAAG,EAAIjB,EAItBqlB,EAAa,WAAa,SAG1B,SAAW,CAACpkB,EAAKjB,CAAK,IAAK,OAAO,QAAQqlB,CAAY,EACpD,KAAK,mBAAmB,IAAIpkB,EAAKjB,CAAK,EAIxC,UAAWpF,KAAM,KAAK,qBACpBA,EAAG,KAAK,mBAAoByqB,CAAY,EAG1C,KAAK,qBACP,CAAC,CACH,CAKA,qBAAsB,CACpB,KAAK,gBAAgB,YAAY,MAAS,EAC1C,KAAK,mBAAqB,IAC5B,CAQA,aAAa1tB,EAAU,CACrB,KAAK,qBAAqB,KAAKA,CAAQ,CACzC,CAUA,kBAAmB,CACjB,KAAK,kBAAoB,SAAS,cAAc,KAAK,EACrD,KAAK,kBAAkB,UAAY,kBACnC,KAAK,kBAAkB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBvC,KAAK,WAAa,IAAI4pB,GAAQ,CAC5B,QAAS,KAAK,kBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAAE,SAAU,IAAI,CACnC,EAED,KAAK,IAAI,WAAW,KAAK,UAAU,CACrC,CAWA,yBAAyB1H,EAAeyL,EAAQC,EAAQ1G,EAAY,CAElE,MAAMa,EAAW,CAAC,MAAO,MAAO,KAAM,WAAY,YAAa,WAAY,YAAa,IAAI,EACtF8F,EAAYzhB,GAAU,CAC1B,UAAW4b,KAASD,EAClB,GAAI3b,EAAM4b,CAAK,IAAM,QAAa5b,EAAM4b,CAAK,IAAM,MAAQ,OAAO5b,EAAM4b,CAAK,CAAC,EAAE,OAC9E,MAAO,CAAE,MAAAA,EAAO,MAAO,OAAO5b,EAAM4b,CAAK,CAAC,GAG9C,MAAO,CAAE,MAAO,KAAM,MAAO,UAC/B,EAEM8F,EAASD,EAASF,CAAM,EACxBI,EAASF,EAASD,CAAM,EAExB9D,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kFAciE,KAAK,WAAWgE,EAAO,KAAK,CAAC,KAAK,KAAK,WAAWA,EAAO,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kFAQ/D,KAAK,WAAWC,EAAO,KAAK,CAAC,KAAK,KAAK,WAAWA,EAAO,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAc7I,KAAK,kBAAkB,UAAYjE,EACnC,KAAK,WAAW,YAAY5C,CAAU,EAGtC,MAAM8G,EAAQ,IAAM,CAClB,KAAK,WAAW,YAAY,MAAS,CACvC,EACA,KAAK,kBAAkB,cAAc,oBAAoB,EAAE,iBAAiB,QAASA,CAAK,EAC1F,KAAK,kBAAkB,cAAc,qBAAqB,EAAE,iBAAiB,QAASA,CAAK,EAG3F,KAAK,kBAAkB,cAAc,sBAAsB,EAAE,iBAAiB,QAAS,IAAM,CAE3F,MAAMC,EADS,KAAK,kBAAkB,cAAc,oCAAoC,EAAE,QAC3D,IAAMN,EAASC,EAGxCvD,EAAW,CAAC,UAAU,EAC5B,SAAW,CAAC/gB,EAAKjB,CAAK,IAAK,OAAO,QAAQ4lB,CAAW,EAC/C5D,EAAS,SAAS/gB,CAAG,GACzB4Y,EAAc,IAAI5Y,EAAKjB,CAAK,EAG9B6Z,EAAc,IAAI,aAAc,QAAQ,EAGxC,UAAWjf,KAAM,KAAK,qBACpBA,EAAGif,EAAe+L,CAAW,EAG/BD,EAAA,CACF,CAAC,EAGD,MAAME,EAAS,KAAK,kBAAkB,iBAAiB,OAAO,EACxDC,EAAS,KAAK,kBAAkB,iBAAiB,4BAA4B,EAC7EC,EAAkB,IAAM,CAC5BF,EAAO,QAASG,GAAQ,CACtB,MAAMC,EAAQD,EAAI,cAAc,OAAO,EACvCA,EAAI,MAAM,YAAcC,EAAM,QAAWA,EAAM,QAAU,IAAM,UAAY,UAAa,0BAC1F,CAAC,CACH,EACAH,EAAO,QAAS7hB,GAAMA,EAAE,iBAAiB,SAAU8hB,CAAe,CAAC,EACnEA,EAAA,CACF,CAWA,mBAAoB,CAClB,KAAK,mBAAqB,SAAS,cAAc,KAAK,EACtD,KAAK,mBAAmB,UAAY,mBACpC,KAAK,mBAAmB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBxC,KAAK,YAAc,IAAIxE,GAAQ,CAC7B,QAAS,KAAK,mBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAAE,SAAU,IAAI,CACnC,EAED,KAAK,IAAI,WAAW,KAAK,WAAW,CACtC,CASA,gBAAgBhN,EAASV,EAAQgL,EAAY,CAC3C,MAAM4C,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAsBb,KAAK,mBAAmB,UAAYA,EACpC,KAAK,YAAY,YAAY5C,CAAU,EAEvC,MAAMqH,EAAQ,KAAK,mBAAmB,cAAc,eAAe,EACnEA,EAAM,QACNA,EAAM,SAGN,MAAM9pB,EAAS,IAAM,CACnB,KAAK,kBACL,KAAK,0BAA0B,cACjC,EACA,KAAK,mBAAmB,cAAc,qBAAqB,EAAE,iBAAiB,QAASA,CAAM,EAC7F,KAAK,mBAAmB,cAAc,sBAAsB,EAAE,iBAAiB,QAASA,CAAM,EAG9F,KAAK,mBAAmB,cAAc,uBAAuB,EAAE,iBAAiB,QAAS,IAAM,CAC7F,MAAM6J,EAAI,SAASigB,EAAM,MAAO,EAAE,EAClC,GAAI,CAACjgB,GAAKA,EAAI,EAAG,CACfigB,EAAM,MAAM,YAAc,UAC1B,MACF,CACA,KAAK,kBACL,KAAK,0BAA0B,cAAcjgB,CAAC,CAChD,CAAC,EAGDigB,EAAM,iBAAiB,UAAY9jB,GAAM,CACnCA,EAAE,MAAQ,UACZA,EAAE,iBACF,KAAK,mBAAmB,cAAc,uBAAuB,EAAE,QAEnE,CAAC,CACH,CAKA,iBAAkB,CAChB,KAAK,YAAY,YAAY,MAAS,CACxC,CAWA,yBAA0B,CACxB,KAAK,oBAAsB,SAAS,cAAc,KAAK,EACvD,KAAK,oBAAoB,UAAY,0BACrC,KAAK,oBAAoB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBzC,KAAK,kBAAoB,IAAImf,GAAQ,CACnC,QAAS,KAAK,oBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAAE,SAAU,IAAI,CACnC,EAED,KAAK,IAAI,WAAW,KAAK,iBAAiB,EAC1C,KAAK,uBAAyB,GAC9B,KAAK,qBAAuB,IAC9B,CASA,wBAAyB,CACvB,MAAMS,EAAW,CAAC,WAAY,YAAY,EACpCmE,EAAO,GAEPtC,EAAaC,GAAU,CACvBqC,EAAK,OAAS,GAClBrC,EAAM,YAAY,QAAStQ,GAAU,CACnC,GAAI,EAAA2S,EAAK,OAAS,IAClB,GAAI3S,aAAiBwK,GACnB6F,EAAUrQ,CAAK,UACNA,aAAiBN,EAAa,CACvC,MAAMW,EAASL,EAAM,YACrB,GAAI,CAACK,EAAQ,OACb,UAAW1O,KAAK0O,EAAO,cAAe,CACpC,GAAI1O,EAAE,IAAI,YAAY,IAAM,SAAU,SACtC,MAAMpB,EAAQoB,EAAE,gBAChB,UAAWlE,KAAO,OAAO,KAAK8C,CAAK,EAC5Bie,EAAS,SAAS/gB,CAAG,GAAGklB,EAAK,KAAKllB,CAAG,EAE5C,MACF,CACF,EACF,CAAC,CACH,EAEA,OAAA4iB,EAAU,KAAK,YAAY,EACpBsC,CACT,CAUA,sBAAsB5R,EAASsK,EAAY,CACzC,KAAK,qBAAuBtK,EAG5B,MAAM6R,EAAgB,KAAK,yBAE3B,GAAIA,EAAc,SAAW,EAAG,CAC9B,QAAQ,KAAK,0DAA0D,EACvE,MACF,CAGA,IAAIrB,EAAa,GACjB,UAAW9jB,KAAOmlB,EAAe,CAC/B,MAAMnB,EAAa,KAAK,WAAWhkB,CAAG,EACtC8jB,GAAc;AAAA;AAAA,kIAE8GE,CAAU;AAAA,qCACvGA,CAAU;AAAA;AAAA;AAAA;AAAA,OAK3C,CAGA,MAAMlR,EAAOQ,EAAQ,cACf0N,EAAUC,GAAQnO,EAAM,CAAE,WAAY,YAAa,EAGnD0N,EAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAFSnW,GAAW2W,CAAO,CAQP;AAAA;AAAA;AAAA,UAG3B8C,CAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAYhB,KAAK,oBAAoB,UAAYtD,EACrC,KAAK,kBAAkB,YAAY5C,CAAU,EAG7C,KAAK,oBAAoB,cAAc,sBAAsB,EAAE,iBAAiB,QAAS,IAAM,CAC7F,KAAK,uBACP,CAAC,EACD,KAAK,oBAAoB,cAAc,uBAAuB,EAAE,iBAAiB,QAAS,IAAM,CAC9F,KAAK,uBACP,CAAC,EAGD,MAAMsG,EAAO,KAAK,oBAAoB,cAAc,qBAAqB,EACzEA,EAAK,iBAAiB,SAAW/iB,GAAM,CACrCA,EAAE,iBAEF,MAAMgjB,EAAW,IAAI,SAASD,CAAI,EAC5BphB,EAAQ,GACd,SAAW,CAAC9C,EAAKjB,CAAK,IAAKolB,EAAS,UAClCrhB,EAAM9C,CAAG,EAAIjB,EAIf,SAAW,CAACiB,EAAKjB,CAAK,IAAK,OAAO,QAAQ+D,CAAK,EAC7C,KAAK,qBAAqB,IAAI9C,EAAKjB,CAAK,EAI1C,KAAK,qBAAqB,IAAI,aAAc,QAAQ,EAGpD,UAAWpF,KAAM,KAAK,uBACpBA,EAAG,KAAK,qBAAsBmJ,CAAK,EAGrC,KAAK,uBACP,CAAC,CACH,CAKA,uBAAwB,CACtB,KAAK,kBAAkB,YAAY,MAAS,EAC5C,KAAK,qBAAuB,IAC9B,CAQA,mBAAmBpM,EAAU,CAC3B,KAAK,uBAAuB,KAAKA,CAAQ,CAC3C,CASA,WAAWA,EAAU,CACnB,YAAK,kBAAkB,KAAKA,CAAQ,EAGhC,KAAK,kBAAkB,SAAW,GACpC,KAAK,IAAI,GAAG,WAAayc,GAAQ,CAC/B,KAAM,CAAC5K,EAAKC,CAAG,EAAI8Y,GAASnO,EAAI,UAAU,EAG1C,IAAIiS,EAAiB,KACrB,KAAK,IAAI,sBAAsBjS,EAAI,MAAQG,IACzC8R,EAAiB9R,EACV,GACR,EAGG8R,IACFjS,EAAI,iBACJA,EAAI,mBAIN,UAAWxZ,KAAM,KAAK,kBACpBA,EAAG4O,EAAKC,EAAK4c,EAAgBjS,CAAG,EAIlC,GAAIiS,EAAgB,MAAO,EAC7B,CAAC,EAGI,IAAM,CACX,MAAMzX,EAAM,KAAK,kBAAkB,QAAQjX,CAAQ,EAC/CiX,EAAM,IAAI,KAAK,kBAAkB,OAAOA,EAAK,CAAC,CACpD,CACF,CAKA,WAAW0X,EAAM,CACf,GAAI,CAACA,EAAM,MAAO,GAClB,MAAMC,EAAM,SAAS,cAAc,KAAK,EACxC,OAAAA,EAAI,YAAcD,EACXC,EAAI,SACb,CAKA,wBAAyB,CAEvB,KAAK,wBAA0B,SAAS,cAAc,KAAK,EAC3D,KAAK,wBAAwB,UAAY,yBACzC,KAAK,wBAAwB,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,cAa/B,KAAK,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAevC,KAAK,iBAAmB,IAAIhF,GAAQ,CAClC,QAAS,KAAK,wBACd,YAAa,gBACb,OAAQ,CAAC,EAAG,GAAG,EACf,UAAW,GACX,QAAS,GACT,iBAAkB,CAChB,SAAU,IACZ,CACD,EAED,KAAK,IAAI,WAAW,KAAK,gBAAgB,EAGzC,KAAK,kBAAoB,KAGR,KAAK,wBAAwB,cAAc,2BAA2B,EAC9E,iBAAiB,QAAS,IAAM,CACvC,KAAK,sBACP,CAAC,EAGD,KAAK,qBAAuB,EAC9B,CAKA,qBAAqB1C,EAAY,CAC/B,KAAM,CAACrV,EAAKC,CAAG,EAAI8Y,GAAS1D,CAAU,EACtC,KAAK,kBAAoB,CAAE,IAAArV,EAAK,IAAAC,CAAA,EAGhC,MAAM+c,EAAW,KAAK,wBAAwB,cAAc,sBAAsB,EAClFA,EAAS,YAAc,GAAGhd,EAAI,QAAQ,CAAC,CAAC,KAAKC,EAAI,QAAQ,CAAC,CAAC,GAG9C,KAAK,wBAAwB,cAAc,wBAAwB,EAC3E,QAGL,KAAK,iBAAiB,YAAYoV,CAAU,CAC9C,CAKA,sBAAuB,CACrB,KAAK,iBAAiB,YAAY,MAAS,EAC3C,KAAK,kBAAoB,IAC3B,CAMA,cAAclnB,EAAU,CAItB,GAHA,KAAK,qBAAqB,KAAKA,CAAQ,EAGnC,KAAK,qBAAqB,SAAW,EAAG,CAC1C,MAAMwtB,EAAO,KAAK,wBAAwB,cAAc,wBAAwB,EAChFA,EAAK,iBAAiB,SAAW/iB,GAAM,CAGrC,GAFAA,EAAE,iBAEE,CAAC,KAAK,kBAAmB,OAE7B,MAAMgjB,EAAW,IAAI,SAASD,CAAI,EAC5B/vB,EAAO,CACX,KAAMgwB,EAAS,IAAI,MAAM,EACzB,SAAUA,EAAS,IAAI,UAAU,EACjC,YAAaA,EAAS,IAAI,aAAa,EACvC,IAAK,KAAK,kBAAkB,IAC5B,IAAK,KAAK,kBAAkB,KAI9B,KAAK,qBAAqB,QAAQxqB,GAAMA,EAAGxF,CAAI,CAAC,EAGhD,KAAK,sBACP,CAAC,CACH,CACF,CAKA,iBAAiBqxB,EAAgB,CAG/B,MAAMC,EAAY,IAAIC,GAAU,CAC9B,MAAO,cACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,OAC5B,OAAQ,IAAIG,GAAI,CACd,IAAK,qDACL,aAAc,0BACd,QAAS,GACT,YAAa,YACd,EACF,EACDF,EAAU,IAAI,aAAc,MAAM,EAElC,MAAMG,EAAkB,IAAIF,GAAU,CACpC,MAAO,cACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,cAC5B,OAAQ,IAAIG,GAAI,CACd,IAAK,gEACL,aAAc,UACd,QAAS,GACT,YAAa,YACd,EACF,EACDC,EAAgB,IAAI,aAAc,aAAa,EAE/C,MAAMC,EAAiB,IAAIH,GAAU,CACnC,MAAO,aACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,aAC5B,OAAQ,IAAIG,GAAI,CACd,IAAK,+DACL,aAAc,UACd,QAAS,GACT,YAAa,YACd,EACF,EACDE,EAAe,IAAI,aAAc,YAAY,EAE7C,MAAMC,EAAgB,IAAIJ,GAAU,CAClC,MAAO,gBACP,KAAM,OACN,OAAQ,KACR,QAAS,GACT,OAAQ,IAAIK,GAAI,CACX,IAAQ,+FACZ,EACF,EAEDD,EAAc,IAAI,aAAc,OAAO,EAEvC,MAAME,EAAiB,IAAIN,GAAU,CACnC,MAAO,YACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,YAC5B,OAAQ,IAAIG,GAAI,CACd,IAAK,gGACL,aAAc,eACd,QAAS,GACT,YAAa,YACd,EACF,EACDK,EAAe,IAAI,aAAc,WAAW,EAC5C,MAAMC,EAAc,IAAIP,GAAU,CAChC,MAAO,aACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,YAC5B,OAAQ,IAAIG,GAAI,CAEd,IAAK,+DACL,aAAc,iBACd,QAAS,GACT,YAAa,YACd,EACF,EACDM,EAAY,IAAI,aAAc,WAAW,EAEzC,MAAMC,EAAW,IAAIR,GAAU,CAC7B,MAAO,gBACP,KAAM,OACN,OAAQ,KACR,QAASF,IAAmB,MAC5B,OAAQ,IAAIO,EAAI,CACjB,EACDG,EAAS,IAAI,aAAc,KAAK,EAGhC,KAAK,eAAiB,CACpBN,EAAiBC,EAAgBC,EACjCE,EAAgBC,EAAaC,EAAUT,CAAA,EAOzC,MAAMU,EAAY,IAAIpJ,GAAW,CAC/B,MAAO,YACP,OAAQ,CACN6I,EACAC,EACAG,EACAF,EACAG,EACAC,EACAT,CAAA,CACF,CACD,EACD,OAAAU,EAAU,IAAI,yBAA0B,EAAK,EACtCA,CACT,CASA,WAAWnmB,EAAK,CACd,GAAI,CAAC,KAAK,eAAgB,MAAO,GAIjC,GAAIA,IAAQ,OAAQ,CAClB,UAAWuS,KAAS,KAAK,eAAgBA,EAAM,WAAW,EAAK,EAC/D,eAAQ,IAAI,wCAAwC,EACpD,KAAK,IAAI,cAAc,CAAE,KAAM,gBAAiB,IAAK,OAAQ,EACtD,EACT,CACA,IAAI6T,EAAU,GACd,UAAW7T,KAAS,KAAK,eAAgB,CACvC,MAAM8T,EAAK9T,EAAM,IAAI,YAAY,IAAMvS,EACvCuS,EAAM,WAAW8T,CAAE,EACfA,IAAID,EAAU,GACpB,CACA,OAAIA,IACF,QAAQ,IAAI,kCAAmCpmB,CAAG,EAGlD,KAAK,IAAI,cAAc,CAAE,KAAM,gBAAiB,IAAAA,EAAK,GAEhDomB,CACT,CAaA,sBAAuB,CAIrB,MAAME,EAAU,CACd,CAAE,IAAK,OAAe,MAAO,cAAgB,KAAM,2CACnD,CAAE,IAAK,MAAe,MAAO,gBAAgB,KAAM,2CACnD,CAAE,IAAK,YAAe,MAAO,YAAgB,KAAM,2CACnD,CAAE,IAAK,YAAe,MAAO,aAAgB,KAAM,2CACnD,CAAE,IAAK,cAAe,MAAO,cAAgB,KAAM,2CACnD,CAAE,IAAK,aAAe,MAAO,aAAgB,KAAM,2CAEnD,CAAE,IAAK,OAAe,MAAO,OAAgB,KAAM,sEAAsE,EAGrHC,EAAS,KAAK,IAAI,mBACxB,GAAI,CAACA,EAAQ,OAGb,MAAMnJ,EAAM,SAAS,cAAc,QAAQ,EAC3CA,EAAI,KAAO,SACXA,EAAI,UAAY,oBAChBA,EAAI,MAAQ,kBACZA,EAAI,aAAa,aAAc,iBAAiB,EAChDA,EAAI,UACF,uZAKFmJ,EAAO,YAAYnJ,CAAG,EAGtB,MAAMoJ,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,mBAClBA,EAAM,UACJ,6EAEEF,EAAQ,IAAKG,GAAQ;AAAA;AAAA,+DAEkCA,EAAI,GAAG;AAAA;AAAA,2DAEXA,EAAI,IAAI;AAAA,wCAC3BA,EAAI,KAAK;AAAA;AAAA;AAAA,SAGxC,EAAE,KAAK,EAAE,EACZ,SACFF,EAAO,YAAYC,CAAK,EAExB,KAAK,cAAiBA,EACtB,KAAK,eAAiBpJ,EAGtB,MAAMsJ,EAAiB1mB,GAAQ,CAC7B,MAAMgG,EAAIhG,GAAO,KAAK,gBAAgB,KAAM,GAAM,EAAE,YAAY,GAAG,IAAI,YAAY,EACnFwmB,EAAM,iBAAiB,8BAA8B,EAAE,QAASxjB,GAAM,CACpEA,EAAE,QAAWA,EAAE,QAAUgD,CAC3B,CAAC,CACH,EACA0gB,EAAA,EAKAtJ,EAAI,iBAAiB,QAAUjc,GAAM,CACnCA,EAAE,kBACF,MAAMwlB,EAAO,CAACH,EAAM,UAAU,SAAS,MAAM,EAC7CA,EAAM,UAAU,OAAO,OAAQG,CAAI,EACnCvJ,EAAI,UAAU,OAAO,SAAUuJ,CAAI,EAC/BA,GAAMD,EAAA,CACZ,CAAC,EAGD,SAAS,iBAAiB,QAAUvlB,GAAM,CACnCqlB,EAAM,UAAU,SAAS,MAAM,IAChCA,EAAM,SAASrlB,EAAE,MAAM,GAAKic,EAAI,SAASjc,EAAE,MAAM,IACrDqlB,EAAM,UAAU,OAAO,MAAM,EAC7BpJ,EAAI,UAAU,OAAO,QAAQ,GAC/B,CAAC,EAGDoJ,EAAM,iBAAiB,SAAWrlB,GAAM,CACtC,MAAM6jB,EAAQ7jB,EAAE,OAAO,QAAQ,0CAA0C,EACzE,GAAI,CAAC6jB,EAAO,OACZ,MAAMhlB,EAAMglB,EAAM,MAClB,KAAK,WAAWhlB,CAAG,EACnB,GAAI,CAAE,aAAa,QAAQ,kBAAmBA,CAAG,CAAG,MAAQ,CAAC,CAC7DwmB,EAAM,UAAU,OAAO,MAAM,EAC7BpJ,EAAI,UAAU,OAAO,QAAQ,CAC/B,CAAC,EAGD,KAAK,IAAI,GAAG,gBAAkBjK,GAAQuT,EAAcvT,EAAI,GAAG,CAAC,CAC9D,CAYA,mBAAoB,CAClB,KAAK,mBAAqB,IAAInB,EAC9B,KAAK,gBAAkB,IAAIA,EAC3B,KAAK,gBAAkB,GAGvB,KAAK,eAAiB,IAAIC,EAAY,CACpC,OAAQ,KAAK,gBACb,OAAQ,IACR,MAAO,IAAIR,EAAM,CACf,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,QAAS,QAAS,SAAU,QAAS,EACvF,EACD,WAAY,CAAE,MAAO,YAAa,uBAAwB,GAAM,CACjE,EAGD,KAAK,kBAAoB,IAAIO,EAAY,CACvC,OAAQ,KAAK,mBACb,OAAQ,IACR,MAAQqB,GACFA,EAAQ,IAAI,OAAO,IAAM,WACpB,IAAI7B,EAAM,CACf,KAAM,IAAIE,EAAK,CAAE,MAAO,sBAAuB,EAC/C,OAAQ,IAAID,EAAO,CAAE,MAAO,sBAAuB,MAAO,EAAG,EAC9D,EAEI,IAAID,EAAM,CACf,MAAO,IAAIoM,GAAO,CAChB,OAAQ,EACR,KAAM,IAAIlM,EAAK,CAAE,MAAO,UAAW,EACnC,OAAQ,IAAID,EAAO,CAAE,MAAO,UAAW,MAAO,IAAK,EACpD,EACF,EAEH,WAAY,CAAE,MAAO,eAAgB,uBAAwB,GAAM,CACpE,EAED,KAAK,IAAI,SAAS,KAAK,cAAc,EACrC,KAAK,IAAI,SAAS,KAAK,iBAAiB,EAExC,KAAK,cAAgB,CAAE,OAAQ,GAAI,OAAQ,EAAC,EAC5C,KAAK,cAAgB,EACvB,CAGA,WAAW/X,EAAI,CAAE,KAAK,cAAc,OAAO,KAAKA,CAAE,CAAG,CAErD,kBAAkBA,EAAI,CAAE,KAAK,cAAc,OAAO,KAAKA,CAAE,CAAG,CAQ5D,oBAAoB4O,EAAKC,EAAKE,EAAW,KAAM,CAC7C,GAAIH,GAAO,MAAQC,GAAO,KAAM,OAChC,MAAM8T,EAASW,EAAW,CAAC1U,EAAKC,CAAG,CAAC,EAGpC,GAFA,KAAK,mBAAmB,QAEpBE,GAAYA,EAAW,EAAG,CAG5B,MAAMke,EAAWle,EAAW,KAAK,IAAKF,EAAM,KAAK,GAAM,GAAG,EACpDqe,EAAO,IAAIxO,GAAQ,CAAE,SAAU,IAAI3E,GAAY,CAAC,KAAK,YAAY4I,EAAQsK,CAAQ,CAAC,CAAC,EAAG,EAC5FC,EAAK,IAAI,QAAS,UAAU,EAC5B,KAAK,mBAAmB,WAAWA,CAAI,CACzC,CACA,MAAMC,EAAM,IAAIzO,GAAQ,CAAE,SAAU,IAAIwH,GAAMvD,CAAM,EAAG,EACvDwK,EAAI,IAAI,QAAS,KAAK,EACtB,KAAK,mBAAmB,WAAWA,CAAG,CACxC,CAGA,YAAYxK,EAAQyK,EAAcC,EAAW,GAAI,CAG/C,MAAMpb,EAAO,GAEP5I,EAAI+jB,EAAe,EACzB,QAASxyB,EAAI,EAAGA,GAAKyyB,EAAUzyB,IAAK,CAClC,MAAMoS,EAAKpS,EAAIyyB,EAAY,EAAI,KAAK,GACpCpb,EAAK,KAAK,CAAC0Q,EAAO,CAAC,EAAItZ,EAAI,KAAK,IAAI2D,CAAC,EAAG2V,EAAO,CAAC,EAAItZ,EAAI,KAAK,IAAI2D,CAAC,CAAC,CAAC,CACtE,CACA,OAAOiF,CACT,CAGA,SAASrD,EAAKC,EAAKye,EAAO,GAAI,CACf,KAAK,IAAI,UACjB,QAAQ,CAAE,OAAQhK,EAAW,CAAC1U,EAAKC,CAAG,CAAC,EAAG,KAAAye,EAAM,SAAU,IAAK,CACtE,CAGA,kBAAmB,CACjB,KAAK,gBAAkB,GACvB,KAAK,gBAAgB,OACvB,CAGA,iBAAiB1e,EAAKC,EAAK,CACrBD,GAAO,MAAQC,GAAO,OAC1B,KAAK,gBAAgB,KAAKyU,EAAW,CAAC1U,EAAKC,CAAG,CAAC,CAAC,EAChD,KAAK,gBAAgB,QACjB,KAAK,gBAAgB,QAAU,GACjC,KAAK,gBAAgB,WAAW,IAAI6P,GAAQ,CAAE,SAAU,IAAIpF,GAAW,KAAK,eAAe,EAAG,CAAC,EAEnG,CAGA,kBAAmB,CACjB,KAAK,gBAAkB,GACvB,KAAK,gBAAgB,OACvB,CAGA,kBAAkBd,EAAQ,CACxB,KAAK,cAAgB,CAAC,CAACA,EACnB,KAAK,aACP,KAAK,WAAW,UAAU,OAAO,YAAa,KAAK,aAAa,EAChE,KAAK,WAAW,MAAQ,KAAK,cAAgB,uBAAyB,mBACtE,KAAK,WAAW,UAAY,KAAK,cAC7B,kCACA,uCAEF,KAAK,eAAe,KAAK,cAAc,UAAU,OAAO,YAAa,KAAK,aAAa,CAC7F,CAQA,wBAAyB,CACvB,MAAMoU,EAAS,KAAK,IAAI,mBACxB,GAAI,CAACA,EAAQ,OAGb,MAAMW,EAAS,SAAS,cAAc,QAAQ,EAC9CA,EAAO,KAAO,SACdA,EAAO,UAAY,mBACnBA,EAAO,MAAQ,cACfA,EAAO,aAAa,aAAc,aAAa,EAC/CA,EAAO,UAAY,qCACnBX,EAAO,YAAYW,CAAM,EAGzB,MAAMzwB,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,oBACpBA,EAAQ,UACN,wPAIF8vB,EAAO,YAAY9vB,CAAO,EAE1B,KAAK,cAAgBywB,EACrB,KAAK,eAAiBzwB,EACtB,KAAK,aAAeA,EAAQ,cAAc,eAAe,EACzD,KAAK,WAAaA,EAAQ,cAAc,mBAAmB,EAE3D,MAAMiuB,EAAQ,IAAM,CAAEjuB,EAAQ,UAAU,OAAO,MAAM,EAAGywB,EAAO,UAAU,OAAO,QAAQ,CAAG,EACrFP,EAAO,IAAM,CAAElwB,EAAQ,UAAU,IAAI,MAAM,EAAGywB,EAAO,UAAU,IAAI,QAAQ,CAAG,EAEpFA,EAAO,iBAAiB,QAAU/lB,GAAM,CACtCA,EAAE,kBACF1K,EAAQ,UAAU,SAAS,MAAM,EAAIiuB,EAAA,EAAUiC,EAAA,CACjD,CAAC,EAID,SAAS,iBAAiB,QAAUxlB,GAAM,CACnC1K,EAAQ,UAAU,SAAS,MAAM,IAClCA,EAAQ,SAAS0K,EAAE,MAAM,GAAK+lB,EAAO,SAAS/lB,EAAE,MAAM,GACtD,KAAK,eACTujB,EAAA,EACF,CAAC,EAED,KAAK,aAAa,iBAAiB,QAAUvjB,GAAM,CACjDA,EAAE,kBACF,UAAWxH,KAAM,KAAK,cAAc,OAAU,GAAI,CAAEA,EAAA,CAAM,OAASmF,EAAK,CAAE,QAAQ,MAAMA,CAAG,CAAG,CACzF,KAAK,eAAe4lB,EAAA,CAC3B,CAAC,EAED,KAAK,WAAW,iBAAiB,QAAUvjB,GAAM,CAC/CA,EAAE,kBACF,MAAMgmB,EAAO,CAAC,KAAK,cACnB,UAAWxtB,KAAM,KAAK,cAAc,OAAU,GAAI,CAAEA,EAAGwtB,CAAI,CAAG,OAASroB,EAAK,CAAE,QAAQ,MAAMA,CAAG,CAAG,CACpG,CAAC,CACH,CAKA,gBAAgBwU,EAAS,CACvB,MAAMtR,EAAWsR,EAAQ,IAAI,UAAU,GAAK,UACtCqJ,EAAQ,KAAK,SAAS3a,CAAQ,EAEpC,GAAIsR,IAAY,KAAK,gBAEnB,MAAO,CAEL,IAAI7B,EAAM,CACR,MAAO,IAAIoM,GAAO,CAChB,OAAQ,GACR,KAAM,IAAIlM,EAAK,CAAE,MAAO,0BAA2B,EACnD,OAAQ,IAAID,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EAClD,EACF,EAED,IAAID,EAAM,CACR,KAAM,IAAImG,GAAK,CACb,KAAM+E,EACN,KAAM,kBACN,aAAc,SACd,UAAW,SACX,QAAS,GACV,EACF,GAKL,MAAMyK,EAAc9T,EAAQ,IAAI,OAAO,EACvC,OAAI8T,IAKA,KAAK,eAAeplB,CAAQ,EACvB,KAAK,eAAeA,CAAQ,EAG9B,KAAK,aACd,CAMA,kBAAkBqlB,EAAQ,CACxB,SAAW,CAACrlB,EAAUhK,CAAM,IAAK,OAAO,QAAQqvB,CAAM,EAAG,CAEnDrvB,EAAO,QACJ,KAAK,eAAegK,CAAQ,GAG/B,KAAK,eAAeA,CAAQ,EAAE,MAAQhK,EAAO,MACzCA,EAAO,QACT,KAAK,eAAegK,CAAQ,EAAE,MAAQhK,EAAO,QAJ/C,KAAK,eAAegK,CAAQ,EAAI,CAAE,MAAOhK,EAAO,MAAO,MAAOA,EAAO,OAASgK,CAAA,GAUlF,MAAM2a,EAAQ,KAAK,SAAS3a,CAAQ,EAC9B6a,EAAW7kB,EAAO,UAAY,GAEpC,KAAK,eAAegK,CAAQ,EAAI,KAAK,iBAAiB2a,EAAOE,CAAQ,CACvE,CAGA,KAAK,aAAa,SACpB,CAKA,UAAUtU,EAAKC,EAAKoY,EAAa,GAAI,CACnC,QAAQ,IAAI,6BAA8BrY,EAAKC,EAAK,mBAAoBoY,CAAU,EAElF,MAAMtN,EAAU,IAAI+E,GAAQ,CAC1B,SAAU,IAAIwH,GAAM5C,EAAW,CAAC1U,EAAKC,CAAG,CAAC,CAAC,EAC1C,GAAGoY,CAAA,CACJ,EAGD,OAAAtN,EAAQ,IAAI,MAAO/K,CAAG,EACtB+K,EAAQ,IAAI,MAAO9K,CAAG,EAEtB,KAAK,aAAa,WAAW8K,CAAO,EACpC,QAAQ,IAAI,0CAA2C,KAAK,aAAa,cAAc,MAAM,EACtFA,CACT,CAKA,WAAWgU,EAAW,CACpB,QAAQ,IAAI,mBAAoBA,EAAU,OAAQ,SAAS,EAE3D,MAAMtjB,EAAWsjB,EAAU,IAAKzgB,GACd,IAAIwR,GAAQ,CAC1B,SAAU,IAAIwH,GAAM5C,EAAW,CAACpW,EAAI,UAAWA,EAAI,QAAQ,CAAC,CAAC,EAC7D,GAAIA,EAAI,GACR,KAAMA,EAAI,KACV,YAAaA,EAAI,YACjB,SAAUA,EAAI,SACd,IAAKA,EAAI,UACT,IAAKA,EAAI,SACV,CAEF,EAED,YAAK,aAAa,YAAY7C,CAAQ,EACtC,QAAQ,IAAI,2CAA4C,KAAK,aAAa,cAAc,MAAM,EACvFA,CACT,CAKA,cAAe,CACb,KAAK,aAAa,QAClB,KAAK,gBAAkB,IACzB,CAKA,aAAaujB,EAAa,CACxB,GAAI,OAAOA,GAAgB,SACzB,KAAK,aAAa,cAAcA,CAAW,MACtC,CACL,MAAMjU,EAAU,KAAK,aAAa,cAAc,KAC9CpP,GAAKA,EAAE,IAAI,IAAI,IAAMqjB,CAAA,EAEnBjU,GACF,KAAK,aAAa,cAAcA,CAAO,CAE3C,CACF,CAKA,YAAa,CACX,OAAO,KAAK,aAAa,aAC3B,CAKA,WAAWrf,EAAI,CACb,OAAO,KAAK,aAAa,cAAc,QAAUiQ,EAAE,IAAI,IAAI,IAAMjQ,CAAE,CACrE,CAKA,aAAaszB,EAAa,CACxB,OAAI,OAAOA,GAAgB,SACzB,KAAK,gBAAkBA,EAEvB,KAAK,gBAAkB,KAAK,WAAWA,CAAW,EAEpD,KAAK,aAAa,UACX,KAAK,eACd,CAKA,gBAAiB,CACf,KAAK,gBAAkB,KACvB,KAAK,aAAa,SACpB,CAKA,OAAOhf,EAAKC,EAAKye,EAAO,GAAI,CAC1B,KAAK,IAAI,UAAU,QAAQ,CACzB,OAAQhK,EAAW,CAAC1U,EAAKC,CAAG,CAAC,EAC7B,KAAAye,EACA,SAAU,IACX,CACH,CAKA,aAAaO,EAAU,GAAI,CACzB,MAAM5N,EAAS,KAAK,aAAa,YAC7BA,GAAUA,EAAO,CAAC,IAAM,KAC1B,KAAK,IAAI,UAAU,IAAIA,EAAQ,CAC7B,QAAS,CAAC4N,EAASA,EAASA,EAASA,CAAO,EAC5C,SAAU,IACV,QAAS,GACV,CAEL,CAKA,WAAY,CACV,MAAMlL,EAAS,KAAK,IAAI,UAAU,YAClC,OAAOgF,GAAShF,CAAM,CACxB,CAKA,SAAU,CACR,OAAO,KAAK,IAAI,UAAU,SAC5B,CAKA,UAAU/T,EAAKC,EAAK,CAClB,KAAK,IAAI,UAAU,UAAUyU,EAAW,CAAC1U,EAAKC,CAAG,CAAC,CAAC,CACrD,CAKA,QAAQye,EAAM,CACZ,KAAK,IAAI,UAAU,QAAQA,CAAI,CACjC,CAUA,QAAQvwB,EAAU,CAChB,YAAK,eAAe,KAAKA,CAAQ,EAG7B,KAAK,eAAe,SAAW,IACjC,KAAK,YAAc,KAGnB,KAAK,IAAI,GAAG,WAAY,IAAM,CACxB,KAAK,cACP,aAAa,KAAK,WAAW,EAC7B,KAAK,YAAc,KAEvB,CAAC,EAED,KAAK,IAAI,GAAG,QAAUyc,GAAQ,CAExB,KAAK,cACP,aAAa,KAAK,WAAW,EAC7B,KAAK,YAAc,MAMjB,CAAC,KAAK,gBAAkB,KAAK,oBAC/B,KAAK,mBAAmB,cAAc,QAIxC,IAAIsU,EAAoB,GACpBC,EAAmB,GACnBC,EAAgB,KAapB,GAZA,KAAK,IAAI,sBAAsBxU,EAAI,MAAQG,GAAY,CACjDA,EAAQ,IAAI,YAAY,IAAM,WAChCoU,EAAmB,IAEjBpU,EAAQ,IAAI,MAAM,IACpBqU,EAAgBrU,GAElBmU,EAAoB,EACtB,CAAC,EAIGA,GAAqB,CAACC,GAAoB,CAACC,EAC7C,OAIF,KAAM,CAACpf,EAAKC,CAAG,EAAI8Y,GAASnO,EAAI,UAAU,EAC1C,KAAK,YAAc,WAAW,IAAM,CAClC,KAAK,YAAc,KAGnB,IAAIiS,EAAiB,KACrB,KAAK,IAAI,sBAAsBjS,EAAI,MAAQG,GAAY,CACrD,GAAIA,EAAQ,IAAI,MAAM,EACpB,OAAA8R,EAAiB9R,EACV,EAEX,CAAC,EAED,UAAW3Z,KAAM,KAAK,eACpBA,EAAG4O,EAAKC,EAAK4c,EAAgBjS,CAAG,CAEpC,EAAG,GAAG,CACR,CAAC,GAII,IAAM,CACX,MAAMyU,EAAQ,KAAK,eAAe,QAAQlxB,CAAQ,EAC9CkxB,EAAQ,IACV,KAAK,eAAe,OAAOA,EAAO,CAAC,CAEvC,CACF,CAKA,cAAclxB,EAAU,CACtB,KAAK,IAAI,GAAG,cAAgByc,GAAQ,CAClC,GAAIA,EAAI,SAAU,OAElB,KAAM,CAAC5K,EAAKC,CAAG,EAAI8Y,GAASnO,EAAI,UAAU,EAG1C,IAAI0U,EAAiB,KACrB,KAAK,IAAI,sBAAsB1U,EAAI,MAAQG,GAAY,CACrD,GAAIA,EAAQ,IAAI,MAAM,EACtB,OAAAuU,EAAiBvU,EACV,EAET,CAAC,EAGD,KAAK,IAAI,mBAAmB,MAAM,OAASuU,EAAiB,UAAY,GAExEnxB,EAAS6R,EAAKC,EAAKqf,EAAgB1U,CAAG,CACxC,CAAC,CACH,CAMA,mBAAoB,CAGpB,CAoBA,gBAAgB2U,EAASpH,EAAOqH,EAAe,GAAIC,EAAc,KAAM,CACrE,KAAM,CACJ,YAAAC,EAAc,UACd,YAAAC,EAAc,EACd,WAAAC,EAAc,KACd,UAAAC,EAAc,uBAKd,gBAAAC,EAAkB,KAClB,gBAAAC,EAAkB,KAClB,YAAAC,EAAc,EACd,eAAAC,EAAmB,KACnB,iBAAAC,EAAmB,UACnB,iBAAAC,EAAmB,KACjBX,EAEEnV,EAAS,IAAIZ,EAAa,CAC9B,SAAU,IAAI2W,KAAU,aAAab,EAAS,CAC5C,kBAAmB,YACpB,EACF,EAOKc,EAAa,IAAIjX,EAAK,CAAE,MAAOyW,EAAW,EAC1CS,EAAa,IAAIhL,GAAO,CAC5B,OAAQ0K,EACR,KAAQ,IAAI5W,EAAK,CAAE,MAAO6W,GAAkBP,EAAa,EACzD,OAAQ,IAAIvW,EAAO,CAAE,MAAO+W,EAAkB,MAAOC,EAAkB,EACxE,EAMKI,EAAa,IAAIpX,EAAO,CAC5B,MAAOuW,EACP,MAAOC,EACP,GAAIC,EAAa,CAAE,SAAUA,GAAe,EAAC,CAC9C,EAED,IAAIY,EACJ,GAAIV,EAAiB,CACnB,MAAMW,EAAUV,GAA4CJ,EAAc,EAC1Ea,EAAa,CACX,IAAItX,EAAM,CACR,OAAQ,IAAIC,EAAO,CAAE,MAAO2W,EAAiB,MAAOW,EAAS,EAC9D,EACD,IAAIvX,EAAM,CACR,OAAQqX,EACR,KAAQF,EACR,MAAQC,CAAA,CACT,EAEL,MACEE,EAAa,IAAItX,EAAM,CACrB,OAAQqX,EACR,KAAQF,EACR,MAAQC,CAAA,CACT,EAGH,MAAMtW,EAAQ,IAAIN,EAAY,CAC5B,MAAAyO,EACA,OAAA9N,EACA,MAAOmW,CAAA,CACR,EACDxW,EAAM,IAAI,UAAWwV,EAAa,SAAW,KAAK,EASlD,MAAMkB,EAAoBnI,GACnBA,EACDA,EAAS,SAAS,SAAS,EAAa,mBACxCA,EAAS,SAAS,YAAY,EAAU,gBACxCA,EAAS,SAAS,OAAO,EAAe,iBACrC,SAJe,KAOxB,GAAIiH,EAAa,gBACfxV,EAAM,IAAI,kBAAmBwV,EAAa,eAAe,MACpD,CACL,MAAMmB,EAAQtW,EAAO,cACfuW,EAAUF,EAAiBC,EAAM,CAAC,GAAG,iBAAiB,WAAW,EACvE,GAAIC,EACF5W,EAAM,IAAI,kBAAmB4W,CAAO,MAC/B,CAEL,MAAMC,EAAQC,GAAO,CACnB,MAAMC,EAAOL,EAAiBI,EAAG,QAAQ,iBAAiB,WAAW,EACjEC,GAAM/W,EAAM,IAAI,kBAAmB+W,CAAI,EAC3C1W,EAAO,GAAG,aAAcwW,CAAI,CAC9B,EACAxW,EAAO,GAAG,aAAcwW,CAAI,CAC9B,CACF,CAGA,OADcpB,GAAe,KAAK,cAC5B,YAAY,KAAKzV,CAAK,EAE5B,QAAQ,IAAI,iCAAkCmO,EAAO,IAAK9N,EAAO,cAAc,OAAQ,WACrFoV,EAAc,cAAcA,EAAY,IAAI,OAAO,CAAC,KAAO,IACtDzV,CACT,CAYA,cAActe,EAAIysB,EAAO3e,EAAc,GAAI,CACzC,MAAM8gB,EAAQ,IAAI9F,GAAW,CAC3B,MAAO2D,EAAM,MAAK,CACnB,EAGD,OAAAmC,EAAM,IAAI,UAAW5uB,CAAE,EACvB4uB,EAAM,IAAI,cAAe9gB,CAAW,EAEpC,KAAK,aAAa,YAAY,KAAK8gB,CAAK,EAExC,QAAQ,IAAI,+BAAgCnC,EAAM,OAAQ,OAAQzsB,EAAK,GAAG,EACnE4uB,CACT,CAsBA,YAAYC,EAAYpC,EAAOha,EAAK4L,EAAQxY,EAAU,GAAI,CACxD,MAAM+oB,EAAQ,KAAK,qBAAqBC,CAAU,EAClD,GAAI,CAACD,EACH,eAAQ,KAAK,0BAA0BC,CAAU,uCAAuCpC,CAAK,GAAG,EACzF,KAGT,MAAM/jB,EAAS,CAAE,OAAQ2V,EAAQ,MAAO,GAAM,MAAO,IAAK,OAAQ,KAC9DxY,EAAQ,QAAU,SAAW6C,EAAO,OAAS7C,EAAQ,OAEzD,MAAMyvB,EAAY,IAAIC,GAAQ,CAC5B,IAAA9iB,EACA,OAAA/J,EACA,WAAY7C,EAAQ,aAAe,OAAYA,EAAQ,WAAa,YACpE,YAAa,YACb,MAAO,GACP,aAAcA,EAAQ,aACvB,EAEK2vB,EAAW,IAAI/D,GAAU,CAC7B,MAAAhF,EACA,QAAS5mB,EAAQ,UAAY,OAAYA,EAAQ,QAAU,GAC3D,OAAQyvB,EACR,QAASzvB,EAAQ,UAAY,OAAYA,EAAQ,QAAU,EAC3D,OAAQA,EAAQ,OACjB,EAYD,GAXA2vB,EAAS,IAAI,UAAW,KAAK,EAC7BA,EAAS,IAAI,kBAAmB,cAAc,EAG9CF,EAAU,GAAG,gBAAiB,IAAM,CAClCtY,EAAU,cAAcyP,CAAK,qDAAsD,UAAW,GAAI,CACpG,CAAC,EAEDmC,EAAM,YAAY,KAAK4G,CAAQ,EAG3B3vB,EAAQ,UACV,GAAI,CACF,KAAK,gBAAgB2vB,EAAU/I,EAAO5mB,EAAQ,SAAS,CACzD,OAASgF,EAAK,CACZ,QAAQ,KAAK,4CAA4C4hB,CAAK,KAAM5hB,CAAG,CACzE,CAKF,OAAIhF,EAAQ,YACV,KAAK,yBAAyB2vB,EAAU/I,CAAK,EAG/C,QAAQ,IAAI,+BAA+BA,CAAK,cAAcoC,CAAU,GAAG,EACpE2G,CACT,CAmBA,YAAY3G,EAAYpC,EAAOha,EAAK5M,EAAU,GAAI,CAChD,MAAM+oB,EAAQ,KAAK,qBAAqBC,CAAU,EAClD,GAAI,CAACD,EACH,eAAQ,KAAK,0BAA0BC,CAAU,uCAAuCpC,CAAK,GAAG,EACzF,KAGT,MAAMgJ,EAAY,IAAI/D,GAAI,CACxB,IAAAjf,EACA,YAAa,YACb,QAAS5M,EAAQ,UAAY,OAAYA,EAAQ,QAAU,GAC3D,aAAcA,EAAQ,aACvB,EAEK6vB,EAAW,IAAIjE,GAAU,CAC7B,MAAAhF,EACA,QAAS5mB,EAAQ,UAAY,OAAYA,EAAQ,QAAU,GAC3D,OAAQ4vB,EACR,QAAS5vB,EAAQ,UAAY,OAAYA,EAAQ,QAAU,EAC3D,OAAQA,EAAQ,OACjB,EAYD,GAXA6vB,EAAS,IAAI,UAAW,KAAK,EAC7BA,EAAS,IAAI,kBAAmB,YAAY,EAG5CD,EAAU,GAAG,gBAAiB,IAAM,CAClCzY,EAAU,cAAcyP,CAAK,sCAAuC,UAAW,GAAI,CACrF,CAAC,EAEDmC,EAAM,YAAY,KAAK8G,CAAQ,EAG3B7vB,EAAQ,UACV,GAAI,CACF,KAAK,gBAAgB6vB,EAAUjJ,EAAO5mB,EAAQ,SAAS,CACzD,OAASgF,EAAK,CACZ,QAAQ,KAAK,4CAA4C4hB,CAAK,KAAM5hB,CAAG,CACzE,CAKF,OAAIhF,EAAQ,YACV,KAAK,yBAAyB6vB,EAAUjJ,CAAK,EAG/C,QAAQ,IAAI,+BAA+BA,CAAK,cAAcoC,CAAU,GAAG,EACpE6G,CACT,CAUA,uBAAwB,CACtB,KAAK,gBAAkB,SAAS,cAAc,KAAK,EACnD,KAAK,gBAAgB,UAAY,uBACjC,KAAK,gBAAgB,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA,MAMrC,MAAMC,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA,MAOrBA,EAAK,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiDjB,KAAK,gBAAgB,YAAYA,CAAI,EACrC,KAAK,IAAI,mBAAmB,YAAY,KAAK,eAAe,EAG5D,MAAMC,EAAUD,EAAK,cAAc,qBAAqB,EAClDE,EAAWF,EAAK,cAAc,sBAAsB,EACpDG,EAAWH,EAAK,cAAc,gBAAgB,EACpDA,EAAK,iBAAiB,8BAA8B,EAAE,QAAS5E,GAAU,CACvEA,EAAM,iBAAiB,SAAU,IAAM,CACrC,MAAMruB,EAAOquB,EAAM,MACfruB,IAAS,OACXkzB,EAAQ,MAAM,QAAU,OACxBE,EAAS,YAAc,8CAEvBF,EAAQ,MAAM,QAAU,GACxBE,EAAS,YAAcpzB,IAAS,MAC5B,0BACA,0BACJmzB,EAAS,YAAcnzB,IAAS,MAC5B,8CACA,sCAER,CAAC,CACH,CAAC,EAGD,MAAM+tB,EAAQ,IAAM,KAAK,sBACzBkF,EAAK,cAAc,kBAAkB,EAAE,iBAAiB,QAASlF,CAAK,EACtEkF,EAAK,cAAc,mBAAmB,EAAE,iBAAiB,QAASlF,CAAK,EACvE,KAAK,gBAAgB,iBAAiB,QAAUvjB,GAAM,CAChDA,EAAE,SAAW,KAAK,iBAAiBujB,EAAA,CACzC,CAAC,EAGDkF,EAAK,cAAc,oBAAoB,EAAE,iBAAiB,QAAS,IAAM,CACvE,MAAMjzB,EAAOizB,EAAK,cAAc,sCAAsC,EAAE,MAClEljB,EAAMkjB,EAAK,cAAc,gBAAgB,EAAE,MAAM,OACjDI,EAAYJ,EAAK,cAAc,iBAAiB,EAAE,MAAM,OACxDlJ,EAAQkJ,EAAK,cAAc,kBAAkB,EAAE,MAAM,OAE3D,GAAI,CAACljB,EAAK,CACRkjB,EAAK,cAAc,gBAAgB,EAAE,MAAM,YAAc,UACzD,MACF,CACA,IAAKjzB,IAAS,OAASA,IAAS,QAAU,CAACqzB,EAAW,CACpDJ,EAAK,cAAc,iBAAiB,EAAE,MAAM,YAAc,UAC1D,MACF,CACA,GAAI,CAAClJ,EAAO,CACVkJ,EAAK,cAAc,kBAAkB,EAAE,MAAM,YAAc,UAC3D,MACF,CAEA,KAAK,kBAAkBjzB,EAAM+P,EAAKsjB,EAAWtJ,CAAK,EAClD,KAAK,qBACP,CAAC,EAGDkJ,EAAK,iBAAiB,UAAYzoB,GAAM,CAClCA,EAAE,MAAQ,UACZA,EAAE,iBACFyoB,EAAK,cAAc,oBAAoB,EAAE,SAEvCzoB,EAAE,MAAQ,WACZA,EAAE,iBACFujB,EAAA,EAEJ,CAAC,CACH,CAKA,oBAAqB,CACnB,MAAMuF,EAAM,KAAK,gBAEjBA,EAAI,cAAc,gBAAgB,EAAE,MAAQ,GAC5CA,EAAI,cAAc,iBAAiB,EAAE,MAAQ,GAC7CA,EAAI,cAAc,kBAAkB,EAAE,MAAQ,GAC9CA,EAAI,iBAAiB,8BAA8B,EAAE,CAAC,EAAE,QAAU,GAClEA,EAAI,cAAc,qBAAqB,EAAE,MAAM,QAAU,GACzDA,EAAI,cAAc,gBAAgB,EAAE,YAAc,0BAClDA,EAAI,cAAc,sBAAsB,EAAE,YAAc,8CAGxDA,EAAI,iBAAiB,oBAAoB,EAAE,QAASC,GAAQ,CAC1DA,EAAI,MAAM,YAAc,0BAC1B,CAAC,EAEDD,EAAI,MAAM,QAAU,OACpBA,EAAI,cAAc,gBAAgB,EAAE,OACtC,CAKA,qBAAsB,CACpB,KAAK,gBAAgB,MAAM,QAAU,MACvC,CAUA,kBAAkBtzB,EAAM+P,EAAKsjB,EAAWtJ,EAAO,CAC7C,MAAMmC,EAAQ,KAAK,qBACnB,GAAI,CAACA,EAAO,CACV5R,EAAU,2CAA4C,QAAS,GAAI,EACnE,MACF,CAEA,IAAIsB,EAEJ,OAAQ5b,EAAA,CACN,IAAK,MAAO,CACV,MAAMwzB,EAAS,IAAIX,GAAQ,CACzB,IAAA9iB,EACA,OAAQ,CAAE,OAAQsjB,EAAW,MAAO,GAAM,MAAO,IAAK,OAAQ,KAC9D,WAAY,YACZ,YAAa,YACb,MAAO,GACR,EACDzX,EAAQ,IAAImT,GAAU,CACpB,MAAAhF,EACA,QAAS,GACT,OAAQyJ,CAAA,CACT,EACDA,EAAO,GAAG,gBAAiB,IAAM,CAC/BlZ,EAAU,QAAQyP,CAAK,iDAAkD,UAAW,GAAI,CAC1F,CAAC,EACD,KACF,CAEA,IAAK,MAAO,CACV,MAAM0J,EAAS,GAAG1jB,CAAG,GAAGA,EAAI,SAAS,GAAG,EAAI,IAAM,GAAG,yDAEtC,mBAAmBsjB,CAAS,CAAC,mDAGtCK,EAAY,IAAIrY,EAAa,CACjC,IAAKoY,EACL,OAAQ,IAAIzB,EAAQ,CACrB,EACD0B,EAAU,GAAG,oBAAqB,IAAM,CACtCpZ,EAAU,QAAQyP,CAAK,4CAA6C,UAAW,GAAI,CACrF,CAAC,EAEDnO,EAAQ,IAAIN,EAAY,CACtB,MAAAyO,EACA,QAAS,GACT,OAAQ2J,EACR,MAAO,IAAI5Y,EAAM,CACf,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAM,IAAIC,EAAK,CAAE,MAAO,uBAAwB,EACjD,EACF,EACD,KACF,CAEA,IAAK,MACHY,EAAQ,IAAImT,GAAU,CACpB,MAAAhF,EACA,QAAS,GACT,OAAQ,IAAIiF,GAAI,CACd,IAAAjf,EACA,YAAa,YACd,EACF,EACD6L,EAAM,YAAY,GAAG,gBAAiB,IAAM,CAC1CtB,EAAU,QAAQyP,CAAK,+CAAgD,UAAW,GAAI,CACxF,CAAC,EACD,MAEF,QACEzP,EAAU,uBAAuBta,CAAI,GAAI,QAAS,GAAI,EACtD,OAIJ4b,EAAM,IAAI,UAAW5b,EAAK,aAAa,EACvC4b,EAAM,IAAI,kBAAmB,CAC3B,IAAK,eACL,IAAK,eACL,IAAK,cACL5b,CAAI,GAAKA,EAAK,aAAa,EAI7B4b,EAAM,IAAI,YAAa,EAAI,EAE3BsQ,EAAM,YAAY,KAAKtQ,CAAK,EAC5BtB,EAAU,UAAUyP,CAAK,8BAA+B,UAAW,GAAI,EACvE,QAAQ,IAAI,sBAAsB/pB,EAAK,aAAa,kBAAkB+pB,CAAK,GAAG,CAChF,CAcA,uBAAuBnO,EAAO5F,EAAI,CAIhC,MAAM2d,EAAM/X,EAAM,IAAI,SAAS,EAC/B,GAAI+X,EAAK,CACP,MAAMC,EAAY5d,EAAG,cAAc,qCAAqC,EACxE,GAAI4d,GAAa,CAACA,EAAU,cAAc,uBAAuB,EAAG,CAClE,MAAMC,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,UAAY,2BAA2B,OAAOF,CAAG,EAAE,aAAa,GACrEE,EAAK,YAAc,OAAOF,CAAG,EAC7BE,EAAK,MAAQ,GAAGF,CAAG,SACnBC,EAAU,YAAYC,CAAI,CAC5B,CACF,CAKA,MAAMC,EAAS9d,EAAG,cAAc,oCAAoC,EACpE,GAAI8d,EAAQ,CACV,MAAMC,EAAYD,EAAO,cAAc,oDAAoD,EACvFC,GAAa,CAACA,EAAU,cAAc,6BAA6B,IACrEA,EAAU,UACR,+MAIN,CAOA,MAAMC,EAAUhe,EAAG,cAAc,sBAAsB,EACjDie,EAAiB,IAAM,CAC3B,GAAI,CAACD,EAAS,OACd,MAAMtF,EAAO9S,EAAM,IAAI,iBAAiB,EACxC,IAAI6N,EAAMuK,EAAQ,cAAc,6BAA6B,EAC7D,GAAI,CAACtF,EAAM,CACLjF,KAAS,SACb,MACF,CACA,GAAI,CAACA,EAAK,CACRA,EAAM,SAAS,cAAc,KAAK,EAClCA,EAAI,UAAY,oBAChB,MAAMxD,EAAQ+N,EAAQ,cAAc,gBAAgB,EAChD/N,GAASA,EAAM,YACjB+N,EAAQ,aAAavK,EAAKxD,EAAM,WAAW,EAE3C+N,EAAQ,YAAYvK,CAAG,CAE3B,CACAA,EAAI,YAAciF,CACpB,EAgBA,GAfAuF,EAAA,EACKrY,EAAM,oBACTA,EAAM,kBAAoB,GAC1BA,EAAM,GAAG,yBAA0B,IAAM,CAIvCqY,EAAA,CACF,CAAC,GAOCrY,EAAM,IAAI,WAAW,IAAM,IAAQkY,GAAU,CAACA,EAAO,cAAc,yBAAyB,EAAG,CACjG,MAAMI,EAAY,SAAS,cAAc,QAAQ,EACjDA,EAAU,KAAO,SACjBA,EAAU,UAAY,gBACtBA,EAAU,MAAQ,oBAClBA,EAAU,aAAa,aAAc,cAAc,EACnDA,EAAU,UACR,0LAGFA,EAAU,iBAAiB,QAAU1pB,GAAM,CACzCA,EAAE,kBACF,KAAK,aAAaoR,CAAK,CACzB,CAAC,EACDkY,EAAO,YAAYI,CAAS,CAC9B,CAaA,MAAM9mB,EAAWwO,EAAM,IAAI,mBAAmB,EAC9C,GAAIxO,GAAY,KAAM,CACpB,MAAMwmB,EAAY5d,EAAG,cAAc,qCAAqC,EACxE,IAAI6d,EAAOD,EAAYA,EAAU,cAAc,0BAA0B,EAAI,KAC7E,MAAM9lB,EAAS8N,EAAM,IAAI,uBAAuB,GAAK,SAC/C3O,EAAe2O,EAAM,aAAa,cAAc,QAAU,EAC1D7N,EAAa6N,EAAM,IAAI,2BAA2B,GAAK,EAGvDuY,GAAY,IAAM,CACtB,OAAQrmB,EAAA,CACN,IAAK,SACH,MAAO,CAAE,KAAM,UAAUb,CAAY,GAAI,IAAK,wBACrC,MAAO,sCAAuC,UAAW,IACpE,IAAK,YACH,MAAO,CAAE,KAAM,IAAK,IAAK,2BAChB,MAAO,aAAc,UAAW,IAC3C,IAAK,YACH,MAAO,CAAE,KAAM,cAAe,IAAK,2BAC1B,MAAO,wCAAyC,UAAW,IACtE,IAAK,WACH,MAAO,CAAE,KAAM,SAAU,IAAK,0BACrB,MAAO,gDAAiD,UAAW,IAC9E,IAAK,SACH,MAAO,CAAE,KAAM,GAAGc,CAAU,iBAAkB,IAAK,wBAC1C,MAAO,oCAAqC,UAAW,IAClE,IAAK,QACL,KAAK,KACL,KAAK,OACL,QACE,OAAO,KAEb,KAEA,GAAI,CAAComB,EACCN,KAAW,iBACND,EAAW,CACfC,IACHA,EAAO,SAAS,cAAc,MAAM,EACpCA,EAAK,UAAY,iBACjBD,EAAU,YAAYC,CAAI,GAE5BA,EAAK,UAAY,kBAAkBM,EAAS,GAAG,GAC/CN,EAAK,YAAcM,EAAS,KAC5BN,EAAK,MAAQM,EAAS,MACtBN,EAAK,MAAM,OAASM,EAAS,UAAY,UAAY,UACrDN,EAAK,MAAM,QAAUM,EAAS,UAAY,IAAM,OAGhD,MAAMC,EAAQP,EAAK,UAAU,EAAI,EACjCA,EAAK,YAAYO,CAAK,EACtBP,EAAOO,EAEHD,EAAS,WACXN,EAAK,iBAAiB,QAAUrpB,GAAM,CACpCA,EAAE,iBACFA,EAAE,kBACF,OAAO,cAAc,IAAI,YAAY,2BAA4B,CAC/D,OAAQ,CAAE,SAAA4C,EAAU,OAAAU,EAAQ,MAAA8N,CAAA,CAAM,CACnC,CAAC,CACJ,CAAC,CAEL,CACF,CAIA,IADoBA,EAAM,IAAI,OAAO,GAAK,IAAI,cAC/B,SAAS,UAAU,IAChC,KAAK,qBAAuBA,EAExBkY,GAAU,CAACA,EAAO,cAAc,eAAe,GAAG,CACpD,MAAMO,EAAS,SAAS,cAAc,MAAM,EAC5CA,EAAO,UAAY,eACnBA,EAAO,MAAQ,qBACfA,EAAO,YAAc,IACrBA,EAAO,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UASvBA,EAAO,iBAAiB,aAAc,IAAM,CAAEA,EAAO,MAAM,WAAa,SAAW,CAAC,EACpFA,EAAO,iBAAiB,aAAc,IAAM,CAAEA,EAAO,MAAM,WAAa,SAAW,CAAC,EACpFA,EAAO,iBAAiB,QAAU7pB,GAAM,CACtCA,EAAE,kBACF,KAAK,oBACP,CAAC,EACDspB,EAAO,QAAQO,CAAM,CACvB,CAEJ,CAUA,aAAazY,EAAO,CAClB,MAAMmO,EAAQnO,EAAM,IAAI,OAAO,GAAK,aACpC,GAAI,CAAC,QAAQ,WAAWmO,CAAK;;AAAA,2EAA+F,EAC1H,OAKF,MAAMuK,EAASpI,GAAU,CACvB,MAAMvQ,EAASuQ,EAAM,YACrB,GAAIvQ,EAAO,WAAW,SAASC,CAAK,EAClC,OAAAD,EAAO,OAAOC,CAAK,EACZ,GAET,IAAI2Y,EAAU,GACd,OAAA5Y,EAAO,QAAS6Y,GAAU,CACpB,CAACD,GAAWC,EAAM,YACpBD,EAAUD,EAAME,CAAK,EAEzB,CAAC,EACMD,CACT,EAEWD,EAAM,KAAK,YAAY,GAEhC,QAAQ,IAAI,4BAA4BvK,CAAK,GAAG,EAChDzP,EAAU,YAAYyP,CAAK,kBAAmB,OAAQ,GAAI,GAE1D,QAAQ,KAAK,mCAAmCA,CAAK,gBAAgB,CAEzE,CAaA,4BAA4BxD,EAAe,CACzC,MAAMkO,EAAiBlO,EAAc,SAAS,cAAc,kBAAkB,EACxEmO,EAAKnO,EAAc,SAAS,cAAc,UAAU,EAC1D,GAAI,CAACkO,GAAkB,CAACC,EAAI,OAG5B,IAAIC,EAAQF,EAAe,cAAc,2BAA2B,EAC/DE,IACHA,EAAQ,SAAS,cAAc,KAAK,EACpCA,EAAM,UAAY,kBAClBA,EAAM,UAAY;AAAA;AAAA;AAAA,QAIlBF,EAAe,aAAaE,EAAOD,CAAE,GAIvC,IAAIE,EAASH,EAAe,cAAc,yBAAyB,EAC9DG,IACHA,EAAS,SAAS,cAAc,KAAK,EACrCA,EAAO,UAAY,gBACnBA,EAAO,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOnBH,EAAe,YAAYG,CAAM,EAEjCA,EAAO,cAAc,gBAAgB,EAAE,iBAAiB,QAAUpqB,GAAM,CACtEA,EAAE,kBACF,KAAK,mBACP,CAAC,GAIH,MAAMqqB,EAAS,KAAK,eACpBF,EAAM,cAAc,wBAAwB,EAAE,YAC5C,GAAGE,EAAO,cAAc,UAC1BD,EAAO,cAAc,iBAAiB,EAAE,YACtC,GAAGC,EAAO,aAAa,WAAWA,EAAO,gBAAkB,EAAI,GAAK,GAAG,EAC3E,CAOA,cAAe,CACb,IAAIC,EAAgB,EAChBC,EAAiB,EAErB,MAAMC,EAAkB,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAElDV,EAASpI,GAAU,CACvBA,EAAM,YAAY,QAAStQ,GAAU,CAC/BA,EAAM,IAAI,wBAAwB,IAAM,KACxCoZ,EAAgB,IAAIpZ,EAAM,IAAI,OAAO,CAAC,IAEtCA,EAAM,UACR0Y,EAAM1Y,CAAK,GAEXkZ,IACIlZ,EAAM,cAAcmZ,MAE5B,CAAC,CACH,EACA,OAAI,KAAK,cAAcT,EAAM,KAAK,YAAY,EACvC,CAAE,cAAAQ,EAAe,eAAAC,CAAA,CAC1B,CAMA,mBAAoB,CAClB,MAAMC,EAAkB,IAAI,IAAI,CAAC,sBAAsB,CAAC,EAClDV,EAASpI,GAAU,CACvBA,EAAM,YAAY,QAAStQ,GAAU,CAC/BA,EAAM,IAAI,wBAAwB,IAAM,KACxCoZ,EAAgB,IAAIpZ,EAAM,IAAI,OAAO,CAAC,IAEtCA,EAAM,UACR0Y,EAAM1Y,CAAK,EAEXA,EAAM,WAAW,EAAK,GAE1B,CAAC,CACH,EACI,KAAK,cAAc0Y,EAAM,KAAK,YAAY,EAC9C,QAAQ,IAAI,uCAAuC,CACrD,CAQA,kCAAkC/N,EAAe,CAC/C,MAAM0O,EAAU,IAAM,KAAK,4BAA4B1O,CAAa,EAE9D2O,EAAatZ,GAAU,CACvBA,EAAM,eACVA,EAAM,aAAe,GACrBA,EAAM,GAAG,iBAAkBqZ,CAAO,EACpC,EAEMX,EAASpI,GAAU,CACvBA,EAAM,YAAY,QAAStQ,GAAU,CAC/BA,EAAM,WACR0Y,EAAM1Y,CAAK,EAENsQ,EAAM,eACTA,EAAM,aAAe,GACrBA,EAAM,YAAY,GAAG,MAAQwG,GAAO,CAClC,MAAMyC,EAAQzC,EAAG,QACbyC,EAAM,UAAWb,EAAMa,CAAK,IAAkBA,CAAK,EACvDF,EAAA,CACF,CAAC,IAGHC,EAAUtZ,CAAK,CAEnB,CAAC,CACH,EAEI,KAAK,cAAc0Y,EAAM,KAAK,YAAY,CAChD,CAkBA,yBAAyB1Y,EAAOmO,EAAO,CACrCnO,EAAM,IAAI,aAAc,EAAI,EAC5BA,EAAM,GAAG,iBAAkB,IAAM,CAC3BA,EAAM,cAAgB,CAAC,UAAU,QACnCtB,EACE,IAAIyP,CAAK,iEACT,OACA,IAGN,CAAC,CACH,CAUA,oBAAqB,CACnB,KAAK,aAAe,SAAS,cAAc,KAAK,EAChD,KAAK,aAAa,UAAY,mBAC9B,KAAK,aAAa,MAAM,QAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAUlC,KAAK,IAAI,mBAAmB,YAAY,KAAK,YAAY,EAGzD,KAAK,eAAiB,IAAIhsB,EAC5B,CAUA,gBAAgB6d,EAAOmO,EAAOqL,EAAW,CACvC,GAAI,CAAC,KAAK,aAAc,OAGxB,MAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,mBACpBA,EAAQ,MAAM,QAAU,uEACxBA,EAAQ,UAAY;AAAA;AAAA,UAEd,KAAK,YAAYtL,CAAK,CAAC;AAAA;AAAA,kBAEfqL,CAAS,UAAU,KAAK,YAAYrL,CAAK,CAAC;AAAA;AAAA;AAAA,MAKxD,KAAK,eAAe,IAAInO,EAAOyZ,CAAO,EAKtC,MAAMC,EAAS,IAAM,CACnB,GAAI,CAAE,KAAK,oBAAsB,OAC1BntB,EAAK,CAAE,QAAQ,KAAK,wCAAyCA,CAAG,CAAG,CAC5E,EACAyT,EAAM,GAAG,iBAAkB0Z,CAAM,EAGjCA,EAAA,CACF,CAMA,oBAAqB,CACnB,GAAI,CAAC,KAAK,aAAc,OAGxB,MAAMC,EAAW,GACjB,SAAW,CAAC3Z,EAAOyZ,CAAO,IAAK,KAAK,eAC9BzZ,EAAM,cAAc2Z,EAAS,KAAKF,CAAO,EAI/C,KAAK,eAAe,QAASt4B,GAAM,CACjCA,EAAE,MAAM,aAAe,qCACvBA,EAAE,MAAM,cAAgB,KAC1B,CAAC,EACGw4B,EAAS,OAAS,IACpBA,EAASA,EAAS,OAAS,CAAC,EAAE,MAAM,aAAe,OACnDA,EAASA,EAAS,OAAS,CAAC,EAAE,MAAM,cAAgB,KAItD,KAAK,aAAa,gBAAgB,GAAGA,CAAQ,EAC7C,KAAK,aAAa,MAAM,QAAUA,EAAS,OAAS,EAAI,OAAS,MACnE,CAKA,YAAYC,EAAK,CACf,OAAO,OAAOA,CAAG,EACd,QAAQ,KAAM,OAAO,EACrB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,MAAM,EACpB,QAAQ,KAAM,QAAQ,EACtB,QAAQ,KAAM,OAAO,CAC1B,CAQA,cAAcl4B,EAAI,CAChB,IAAIm4B,EAAQ,KACZ,YAAK,aAAa,YAAY,QAAS7Z,GAAU,CAC3CA,EAAM,IAAI,SAAS,IAAMte,IAC3Bm4B,EAAQ7Z,EAEZ,CAAC,EACM6Z,CACT,CAQA,qBAAqB1L,EAAO,CAC1B,IAAI0L,EAAQ,KACZ,YAAK,aAAa,YAAY,QAAS7Z,GAAU,CAC3CA,EAAM,IAAI,OAAO,IAAMmO,IACzB0L,EAAQ7Z,EAEZ,CAAC,EACM6Z,CACT,CAKA,iBAAkB,CAChB,OAAO,KAAK,YACd,CAKA,QAAS,CACP,OAAO,KAAK,GACd,CAUA,sBAAuB,CACrB,MAAMC,EAAO,KAAK,IAAI,UAChBzzB,EAAO,KAAK,IAAI,UACtB,OAAKA,EACEyzB,EAAK,gBAAgBzzB,CAAI,EADd,IAEpB,CASA,2BAA4B,CAC1B,IAAIwzB,EAAQ,KACZ,MAAMnB,EAASpI,GAAU,CACvBA,EAAM,YAAY,QAAStQ,GAAU,CACnC,GAAIA,EAAM,UACR0Y,EAAM1Y,CAAK,UACFA,EAAM,IAAI,OAAO,IAAM,oBAAqB,CACrD,MAAM+Z,EAAM/Z,EAAM,WAAaA,EAAM,YACrC,GAAI+Z,GAAO,OAAOA,EAAI,WAAc,WAAY,CAC9C,MAAMC,EAAKD,EAAI,YACXC,GAAM,OAAO,SAASA,EAAG,CAAC,CAAC,IAC7BH,EAAQ,CAAE,OAAQG,EAAI,MAAOha,EAAM,IAAI,OAAO,GAElD,CACF,CACF,CAAC,CACH,EACA,OAAA0Y,EAAM,KAAK,YAAY,EAChBmB,CACT,CAKA,iBAAkB,CAChB,OAAO,KAAK,YACd,CAKA,iBAAkB,CAChB,OAAO,KAAK,YACd,CAKA,YAAa,CACX,KAAK,IAAI,YACX,CAOA,eAAe11B,EAAU,CACvB,KAAK,sBAAsB,KAAKA,CAAQ,CAC1C,CASA,WAAW6R,EAAKC,EAAKye,EAAO,GAAI/V,EAAW,IAAK,CAC9C,MAAM0M,EAAaX,EAAW,CAAC1U,EAAKC,CAAG,CAAC,EACxC,KAAK,IAAI,UAAU,QAAQ,CACzB,OAAQoV,EACR,KAAAqJ,EACA,SAAA/V,CAAA,CACD,CACH,CACF,CCrxIO,MAAMsb,EAAS,CACpB,YAAYta,EAAKpY,EAAU,GAAI,CAC7B,KAAK,IAAMoY,EACX,KAAK,QAAUpY,EAGf,KAAK,cAAgB,IAAIkY,EACzB,KAAK,aAAe,IAAIC,EAAY,CAClC,OAAQ,KAAK,cACb,MAAO,KAAK,gBAAe,EAC3B,MAAO,eACP,OAAQ,GACd,CAAK,EAID,KAAK,WAAa,IAAID,EACtB,KAAK,UAAY,IAAIC,EAAY,CAC/B,OAAQ,KAAK,WACb,MAAO,KAAK,aAAY,EACxB,MAAO,gBACP,uBAAwB,GACxB,OAAQ,EACd,CAAK,EAMD,MAAMK,EAAS,KAAK,IAAI,UAAS,EACjC,IAAIyL,EAAazL,EAAO,SAAQ,EAAG,UAAWma,GAAMA,EAAE,IAAI,OAAO,IAAM,UAAU,EAC7E1O,EAAa,IAAGA,EAAazL,EAAO,UAAS,GACjDA,EAAO,SAASyL,EAAY,KAAK,SAAS,EAC1CzL,EAAO,SAASyL,EAAY,KAAK,YAAY,EAG7C,KAAK,kBAAoB,KACzB,KAAK,eAAiB,KACtB,KAAK,sBAAwB,KAG7B,KAAK,2BAA6B,GAClC,KAAK,wBAA0B,EACjC,CAKA,iBAAkB,CAChB,OAAO,IAAItM,EAAM,CACf,KAAM,IAAIE,EAAK,CACb,MAAO,0BACf,CAAO,EACD,OAAQ,IAAID,EAAO,CACjB,MAAO,UACP,SAAU,CAAC,GAAI,EAAE,EACjB,MAAO,CACf,CAAO,EACD,MAAO,IAAIG,GAAY,CACrB,OAAQ,EACR,OAAQ,IAAIH,EAAO,CACjB,MAAO,SACjB,CAAS,EACD,KAAM,IAAIC,EAAK,CACb,MAAO,0BACjB,CAAS,CACT,CAAO,CACP,CAAK,CACH,CAKA,cAAe,CACb,OAAO,IAAIF,EAAM,CACf,KAAM,IAAIE,EAAK,CACb,MAAO,0BACf,CAAO,EACD,OAAQ,IAAID,EAAO,CACjB,MAAO,UACP,MAAO,CACf,CAAO,EACD,MAAO,IAAIG,GAAY,CACrB,OAAQ,EACR,OAAQ,IAAIH,EAAO,CACjB,MAAO,UACP,MAAO,CACjB,CAAS,EACD,KAAM,IAAIC,EAAK,CACb,MAAO,SACjB,CAAS,CACT,CAAO,CACP,CAAK,CACH,CAKA,sBAAuB,CACjB,KAAK,uBACP,KAAK,sBAAsB,WAAW,YAAY,KAAK,qBAAqB,EAE9E,KAAK,sBAAwB,SAAS,cAAc,KAAK,EACzD,KAAK,sBAAsB,UAAY,kBACvC,KAAK,eAAiB,IAAI2O,GAAQ,CAChC,QAAS,KAAK,sBACd,OAAQ,CAAC,GAAI,CAAC,EACd,YAAa,cACb,UAAW,EACjB,CAAK,EACD,KAAK,IAAI,WAAW,KAAK,cAAc,CACzC,CAKA,YAAa,CACP,KAAK,oBACP,KAAK,IAAI,kBAAkB,KAAK,iBAAiB,EACjD,KAAK,kBAAoB,MAEvB,KAAK,iBACP,KAAK,IAAI,cAAc,KAAK,cAAc,EAC1C,KAAK,eAAiB,MAEpB,KAAK,uBAAyB,KAAK,sBAAsB,aAC3D,KAAK,sBAAsB,WAAW,YAAY,KAAK,qBAAqB,EAC5E,KAAK,sBAAwB,KAEjC,CAMA,oBAAqB,CACnB,KAAK,WAAU,EACf,KAAK,qBAAoB,EAEzB,MAAMoM,EAAa,IAAIC,GAAK,CAC1B,OAAQ,KAAK,cACb,KAAM,SACN,MAAO,IAAIlb,EAAM,CACf,KAAM,IAAIE,EAAK,CACb,MAAO,0BACjB,CAAS,EACD,OAAQ,IAAID,EAAO,CACjB,MAAO,yBACP,SAAU,CAAC,GAAI,EAAE,EACjB,MAAO,CACjB,CAAS,EACD,MAAO,IAAIG,GAAY,CACrB,OAAQ,EACR,OAAQ,IAAIH,EAAO,CACjB,MAAO,wBACnB,CAAW,EACD,KAAM,IAAIC,EAAK,CACb,MAAO,0BACnB,CAAW,CACX,CAAS,CACT,CAAO,CACP,CAAK,EAED,KAAK,kBAAoB+a,EACzB,KAAK,IAAI,eAAeA,CAAU,EAElC,IAAI54B,EAEJ,OAAA44B,EAAW,GAAG,YAAcvZ,GAAQ,CAGlCrf,EAFeqf,EAAI,QAED,YAAW,EAAG,GAAG,SAAWhS,GAAM,CAClD,MAAM2R,EAAO3R,EAAE,OAEf,GAAI2R,aAAgB+K,GAAQ,CAC1B,MAAM4E,EAAS3P,EAAK,UAAS,EACvBjH,EAAOlB,GAAmB8X,CAAM,EAGhCmK,EAAS,WAFS5iB,GAAayY,CAAM,CAEF,uBAAuB5W,CAAI,WAEpE,KAAK,sBAAsB,UAAY+gB,EACvC,KAAK,eAAe,YAAY9Z,EAAK,kBAAiB,CAAE,CAC1D,CACF,CAAC,CACH,CAAC,EAED4Z,EAAW,GAAG,UAAYvZ,GAAQ,CAChC,MAAMG,EAAUH,EAAI,QACdL,EAAOQ,EAAQ,YAAW,EAC1BgJ,EAASxJ,EAAK,UAAS,EACvB2P,EAAS3P,EAAK,UAAS,EAG7BQ,EAAQ,IAAI,aAAc,gBAAgB,EAC1CA,EAAQ,IAAI,UAAWmP,CAAM,EAC7BnP,EAAQ,IAAI,UAAWgJ,CAAM,EAG7B,MAAMuQ,EAAa,IAAIxU,GAAQ,CAC7B,SAAU,IAAIpF,GAAW,CACvBqJ,EACA,CAACA,EAAO,CAAC,EAAImG,EAAQnG,EAAO,CAAC,CAAC,CACxC,CAAS,CACT,CAAO,EACDuQ,EAAW,IAAI,aAAc,uBAAuB,EACpD,KAAK,cAAc,WAAWA,CAAU,EAGxC,KAAK,sBAAsB,UAAY,yCACvC,KAAK,eAAe,UAAU,CAAC,EAAG,EAAE,CAAC,EAGrC,KAAK,sBAAwB,KAC7B,KAAK,qBAAoB,EAEzBC,GAAQh5B,CAAQ,EAGhB,MAAMgD,EAAS,CACb,KAAM,SACN,OAAQwlB,EACR,OAAQmG,EACR,KAAM,KAAK,GAAKA,EAASA,EACzB,QAASnP,CACjB,EACM,KAAK,2BAA2B,QAAQ3Z,GAAMA,EAAG7C,CAAM,CAAC,CAC1D,CAAC,EAEM41B,CACT,CAKA,kBAAmB,CACjB,KAAK,WAAU,EACf,KAAK,qBAAoB,EAEzB,MAAMK,EAAW,IAAIJ,GAAK,CACxB,OAAQ,KAAK,cACb,KAAM,aACN,MAAO,KAAK,gBAAe,CACjC,CAAK,EAED,KAAK,kBAAoBI,EACzB,KAAK,IAAI,eAAeA,CAAQ,EAEhC,IAAIj5B,EAEJ,OAAAi5B,EAAS,GAAG,YAAc5Z,GAAQ,CAGhCrf,EAFeqf,EAAI,QAED,YAAW,EAAG,GAAG,SAAWhS,GAAM,CAClD,MAAM2R,EAAO3R,EAAE,OACT5K,EAAS6qB,GAAUtO,CAAI,EACvB8Z,EAAS5iB,GAAazT,CAAM,EAElC,KAAK,sBAAsB,UAAYq2B,EACvC,KAAK,eAAe,YAAY9Z,EAAK,kBAAiB,CAAE,CAC1D,CAAC,CACH,CAAC,EAEDia,EAAS,GAAG,UAAY5Z,GAAQ,CAC9B,MAAMG,EAAUH,EAAI,QACdL,EAAOQ,EAAQ,YAAW,EAC1B/c,EAAS6qB,GAAUtO,CAAI,EAE7B,KAAK,sBAAsB,UAAY,yCACvC,KAAK,sBAAwB,KAC7B,KAAK,qBAAoB,EAEzBga,GAAQh5B,CAAQ,EAEhB,MAAMgD,EAAS,CACb,KAAM,OACN,OAAQP,EACR,QAAS+c,CACjB,EACM,KAAK,2BAA2B,QAAQ3Z,GAAMA,EAAG7C,CAAM,CAAC,CAC1D,CAAC,EAEMi2B,CACT,CAKA,kBAAmB,CACjB,KAAK,WAAU,EACf,KAAK,qBAAoB,EAEzB,MAAMC,EAAc,IAAIL,GAAK,CAC3B,OAAQ,KAAK,cACb,KAAM,UACN,MAAO,KAAK,gBAAe,CACjC,CAAK,EAED,KAAK,kBAAoBK,EACzB,KAAK,IAAI,eAAeA,CAAW,EAEnC,IAAIl5B,EAEJ,OAAAk5B,EAAY,GAAG,YAAc7Z,GAAQ,CAGnCrf,EAFeqf,EAAI,QAED,YAAW,EAAG,GAAG,SAAWhS,GAAM,CAClD,MAAM2R,EAAO3R,EAAE,OACT0K,EAAOoV,GAAQnO,CAAI,EACnB8Z,EAASviB,GAAWwB,CAAI,EAE9B,KAAK,sBAAsB,UAAY+gB,EACvC,KAAK,eAAe,YAAY9Z,EAAK,iBAAgB,EAAG,gBAAgB,CAC1E,CAAC,CACH,CAAC,EAEDka,EAAY,GAAG,UAAY7Z,GAAQ,CACjC,MAAMG,EAAUH,EAAI,QACdL,EAAOQ,EAAQ,YAAW,EAC1BzH,EAAOoV,GAAQnO,CAAI,EAGzBQ,EAAQ,IAAI,aAAc,cAAc,EACxCA,EAAQ,IAAI,QAASzH,CAAI,EAEzB,KAAK,sBAAsB,UAAY,yCACvC,KAAK,sBAAwB,KAC7B,KAAK,qBAAoB,EAEzBihB,GAAQh5B,CAAQ,EAEhB,MAAMgD,EAAS,CACb,KAAM,UACN,KAAM+U,EACN,QAASyH,EACT,WAAYR,EAAK,iBAAgB,EAAG,eAAc,CAC1D,EACM,KAAK,2BAA2B,QAAQnZ,GAAMA,EAAG7C,CAAM,CAAC,CAC1D,CAAC,EAEMk2B,CACT,CAKA,gBAAiB,CACf,KAAK,WAAU,EAEf,MAAMC,EAAY,IAAIN,GAAK,CACzB,OAAQ,KAAK,WACb,KAAM,QACN,MAAO,KAAK,aAAY,CAC9B,CAAK,EAED,YAAK,kBAAoBM,EACzB,KAAK,IAAI,eAAeA,CAAS,EAEjCA,EAAU,GAAG,UAAY9Z,GAAQ,CAC/B,MAAMrc,EAAS,CACb,KAAM,QACN,QAASqc,EAAI,OACrB,EACM,KAAK,wBAAwB,QAAQxZ,GAAMA,EAAG7C,CAAM,CAAC,CACvD,CAAC,EAEMm2B,CACT,CAKA,eAAgB,CACd,KAAK,WAAU,EAEf,MAAMF,EAAW,IAAIJ,GAAK,CACxB,OAAQ,KAAK,WACb,KAAM,aACN,MAAO,KAAK,aAAY,CAC9B,CAAK,EAED,YAAK,kBAAoBI,EACzB,KAAK,IAAI,eAAeA,CAAQ,EAEhCA,EAAS,GAAG,UAAY5Z,GAAQ,CAC9B,MAAMrc,EAAS,CACb,KAAM,OACN,QAASqc,EAAI,OACrB,EACM,KAAK,wBAAwB,QAAQxZ,GAAMA,EAAG7C,CAAM,CAAC,CACvD,CAAC,EAEMi2B,CACT,CAKA,kBAAmB,CACjB,KAAK,WAAU,EAEf,MAAMC,EAAc,IAAIL,GAAK,CAC3B,OAAQ,KAAK,WACb,KAAM,UACN,MAAO,KAAK,aAAY,CAC9B,CAAK,EAED,YAAK,kBAAoBK,EACzB,KAAK,IAAI,eAAeA,CAAW,EAEnCA,EAAY,GAAG,UAAY7Z,GAAQ,CACjC,MAAMrc,EAAS,CACb,KAAM,UACN,QAASqc,EAAI,OACrB,EACM,KAAK,wBAAwB,QAAQxZ,GAAMA,EAAG7C,CAAM,CAAC,CACvD,CAAC,EAEMk2B,CACT,CAKA,mBAAoB,CAClB,KAAK,cAAc,MAAK,EAEP,SAAS,iBAAiB,yBAAyB,EAC3D,QAAQ3b,GAAMA,EAAG,WAAW,YAAYA,CAAE,CAAC,CACtD,CAKA,eAAgB,CACd,KAAK,WAAW,MAAK,CACvB,CAKA,UAAW,CACT,KAAK,kBAAiB,EACtB,KAAK,cAAa,CACpB,CAKA,kBAAkB3a,EAAU,CAC1B,KAAK,2BAA2B,KAAKA,CAAQ,CAC/C,CAKA,eAAeA,EAAU,CACvB,KAAK,wBAAwB,KAAKA,CAAQ,CAC5C,CAMA,iBAAiBoD,EAAU,GAAI,CACZA,EAAQ,SAGzB,MAAMozB,EAAU,IAAI9O,GAAQ,CAC1B,MAAO,GACP,UAAW,eACjB,CAAK,EAGK+O,EAAa,IAAI/O,GAAQ,CAC7B,UAAW,GACX,MAAO,EACb,CAAK,EAGKgP,EAAY,IAAIxO,GAAO,CAC3B,KAAM,mCACN,MAAO,iCACP,UAAW,qBACX,SAAWzM,GAAW,CAChBA,EACF,KAAK,mBAAkB,EAEvB,KAAK,WAAU,CAEnB,CACN,CAAK,EACDgb,EAAW,WAAWC,CAAS,EAG/B,MAAMC,EAAU,IAAIzO,GAAO,CACzB,KAAM,oCACN,MAAO,mBACP,UAAW,mBACX,SAAWzM,GAAW,CAChBA,EACF,KAAK,iBAAgB,EAErB,KAAK,WAAU,CAEnB,CACN,CAAK,EACDgb,EAAW,WAAWE,CAAO,EAG7B,MAAMC,EAAU,IAAI1O,GAAO,CACzB,KAAM,mCACN,MAAO,eACP,UAAW,mBACX,SAAWzM,GAAW,CAChBA,EACF,KAAK,iBAAgB,EAErB,KAAK,WAAU,CAEnB,CACN,CAAK,EACDgb,EAAW,WAAWG,CAAO,EAG7B,MAAMC,EAAW,IAAIhP,GAAO,CAC1B,KAAM,qCACN,MAAO,qBACP,UAAW,oBACX,YAAa,IAAM,CACjB,KAAK,kBAAiB,EAEtB6O,EAAU,UAAU,EAAK,EACzBC,EAAQ,UAAU,EAAK,EACvBC,EAAQ,UAAU,EAAK,CACzB,CACN,CAAK,EACD,OAAAH,EAAW,WAAWI,CAAQ,EAE9BL,EAAQ,WAAWC,CAAU,EAEtBD,CACT,CAKA,iBAAkB,CAChB,OAAO,KAAK,YACd,CAKA,cAAe,CACb,OAAO,KAAK,SACd,CAKA,kBAAmB,CACjB,OAAO,KAAK,aACd,CAKA,eAAgB,CACd,OAAO,KAAK,UACd,CAKA,UAAW,CACT,OAAO,KAAK,oBAAsB,IACpC,CACF,CC3kBA,IAAIM,GAAiB,KAEd,eAAeC,IAAwB,CAC5C,GAAI,EAAE,kBAAmB,WACvB,eAAQ,KAAK,qCAAqC,EAC3C,KAGT,GAAI,CACF,OAAAD,GAAiB,MAAM,UAAU,cAAc,SAAS,SAAU,CAChE,MAAO,GACb,CAAK,EAED,QAAQ,IAAI,mCAAoCA,GAAe,KAAK,EAGpEA,GAAe,iBAAiB,cAAe,IAAM,CACnD,MAAME,EAAYF,GAAe,WAEjCE,EAAU,iBAAiB,cAAe,IAAM,CAC1CA,EAAU,QAAU,aAAe,UAAU,cAAc,aAE7D,QAAQ,IAAI,6BAA6B,EACzCC,GAAsB,EAE1B,CAAC,CACH,CAAC,EAEMH,EAET,OAAS32B,EAAO,CACd,eAAQ,MAAM,4CAA6CA,CAAK,EACzD,IACT,CACF,CAMA,IAAI+2B,GAAiB,KACjBC,GAAgB,KAMb,SAASC,GAAkBC,EAAiB,eAAgB,CAKjE,GAJAF,GAAgB,OAAOE,GAAmB,SACtC,SAAS,cAAcA,CAAc,EACrCA,EAEA,CAACF,GAAe,CAClB,QAAQ,KAAK,kCAAmCE,CAAc,EAC9D,MACF,CAGAF,GAAc,MAAM,QAAU,OAG9B,OAAO,iBAAiB,sBAAwB,GAAM,CACpD,EAAE,eAAc,EAChBD,GAAiB,EAGjBC,GAAc,MAAM,QAAU,QAC9B,QAAQ,IAAI,4BAA4B,CAC1C,CAAC,EAGDA,GAAc,iBAAiB,QAAS,SAAY,CAClD,GAAI,CAACD,GAAgB,CAEnBI,GAA6B,EAC7B,MACF,CAEAJ,GAAe,OAAM,EACrB,KAAM,CAAE,QAAAK,CAAO,EAAK,MAAML,GAAe,WAEzC,QAAQ,IAAI,gCAAiCK,CAAO,EAEpDL,GAAiB,KACjBC,GAAc,MAAM,QAAU,MAChC,CAAC,EAGD,OAAO,iBAAiB,eAAgB,IAAM,CAC5C,QAAQ,IAAI,qBAAqB,EACjCD,GAAiB,KACjBC,GAAc,MAAM,QAAU,MAChC,CAAC,EAGG,OAAO,WAAW,4BAA4B,EAAE,UAClDA,GAAc,MAAM,QAAU,OAElC,CAEA,SAASG,IAAgC,CACvC,MAAME,EAAQ,mBAAmB,KAAK,UAAU,SAAS,EACnDC,EAAW,iCAAiC,KAAK,UAAU,SAAS,EAE1E,IAAIpyB,EAAU;;AAAA,EAEVmyB,GACFnyB,GAAW;AAAA,EACXA,GAAW,+CACFoyB,GACTpyB,GAAW;AAAA,EACXA,GAAW,2BAEXA,GAAW;AAAA,EACXA,GAAW,8CAGb,MAAMA,CAAO,CACf,CAMA,IAAIqyB,GAAmB,KACvB,MAAMC,GAAmB,IAAI,IAMtB,SAASC,GAAqBC,EAAoB,qBAAsB,CAC7EH,GAAmB,OAAOG,GAAsB,SAC5C,SAAS,cAAcA,CAAiB,EACxCA,EAGJC,GAAgB,CAAC,UAAU,MAAM,EAGjC,OAAO,iBAAiB,SAAU,IAAM,CACtC,QAAQ,IAAI,mBAAmB,EAC/BA,GAAgB,EAAK,EACrBC,GAAuB,EAAK,CAC9B,CAAC,EAED,OAAO,iBAAiB,UAAW,IAAM,CACvC,QAAQ,IAAI,oBAAoB,EAChCD,GAAgB,EAAI,EACpBC,GAAuB,EAAI,CAC7B,CAAC,CACH,CAEA,SAASD,GAAgBE,EAAW,CAC9BN,KACFA,GAAiB,MAAM,QAAUM,EAAY,QAAU,QAIzD,SAAS,KAAK,UAAU,OAAO,aAAcA,CAAS,CACxD,CAOO,SAASC,GAAgB76B,EAAU,CACxC,OAAAu6B,GAAiB,IAAIv6B,CAAQ,EAE7BA,EAAS,CAAC,UAAU,MAAM,EACnB,IAAMu6B,GAAiB,OAAOv6B,CAAQ,CAC/C,CAEA,SAAS26B,GAAuBC,EAAW,CACzC,UAAW56B,KAAYu6B,GACrB,GAAI,CACFv6B,EAAS46B,CAAS,CACpB,OAASvtB,EAAG,CACV,QAAQ,MAAM,gCAAiCA,CAAC,CAClD,CAEJ,CAKO,SAASytB,GAAW,CACzB,OAAO,UAAU,MACnB,CAgBA,SAASjB,IAAyB,CAO5B,QAAQ,yCAAyC,GACnDkB,GAAW,CAEf,CAKO,SAASA,IAAc,CACxBrB,IAAgB,SAClBA,GAAe,QAAQ,YAAY,CAAE,KAAM,cAAc,CAAE,EAE7D,OAAO,SAAS,OAAM,CACxB,CAiDO,eAAesB,GAAuB,CAAE,UAAAC,EAAY,GAAK,EAAK,GAAI,CACvE,GAAI,EAAE,kBAAmB,WACvB,MAAM,IAAI,MAAM,+CAA+C,EAIjE,GAAI,UAAU,cAAc,WAC1B,OAAO,UAAU,cAAc,WAKjC,MAAMC,EAAQ,UAAU,cAAc,MAChCC,EAAU,IAAI,QAAQ,CAAC74B,EAAGiI,IAC9B,WAAW,IAAMA,EAAO,IAAI,MAAM,kCAAkC,CAAC,EAAG0wB,CAAS,CACrF,EAEQG,EAAe,MAAM,QAAQ,KAAK,CAACF,EAAOC,CAAO,CAAC,EAKlDE,EAAK,UAAU,cAAc,YAAcD,EAAa,OAC9D,GAAI,CAACC,EACH,MAAM,IAAI,MAAM,oCAAoC,EAEtD,OAAOA,CACT,CAWO,SAASC,GAAgC14B,EAAU,CACxD,GAAI,EAAE,kBAAmB,WAAY,MAAO,IAAM,CAAC,EACnD,MAAM1B,EAAU,IAAM,CACpB,GAAI,CAAE0B,EAAQ,CAAI,OAASyK,EAAG,CAAE,QAAQ,MAAM,wCAAyCA,CAAC,CAAG,CAC7F,EACA,iBAAU,cAAc,iBAAiB,mBAAoBnM,CAAO,EAC7D,IAAM,UAAU,cAAc,oBAAoB,mBAAoBA,CAAO,CACtF,CAeA,eAAeq6B,GAAyBC,EAAaC,EAAcC,EAAQ,GAAIT,EAAY,IAAMU,EAAiB,IAAO,CACvH,MAAMN,EAAK,MAAML,GAAuB,CAAE,UAAWW,CAAc,CAAE,EAErE,OAAO,IAAI,QAAQ,CAACp7B,EAASgK,IAAW,CACtC,MAAMsC,EAAU,IAAI,eACd+uB,EAAQ,WAAW,IAAM,CAC7B/uB,EAAQ,MAAM,MAAK,EACnBtC,EAAO,IAAI,MAAM,yBAAyBkxB,CAAY,aAAa,CAAC,CACtE,EAAGR,CAAS,EAEZpuB,EAAQ,MAAM,UAAa5M,GAAU,CACnC,GAAIA,EAAM,MAAM,OAASw7B,EAAc,CACrC,aAAaG,CAAK,EAClB/uB,EAAQ,MAAM,MAAK,EACnB,KAAM,CAAE,KAAAhK,EAAM,GAAGvC,CAAI,EAAKL,EAAM,KAChCM,EAAQD,CAAI,CACd,CACF,EAEA+6B,EAAG,YAAY,CAAE,KAAMG,EAAa,GAAGE,GAAS,CAAC7uB,EAAQ,KAAK,CAAC,CACjE,CAAC,CACH,CAaO,eAAegvB,IAAoB,CACxC,GAAI,CAEF,OADc,MAAMN,GAAyB,iBAAkB,YAAY,GAC9D,KACf,OAASvwB,EAAK,CACZ,eAAQ,KAAK,kCAAmCA,CAAG,EAC5C,IACT,CACF,CASO,eAAe8wB,IAAkB,CACtC,GAAI,CACF,aAAMP,GAAyB,oBAAqB,qBAAqB,EAClE,EACT,OAASvwB,EAAK,CACZ,eAAQ,KAAK,gCAAiCA,CAAG,EAC1C,EACT,CACF,CAUO,eAAe+wB,GAA0BC,EAAW,CACzD,GAAI,CAACA,EAAW,MAAO,GACvB,GAAI,CAKF,MAAO,CAAC,EAJM,MAAMT,GAClB,mBAAoB,qBACpB,CAAE,UAAAS,CAAS,CACjB,GACmB,OACjB,OAAShxB,EAAK,CACZ,eAAQ,KAAK,mCAAmCgxB,CAAS,YAAahxB,CAAG,EAClE,EACT,CACF,CAQO,eAAeixB,IAAqB,CACzC,GAAI,CAAC,UAAU,SAAS,SAAU,OAAO,KACzC,GAAI,CACF,KAAM,CAAE,MAAAC,EAAO,MAAAC,CAAK,EAAK,MAAM,UAAU,QAAQ,SAAQ,EACzD,MAAO,CAAE,MAAOD,GAAS,EAAG,MAAOC,GAAS,CAAC,CAC/C,OAASnxB,EAAK,CACZ,eAAQ,KAAK,mCAAoCA,CAAG,EAC7C,IACT,CACF,CAUO,eAAeoxB,GAAQp2B,EAAU,GAAI,CAC1C,KAAM,CACJ,cAAA+zB,EAAgB,eAChB,iBAAAO,EAAmB,qBACnB,eAAA+B,EAAiB,EACrB,EAAMr2B,EAEAq2B,GACF,MAAM1C,GAAqB,EAG7BK,GAAkBD,CAAa,EAC/BS,GAAqBF,CAAgB,EAErC,QAAQ,IAAI,mBAAmB,CACjC,CCrbO,MAAMgC,GAAoB,CAC/B,KAAM,CACJ,IAAK,iDACL,MAAO,cACP,QAAS,GACT,SAAU,YACd,EACE,IAAK,CACH,IAAK,mDACL,MAAO,gBACP,QAAS,GACT,SAAU,WACd,CACA,EAGaC,GAAiB,GAAK,KAM7BC,GAAe,EAAI,KAAK,GAAK,QAAU,EAG7C,SAASC,GAAeC,EAAGC,EAAG,CAC5B,MAAMloB,EAAOioB,EAAIF,GAAgB,IACjC,IAAI9nB,EAAOioB,EAAIH,GAAgB,IAC/B,OAAA9nB,EAAM,IAAM,KAAK,IAAM,EAAI,KAAK,KAAK,KAAK,IAAIA,EAAM,KAAK,GAAK,GAAG,CAAC,EAAI,KAAK,GAAK,GACzE,CAACD,EAAKC,CAAG,CAClB,CAGA,SAASkoB,GAAanoB,EAAKC,EAAK3F,EAAG,CACjC,MAAMmC,EAAI,KAAK,IAAI,EAAGnC,CAAC,EACjB2tB,EAAI,KAAK,OAAOjoB,EAAM,KAAO,IAAMvD,CAAC,EACpC2rB,EAASnoB,EAAM,KAAK,GAAK,IACzBioB,EAAI,KAAK,OACZ,EAAI,KAAK,IAAI,KAAK,IAAIE,CAAM,EAAI,EAAI,KAAK,IAAIA,CAAM,CAAC,EAAI,KAAK,IAAM,EAAI3rB,CAC5E,EACE,MAAO,CAAE,EAAAwrB,EAAG,EAAAC,CAAC,CACf,CAGO,SAASG,GAAmBC,EAAYhuB,EAAG,CAChD,KAAM,CAAC0L,EAAMC,EAAMC,EAAMC,CAAI,EAAImiB,EAC3B,CAACC,EAAQC,CAAM,EAAIR,GAAehiB,EAAMC,CAAI,EAC5C,CAACwiB,EAAQC,CAAM,EAAIV,GAAe9hB,EAAMC,CAAI,EAE5CwiB,EAAKR,GAAaI,EAAQG,EAAQpuB,CAAC,EACnCsuB,EAAKT,GAAaM,EAAQD,EAAQluB,CAAC,EAEnCmC,EAAI,KAAK,IAAI,EAAGnC,CAAC,EACjBuuB,EAAW,KAAK,IAAI,EAAG,KAAK,IAAIF,EAAG,EAAGC,EAAG,CAAC,CAAC,EAC3CE,EAAW,KAAK,IAAIrsB,EAAI,EAAG,KAAK,IAAIksB,EAAG,EAAGC,EAAG,CAAC,CAAC,EAC/CG,EAAW,KAAK,IAAI,EAAG,KAAK,IAAIJ,EAAG,EAAGC,EAAG,CAAC,CAAC,EAC3CI,EAAW,KAAK,IAAIvsB,EAAI,EAAG,KAAK,IAAIksB,EAAG,EAAGC,EAAG,CAAC,CAAC,EAErD,MAAO,CACL,EAAAtuB,EACA,KAAMuuB,EAAU,KAAMC,EACtB,KAAMC,EAAU,KAAMC,EACtB,OAAQF,EAAWD,EAAW,IAAMG,EAAWD,EAAW,EAC9D,CACA,CAGO,SAASE,GAAWX,EAAYY,EAAMC,EAAM,CACjD,IAAIjqB,EAAQ,EACZ,QAAS5E,EAAI4uB,EAAM5uB,GAAK6uB,EAAM7uB,IAC5B4E,GAASmpB,GAAmBC,EAAYhuB,CAAC,EAAE,MAE7C,OAAO4E,CACT,CAOO,SAASkqB,GAAed,EAAYY,EAAMC,EAAM,CACrD,MAAM5R,EAAM,GACZ,QAASjd,EAAI4uB,EAAM5uB,GAAK6uB,EAAM7uB,IAAK,CACjC,MAAMG,EAAI4tB,GAAmBC,EAAYhuB,CAAC,EAC1C,QAAS2tB,EAAIxtB,EAAE,KAAMwtB,GAAKxtB,EAAE,KAAMwtB,IAChC,QAASC,EAAIztB,EAAE,KAAMytB,GAAKztB,EAAE,KAAMytB,IAChC3Q,EAAI,KAAK,CAAE,EAAAjd,EAAG,EAAA2tB,EAAG,EAAAC,CAAC,CAAE,CAG1B,CACA,OAAO3Q,CACT,CAKO,SAAS8R,GAAcC,EAAU,CAAE,EAAAhvB,EAAG,EAAA2tB,EAAG,EAAAC,CAAC,EAAI,CACnD,OAAOoB,EACJ,QAAQ,MAAOhvB,CAAC,EAChB,QAAQ,MAAO2tB,CAAC,EAChB,QAAQ,MAAOC,CAAC,CACrB,CAeO,MAAMqB,EAAsB,CACjC,YAAY,CACV,QAAAC,EACA,WAAAlB,EACA,QAAAmB,EACA,QAAAC,EACA,YAAAC,EAAc,EACd,kBAAAC,EAAoB,GACpB,WAAAC,EAAa,IAAM,CAAC,CACxB,EAAK,CACD,MAAMC,EAAMjC,GAAkB2B,CAAO,EACrC,GAAI,CAACM,EAAK,MAAM,IAAI,MAAM,qBAAqBN,CAAO,EAAE,EACpDE,EAAUI,EAAI,UAChB,QAAQ,KAAK,kBAAkBN,CAAO,aAAaE,CAAO,gBAAgBI,EAAI,OAAO,YAAY,EACjGJ,EAAUI,EAAI,SAGhB,KAAK,QAAmBN,EACxB,KAAK,SAAmBM,EAAI,IAC5B,KAAK,OAAmBxB,EACxB,KAAK,QAAmBmB,EACxB,KAAK,QAAmBC,EACxB,KAAK,YAAmB,KAAK,IAAI,EAAG,KAAK,IAAIC,EAAa,CAAC,CAAC,EAC5D,KAAK,kBAAoBC,EACzB,KAAK,WAAmBC,EAExB,KAAK,WAAmB,KACxB,KAAK,WAAmB,EAC1B,CAMA,MAAM,OAAQ,CACZ,GAAI,KAAK,WAAY,MAAM,IAAI,MAAM,4BAA4B,EACjE,KAAK,WAAa,IAAI,gBACtB,KAAK,WAAa,GAElB,MAAME,EAAQX,GAAe,KAAK,OAAQ,KAAK,QAAS,KAAK,OAAO,EAC9DlqB,EAAQ6qB,EAAM,OACdpqB,EAAY,KAAK,IAAG,EAE1B,IAAIqqB,EAAO,EAAGC,EAAK,EAAGC,EAAS,EAAGC,EAAS,EAE3C,MAAMC,EAAQC,GAAU,CACtB,MAAMC,EAAY,KAAK,IAAG,EAAK3qB,EACzB4qB,EAAQP,EAAO,EAAI,KAAK,MAAOM,EAAYN,GAAS9qB,EAAQ8qB,EAAK,EAAI,KAC3E,KAAK,WAAW,CAAE,MAAAK,EAAO,KAAAL,EAAM,MAAA9qB,EAAO,GAAA+qB,EAAI,OAAAC,EAAQ,OAAAC,EAAQ,UAAAG,EAAW,MAAAC,CAAK,CAAE,CAC9E,EAEAH,EAAK,SAAS,EAGd,QAASp+B,EAAI,EAAGA,EAAI+9B,EAAM,QACpB,MAAK,WADuB/9B,GAAK,KAAK,YAAa,CAGvD,MAAMw+B,EAAQT,EAAM,MAAM/9B,EAAGA,EAAI,KAAK,WAAW,EACjD,MAAM,QAAQ,IAAIw+B,EAAM,IAAI,MAAOpxB,GAAM,CACvC,GAAI,KAAK,WAAY,OACrB,MAAM+E,EAAMkrB,GAAc,KAAK,SAAUjwB,CAAC,EAE1C,GAAI,CACF,MAAMxK,EAAM,MAAM,MAAMuP,EAAK,CAC3B,OAAQ,KAAK,WAAW,OAExB,MAAO,SACnB,CAAW,EAEGvP,EAAI,IACNq7B,IAIIr7B,EAAI,MAAMA,EAAI,KAAK,SAAS,MAAM,IAAM,CAAC,CAAC,IACrCA,EAAI,OAEbs7B,IAIJ,OAAS3zB,EAAK,CACRA,EAAI,OAAS,cAGf2zB,GAEJ,CACAF,GACF,CAAC,CAAC,EAEFI,EAAK,SAAS,EAEV,KAAK,kBAAoB,GAAKp+B,EAAI,KAAK,YAAc+9B,EAAM,QAC7D,MAAM,IAAI,QAAStvB,GAAM,WAAWA,EAAG,KAAK,iBAAiB,CAAC,CAElE,CAEA,OAAA2vB,EAAK,KAAK,WAAa,YAAc,MAAM,EAEpC,CACL,MAAU,KAAK,WAAa,YAAc,OAC1C,KAAAJ,EAAM,MAAA9qB,EAAO,GAAA+qB,EAAI,OAAAC,EAAQ,OAAAC,EACzB,UAAW,KAAK,IAAG,EAAKxqB,CAC9B,CACE,CAKA,QAAS,CACP,KAAK,WAAa,GACd,KAAK,YAAY,KAAK,WAAW,MAAK,CAC5C,CACF,CAUO,MAAM8qB,IAAqB,IAAM,CACtC,MAAMC,EAAiB,CAAC1qB,EAAKC,IAAQ,CACnC,MAAMgoB,EAAIjoB,EAAM+nB,GAAe,IACzBG,EAAI,KAAK,IAAI,KAAK,KAAK,GAAKjoB,GAAO,KAAK,GAAK,GAAG,CAAC,GAAK,KAAK,GAAK,KACtE,MAAO,CAACgoB,EAAGC,EAAIH,GAAe,GAAG,CACnC,EACMnB,EAAK8D,EAAe,KAAM,GAAG,EAC7BC,EAAKD,EAAe,IAAK,IAAI,EACnC,MAAO,CAAC9D,EAAG,CAAC,EAAGA,EAAG,CAAC,EAAG+D,EAAG,CAAC,EAAGA,EAAG,CAAC,CAAC,CACpC,GAAC,EAGM,SAASC,GAAmBC,EAAW,CAC5C,OAAOA,EAAY/C,EACrB,CCpRA,MAAMgD,GAAW,oDAcXC,GAAuB,IACvBC,GAAY,mBAgBlB,SAASC,IAAoB,CAC3B,GAAI,CACF,GAAI,OAAO,OAAW,IAAa,OAAOF,GAC1C,MAAMG,EAAU,OAAO,eACvB,GAAI,CAACA,GAAW,OAAOA,GAAY,SAAU,OAAOH,GACpD,MAAMr/B,EAAKw/B,EAAQ,YACnB,OAAIx/B,GAAO,MAA4B,OAAOA,CAAE,EAAE,SAAW,EAAU,KAChE,OAAOA,CAAE,CAClB,MAAQ,CAAc,CACtB,OAAOq/B,EACT,CAEA,MAAMI,GAAkB,CACtB,IAAI,aAAc,CAAE,OAAOF,GAAiB,CAAI,EAChD,UAAWD,EACb,EAWO,SAASI,IAAa,CAE3B,GAAI,OAAO,OAAW,KAAe,OAAO,gBAAkB,OAAO,eAAe,QAClF,OAAO,OAAO,eAGhB,GAAI,CACF,MAAMC,EAAM,aAAa,QAAQ,aAAa,EAC9C,GAAIA,EAAK,CACP,MAAMlxB,EAAS,KAAK,MAAMkxB,CAAG,EAC7B,GAAIlxB,GAAUA,EAAO,QAAS,OAAOA,CACvC,CACF,MAAQ,CAAe,CACvB,OAAO,IACT,CAKI,OAAO,OAAW,MACpB,OAAO,iBAAoBxB,GAAY,CACjCA,GAAW,MACb,aAAa,WAAW,aAAa,EACrC,QAAQ,IAAI,kDAAkD,IAE9D,aAAa,QAAQ,cAAe,KAAK,UAAUA,CAAO,CAAC,EAC3D,QAAQ,IAAI,iDAAkDA,CAAO,EAEzE,GAQF,MAAM2yB,GAAkB,IAGlBC,GAAe,IAGrB,IAAIC,GAAmB,KAWhB,eAAeC,GAAqBC,EAAQ,GAAO,CACxD,GAAIF,KAAqB,MAAQ,CAACE,EAAO,OAAOF,GAEhD,MAAMG,EAAa,IAAI,gBACjBxE,EAAQ,WAAW,IAAMwE,EAAW,MAAK,EAAIJ,EAAY,EAE/D,GAAI,CAOFC,IANiB,MAAM,MAAM,GAAGV,EAAQ,kBAAmB,CACzD,OAAQ,OACR,QAAS,CAAE,eAAgB,mBAAoB,OAAU,kBAAkB,EAC3E,KAAM,KAAK,UAAUK,EAAe,EACpC,OAAQQ,EAAW,MACzB,CAAK,GAC2B,EAC9B,MAAQ,CACNH,GAAmB,EACrB,QAAC,CACC,aAAarE,CAAK,CACpB,CAEA,eAAQ,IAAI,+BAAgCqE,EAAgB,EACrDA,EACT,CAOO,SAASI,IAAoB,CAClC,OAAOJ,EACT,CAWA,SAASK,GAAYt6B,EAASu6B,EAAKR,GAAiB,CAClD,MAAMK,EAAa,IAAI,gBACjBxE,EAAQ,WAAW,IAAMwE,EAAW,MAAK,EAAIG,CAAE,EAGrD,OAAIv6B,EAAQ,QACVA,EAAQ,OAAO,iBAAiB,QAAS,IAAMo6B,EAAW,OAAO,EAG5D,CACL,OAAQA,EAAW,OACnB,MAAO,IAAM,aAAaxE,CAAK,CACnC,CACA,CAgEO,eAAe4E,GAAWC,EAAUC,EAAO,GAAI16B,EAAU,GAAI,CAClE,MAAM4M,EAAM,GAAG2sB,EAAQ,IAAIkB,CAAQ,GAE7BrzB,EAAU,CAAE,GAAGwyB,GAAiB,GAAGc,CAAI,EAE7C,QAAQ,IAAI,kBAAmB9tB,CAAG,EAElC,MAAMuoB,EAAUmF,GAAYt6B,CAAO,EACnC,GAAI,CACF,MAAMoC,EAAW,MAAM,MAAMwK,EAAK,CAChC,OAAQ,OACR,QAAS,CACP,eAAgB,mBAChB,OAAU,kBAClB,EACM,KAAM,KAAK,UAAUxF,CAAO,EAC5B,GAAGpH,EACH,OAAQm1B,EAAQ,MACtB,CAAK,EAED,GAAI,CAAC/yB,EAAS,GACZ,MAAM,IAAI,MAAM,QAAQA,EAAS,MAAM,KAAKA,EAAS,UAAU,EAAE,EAGnE,MAAM/H,EAAO,MAAM+H,EAAS,KAAI,EAChC,eAAQ,IAAI,4BAA6Bq4B,EAAU,IAAK,OAAOpgC,GAAS,SAAW,GAAG,MAAM,QAAQA,CAAI,EAAIA,EAAK,OAAS,SAAW,QAAQ,GAAKA,CAAI,EAC/IA,CAET,OAAS0C,EAAO,CACd,MAAIA,EAAM,OAAS,cACjB,QAAQ,MAAM,6BAA8B09B,CAAQ,EAC9C,IAAI,MAAM,sBAAsBA,CAAQ,EAAE,IAElD,QAAQ,MAAM,0BAA2BA,EAAU19B,CAAK,EAClDA,EACR,QAAC,CACCo4B,EAAQ,MAAK,CACf,CACF,CAWO,eAAewF,IAAsB,CAC1C,OAAOH,GAAW,2BAA2B,CAC/C,CAUO,eAAeI,IAAY,CAChC,OAAOJ,GAAW,gBAAgB,CACpC,CAUO,eAAeK,IAAoB,CACxC,OAAOL,GAAW,yCAAyC,CAC7D,CAUO,eAAeM,IAAqB,CACzC,OAAON,GAAW,8BAA8B,CAClD,CAUO,eAAeO,IAAwB,CAC5C,OAAOP,GAAW,oCAAoC,CACxD,CAeO,eAAeQ,IAAuB,CAC3C,OAAOR,GAAW,4BAA4B,CAChD,CAaO,eAAeS,IAAc,CAClC,OAAOT,GAAW,mBAAmB,CACvC,CAoBO,eAAeU,IAAa,CACjC,OAAOV,GAAW,+BAA+B,CACnD,CAmDO,eAAeW,GAAaC,EAAOC,EAAQ,CAChD,MAAMj0B,EAAU,CACd,YAAag0B,EAAM,YACnB,KAAMA,EAAM,MAAQ,KACpB,WAAYA,EAAM,WAClB,SAAUA,EAAM,SAChB,YAAaA,EAAM,aAAeC,EAAO,OACzC,WAAYD,EAAM,YAAc,EAChC,QAASC,GAAU,IAAI,IAAK7vB,IAAO,CACjC,IAAKA,EAAE,IACP,UAAWA,EAAE,UACb,SAAUA,EAAE,SACZ,SAAUA,EAAE,UAAY,KACxB,SAAUA,EAAE,UAAY,KACxB,kBAAmBA,EAAE,mBAAqB,KAC1C,QAASA,EAAE,SAAW,KACtB,MAAOA,EAAE,OAAS,KAClB,WAAYA,EAAE,YAAc,KAC5B,YAAaA,EAAE,WACrB,EAAM,CACN,EACQnO,EAAM,MAAMm9B,GAAW,qBAAsBpzB,CAAO,EAC1D,MAAO,CAAE,SAAU/J,GAAK,IAAMA,GAAK,WAAa,IAAI,CACtD,CChdA,MAAMi+B,GAAiB,YACjBC,GAAU,KAAK,GAAK,IAYnB,SAASC,GAAgBC,EAAMC,EAAMC,EAAMC,EAAM,CACtD,MAAMC,GAAQD,EAAOF,GAAQH,GACvBO,GAAQH,EAAOF,GAAQF,GACvB1uB,EACJ,KAAK,IAAIgvB,EAAO,CAAC,GAAK,EACtB,KAAK,IAAIH,EAAOH,EAAO,EAAI,KAAK,IAAIK,EAAOL,EAAO,EAAI,KAAK,IAAIO,EAAO,CAAC,GAAK,EAC9E,MAAO,GAAIR,GAAiB,KAAK,KAAK,KAAK,IAAI,EAAG,KAAK,KAAKzuB,CAAC,CAAC,CAAC,CACjE,CAqBO,SAASkvB,GAAY92B,EAAO+2B,EAAW,EAAG,CAC/C,OAAI/2B,GAAS,MAAQ,OAAO,MAAMA,CAAK,EAAU,IAC1CA,EAAM,QAAQ+2B,CAAQ,CAC/B,CAOO,SAASC,GAAeC,EAAQ,CACrC,OAAIA,GAAU,MAAQ,OAAO,MAAMA,CAAM,EAAU,IAC/CA,EAAS,IAAa,GAAG,KAAK,MAAMA,CAAM,CAAC,KACxC,IAAIA,EAAS,KAAM,QAAQ,CAAC,CAAC,KACtC,CAOO,SAASC,GAAeD,EAAQ,CACrC,OAAIA,GAAU,MAAQ,OAAO,MAAMA,CAAM,EAAU,IAC5C,IAAI,KAAK,MAAMA,CAAM,CAAC,IAC/B,CAQO,SAASE,GAAgBF,EAAQ,CACtC,OAAIA,GAAU,MAAQ,OAAO,MAAMA,CAAM,EAAU,OAC/CA,GAAU,GAAW,OACrBA,GAAU,GAAW,OAClB,MACT,CCrDA,MAAMG,GAAW,CAEf,aAAc,EAEd,cAAe,IAEf,YAAa,IAEb,aAAc,GAEd,mBAAoB,GACpB,UAAW,KACX,aAAc,CAChB,EAEO,MAAMC,EAAW,CAYtB,YAAYt8B,EAAU,GAAI,CACxB,KAAK,KAAO,CAAE,GAAGq8B,GAAU,GAAGr8B,CAAO,EACrC,KAAK,QAAUA,EAAQ,SAAW,KAClC,KAAK,KAAOA,EAAQ,MAAQ,KAC5B,KAAK,KAAOA,EAAQ,cACjB,OAAO,UAAc,IAAc,UAAU,YAAc,MAG9D,KAAK,OAAS,OACd,KAAK,SAAW,KAChB,KAAK,MAAQ,GACb,KAAK,WAAa,GAElB,KAAK,eAAiB,KACtB,KAAK,iBAAmB,KACxB,KAAK,cAAgB,KACrB,KAAK,gBAAkB,EACvB,KAAK,WAAa,EAClB,KAAK,YAAc,EACnB,KAAK,SAAW,KAGhB,KAAK,WAAa,OAAO,OAAO,IAAI,CACtC,CAYA,GAAG/F,EAAO4F,EAAI,CACZ,OAAC,KAAK,WAAW5F,CAAK,IAAM,KAAK,WAAWA,CAAK,EAAI,IAAI,MAAQ,IAAI4F,CAAE,EAChE,IAAM,KAAK,WAAW5F,CAAK,GAAG,OAAO4F,CAAE,CAChD,CAEA,MAAM5F,EAAOmN,EAAS,CACpB,MAAMm1B,EAAM,KAAK,WAAWtiC,CAAK,EACjC,GAAKsiC,EACL,UAAW18B,KAAM08B,EACf,GAAI,CAAE18B,EAAGuH,CAAO,CAAG,OAASpC,EAAK,CAAE,QAAQ,MAAM,8BAA8B/K,CAAK,UAAW+K,CAAG,CAAG,CAEzG,CAKA,IAAI,OAAQ,CAAE,OAAO,KAAK,MAAQ,CAClC,IAAI,aAAc,CAAE,OAAO,KAAK,UAAY,CAC5C,IAAI,SAAU,CAAE,OAAO,KAAK,QAAU,CACtC,IAAI,aAAc,CAAE,MAAO,CAAC,CAAC,KAAK,IAAM,CAExC,UAAU4I,EAAG,CACP,KAAK,SAAWA,IACpB,KAAK,OAASA,EACd,KAAK,MAAM,cAAeA,CAAC,EAC7B,CAQA,WAAY,CACV,GAAI,CAAC,KAAK,KAAM,CAAE,KAAK,MAAM,QAAS,IAAI,MAAM,2BAA2B,CAAC,EAAG,MAAQ,CACvF,KAAK,MAAQ,GACb,KAAK,aAAY,CACnB,CAGA,UAAW,CACT,KAAK,MAAQ,GACR,KAAK,YAAY,KAAK,eAAc,CAC3C,CAOA,oBAAqB,CACnB,OAAO,IAAI,QAAQ,CAACrT,EAASgK,IAAW,CACtC,GAAI,CAAC,KAAK,KAAM,CAAEA,EAAO,IAAI,MAAM,2BAA2B,CAAC,EAAG,MAAQ,CAC1E,KAAK,KAAK,mBACPi4B,GAAQ,CACP,MAAMC,EAAMH,GAAW,UAAUE,CAAG,EACpC,KAAK,SAAWC,EAChB,KAAK,MAAM,WAAYA,CAAG,EAC1BliC,EAAQkiC,CAAG,CACb,EACCz3B,GAAQ,CAAE,KAAK,MAAM,QAASA,CAAG,EAAGT,EAAOS,CAAG,CAAG,EAClD,CACE,mBAAoB,KAAK,KAAK,mBAC9B,QAAS,KAAK,KAAK,UACnB,WAAY,KAAK,KAAK,YAChC,CACA,CACI,CAAC,CACH,CAUA,MAAM,eAAekJ,EAAO,GAAI,CAC9B,GAAI,CAAC,KAAK,KAAM,MAAM,IAAI,MAAM,2BAA2B,EAC3D,GAAI,CAAC,KAAK,QAAS,MAAM,IAAI,MAAM,2CAA2C,EAC9E,GAAI,KAAK,WAAY,MAAO,CAAE,QAAS,KAAK,eAAgB,KAAM,KAAK,gBAAgB,EAEvF,MAAMC,EAAOmuB,GAAW,KAAI,EACtBluB,EAAY,IAAI,KAAI,EAAG,YAAW,EAClCsuB,EAAY,CAAE,KAAAvuB,EAAM,KAAMD,EAAK,MAAQ,KAAM,UAAAE,EAAW,GAAGF,CAAI,EAC/DI,EAAU,MAAM,KAAK,QAAQ,YAAYouB,CAAS,EAExD,YAAK,eAAiBpuB,EACtB,KAAK,iBAAmBH,EACxB,KAAK,cAAgB,KACrB,KAAK,gBAAkB,EACvB,KAAK,WAAa,EAClB,KAAK,YAAc,EACnB,KAAK,WAAa,GAElB,KAAK,aAAY,EACjB,KAAK,UAAU,WAAW,EAC1B,KAAK,MAAM,aAAc,CAAE,QAAAG,EAAS,KAAAH,EAAM,UAAAC,EAAW,EAC9C,CAAE,QAAAE,EAAS,KAAAH,CAAI,CACxB,CAOA,MAAM,eAAgB,CACpB,GAAI,CAAC,KAAK,WAAY,OAAO,KAC7B,MAAMG,EAAU,KAAK,eAEfc,EAAU,CAAE,QADF,IAAI,KAAI,EAAG,YAAW,EACX,WAAY,KAAK,YAAa,UAAW,KAAK,UAAU,EAEnF,KAAK,WAAa,GACb,KAAK,OAAO,KAAK,eAAc,EACpC,KAAK,UAAU,KAAK,MAAQ,WAAa,MAAM,EAE/C,GAAI,CACF,MAAM,KAAK,QAAQ,YAAYd,EAASc,CAAO,CACjD,OAASpK,EAAK,CACZ,KAAK,MAAM,QAASA,CAAG,CACzB,CACA,KAAK,MAAM,YAAa,CAAE,QAAAsJ,EAAS,GAAGc,CAAO,CAAE,EAE/C,IAAIutB,EAAS,GACb,GAAI,KAAK,KACP,GAAI,CAAEA,EAAS,MAAM,KAAK,WAAWruB,CAAO,CAAG,OACxCtJ,EAAK,CAAE,KAAK,MAAM,QAASA,CAAG,CAAG,CAG1C,YAAK,eAAiB,KACtB,KAAK,iBAAmB,KACjB,CAAE,QAAAsJ,EAAS,WAAYc,EAAQ,WAAY,UAAWA,EAAQ,UAAW,OAAAutB,CAAM,CACxF,CASA,MAAM,aAAc,CAClB,GAAI,CAAC,KAAK,MAAQ,CAAC,KAAK,QAAS,MAAO,CAAE,OAAQ,EAAG,OAAQ,CAAC,EAC9D,GAAI,KAAK,KAAK,UAAY,CAAC,KAAK,KAAK,SAAQ,EAAI,MAAO,CAAE,OAAQ,EAAG,OAAQ,CAAC,EAE9E,IAAIC,EAAS,EAAGjE,EAAS,EACzB,MAAMkE,EAAS,MAAM,KAAK,QAAQ,kBAAiB,EACnD,UAAWzB,KAASyB,EAClB,GAAI,CACS,MAAM,KAAK,WAAWzB,EAAM,IAAMA,EAAM,QAASA,CAAK,EAC5DwB,IAAWjE,GAClB,OAAS3zB,EAAK,CACZ2zB,IACA,KAAK,MAAM,QAAS3zB,CAAG,CACzB,CAEF,YAAK,MAAM,aAAc,CAAE,OAAA43B,EAAQ,OAAAjE,CAAM,CAAE,EACpC,CAAE,OAAAiE,EAAQ,OAAAjE,CAAM,CACzB,CAGA,MAAM,WAAWrqB,EAASwuB,EAAU,CAClC,MAAMzB,EAAS,MAAM,KAAK,QAAQ,eAAe/sB,CAAO,EAClD8sB,EAAQ0B,GAAY,CAAE,GAAIxuB,CAAO,EACjCtR,EAAS,MAAM,KAAK,KAAK,UAAUo+B,EAAOC,CAAM,EAChD1rB,EAAW3S,IAAWA,EAAO,UAAYA,EAAO,IAAM,MAC5D,aAAM,KAAK,QAAQ,gBAAgBsR,EAASqB,CAAQ,EAC7C,EACT,CAKA,cAAe,CACb,GAAI,KAAK,UAAY,MAAQ,CAAC,KAAK,KAAM,CACnC,KAAK,SAAW,QAAU,KAAK,OAAO,KAAK,UAAU,UAAU,EACnE,MACF,CACA,KAAK,SAAW,KAAK,KAAK,cACvB6sB,GAAQ,KAAK,OAAOA,CAAG,EACvBx3B,GAAQ,KAAK,MAAM,QAASA,CAAG,EAChC,CACE,mBAAoB,KAAK,KAAK,mBAC9B,QAAS,KAAK,KAAK,UACnB,WAAY,KAAK,KAAK,YAC9B,CACA,EACS,KAAK,YAAY,KAAK,UAAU,UAAU,CACjD,CAGA,gBAAiB,CACX,KAAK,UAAY,MAAQ,KAAK,MAChC,KAAK,KAAK,WAAW,KAAK,QAAQ,EAEpC,KAAK,SAAW,IAClB,CAGA,MAAM,OAAOw3B,EAAK,CAChB,MAAMC,EAAMH,GAAW,UAAUE,CAAG,EAIpC,GAHA,KAAK,SAAWC,EAChB,KAAK,MAAM,WAAYA,CAAG,EAEtB,CAAC,KAAK,WAAY,OAEtB,KAAM,CAAE,cAAAM,EAAe,aAAAC,EAAc,YAAAC,EAAa,aAAAC,CAAY,EAAK,KAAK,KAClEC,EAAMV,EAAI,UAKhB,GAFI,KAAK,iBAAoBU,EAAM,KAAK,gBAAmBJ,GAEvDG,EAAe,GAAKT,EAAI,UAAY,MAAQA,EAAI,SAAWS,GAAgB,KAAK,cAAe,OAEnG,IAAIE,EAAO,GACPC,EAAQ,EACZ,GAAI,CAAC,KAAK,cACRD,EAAO,OACF,CACLC,EAAQ7B,GAAgB,KAAK,cAAc,IAAK,KAAK,cAAc,IAAKiB,EAAI,IAAKA,EAAI,GAAG,EACxF,MAAMa,EAAUH,EAAM,KAAK,iBACvBE,GAASL,GAAgBM,GAAWL,KAAaG,EAAO,GAC9D,CACA,GAAKA,EAEL,CAAI,KAAK,gBAAe,KAAK,YAAcC,GAC3C,KAAK,aAAe,EACpB,KAAK,cAAgB,CAAE,IAAKZ,EAAI,IAAK,IAAKA,EAAI,IAAK,UAAWU,CAAG,EACjE,KAAK,gBAAkBA,EAEvB,GAAI,CACF,MAAM,KAAK,QAAQ,SAAS,KAAK,eAAgB,CAAE,GAAGV,EAAK,IAAK,KAAK,WAAW,CAAE,EAClF,KAAK,MAAM,QAAS,CAClB,QAAS,KAAK,eACd,IAAK,KAAK,YACV,MAAOA,EACP,UAAW,KAAK,WAChB,WAAY,KAAK,WACzB,CAAO,CACH,OAASz3B,EAAK,CACZ,KAAK,MAAM,QAASA,CAAG,CACzB,EACF,CAKA,OAAO,UAAUw3B,EAAK,CACpB,MAAM70B,EAAI60B,EAAI,QAAU,GAClBe,EAAOlyB,GAAOA,GAAK,MAAQ,CAAC,OAAO,MAAMA,CAAC,EAAIA,EAAI,KACxD,MAAO,CACL,IAAK1D,EAAE,UACP,IAAKA,EAAE,SACP,SAAU41B,EAAI51B,EAAE,QAAQ,EACxB,SAAU41B,EAAI51B,EAAE,QAAQ,EACxB,iBAAkB41B,EAAI51B,EAAE,gBAAgB,EACxC,QAAS41B,EAAI51B,EAAE,OAAO,EACtB,MAAO41B,EAAI51B,EAAE,KAAK,EAClB,WAAY,KACZ,UAAW60B,EAAI,WAAa,KAAK,IAAG,CAC1C,CACE,CAGA,OAAO,MAAO,CACZ,OAAI,OAAO,OAAW,KAAe,OAAO,WAAmB,OAAO,WAAU,EACzE,uCAAuC,QAAQ,QAAUgB,GAAO,CACrE,MAAMt0B,EAAK,KAAK,OAAM,EAAK,GAAM,EAEjC,OADUs0B,IAAO,IAAMt0B,EAAKA,EAAI,EAAO,GAC9B,SAAS,EAAE,CACtB,CAAC,CACH,CACF,CCpVA,MAAMu0B,GAAiB,CACrB,MAAM,YAAYvvB,EAAM,CACtB,MAAM9E,EAAa8E,EAAK,YACnB2rB,MAAc,aACd,KACL,OAAO5rB,GAAe,CAAE,GAAGC,EAAM,WAAY9E,GAAc,KAAO,OAAOA,CAAU,EAAI,KAAM,CAC/F,EACA,SAAiB,CAACkF,EAASC,IAAYF,GAAiBC,EAASC,CAAK,EACtE,YAAiB,CAACD,EAASc,IAAYD,GAAeb,EAASc,CAAO,EACtE,kBAAmB,IAAoBI,GAAoB,EAC3D,eAAkBlB,GAAqBmB,GAAkBnB,CAAO,EAChE,gBAAiB,CAACA,EAASovB,IAAYhuB,GAAmBpB,EAASovB,CAAM,CAC3E,EAMMC,GAAa,CACjB,UAAW,CAACvC,EAAOC,IAAWF,GAAaC,EAAOC,CAAM,EACxD,SAAW,IAAMvG,EAAQ,CAC3B,EAQa8I,GAAa,IAAItB,GAAW,CACvC,QAASmB,GACT,KAAME,GACN,aAAc,EACd,cAAe,IACf,YAAa,IACb,aAAc,GACd,mBAAoB,EACtB,CAAC,ECzBKE,GAAiB,IAAI,IAAI,CAC7B,WACA,eACA,iBACA,aACF,CAAC,EAWM,SAASC,GAAkB,CAAE,QAAAC,EAAS,YAAAC,GAAe,CAC1D,MAAM5lB,EAAM2lB,EAAQ,OAAM,EACpB1mB,EAAU,OAAO,QAAU,OAAO,SAAW,OAAU,OAAO,OAAS,KAKvE4mB,EAAkB,IAAI/lB,EACtBgmB,EAAiB,IAAI/lB,EAAY,CACrC,OAAQ8lB,EACR,OAAQ,KACR,MAAO,IAAItmB,EAAM,CACf,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,EAAG,EACjD,KAAQ,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CACzD,CAAK,EACD,WAAY,CACV,MAAO,mBACP,uBAAwB,EAC9B,CACA,CAAG,EACDO,EAAI,SAAS8lB,CAAc,EAE3B,IAAIC,EAAkB,KAClBC,EAAmBJ,GAAa,IAAM,OAAOA,EAAY,GAAG,EAAI,KAChEK,EAAmB,GAKvB,SAASC,EAAKr8B,EAAS,CACrB,GAAI,CAACoV,EAAQ,CACX,QAAQ,KAAK,qDAAsDpV,CAAO,EAC1E,MACF,CACA,GAAI,CACFoV,EAAO,YAAYpV,EAAS,GAAG,CACjC,OAASoF,EAAG,CACV,QAAQ,KAAK,qCAAsCA,CAAC,CACtD,CACF,CAEA,SAASk3B,EAAUC,EAAMv8B,EAAS,CAChCq8B,EAAK,CAAE,KAAM,QAAS,KAAAE,EAAM,QAAAv8B,CAAO,CAAE,CACvC,CAEA,SAASw8B,GAAY,CACfJ,IACJA,EAAe,GACfC,EAAK,CAAE,KAAM,QAAS,EACxB,CAGA,SAASI,EAAcllB,EAAS/K,EAAKC,EAAK,CACxC,MAAMlD,EAAIgO,EAAQ,cAAa,EAC/B,IAAImlB,EAASlwB,EAAKmwB,EAASlwB,EAC3B,GAAIiwB,GAAU,MAAQC,GAAU,KAAM,CACpC,MAAMrc,EAAM/I,EAAQ,YAAW,GAAI,UAAS,EAC5C,GAAI+I,EAAK,CACP,KAAM,CAACzL,EAAIC,CAAE,EAAIyQ,GAASqX,GAAUtc,CAAG,CAAC,EACxCoc,EAAS7nB,EAAI8nB,EAAS7nB,CACxB,CACF,CACA,MAAO,CACL,KAAM,gBACN,IAAYvL,EAAE,KAAc,KAC5B,UAAYA,EAAE,IAAc,KAC5B,IAAYmzB,GAAgB,KAC5B,IAAYC,GAAgB,KAC5B,UAAYpzB,EAAE,WAAc,KAC5B,UAAYA,EAAE,WAAc,KAC5B,QAAYA,EAAE,SAAc,KAC5B,WAAYA,EAAE,YAAc,KAC5B,WAAYA,EAAE,YAAc,IAClC,CACE,CAEA,SAASszB,EAAiBtlB,EAAS,CAEjC,GADAykB,EAAgB,MAAK,EACjBzkB,EAAS,CACX,MAAMb,EAAQa,EAAQ,MAAK,EAC3BykB,EAAgB,WAAWtlB,CAAK,CAClC,CACF,CAKAolB,EAAQ,QAAQ,CAACtvB,EAAKC,EAAKqwB,EAAgB1lB,IAAQ,CACjD,IAAI2lB,EAAgB,KACpB5mB,EAAI,sBAAsBiB,EAAI,MAAQjP,GAAM,CAC1C,GAAIA,EAAE,IAAI,YAAY,IAAM,SAC1B,OAAA40B,EAAgB50B,EACT,EAEX,CAAC,EACG40B,GACFF,EAAiBE,CAAa,EAC9BV,EAAKI,EAAcM,EAAevwB,EAAKC,CAAG,CAAC,IAE3CowB,EAAiB,IAAI,EACrBR,EAAK,CAAE,KAAM,iBAAkB,EAEnC,CAAC,EAKD,OAAO,iBAAiB,UAAYrkC,GAAU,CAC5C,MAAMglC,EAAMhlC,EAAM,KAClB,GAAI,GAACglC,GAAO,OAAOA,GAAQ,UAAY,CAACpB,GAAe,IAAIoB,EAAI,IAAI,GACnE,GAAI,CACF,OAAQA,EAAI,KAAI,CACd,IAAK,WAAY,CACf,GAAI,OAAOA,EAAI,KAAQ,UAAY,OAAOA,EAAI,KAAQ,SAAU,CAC9D,MAAM1M,EAAOna,EAAI,QAAO,EACxBma,EAAK,UAAUpP,EAAW,CAAC8b,EAAI,IAAKA,EAAI,GAAG,CAAC,CAAC,EACzC,OAAOA,EAAI,MAAS,UAAU1M,EAAK,QAAQ0M,EAAI,IAAI,CACzD,CACA,KACF,CACA,IAAK,eACCA,EAAI,KAAKC,EAAY,OAAOD,EAAI,GAAG,CAAC,EACxC,MACF,IAAK,iBACHH,EAAiB,IAAI,EACrBV,EAAmB,KACnB,MACF,IAAK,cACCa,EAAI,KAAO,OAAOlB,EAAQ,YAAe,YAC3CA,EAAQ,WAAWkB,EAAI,GAAG,EAE5B,KACV,CACI,OAAS53B,EAAG,CACVk3B,EAAU,iBAAkB,oBAAoBU,EAAI,IAAI,KAAK53B,EAAE,OAAO,EAAE,CAC1E,CACF,CAAC,EAQD,SAAS63B,EAAYC,EAAK,CACxB,GAAI,CAAChB,EAAc,CAAEC,EAAmBe,EAAK,MAAQ,CAErD,MAAM3lB,EADW2kB,EAAa,UAAS,EAAG,YAAW,EAC5B,KAAM/zB,GAAM,OAAOA,EAAE,IAAI,KAAK,GAAK,EAAE,IAAM+0B,CAAG,EACvE,GAAI,CAAC3lB,EAAS,CAAE4kB,EAAmBe,EAAK,MAAQ,CAEhDf,EAAmB,KACnBU,EAAiBtlB,CAAO,EACxB,MAAM+I,EAAM/I,EAAQ,YAAW,GAAI,UAAS,EACxC+I,GACFnK,EAAI,QAAO,EAAG,IAAImK,EAAK,CAAE,QAAS,CAAC,GAAI,GAAI,GAAI,EAAE,EAAG,SAAU,IAAK,QAAS,GAAI,EAElF+b,EAAKI,EAAcllB,EAAS,KAAM,IAAI,CAAC,CACzC,CAKA,SAAS4lB,EAAmB3mB,EAAO,CACjC0lB,EAAe1lB,EACf,MAAMK,EAASL,EAAM,UAAS,EAExB4mB,EAAQ,IAAM,CAElB,eAAe,IAAM,CACfjB,GAAkBc,EAAYd,CAAgB,EAClDK,EAAS,CACX,CAAC,CACH,EAEA,GAAI3lB,EAAO,cAAc,OAAS,EAChCumB,EAAK,MACA,CAGL,IAAIC,EAAY,GAChBxmB,EAAO,GAAG,aAAc,IAAM,CACxBwmB,IACJA,EAAY,GACZ,eAAe,IAAM,CACnBA,EAAY,GACRlB,GAAkBc,EAAYd,CAAgB,EAClDK,EAAS,CACX,CAAC,EACH,CAAC,CACH,CACF,CAQA,GAHIT,GAAa,SAAW,OAAOD,EAAQ,YAAe,YACxDA,EAAQ,WAAWC,EAAY,OAAO,EAEpC,OAAOA,GAAa,KAAQ,UAAY,OAAOA,GAAa,KAAQ,SAAU,CAChF,MAAMzL,EAAOna,EAAI,QAAO,EACxBma,EAAK,UAAUpP,EAAW,CAAC6a,EAAY,IAAKA,EAAY,GAAG,CAAC,CAAC,EAC7DzL,EAAK,QAAQ,OAAOyL,GAAa,MAAS,SAAWA,EAAY,KAAO,EAAE,CAC5E,CAEA,MAAO,CAAE,mBAAAoB,EAAoB,UAAAb,CAAS,CACxC,CChPO,MAAMgB,GAAe,CAC1B,CAAE,IAAK,UAAwB,MAAO,UAAwB,eAAgB,SAAS,EACvF,CAAE,IAAK,kBAAwB,MAAO,kBAAwB,eAAgB,SAAS,EACvF,CAAE,IAAK,sBAAwB,MAAO,sBAAwB,eAAgB,SAAS,EACvF,CAAE,IAAK,YAAwB,MAAO,YAAwB,eAAgB,MAAM,EACpF,CAAE,IAAK,QAAwB,MAAO,oBAAwB,eAAgB,KAAK,CACrF,EAMaC,GAAgB,CAC3B,QAAS,CACP,MAAO,UAAW,YAAa,YAAa,SAAU,QACtD,YAAa,UAAW,UAAW,WAAY,WAC/C,aAAc,aAAc,WAAY,UAAW,WACnD,OAAQ,cAAe,SAC3B,EACE,gBAAiB,CACf,WACJ,EACE,oBAAqB,CAGvB,EACE,UAAW,CACT,SAAU,OAAQ,SACtB,EACE,MAAO,EACT,EAYA,SAASC,GAAuBC,EAAI,CAClC,GAAI,CAACA,GAAI,UAAU,OAAQ,MAAO,OAClC,IAAIC,EAAQ,EAAGC,EAAQ,EAAGvE,EAAS,EACnC,UAAWjxB,KAAKs1B,EAAG,SAAU,CAC3B,MAAM73B,EAAIuC,GAAG,UAAU,KAClBvC,IACDA,IAAM,WAAaA,IAAM,eAAgB83B,IACpC93B,IAAM,cAAgBA,IAAM,kBAAmB+3B,KAC/C/3B,IAAM,SAAWA,IAAM,eAAcwzB,IAChD,CACA,MAAM1tB,EAAQgyB,EAAQC,EAAQvE,EAC9B,GAAI1tB,IAAU,EAAG,MAAO,OACxB,MAAMkyB,EAAM,KAAK,IAAIF,EAAOC,EAAOvE,CAAM,EACzC,OAAIwE,EAAMlyB,EAAQ,IAAa,QAC3BgyB,IAAUE,EAAY,UACtBD,IAAUC,EAAY,OACnB,OACT,CAMA,SAASC,GAAqBJ,EAAIK,EAAa,GAAI,CACjD,MAAMxD,EAAM,IAAI,IACVrxB,EAAI,KAAK,IAAI60B,EAAYL,EAAG,SAAS,MAAM,EACjD,QAASjlC,EAAI,EAAGA,EAAIyQ,EAAGzQ,IAAK,CAC1B,MAAMuO,EAAQ02B,EAAG,SAASjlC,CAAC,GAAG,WAC9B,GAAI,GAACuO,GAAS,OAAOA,GAAU,UAC/B,UAAW9C,KAAO,OAAO,KAAK8C,CAAK,EACjCuzB,EAAI,IAAI,OAAOr2B,CAAG,EAAE,YAAW,CAAE,CAErC,CACA,OAAOq2B,CACT,CAGA,SAASyD,GAAIC,KAAO/W,EAAY,CAC9B,UAAWvhB,KAAKuhB,EAAY,GAAI+W,EAAG,IAAIt4B,CAAC,EAAG,MAAO,GAClD,MAAO,EACT,CAOO,SAASu4B,GAAiBR,EAAI,CACnC,MAAMS,EAASV,GAAuBC,CAAE,EACxC,GAAIS,IAAW,QAAUA,IAAW,QAAS,MAAO,QACpD,MAAMF,EAAKH,GAAqBJ,CAAE,EAElC,OAAIS,IAAW,OACTH,GAAIC,EAAI,SAAU,SAAS,EAAU,YAClC,QAGLE,IAAW,UAETH,GAAIC,EAAI,MAAO,YAAa,UAAW,UAAW,WAAW,GAE7DD,GAAIC,EAAI,MAAO,YAAa,UAAW,SAAS,EAC3C,UAELD,GAAIC,EAAI,YAAa,cAAe,WAAW,EAAU,kBACzDD,GAAIC,EAAI,WAAY,kBAAmB,kBAAmB,SAClD,aAAc,YAAY,GAClC,CAACD,GAAIC,EAAI,MAAO,WAAW,EACtB,sBAEF,QAIF,OACT,CAWA,MAAMG,GAAmB,CAEvB,IAAY,CAAC,MAAO,mBAAoB,YAAa,KAAK,EAC1D,QAAY,CAAC,UAAW,WAAY,KAAM,SAAS,EACnD,UAAY,CAAC,YAAa,WAAY,MAAM,EAC5C,UAAY,CAAC,YAAa,WAAY,aAAa,EACnD,OAAY,CAAC,SAAU,KAAK,EAC5B,MAAY,CAAC,QAAS,KAAK,EAC3B,UAAY,CAAC,YAAa,WAAY,UAAW,QAAQ,EACzD,QAAY,CAAC,UAAW,aAAc,aAAa,EACnD,QAAY,CAAC,UAAW,SAAU,cAAe,MAAM,EACvD,SAAY,CAAC,WAAY,UAAW,MAAM,EAC1C,SAAY,CAAC,WAAY,WAAY,cAAc,EACnD,WAAY,CAAC,aAAc,YAAa,OAAO,EAC/C,WAAY,CAAC,aAAc,YAAa,QAAS,QAAQ,EACzD,SAAY,CAAC,WAAY,gBAAiB,SAAS,EACnD,QAAY,CAAC,UAAW,SAAU,WAAW,EAC7C,SAAY,CAAC,WAAY,OAAQ,YAAY,EAC7C,KAAY,CAAC,OAAQ,WAAY,UAAU,EAC3C,YAAY,CAAC,cAAe,aAAc,SAAS,EACnD,QAAY,CAAC,UAAW,QAAS,UAAU,EAG3C,OAAY,CAAC,SAAU,QAAS,IAAI,EACpC,KAAY,CAAC,OAAQ,cAAe,SAAS,EAC7C,QAAY,CAAC,UAAW,aAAc,OAAO,CAC/C,EAGA,SAASC,GAAazyB,EAAG,CACvB,OAAO,OAAOA,CAAC,EAAE,YAAW,EAAG,QAAQ,YAAa,EAAE,CACxD,CAWO,SAAS0yB,GAAcZ,EAAI71B,EAAY,CAC5C,MAAMjL,EAAU4gC,GAAc31B,CAAU,GAAK,GAC7C,GAAIjL,EAAQ,SAAW,EAAG,MAAO,GAEjC,MAAMqhC,EAAKH,GAAqBJ,EAAI,EAAE,EAEhCa,EAAe,IAAI,IACzB,UAAWr6B,KAAO+5B,EAChBM,EAAa,IAAIF,GAAan6B,CAAG,EAAGA,CAAG,EAGzC,MAAMs6B,EAAU,GAChB,UAAWC,KAAO7hC,EAAS,CACzB,MAAMsqB,EAAakX,GAAiBK,CAAG,GAAK,CAACA,CAAG,EAChD,IAAInU,EAAU,KACd,UAAWoU,KAAQxX,EAAY,CAC7B,MAAMhe,EAAIm1B,GAAaK,CAAI,EAC3B,GAAIH,EAAa,IAAIr1B,CAAC,EAAG,CACvBohB,EAAUiU,EAAa,IAAIr1B,CAAC,EAC5B,KACF,CACF,CACAs1B,EAAQC,CAAG,EAAInU,CACjB,CACA,OAAOkU,CACT,CAOO,SAASG,GAAkBC,EAAaJ,EAAS,CACtD,MAAMxa,EAAM,GACZ,SAAW,CAAC6a,EAAWC,CAAS,IAAK,OAAO,QAAQN,GAAW,EAAE,EAC3DM,GAAa,MACbF,GAAe,OAAO,UAAU,eAAe,KAAKA,EAAaE,CAAS,IAC5E9a,EAAI6a,CAAS,EAAID,EAAYE,CAAS,GAG1C,OAAO9a,CACT,CAOO,SAAS+a,GAAiBrB,EAAI,CACnC,MAAMsB,EAAO,IAAI,IACjB,UAAW52B,KAAKs1B,EAAG,UAAY,GAAI,CACjC,MAAM12B,EAAQoB,GAAG,WACjB,GAAI,GAACpB,GAAS,OAAOA,GAAU,UAC/B,UAAWkD,KAAK,OAAO,KAAKlD,CAAK,EAC1Bg4B,EAAK,IAAI90B,CAAC,GAAG80B,EAAK,IAAI90B,EAAG,EAAI,CAEtC,CACA,OAAO,MAAM,KAAK80B,EAAK,KAAI,CAAE,CAC/B,CC9NA,MAAMC,EAAM,GACZ,IAAIC,GAAQ,KACRC,EAAQ,KAEZ,SAASC,IAAW,CACdH,EAAI,OACRA,EAAI,KAAiB,SAAS,eAAe,oBAAoB,EACjEA,EAAI,SAAiB,SAAS,eAAe,uBAAuB,EACpEA,EAAI,QAAiB,SAAS,eAAe,sBAAsB,EACnEA,EAAI,OAAiB,SAAS,eAAe,qBAAqB,EAClEA,EAAI,WAAiB,SAAS,eAAe,0BAA0B,EACvEA,EAAI,WAAiB,SAAS,eAAe,0BAA0B,EACvEA,EAAI,MAAiB,SAAS,eAAe,2BAA2B,EACxEA,EAAI,QAAiB,SAAS,eAAe,mBAAmB,EAChEA,EAAI,cAAiB,SAAS,eAAe,0BAA0B,EACvEA,EAAI,UAAiB,SAAS,eAAe,qBAAqB,EAG9DA,EAAI,QAAU,CAACA,EAAI,OAAO,QAAQ,YACpCA,EAAI,OAAO,UAAY1B,GACpB,IAAK13B,GAAM,kBAAkBA,EAAE,GAAG,KAAKA,EAAE,KAAK,WAAW,EACzD,KAAK,EAAE,EACVo5B,EAAI,OAAO,QAAQ,UAAY,KAI7BA,EAAI,QAAU,CAACA,EAAI,OAAO,QAAQ,QACpCA,EAAI,OAAO,QAAQ,MAAQ,IAC3BA,EAAI,OAAO,iBAAiB,SAAUI,EAAc,GAElDJ,EAAI,SAAW,CAACA,EAAI,QAAQ,QAAQ,QACtCA,EAAI,QAAQ,QAAQ,MAAQ,IAC5BA,EAAI,QAAQ,iBAAiB,QAAS,IAAMK,GAAO,MAAM,CAAC,GAExDL,EAAI,eAAiB,CAACA,EAAI,cAAc,QAAQ,QAClDA,EAAI,cAAc,QAAQ,MAAQ,IAClCA,EAAI,cAAc,iBAAiB,QAAS,IAAMK,GAAO,QAAQ,CAAC,GAIhEL,EAAI,MAAQ,CAACA,EAAI,KAAK,QAAQ,QAChCA,EAAI,KAAK,QAAQ,MAAQ,IACzBA,EAAI,KAAK,iBAAiB,kBAAmB,IAAM,CAC7CE,GAAO,UAAY,CAACA,EAAM,YAC5BA,EAAM,UAAY,GAClBA,EAAM,SAAS,CAAE,OAAQ,QAAQ,CAAE,GAErCA,EAAQ,IACV,CAAC,GAEL,CAGA,SAASI,IAAoB,CAC3B,MAAM13B,EAAas3B,EAAM,WACnBviC,EAAU4gC,GAAc31B,CAAU,GAAK,GAG7C,GAAIA,IAAe,SAAWjL,EAAQ,SAAW,EAAG,CAClDqiC,EAAI,WAAW,MAAM,QAAU,OAC/B,MACF,CACAA,EAAI,WAAW,MAAM,QAAU,GAE/B,MAAMO,EAAc,CAAC,kCAAkC,EACpD,OAAOL,EAAM,aAAa,IAAKvzB,GAC9B,kBAAkB6zB,GAAW7zB,CAAC,CAAC,KAAK8zB,GAAW9zB,CAAC,CAAC,WAAW,CAAC,EAC9D,KAAK,EAAE,EAEVqzB,EAAI,MAAM,UAAYriC,EAAQ,IAAK6hC,GAAQ,CACzC,MAAMkB,EAAUR,EAAM,QAAQV,CAAG,GAAK,GAChCmB,EAASJ,EAAY,QACzB,kBAAkBC,GAAWE,CAAO,CAAC,KACrC,kBAAkBF,GAAWE,CAAO,CAAC,aAC3C,EACI,MAAO;AAAA;AAAA,oBAESD,GAAWjB,CAAG,CAAC;AAAA;AAAA;AAAA,8BAGLgB,GAAWhB,CAAG,CAAC;AAAA,cAC/BmB,CAAM;AAAA;AAAA;AAAA;AAAA,KAKlB,CAAC,EAAE,KAAK,EAAE,EAGVX,EAAI,MAAM,iBAAiB,mBAAmB,EAAE,QAASY,GAAQ,CAC/DA,EAAI,iBAAiB,SAAWx6B,GAAM,CACpC,MAAMo5B,EAAMp5B,EAAE,OAAO,QAAQ,IAC7B85B,EAAM,QAAQV,CAAG,EAAIp5B,EAAE,OAAO,OAAS,IACzC,CAAC,CACH,CAAC,CACH,CAGA,SAASg6B,IAAiB,CACxB,MAAMS,EAAUb,EAAI,OAAO,MAC3BE,EAAM,WAAaW,EACnBX,EAAM,QAAUb,GAAca,EAAM,GAAIW,CAAO,EAG3CA,IAAY,SACdb,EAAI,WAAW,UACb,0HAEFA,EAAI,QAAQ,SAAW,GACvBA,EAAI,cAAc,SAAW,KAE7BA,EAAI,WAAW,UACb,sGAEFA,EAAI,QAAQ,SAAW,GACvBA,EAAI,cAAc,SAAW,IAE/BM,GAAiB,CACnB,CAGA,SAASD,GAAO/kC,EAAQ,CACtB,GAAI,CAAC4kC,GAASA,EAAM,UAAW,OAC/BA,EAAM,UAAY,GAClB,KAAM,CAAE,WAAAt3B,EAAY,QAAA22B,EAAS,SAAAuB,CAAQ,EAAKZ,EAC1CD,GAAM,KAAI,EACNa,GACFA,EAAS,CACP,OAAAxlC,EACA,WAAAsN,EACA,QAASA,IAAe,QAAU,KAAO,CAAE,GAAG22B,CAAO,CAC3D,CAAK,EAEHW,EAAQ,IACV,CAeO,SAASa,GAAuBr4B,EAAM,CAE3C,GADAy3B,GAAQ,EACJ,CAACH,EAAI,KAAM,CACb,QAAQ,KAAK,oEAAoE,EACjFt3B,EAAK,WAAW,CAAE,OAAQ,QAAQ,CAAE,EACpC,MACF,CAEA,MAAM+1B,EAAK/1B,EAAK,GACVG,EAAe41B,GAAI,UAAU,QAAU,EACvC71B,EAAaq2B,GAAiBR,CAAE,EAEtCyB,EAAQ,CACN,SAAUx3B,EAAK,SACf,SAAUA,EAAK,SACf,GAAA+1B,EACA,aAAcqB,GAAiBrB,CAAE,EACjC,WAAA71B,EACA,QAASy2B,GAAcZ,EAAI71B,CAAU,EACrC,SAAUF,EAAK,SACf,UAAW,EACf,EAGEs3B,EAAI,SAAS,YAAct3B,EAAK,UAAY,mBAC5Cs3B,EAAI,QAAQ,YAAe,KAAKn3B,CAAY,WAAWA,IAAiB,EAAI,GAAK,GAAG,GAGpFm3B,EAAI,OAAO,MAAQE,EAAM,WACzBE,GAAc,EAEdH,GAAQe,GAAM,oBAAoBhB,EAAI,IAAI,EAC1CC,GAAM,KAAI,CACZ,CAMA,SAASQ,GAAW9zB,EAAG,CACrB,OAAO,OAAOA,CAAC,EACZ,QAAQ,KAAM,OAAO,EAAE,QAAQ,KAAM,MAAM,EAAE,QAAQ,KAAM,MAAM,EACjE,QAAQ,KAAM,QAAQ,EAAE,QAAQ,KAAM,OAAO,CAClD,CACA,SAAS6zB,GAAW7zB,EAAG,CAAE,OAAO8zB,GAAW9zB,CAAC,CAAG,mDC5N/C3B,GAAA,WAA4B,CACxB,KAAM,EACN,MAAO,EACP,SAAU,EACV,QAAS,EACT,WAAY,EACZ,OAAQ,GACR,UAAW,GACX,SAAU,GACV,YAAa,GACb,OAAQ,GACR,UAAW,GACX,SAAU,GACV,YAAa,GACb,WAAY,uDCdhBi2B,GAAiB,CAEb,EAAG,IAEH,EAAG,EAEH,EAAG,EAEH,EAAG,GAEH,EAAG,GAEH,EAAG,GAEH,EAAG,mDCRPC,GAAA,KAAsB,SAAc9P,EAAKpd,EAAKmtB,EAAM,CAChD,KAAO/P,EAAI,OAASpd,GAAOod,EAAM+P,EAAO/P,EAAO,OAAOA,CAC1D,EAQA8P,GAAA,KAAsB,SAAc9P,EAAKpd,EAAKmtB,EAAM,CAChD,KAAO/P,EAAI,OAASpd,GAAOod,EAAMA,EAAM+P,EAAQ,OAAO/P,CAC1D,EASA8P,GAAA,WAA4B,SAAoB5P,EAAM8P,EAAahQ,EAAKt0B,EAAQ,CAC5E,QAAStD,EAAI,EAAGA,EAAI4nC,EAAa5nC,IAC7B83B,EAAK,SAASx0B,EAAQs0B,EAAI,WAAW53B,CAAC,CAAC,EAAGsD,IAE9C,OAAOA,CACX,sDChCA,IAAIukC,EAAYC,GAAA,EAEZt2B,EAAQ,CACR,OAAQ,IACR,OAAQ,IACR,QAAS,IAET,KAAM,KAGVu2B,GAAA,MAAuBC,EACvBD,GAAA,SAA0BE,EAC1BF,GAAA,IAAqBG,EAErB,SAASF,EAAMv4B,EAAU,CACrB,IAAIs4B,EAAS,GACbt4B,EAAS,QAAQqO,CAAO,EACxB,SAASA,EAAQnO,EAAG,CAAEw4B,EAAQJ,EAAQp4B,CAAC,CAAE,CACzC,OAAOu4B,EAAIH,CAAM,CACrB,CAOA,SAASI,EAAQ/1B,EAAG4F,EAAG,CACnB,QAAShY,KAAKgY,EAAG,CACb,IAAIowB,EAAQ,OAAOpwB,EAAEhY,CAAC,EAAM,KAAegY,EAAEhY,CAAC,IAAM,MAChD,OAAOoS,EAAEpS,CAAC,EAAM,KAAeooC,KACjCh2B,EAAEpS,CAAC,EAAIgY,EAAEhY,CAAC,EAEpB,CACI,OAAOoS,CACX,CAEA,SAAS81B,EAAIrmC,EAAG,CACZ,IAAIkmC,EAAS,GAAIM,EAAI,GACrB,QAASt3B,KAAKlP,EAAGkmC,EAAOh3B,CAAC,EAAIlP,EAAEkP,CAAC,IAAM,KAAO,OAAS,OAAOlP,EAAEkP,CAAC,EAChE,QAASN,KAAKs3B,EAAQ,CAClB,IAAI36B,EAAIoE,EAAMu2B,EAAOt3B,CAAC,CAAC,EACpBrD,GACEi7B,EAAE,KAAK,CACJ,KAAM53B,EACN,KAAMrD,EACN,KAAMy6B,EAAUz6B,CAAC,CACjC,CAAa,CAEb,CACI,OAAOi7B,CACX,CAMA,SAASJ,EAASF,EAAQ,CAEtB,OAAOA,EAAO,OAAO,SAASO,EAAM34B,EAAG,CAAE,OAAO24B,EAAO34B,EAAE,IAAK,EAAI,CAAC,CACvE,wDC3DgBm4B,GAAA,MACZJ,EAAMa,GAAA,EACNR,EAASS,GAAA,EAOb,OAAAC,GAAiB,SAAmB7oC,EAAM6T,EAAM,CAE5C,IAAIi1B,EAAaj1B,GAAQs0B,EAAO,MAAMnoC,CAAI,EACtC+oC,EAAmB,GAAKD,EAAW,OAAU,EAC7CE,EAAiBb,EAAO,SAASW,CAAU,EAC3CzpC,EAAS,IAAI,YAET0pC,EAEA,GAECC,EAAiBhpC,EAAK,OAEvB,GAEJ8iC,EAAM,IAAI,KACV5K,EAAO,IAAI,SAAS74B,CAAM,EAG9B64B,EAAK,SAAS,EAAG,CAAI,EAErBA,EAAK,SAAS,EAAG4K,EAAI,YAAW,EAAK,IAAI,EACzC5K,EAAK,SAAS,EAAG4K,EAAI,SAAQ,CAAE,EAC/B5K,EAAK,SAAS,EAAG4K,EAAI,QAAO,CAAE,EAE9B5K,EAAK,UAAU,EAAGl4B,EAAK,OAAQ,EAAI,EAGnC,IAAIipC,EAAeF,EAAkB,GACrC,OAAA7Q,EAAK,UAAU,EAAG+Q,EAAc,EAAI,EAEpC/Q,EAAK,UAAU,GAAI8Q,EAAgB,EAAI,EAGvC9Q,EAAK,QAAQ,GAAK6Q,EAAkB,EAAG,EAAI,EAE3CD,EAAW,QAAQ,SAAS/4B,EAAG3P,EAAG,CAE9B2P,EAAE,KAAK,MAAM,EAAE,EAAE,MAAM,EAAG,CAAC,EAAE,QAAQ,SAASzC,EAAG+uB,EAAG,CAChDnE,EAAK,QAAQ,GAAK93B,EAAI,GAAKi8B,EAAG/uB,EAAE,WAAW,CAAC,CAAC,CACzD,CAAS,EAED4qB,EAAK,QAAQ,GAAK93B,EAAI,GAAK,GAAI2P,EAAE,KAAK,WAAW,CAAC,CAAC,EAEnDmoB,EAAK,QAAQ,GAAK93B,EAAI,GAAK,GAAI2P,EAAE,IAAI,EACjCA,EAAE,MAAQ,KAAKmoB,EAAK,QAAQ,GAAK93B,EAAI,GAAK,GAAI,CAAC,CAC3D,CAAK,EAED,OAAS2oC,EAAkB,GAE3B/oC,EAAK,QAAQ,SAAS0I,EAAKw6B,EAAK,CAE5BhL,EAAK,SAAS,OAAQ,EAAE,EACxB,SACA4Q,EAAW,QAAQ,SAAS,EAAG,CAC3B,IAAII,EAAMxgC,EAAI,EAAE,IAAI,EAGpB,QAFIwgC,IAAQ,MAAQ,OAAOA,EAAQ,OAAaA,EAAM,IAE9C,EAAE,KAAI,CAEV,IAAK,IACDhR,EAAK,SAAS,OAAQgR,EAAM,GAAK,EAAE,EACnC,SACA,MAGJ,IAAK,IACD,OAASpB,EAAI,WAAW5P,EAAM,EAC1B4P,EAAI,KAAKoB,EAAI,SAAQ,EAAI,EAAG,GAAG,EAAG,MAAM,EAC5C,MAGJ,IAAK,IACD,OAASpB,EAAI,WAAW5P,EAAM,EAAE,KAC5B4P,EAAI,KAAKoB,EAAI,WAAY,EAAE,KAAM,GAAG,EAAE,OAAO,EAAG,EAAE,EAClD,MAAM,EACV,MAGJ,IAAK,IACD,OAASpB,EAAI,WAAW5P,EAAM,EAAE,KAC5B4P,EAAI,KAAKoB,EAAI,SAAQ,EAAI,EAAE,KAAM,GAAG,EAAG,MAAM,EACjD,MAEJ,QACI,MAAM,IAAI,MAAM,oBAAoB,CACxD,CACA,CAAS,CACT,CAAK,EAGDhR,EAAK,SAAS,OAAQ,EAAI,EAEnBA,CACX,2CCvGAiR,GAAA,UAA2BjB,GAAA,+CCA3BkB,GAAiB,kMCAjB3jB,GAAA,QAAyB,SAAuBA,EAAQ7N,EAAI,CACxD,OAAIA,EAAG,CAAC,EAAI6N,EAAO,OAAMA,EAAO,KAAO7N,EAAG,CAAC,GACvCA,EAAG,CAAC,EAAI6N,EAAO,OAAMA,EAAO,KAAO7N,EAAG,CAAC,GACvCA,EAAG,CAAC,EAAI6N,EAAO,OAAMA,EAAO,KAAO7N,EAAG,CAAC,GACvCA,EAAG,CAAC,EAAI6N,EAAO,OAAMA,EAAO,KAAO7N,EAAG,CAAC,GACpC6N,CACX,EAEAA,GAAA,cAA+B,SAAuBA,EAAQyC,EAAK,CAC/D,OAAIA,EAAI,KAAOzC,EAAO,OAAMA,EAAO,KAAOyC,EAAI,MAC1CA,EAAI,KAAOzC,EAAO,OAAMA,EAAO,KAAOyC,EAAI,MAC1CA,EAAI,KAAOzC,EAAO,OAAMA,EAAO,KAAOyC,EAAI,MAC1CA,EAAI,KAAOzC,EAAO,OAAMA,EAAO,KAAOyC,EAAI,MACvCzC,CACX,EAEAA,GAAA,MAAuB,UAAW,CAC9B,MAAO,CACH,KAAM,OAAO,UACb,KAAM,OAAO,UACb,KAAM,CAAC,OAAO,UACd,KAAM,CAAC,OAAO,UAEtB,sDCvBA,IAAI7T,EAAQs2B,GAAA,EAAmB,QAE/BC,GAAA,QAAyBxU,EACzBwU,GAAA,IAAqBG,EAErB,SAAS3U,EAAQ9jB,EAAU,CACvB,IAAIs4B,EAAS,GACbt4B,EAAS,QAAQqO,CAAO,EACxB,SAASA,EAAQnO,EAAG,CAAEw4B,EAAQJ,EAAQp4B,EAAE,UAAU,CAAE,CACpD,OAAOu4B,EAAIH,CAAM,CACrB,CAEA,SAASI,EAAQ/1B,EAAG4F,EAAG,CACnB,QAAS,KAAKA,EAAK5F,EAAE,CAAC,EAAI4F,EAAE,CAAC,EAC7B,OAAO5F,CACX,CAEA,SAAS81B,EAAIrmC,EAAG,CACZ,IAAIkmC,EAAS,GAAIM,EAAI,GACrB,QAASt3B,KAAKlP,EAAGkmC,EAAOh3B,CAAC,EAAI,OAAOlP,EAAEkP,CAAC,EACvC,QAASN,KAAKs3B,EACVM,EAAE,KAAK,CACH,KAAM53B,EACN,KAAMe,EAAMu2B,EAAOt3B,CAAC,CAAC,CACjC,CAAS,EAEL,OAAO43B,CACX,2DC3BA,IAAIvgB,EAAMggB,GAAA,EAEV,OAAAlH,GAAA,MAAuB,SAAqBqI,EAAa5jB,EAAQ6jB,EAASC,EAAS,CAE/E,IAAIC,EAAgB,GAChBC,EAAa,IACbC,EAAO,EACPC,EAAO,EAEXN,EAAY,QAAQ,SAAoBpvB,EAAQ7Z,EAAG,CAI/CkpC,EAAQ,SAASI,EAAMtpC,CAAC,EACxBkpC,EAAQ,SAASI,EAAO,EAAG,EAAE,EAI7BJ,EAAQ,SAASI,EAAO,EAAG,EAAG,EAAI,EAClCJ,EAAQ,WAAWI,EAAO,GAAIzvB,EAAO,CAAC,EAAG,EAAI,EAC7CqvB,EAAQ,WAAWI,EAAO,GAAIzvB,EAAO,CAAC,EAAG,EAAI,EAG7CsvB,EAAQ,SAASI,EAAMF,EAAa,CAAC,EACrCF,EAAQ,SAASI,EAAO,EAAG,EAAE,EAE7BA,GAAQ,EACRD,GAAQF,EACRC,GAAcD,CACtB,CAAK,CACL,EAEAxI,GAAA,OAAwB,SAASqI,EAAa,CAC1C,OAAOA,EAAY,OAAO,SAAS5jB,EAAQxL,EAAQ,CAC/C,OAAOiO,EAAI,QAAQzC,EAAQxL,CAAM,CACzC,EAAOiO,EAAI,OAAO,CAClB,EAEA8Y,GAAA,MAAuB,SAAe4I,EAAYC,EAAM,CACpD,OAAOD,EAAW,MACtB,EAEA5I,GAAA,UAA2B,SAASqI,EAAa,CAC7C,OAAOA,EAAY,OAAS,CAChC,EAEArI,GAAA,UAA2B,SAASqI,EAAa,CAC7C,OAAOA,EAAY,OAAS,EAChC,qDChDA,IAAInhB,EAAMggB,GAAA,EACNt2B,EAAQ+2B,GAAA,EAEZ5c,GAAA,MAAuB,SAAqB6d,EAAYnkB,EAAQ6jB,EAASC,EAASM,EAAM,CAEpF,IAAIH,EAAO,EACPC,EAAO,EACPG,EAAY,IAEhBF,EAAW,QAAQG,CAAa,EAEhC,SAASA,EAAcV,EAAajpC,EAAG,CAEnC,IAAI4pC,EAAYC,EAAWZ,CAAW,EAClCa,EAAUC,EAAM,CAACd,CAAW,EAAGQ,CAAI,EACnCL,EAAiBQ,EAAU,OAAS,GAAM,IAAME,EAAU,GAAK,EAE/DE,EAAgBJ,EAAU,OAAO,SAASvkB,EAAQnY,EAAG,CACrD,OAAO4a,EAAI,QAAQzC,EAAQnY,CAAC,CACxC,EAAW4a,EAAI,OAAO,EAGdqhB,EAAQ,SAASI,EAAMG,EAAY,CAAC,EACpCP,EAAQ,SAASI,EAAO,EAAGH,EAAgB,CAAC,EAE5CG,GAAQ,EACRG,GAAaN,EAAgB,EAE7BF,EAAQ,SAASI,EAAMtpC,EAAI,CAAC,EAC5BkpC,EAAQ,SAASI,EAAO,EAAGF,EAAgB,CAAC,EAC5CF,EAAQ,SAASI,EAAO,EAAGG,EAAM,EAAI,EACrCP,EAAQ,WAAWI,EAAO,GAAIU,EAAc,KAAM,EAAI,EACtDd,EAAQ,WAAWI,EAAO,GAAIU,EAAc,KAAM,EAAI,EACtDd,EAAQ,WAAWI,EAAO,GAAIU,EAAc,KAAM,EAAI,EACtDd,EAAQ,WAAWI,EAAO,GAAIU,EAAc,KAAM,EAAI,EACtDd,EAAQ,SAASI,EAAO,GAAIQ,EAAS,EAAI,EACzCZ,EAAQ,SAASI,EAAO,GAAIM,EAAU,OAAQ,EAAI,EAClDV,EAAQ,SAASI,EAAO,GAAI,EAAG,EAAI,EAUnC,QARIW,EAAYhB,EAAY,OAAO,SAAUrb,EAAK/T,EAAQ,CACtD,OAAI,MAAM,QAAQA,EAAO,CAAC,EAAE,CAAC,CAAC,EAC1B+T,EAAMA,EAAI,OAAO/T,CAAM,EAEvB+T,EAAI,KAAK/T,CAAM,EAEZ+T,CACnB,EAAW,EAAE,EACI7c,EAAI,EAAGA,EAAI+4B,EAAS/4B,IACzBm4B,EAAQ,SACJI,EAAO,GAAMv4B,EAAI,EACjBk5B,EAAU,OAAO,SAAU73B,EAAG4F,EAAGoB,EAAK,CAClC,OAAOA,EAAMrI,EAAIqB,EAAI4F,EAAE,OAAS5F,CACpD,EAAmB,CAAC,EACJ,IAIRw3B,EAAU,QAAQ,SAAmB/vB,EAAQ7Z,EAAG,CAC5CkpC,EAAQ,WAAWI,EAAO,GAAMtpC,EAAI,IAAO8pC,EAAU,GAAK,EAAGjwB,EAAO,CAAC,EAAG,EAAI,EAC5EqvB,EAAQ,WAAWI,EAAO,GAAMtpC,EAAI,IAAO8pC,EAAU,GAAK,EAAI,EAAGjwB,EAAO,CAAC,EAAG,EAAI,CAC5F,CAAS,EAEDyvB,GAAQF,EAAgB,CAChC,CACA,EAEAzd,GAAA,UAA2B,SAAS6d,EAAY,CAC5C,OAAQA,EAAW,OAAS,GAEvBK,EAAWL,CAAU,EAAE,OAAS,EACzC,EAEA7d,GAAA,UAA2B,SAAS6d,EAAY,CAC5C,OAAOA,EAAW,OAAS,CAC/B,EAEA7d,GAAA,OAAwB,SAASsd,EAAa,CAC1C,OAAOY,EAAWZ,CAAW,EAAE,OAAO,SAAS5jB,EAAQnY,EAAG,CACtD,OAAO4a,EAAI,QAAQzC,EAAQnY,CAAC,CACpC,EAAO4a,EAAI,OAAO,CAClB,EAEA,SAASiiB,EAAMP,EAAYC,EAAM,CAC7B,IAAIS,EAAK,EACT,OAAIT,IAASj4B,EAAM,WAAW,SAAWi4B,IAASj4B,EAAM,WAAW,YAC/D04B,EAAKV,EAAW,OAAO,SAAUU,EAAIrwB,EAAQ,CACzC,OAAAqwB,GAAMrwB,EAAO,OACT,MAAM,QAAQA,EAAO,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,IAC7BqwB,GAAMrwB,EAAO,OAAO,SAAUqwB,EAAIC,EAAO,CACrC,OAAOD,EAAKC,EAAM,OAAS,CAC/C,EAAmB,CAAC,GAEDD,CACnB,EAAW,CAAC,GAEDA,CACX,CAEAve,GAAA,MAAuBoe,EAQvB,SAASF,EAAWhwB,EAAQqe,EAAG,CAE3B,OADIA,IAAM,SAAWA,EAAI,IACrB,OAAOre,EAAO,CAAC,EAAE,CAAC,GAAK,SAChBA,EAAO,OAAO,SAASyuB,EAAMp7B,EAAG,CACnC,OAAOo7B,EAAK,OAAOuB,EAAW38B,CAAC,CAAC,CAC5C,EAAWgrB,CAAC,EAEGre,CAEf,wDCnHA,IAAIrI,EAAQs2B,GAAA,EACRiB,EAAMR,GAAA,EACNS,EAAMR,GAAA,EACA4B,GAAA,EACMC,GAAA,MAEZC,EAAcC,GAAA,EACdC,EAAaC,GAAA,EAEbC,EAAU,CACV,EAAGJ,EACH,EAAGE,EACH,EAAGA,GAKPG,GAAiBC,EAGjB,SAASA,EAAMxmC,EAAMymC,EAAerB,EAAYrnC,EAAU,CAEtD,IAAIsnC,EAAOj4B,EAAM,WAAWq5B,CAAa,EACrCC,EAASJ,EAAQjB,CAAI,EACrBM,EAAQe,EAAO,MAAMtB,EAAYC,CAAI,EACrCsB,EAAY,KAAOhB,EAAQP,EAAW,QAAU,EAAIsB,EAAO,UAAUtB,CAAU,EAC/EwB,EAAY,IAAMF,EAAO,UAAUtB,CAAU,EAC7CyB,EAAY,IAAI,YAAYF,CAAS,EACrC7B,EAAU,IAAI,SAAS+B,CAAS,EAChCC,EAAY,IAAI,YAAYF,CAAS,EACrC7B,EAAU,IAAI,SAAS+B,CAAS,EAChC7lB,EAASylB,EAAO,OAAOtB,CAAU,EAErC2B,EAAYjC,EAASO,CAAI,EACzB0B,EAAYhC,EAASM,CAAI,EACzB2B,EAAY/lB,EAAQ6jB,CAAO,EAC3BkC,EAAY/lB,EAAQ8jB,CAAO,EAE3B2B,EAAO,MAAMtB,EAAYnkB,EACrB,IAAI,SAAS4lB,EAAW,GAAG,EAC3B,IAAI,SAASC,EAAW,GAAG,EAC3BzB,CAAI,EAERP,EAAQ,SAAS,GAAI6B,EAAY,CAAC,EAClC5B,EAAQ,SAAS,GAAK,GAAKK,EAAW,OAAS,CAAC,EAEhD,IAAI6B,EAAStC,EAAI,UAAU3kC,CAAI,EAE/BjC,EAAS,KAAM,CACX,IAAK+mC,EACL,IAAKC,EACL,IAAKkC,EACL,IAAKrC,CACb,CAAK,CACL,CAEA,SAASmC,EAAYrT,EAAM2R,EAAM,CAC7B3R,EAAK,SAAS,EAAG,IAAI,EACrBA,EAAK,SAAS,GAAI,IAAM,EAAI,EAC5BA,EAAK,SAAS,GAAI2R,EAAM,EAAI,CAChC,CAEA,SAAS2B,EAAY/lB,EAAQyS,EAAM,CAC/BA,EAAK,WAAW,GAAIzS,EAAO,KAAM,EAAI,EACrCyS,EAAK,WAAW,GAAIzS,EAAO,KAAM,EAAI,EACrCyS,EAAK,WAAW,GAAIzS,EAAO,KAAM,EAAI,EACrCyS,EAAK,WAAW,GAAIzS,EAAO,KAAM,EAAI,CACzC,2DCnEAkO,GAAA,MAAuB+X,EAAS,QAAS,OAAO,EAChD/X,GAAA,KAAsB+X,EAAS,aAAc,UAAU,EACvD/X,GAAA,QAAyB+X,EAAS,UAAW,SAAS,EAEtD,SAASA,EAASlpC,EAAMqnC,EAAM,CAC1B,OAAO,SAAS8B,EAAI,CAChB,IAAIC,EAASD,EAAG,SAAS,OAAOE,EAAOrpC,CAAI,CAAC,EAC5C,MAAO,CACH,WAAaqnC,IAAS,WAAaA,IAAS,WAAc,CAAC+B,EAAO,IAAI3B,CAAU,CAAC,EAAI2B,EAAO,IAAI3B,CAAU,EAC1G,WAAY2B,EAAO,IAAIE,CAAS,EAChC,KAAMjC,EAElB,CACA,CAEA,SAASI,EAAWz8B,EAAG,CACnB,OAAIA,EAAE,SAAS,YAAY,CAAC,IAAM,QAC9BA,EAAE,SAAS,YAAY,CAAC,EAAE,CAAC,IAAM,QACjCA,EAAE,SAAS,YAAY,CAAC,EAAE,CAAC,EAAE,CAAC,IAAM,OAC7BA,EAAE,SAAS,YAAY,CAAC,EAExBA,EAAE,SAAS,WAE1B,CAEA,SAASs+B,EAAUt+B,EAAG,CAClB,OAAOA,EAAE,UACb,CAEA,SAASq+B,EAAOr+B,EAAG,CACf,OAAO,SAASuC,EAAG,CAAE,OAAOA,EAAE,SAAS,OAASvC,CAAE,CACtD,wDC/BA,IAAIw9B,EAAQ9C,GAAA,EACRvU,EAAUgV,GAAA,EACVS,EAAMR,GAAA,EACNmD,EAAQvB,GAAA,EAEZ,OAAAwB,GAAiB,SAASL,EAAIhmC,EAAS,CAEnC,IAAIqmC,EAAM,IAAID,EACV5tB,EAAS6tB,EAAI,OAAOrmC,GAAWA,EAAQ,OAASA,EAAQ,OAAS,QAAQ,EAE7E,CAACguB,EAAQ,MAAMgY,CAAE,EAAGhY,EAAQ,KAAKgY,CAAE,EAAGhY,EAAQ,QAAQgY,CAAE,CAAC,EACpD,QAAQ,SAASrT,EAAG,CACjBA,EAAE,WAAW,QAAUA,EAAE,WAAW,CAAC,EAAE,QACvC0S,EAEI1S,EAAE,WAEFA,EAAE,KAEFA,EAAE,WACF,SAAS3tB,EAAKshC,EAAO,CACjB,IAAIC,EAAWvmC,GAAWA,EAAQ,MAAM2yB,EAAE,KAAK,YAAW,CAAE,EAAI3yB,EAAQ,MAAM2yB,EAAE,KAAK,YAAW,CAAE,EAAIA,EAAE,KACxGna,EAAO,KAAK+tB,EAAW,OAAQD,EAAM,IAAI,OAAQ,CAAE,OAAQ,GAAM,EACjE9tB,EAAO,KAAK+tB,EAAW,OAAQD,EAAM,IAAI,OAAQ,CAAE,OAAQ,GAAM,EACjE9tB,EAAO,KAAK+tB,EAAW,OAAQD,EAAM,IAAI,OAAQ,CAAE,OAAQ,GAAM,EACjE9tB,EAAO,KAAK+tB,EAAW,OAAQ9C,CAAG,CACtD,CAAiB,CAEjB,CAAK,EAED,IAAI+C,EAAkB,CAAE,YAAY,OAAO,EAE3C,OAAK,QAAQ,UACXA,EAAgB,KAAO,cAGlBH,EAAI,SAASG,CAAe,CACvC,kDCrCA,IAAIH,EAAM9D,GAAA,EAEV,OAAAkE,GAAiB,SAAST,EAAIhmC,EAAS,CACnC,IAAI6wB,EAAUwV,EAAIL,EAAIhmC,CAAO,EAC7B,SAAS,KAAO,+BAAiC6wB,CACrD,2CCLA6V,GAAA,SAA0BnE,GAAA,EAC1BmE,GAAA,MAAuB1D,GAAA,EACvB0D,GAAA,IAAqBzD,GAAA,kBCuBrB,MAAM0D,GAAa,YACbC,GAAa,YAMZ,eAAeC,GAAoB,CACxC,SAAA38B,EACA,OAAA48B,EACA,OAAAC,EACA,aAAAC,EAAe,QACjB,EAAG,CACD,GAAI,CAAC,MAAM,QAAQ98B,CAAQ,GAAKA,EAAS,SAAW,EAClD,MAAM,IAAI,MAAM,uBAAuB,EAIzC,MAAM8jB,EAAUiZ,GAAoB/8B,EAAU48B,CAAM,EAGpD,OAAQC,EAAM,CACZ,IAAK,UACH,OAAOG,GACL,IAAI,KAAK,CAAC,KAAK,UAAUlZ,EAAS,KAAM,CAAC,CAAC,EAAG,CAAE,KAAM,sBAAsB,CAAE,EAC7E,GAAGgZ,CAAY,UACvB,EAEI,IAAK,MACH,OAAOE,GACL,IAAI,KAAK,CAACC,GAASj9B,EAAU48B,CAAM,CAAC,EAAG,CAAE,KAAM,uCAAwC,EACvF,GAAGE,CAAY,MACvB,EAEI,IAAK,MACH,OAAOI,GAASpZ,EAASgZ,CAAY,EAEvC,QACE,MAAM,IAAI,MAAM,0BAA0BD,CAAM,EAAE,CACxD,CACA,CAWA,SAASE,GAAoB/8B,EAAU48B,EAAQ,CAC7C,MAAMO,EAAM,IAAIC,GACVthB,EAAM,CAAE,KAAM,oBAAqB,SAAU,EAAE,EAErD,UAAW5b,KAAKF,EAAU,CACxB,GAAI,CAACE,EAAE,cAAe,SAEtB,MAAMm9B,EAAcF,EAAI,oBAAoBj9B,EAAE,YAAW,EAAI,CAC3D,eAAgBw8B,GAChB,kBAAmBD,EACzB,CAAK,EAEK/F,EAAc4G,GAAuBp9B,EAAE,cAAa,CAAE,EACtDq9B,EAAW,GACjB,SAAW,CAACjV,EAAK/F,CAAM,IAAK,OAAO,QAAQqa,GAAU,EAAE,EAChDra,GACD,OAAO,UAAU,eAAe,KAAKmU,EAAapO,CAAG,IACvDiV,EAAShb,CAAM,EAAImU,EAAYpO,CAAG,GAItCxM,EAAI,SAAS,KAAK,CAAE,KAAM,UAAW,SAAUuhB,EAAa,WAAYE,EAAU,CACpF,CACA,OAAOzhB,CACT,CAEA,SAASwhB,GAAuBx+B,EAAO,CACrC,MAAMgd,EAAM,GACZ,SAAW,CAAC9Z,EAAGb,CAAC,IAAK,OAAO,QAAQrC,GAAS,EAAE,EACzCkD,IAAM,aACV8Z,EAAI9Z,CAAC,EAAIb,GAEX,OAAO2a,CACT,CAMA,SAASmhB,GAASj9B,EAAU48B,EAAQ,CAIlC,MAAMY,EAASx9B,EACZ,OAAQE,GAAMA,EAAE,YAAW,CAAE,EAC7B,IAAKA,GAAM,CACV,MAAMuO,EAAQvO,EAAE,MAAK,EACfw2B,EAAc4G,GAAuBp9B,EAAE,cAAa,CAAE,EACtDq9B,EAAW,GACjB,SAAW,CAACjV,EAAK/F,CAAM,IAAK,OAAO,QAAQqa,GAAU,EAAE,EAChDra,GACD,OAAO,UAAU,eAAe,KAAKmU,EAAapO,CAAG,IACvDiV,EAAShb,CAAM,EAAImU,EAAYpO,CAAG,GAGtC7Z,EAAM,cAAc8uB,EAAuB,EAAI,EAE/C,MAAME,EAAW,OAAO,OAAOb,GAAU,EAAE,EAAE,KAC1Cz7B,GAAMA,GAAKo8B,EAASp8B,CAAC,GAAK,MAAQo8B,EAASp8B,CAAC,IAAM,EAC3D,EACM,OAAIs8B,GAAUhvB,EAAM,IAAI,OAAQ,OAAO8uB,EAASE,CAAQ,CAAC,CAAC,EACnDhvB,CACT,CAAC,EAEH,OAAO,IAAIivB,GAAU,CAAE,cAAe,EAAK,CAAE,EAAE,cAAcF,EAAQ,CACnE,eAAgBd,GAChB,kBAAmBD,EACvB,CAAG,CACH,CAYA,eAAeS,GAASpZ,EAASgZ,EAAc,CAC7C,MAAMa,EAAYC,GAAsB9Z,CAAO,EAK/C,OAAO,IAAI,QAAQ,CAACzzB,EAASgK,IAAW,CACtC,GAAI,CACFwjC,YAAkBF,EAAW,CAC3B,OAAQb,EACR,WAAY,OACZ,YAAa,UACb,MAAO,CACL,MAAU,GAAGA,CAAY,SACzB,QAAU,GAAGA,CAAY,WACzB,SAAU,GAAGA,CAAY,OACnC,CACA,CAAO,EACDzsC,EAAO,CACT,OAASyK,EAAK,CACZT,EAAOS,CAAG,CACZ,CACF,CAAC,CACH,CAMA,SAAS8iC,GAAsB9Z,EAAS,CAEtC,MAAMga,EAAU,IAAI,IACpB,UAAW59B,KAAK4jB,EAAQ,SACtB,UAAW9hB,KAAK,OAAO,KAAK9B,EAAE,YAAc,EAAE,EAAG49B,EAAQ,IAAI97B,CAAC,EAIhE,MAAM+7B,EAAO,IAAI,IACXh9B,EAAQ,GACd,UAAWiB,KAAK87B,EAAS,CACvB,IAAIE,EAAO,OAAOh8B,CAAC,EAAE,QAAQ,kBAAmB,GAAG,EAAE,MAAM,EAAG,EAAE,GAAK,QACjEi8B,EAAYD,EACZztC,EAAI,EACR,KAAOwtC,EAAK,IAAIE,CAAS,GAAG,CAC1B,MAAMC,EAAS,OAAO3tC,GAAG,EACzB0tC,EAAYD,EAAK,MAAM,EAAG,KAAK,IAAI,EAAG,GAAKE,EAAO,MAAM,CAAC,EAAIA,CAC/D,CACAH,EAAK,IAAIE,CAAS,EAClBl9B,EAAMiB,CAAC,EAAIi8B,CACb,CAEA,MAAO,CACL,KAAM,oBACN,SAAUna,EAAQ,SAAS,IAAK5jB,GAAM,CACpC,MAAMi+B,EAAW,GACjB,SAAW,CAACn8B,EAAGb,CAAC,IAAK,OAAO,QAAQjB,EAAE,YAAc,EAAE,EACpDi+B,EAASp9B,EAAMiB,CAAC,CAAC,EAAIb,EAEvB,MAAO,CAAE,KAAM,UAAW,SAAUjB,EAAE,SAAU,WAAYi+B,CAAQ,CACtE,CAAC,CACL,CACA,CAMA,SAASnB,GAAav6B,EAAM/C,EAAU,CACpC,MAAMgD,EAAM,IAAI,gBAAgBD,CAAI,EAC9BE,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAWjD,EACb,SAAS,KAAK,YAAYiD,CAAC,EAC3BA,EAAE,MAAK,EACP,SAAS,KAAK,YAAYA,CAAC,EAC3B,WAAW,IAAM,IAAI,gBAAgBD,CAAG,EAAG,GAAI,CACjD,CCrNA,MAAMq0B,EAAM,GACZ,IAAIC,GAAQ,KACRC,GAAQ,KAEZ,SAASC,IAAW,CACdH,EAAI,OACRA,EAAI,KAAW,SAAS,eAAe,gBAAgB,EACvDA,EAAI,QAAW,SAAS,eAAe,oBAAoB,EAC3DA,EAAI,SAAW,SAAS,eAAe,qBAAqB,EAC5DA,EAAI,MAAW,SAAS,eAAe,yBAAyB,EAChEA,EAAI,QAAW,SAAS,eAAe,wBAAwB,EAC/DA,EAAI,MAAW,SAAS,eAAe,eAAe,EACtDA,EAAI,UAAY,MAAM,KAAK,SAAS,iBAAiB,iCAAiC,CAAC,EAGlFA,EAAI,KAAK,QAAQ,QACpBA,EAAI,KAAK,QAAQ,MAAQ,IACzBA,EAAI,UAAU,QAAS/3B,GAAMA,EAAE,iBAAiB,SAAUo/B,EAAc,CAAC,EACzErH,EAAI,MAAM,iBAAiB,QAASsH,EAAa,GAErD,CAMA,SAASC,GAAgBC,EAAK,CAC5B,MAAMziB,EAAM,GACZ,UAAW5b,KAAKq+B,EAAI,gBAAkB,GAAIziB,EAAI,KAAK0iB,GAAct+B,EAAG,SAAS,CAAC,EAC9E,UAAWA,KAAKq+B,EAAI,cAAkB,GAAIziB,EAAI,KAAK0iB,GAAct+B,EAAG,OAAO,CAAC,EAC5E,SAAW,CAAC6e,EAAYZ,CAAG,IAAK,OAAO,QAAQogB,EAAI,cAAgB,EAAE,EACnE,UAAWr+B,KAAKie,EAAKrC,EAAI,KAAK0iB,GAAct+B,EAAG6e,CAAU,CAAC,EAE5D,OAAOjD,CACT,CAMA,SAAS0iB,GAAclvB,EAASmvB,EAAa,CAC3C,MAAMhwB,EAAQa,EAAQ,MAAK,EAC3B,OAAAb,EAAM,IAAI,UAAWgwB,CAAW,EACzBhwB,CACT,CAGA,SAASiwB,GAAmB1+B,EAAU,CACpC,MAAM2+B,EAAO,IAAI,IAAI,CAAC,WAAY,YAAY,CAAC,EACzC7H,EAAO,IAAI,IACjB,UAAW52B,KAAKF,EACd,UAAWgC,KAAK,OAAO,KAAK9B,EAAE,cAAa,GAAM,EAAE,EAC7Cy+B,EAAK,IAAI38B,CAAC,GACT80B,EAAK,IAAI90B,CAAC,GAAG80B,EAAK,IAAI90B,EAAG,EAAI,EAItC80B,EAAK,OAAO,SAAS,EACrB,MAAM5V,EAAO,MAAM,KAAK4V,EAAK,KAAI,CAAE,EACnC,OAAA5V,EAAK,KAAK,SAAS,EACZA,CACT,CAMA,SAASmW,IAAoB,CAC3B,MAAM8F,EAAMyB,GAAa,EACzB7H,EAAI,MAAM,UAAYE,GAAM,KAAK,IAAK3O,GAAQ,CAC5C,MAAMmP,EAAUR,GAAM,OAAO3O,CAAG,GAAKA,EAE/BuW,EADU1B,IAAQ,OAAS1F,EAAQ,OAAS,GAE9C;AAAA,aACKD,GAAWC,EAAQ,MAAM,CAAC;AAAA;AAAA,iBAG/B,GACJ,MAAO;AAAA;AAAA,oBAESD,GAAWlP,CAAG,CAAC;AAAA;AAAA;AAAA,6BAGNiP,GAAWjP,CAAG,CAAC;AAAA,0BAClBiP,GAAWE,CAAO,CAAC;AAAA,YACjCoH,CAAI;AAAA;AAAA;AAAA,KAId,CAAC,EAAE,KAAK,EAAE,EACV9H,EAAI,MAAM,iBAAiB,sBAAsB,EAAE,QAAS7Q,GAAQ,CAClEA,EAAI,iBAAiB,QAAU/oB,GAAM,CACnC,MAAMmrB,EAAMnrB,EAAE,OAAO,QAAQ,IAC7B85B,GAAM,OAAO3O,CAAG,EAAInrB,EAAE,OAAO,MAEzByhC,GAAa,IAAO,OAAOvH,GAAiB,CAClD,CAAC,CACH,CAAC,CACH,CAEA,SAAS+G,IAAiB,CACxB,MAAMjB,EAAMyB,GAAa,EACzB7H,EAAI,QAAQ,UAAY,CACtB,QAAS,gEACT,IAAS,qPAIT,IAAS,oHAEb,EAAIoG,CAAG,EACL9F,GAAiB,CACnB,CAEA,SAASuH,IAAgB,CACvB,OAAO7H,EAAI,UAAU,KAAM/3B,GAAMA,EAAE,OAAO,GAAG,OAAS,SACxD,CAMA,eAAeq/B,IAAgB,CAC7B,MAAMxB,EAAS+B,GAAa,EACtB9B,GAAgB/F,EAAI,SAAS,OAAS,UAAU,QAAQ,oBAAqB,GAAG,EAEtFA,EAAI,MAAM,SAAW,GACrB,GAAI,CACF,MAAM4F,GAAoB,CACxB,SAAU1F,GAAM,SAChB,OAAQA,GAAM,OACd,OAAA4F,EACA,aAAAC,CACN,CAAK,EACD9F,GAAM,KAAI,CACZ,OAASl8B,EAAK,CACZ,QAAQ,MAAM,sBAAuBA,CAAG,EACxC,MAAM,kBAAoBA,EAAI,OAAO,CACvC,QAAC,CACCi8B,EAAI,MAAM,SAAW,EACvB,CACF,CAMO,SAAS+H,GAAmBP,EAAK,CAEtC,GADArH,GAAQ,EACJ,CAACH,EAAI,KAAM,CACb,QAAQ,KAAK,oCAAoC,EACjD,MACF,CAEA,MAAM/2B,EAAWs+B,GAAgBC,CAAG,EACpC,GAAIv+B,EAAS,SAAW,EAAG,CACzB,MAAM,qCAAqC,EAC3C,MACF,CACA,MAAMkhB,EAAOwd,GAAmB1+B,CAAQ,EAClC48B,EAAS,OAAO,YAAY1b,EAAK,IAAKlf,GAAM,CAACA,EAAGA,CAAC,CAAC,CAAC,EAEzDi1B,GAAQ,CAAE,SAAAj3B,EAAU,KAAAkhB,EAAM,OAAA0b,CAAM,EAChC7F,EAAI,QAAQ,YACV,GAAG/2B,EAAS,MAAM,WAAWA,EAAS,SAAW,EAAI,GAAK,GAAG,qBACzCu+B,EAAI,OAAS,SAAW,SAAW,MAAM,GAC/DxH,EAAI,SAAS,MAASwH,EAAI,OAAS,SAAW,kBAAoB,gBAGlE,MAAMQ,EAAM,SAAS,eAAe,wBAAwB,EACxDA,IAAKA,EAAI,QAAU,IACvBX,GAAc,EAEdpH,GAAQe,GAAM,oBAAoBhB,EAAI,IAAI,EAC1CC,GAAM,KAAI,CACZ,CAMA,SAASQ,GAAW9zB,EAAG,CACrB,OAAO,OAAOA,CAAC,EACZ,QAAQ,KAAM,OAAO,EAAE,QAAQ,KAAM,MAAM,EAAE,QAAQ,KAAM,MAAM,EACjE,QAAQ,KAAM,QAAQ,EAAE,QAAQ,KAAM,OAAO,CAClD,CACA,SAAS6zB,GAAW7zB,EAAG,CAAE,OAAO8zB,GAAW9zB,CAAC,CAAG,CCvI/C,IAAIs7B,GAAa,KACjB,eAAeC,IAAS,CACtB,GAAI,CAACD,GAAY,CACf,MAAME,EAAM,aAAM,OAAO,qBAAO,OAAAl+B,KAAA,OAChCg+B,GAAaE,EAAI,SAAWA,CAC9B,CACA,OAAOF,EACT,CAiCA,IAAInL,EAAU,KACVsL,GAAW,KAGXlL,GAAe,KACfmL,GAAc,KAIlB,MAAMC,GAAgB,OAAO,OAAW,KAAe,OAAO,cAAiB,KACzEC,GAAkB,CAAC,EAAED,IAAgBA,GAAa,OAAS,UAKjE,IAAIE,EAAcD,GAAkB,eAAiB,cAiBrD,SAASE,IAAgC,CACvC,MAAM/P,EAAW,OAAO,OAAW,IAAe,OAAO,eAAiB,KAC1E,GAAI,CAACA,GAAW,OAAOA,GAAY,SAAU,MAAO,GACpD,MAAMx/B,EAAKw/B,EAAQ,YACnB,GAAIx/B,GAAO,MAA4B,OAAOA,CAAE,EAAE,OAAS,EAAG,MAAO,GAGrE,QAAQ,KAAK,kEAAkE,EAC/E,MAAMwvC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,GAAK,sBACbA,EAAQ,aAAa,OAAQ,aAAa,EAC1CA,EAAQ,aAAa,aAAc,MAAM,EACzCA,EAAQ,MAAM,QACZ,8IAEF,MAAMpnC,EAAOo3B,EAAQ,WAAaA,EAAQ,UAAY,MACtD,OAAAgQ,EAAQ,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,UASZjI,EAAWn/B,CAAI,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAaxB,SAAS,KAAK,YAAYonC,CAAO,EACjCA,EAAQ,cAAc,yBAAyB,GAAG,iBAAiB,QAAS,IAAM,CAChF,OAAO,SAAS,KAAO,2BACzB,CAAC,EACM,EACT,CAEA,eAAeC,IAAU,CAIvB,GAHA,QAAQ,IAAI,uBAAuB,EAG/BF,GAA6B,EAAI,OAGrC,MAAMtT,GAAQ,CACZ,cAAe,eACf,iBAAkB,qBAClB,eAAgB,EACpB,CAAG,EAID,MAAMyT,EAAe,aAAa,QAAQ,iBAAiB,GAAK,OAEhE9L,EAAU,IAAIrb,GAAQ,MAAO,CAC3B,OAAQ,CAAC,KAAM,GAAG,EAClB,KAAM,EACN,QAASmnB,CACb,CAAG,EAGDR,GAAW,IAAI3W,GAASqL,EAAQ,OAAM,CAAE,EAGxC+L,GAAe,EAGfT,GAAS,kBAAmBrsC,GAAW,CACrC,QAAQ,IAAI,mCAAoCA,CAAM,EAIlDA,EAAO,OAAS,WAAaA,EAAO,YAC3BA,EAAO,SAAS,IAAI,YAAY,IAChC,gBACT+gC,GAAS,sBAAsB/gC,EAAO,QAASA,EAAO,UAAU,CAGtE,CAAC,EAUGwsC,KACFF,GAAcxL,GAAkB,CAAE,QAAAC,EAAS,YAAawL,EAAY,CAAE,GAIxExL,EAAQ,QAAQ,CAACtvB,EAAKC,EAAK8K,EAASH,IAAQ,CAU1C,GAPImwB,KAEJ,QAAQ,IAAI,yBAA0B/6B,EAAI,QAAQ,CAAC,EAAGC,EAAI,QAAQ,CAAC,CAAC,EACpE,QAAQ,IAAI,2BAA4B+6B,CAAW,EAI/CA,IAAgB,QAAUA,EAAY,WAAW,SAAS,GAC5D,OAIF,IAAIzK,EAAgB,KAUpB,GATAjB,EAAQ,OAAM,EAAG,sBAAsB1kB,EAAI,MAAQjP,GAAM,CACvD,GAAIA,EAAE,IAAI,YAAY,IAAM,SAC1B,OAAA40B,EAAgB50B,EACT,EAEX,CAAC,EAIG40B,EAAe,CACjB,QAAQ,IAAI,gDAAgD,EAC5DjB,EAAQ,oBAAoBiB,EAAe3lB,EAAI,UAAU,EACzD,MACF,CAMA,IAAI0wB,EAAiB,KAOrB,GANAhM,EAAQ,OAAM,EAAG,sBAAsB1kB,EAAI,MAAQjP,GAAM,CACvD,GAAIA,EAAE,IAAI,YAAY,IAAM,WAC1B,OAAA2/B,EAAiB3/B,EACV,EAEX,CAAC,EACG2/B,EAAgB,CAClB,QAAQ,IAAI,kDAAkD,EAC9DhM,EAAQ,cAAcgM,EAAgB1wB,EAAI,WAAY,CACpD,MAAO,gBACP,MAAO,SACf,CAAO,EACD,MACF,CAGIowB,IAAgB,gBAIhBjwB,GAEF,QAAQ,IAAI,gCAAiCA,EAAQ,MAAK,CAAE,EAC5DukB,EAAQ,aAAavkB,CAAO,EAC5BwwB,GAAoBxwB,CAAO,IAG3B,QAAQ,IAAI,6CAA6C,EACzDukB,EAAQ,eAAc,EACtBA,EAAQ,qBAAqB1kB,EAAI,UAAU,GAE/C,CAAC,EAID0kB,EAAQ,WAAW,CAACtvB,EAAKC,EAAK8K,EAASH,IAAQ,CAG7C,GADImwB,IACA,CAAChwB,EAAS,OAEd,MAAMywB,EAAYzwB,EAAQ,IAAI,YAAY,EAG1C,GAFA,QAAQ,IAAI,6CAA8CywB,GAAa,MAAM,EAEzEA,IAAc,iBAEhBlM,EAAQ,4BAA4BvkB,EAASH,EAAI,UAAU,MACtD,IAAI4wB,IAAc,wBAEvB,OACSA,IAAc,eAEvBlM,EAAQ,0BAA0BvkB,EAASH,EAAI,UAAU,EAChD4wB,IAAc,iBACvBlM,EAAQ,cAAcvkB,EAASH,EAAI,WAAY,CAC7C,MAAO,YACP,MAAO,SACf,CAAO,EACQ4wB,IAAc,SACvBlM,EAAQ,cAAcvkB,EAASH,EAAI,WAAY,CAC7C,MAAO,cACP,MAAO,SACf,CAAO,EAED0kB,EAAQ,cAAcvkB,EAASH,EAAI,WAAY,CAC7C,MAAO,eACP,MAAO,SACf,CAAO,EAEL,CAAC,EAGD0kB,EAAQ,cAAc,MAAO1jC,GAAS,CACpC,QAAQ,IAAI,qCAAsCA,CAAI,EACtD,GAAI,CACF,MAAM2C,EAAS,MAAM8K,GAAYzN,EAAK,KAAMA,EAAK,IAAKA,EAAK,IAAK,CAC9D,YAAaA,EAAK,aAAe,KACjC,SAAUA,EAAK,UAAY,SACnC,CAAO,EACD,QAAQ,IAAI,wBAAyBA,EAAK,KAAM,MAAO2C,EAAO,EAAE,EAEhE,MAAMktC,GAAa,EAGnBnM,GAAS,OAAO1jC,EAAK,IAAKA,EAAK,IAAK,EAAE,EAGlC2C,EAAO,IACT+gC,GAAS,aAAa/gC,EAAO,EAAE,EAGjCmtC,GAAY,6BAA6B,CAE3C,OAASptC,EAAO,CACd,QAAQ,MAAM,gCAAiCA,CAAK,EACpDqtC,EAAU,2BAA6BrtC,EAAM,OAAO,CACtD,CACF,CAAC,EAGDghC,EAAQ,aAAa,MAAOvkB,EAAS8Q,IAAiB,CACpD,MAAM3e,EAAW2e,EAAa,IAAMA,EAAa,UAAYA,EAAa,UAG1E,GAFA,QAAQ,IAAI,2BAA4B3e,EAAU2e,CAAY,EAE1D,CAAC3e,EAAU,CACb,QAAQ,KAAK,sEAAsE,EACnF,MACF,CAEA,GAAI,CACF,MAAMD,GAAaC,EAAU2e,CAAY,EACzC6f,GAAY,wBAAwB,CACtC,OAASptC,EAAO,CACd,QAAQ,MAAM,sCAAuCA,CAAK,EAC1DqtC,EAAU,0BAA4BrtC,EAAM,OAAO,CACrD,CACF,CAAC,EAGD,MAAMstC,EAAY,IAAIC,GACtBvM,EAAQ,mBAAmB,MAAOvkB,EAASxQ,IAAU,CACnD,QAAQ,IAAI,wCAAyCA,CAAK,EAE1D,GAAI,CAEF,MAAMuhC,EAAYF,EAAU,cAAc7wB,EAAQ,YAAW,EAAI,CAC/D,eAAgB,YAChB,kBAAmB,WAC3B,CAAO,EAEKxc,EAAS,MAAM4O,GAAgB2+B,EAAWvhC,CAAK,EACrD,QAAQ,IAAI,qCAAsChM,EAAO,EAAE,EAC3DmtC,GAAY,yCAAyC,CACvD,OAASptC,EAAO,CACd,QAAQ,MAAM,mCAAoCA,CAAK,EACvDqtC,EAAU,0BAA4BrtC,EAAM,OAAO,CACrD,CACF,CAAC,EAGD,GAAI,CACF,QAAQ,IAAI,gCAAgC,EAI5C,MAAMwK,GAAU,EAGhB,QAAQ,IAAI,sBAAsB,EAGlC,MAAMoD,EAAS,MAAMqC,GAAiB,EACtC,QAAQ,IAAI,yBAA0BrC,CAAM,EAKxCmqB,EAAQ,IACQ,MAAMoF,GAAoB,IAE1C,QAAQ,KAAK,sDAAsD,EACnEsQ,GAAY,8CAA8C,IAO9D,MAAMC,GAAU,EAGhB1M,GAAS,YAAW,EAEpB2M,GAAoB,EACpBC,GAAW,EACXC,GAAkB,EAClBC,GAAW,EAOPrB,IAAmBF,IAAenL,KACpCA,GAAa,WAAW,EAAI,EAC5BmL,GAAY,mBAAmBnL,EAAY,GAE7C2M,GAAsB,EACtBC,GAAqB,EACrBC,GAAY,EACZC,GAAqB,CAEvB,OAASluC,EAAO,CACd,QAAQ,MAAM,wCAAyCA,CAAK,EAC5DqtC,EAAU,yDAAyD,EACnE,MACF,CAGAc,GAAM,EAGN,MAAMhB,GAAa,EAGnB/iC,GAAkBjF,GAAW,CAM3B,GALA,QAAQ,IAAI,yBAA0BA,CAAM,EACxCA,EAAO,QAAU,aAAe,CAACA,EAAO,OAE1CgoC,GAAa,EAEXhoC,EAAO,QAAU,UAAW,CAE9B,MAAMipC,EAAiB,SAAS,eAAe,kBAAkB,EAC7DA,GAAkB,CAACA,EAAe,UAAU,SAAS,QAAQ,GAC/DC,GAAqB,CAEzB,CACF,CAAC,EAGDvW,GAAiBwW,GAAY,CACvBA,EACF,QAAQ,IAAI,yDAAyD,GAErE,QAAQ,IAAI,qCAAqC,EACjDC,GAAQ,EAEZ,CAAC,EAGDC,GAAiB,EAGjBC,GAAqB,EAGrBC,GAAY,EAGZC,GAAkB,EAGlBC,GAAoB,EAGpBC,GAAyB,EAGzBC,GAAe,EAEf,QAAQ,IAAI,gCAAgC,CAC9C,CAMA,SAASX,IAAS,CAChB,QAAQ,IAAI,wCAAwC,EAGpDY,GAAc,EAGd,MAAMC,EAAY,SAAS,eAAe,YAAY,EAClDA,GACFA,EAAU,iBAAiB,QAASC,EAAY,EAIlD,MAAMC,EAAe,SAAS,eAAe,gBAAgB,EACzDA,GACFA,EAAa,iBAAiB,QAAS,IAAMb,GAAqB,CAAE,EAItE,MAAMc,EAAe,SAAS,eAAe,gBAAgB,EACvDC,EAAe,SAAS,eAAe,gBAAgB,EACzDD,GAAgBC,IAClBD,EAAa,iBAAiB,QAAS,IAAMC,EAAa,MAAK,CAAE,EACjEA,EAAa,iBAAiB,SAAUC,EAAqB,GAG/D,MAAMC,EAAmB,SAAS,eAAe,oBAAoB,EAC/DC,EAAmB,SAAS,eAAe,oBAAoB,EACjED,GAAoBC,IACtBD,EAAiB,iBAAiB,QAAS,IAAMC,EAAiB,MAAK,CAAE,EACzEA,EAAiB,iBAAiB,SAAUC,EAAmB,GAGjE,MAAMC,EAAe,SAAS,eAAe,gBAAgB,EACvDC,EAAe,SAAS,eAAe,gBAAgB,EACzDD,GAAgBC,IAClBD,EAAa,iBAAiB,QAAS,IAAMC,EAAa,MAAK,CAAE,EACjEA,EAAa,iBAAiB,SAAUC,EAAe,GAIzDC,GAAe,EAGf,MAAMC,EAAmB,SAAS,eAAe,mBAAmB,EAChEA,GACFA,EAAiB,iBAAiB,QAASC,EAAmB,EAIhE,MAAMC,EAAY,SAAS,eAAe,YAAY,EAClDA,GACFA,EAAU,iBAAiB,QAASC,EAAgB,EAItD,MAAMC,EAAS,SAAS,eAAe,SAAS,EAC5CA,GACFA,EAAO,iBAAiB,QAAS,IAAMjP,GAAS,aAAY,CAAE,EAOhE,MAAMkP,EAAiB,SAAS,eAAe,uBAAuB,EAChEC,EAAmB,SAAS,eAAe,yBAAyB,EACpEC,EAAiB,SAAS,eAAe,uBAAuB,EAChEC,EAAiB,SAAS,eAAe,uBAAuB,EAChEC,EAAU,SAAS,eAAe,eAAe,EACjD5Z,EAAW,SAAS,eAAe,gBAAgB,EAGzD,QAAQ,IAAI,0BAA2B,CACrC,YAAa,CAAC,CAACwZ,EACf,cAAe,CAAC,CAACC,EACjB,YAAa,CAAC,CAACC,EACf,YAAa,CAAC,CAACC,EACf,KAAM,CAAC,CAACC,EACR,MAAO,CAAC,CAAC5Z,CACb,CAAG,EAGD,MAAM6Z,EAAc,CAACL,EAAgBC,EAAkBC,EAAgBC,EAAgBC,CAAO,EAIxFE,EAAU,CAAC1pC,EAAM2pC,IAAc,CAwBnC,OAvBA,QAAQ,IAAI,+BAAgC/D,EAAa,KAAM5lC,CAAI,EACnE4lC,EAAc5lC,EACd,QAAQ,IAAI,gCAAiC4lC,CAAW,EAGxD6D,EAAY,QAAQhqB,GAAO,CACrBA,GAAKA,EAAI,UAAU,OAAO,SAAUA,IAAQkqB,CAAS,CAC3D,CAAC,EAGDnE,IAAU,WAAU,EAGhBxlC,IAAS,QACXk6B,GAAS,YAAY,EAAK,EAIxBl6B,IAAS,eACXk6B,GAAS,qBAAoB,EAIvBl6B,EAAI,CACV,IAAK,gBACHwlC,IAAU,mBAAkB,EAC5B,MACF,IAAK,cACHA,IAAU,iBAAgB,EAC1B,MACF,IAAK,cACHA,IAAU,iBAAgB,EAC1B,MACF,IAAK,OACHtL,GAAS,YAAY,EAAI,EACzB,KAER,CACE,EAGIkP,GACFA,EAAe,iBAAiB,QAAS,IAAM,CAC7C,QAAQ,IAAI,+BAA+B,EAC3CM,EAAQ,cAAeN,CAAc,CACvC,CAAC,EAICC,GACFA,EAAiB,iBAAiB,QAAS,IAAM,CAC/C,QAAQ,IAAI,2CAA4CzD,CAAW,EAC/DA,IAAgB,gBAElB8D,EAAQ,cAAeN,CAAc,EAErCM,EAAQ,gBAAiBL,CAAgB,CAE7C,CAAC,EAICC,GACFA,EAAe,iBAAiB,QAAS,IAAM,CAC7C,QAAQ,IAAI,yCAA0C1D,CAAW,EAC7DA,IAAgB,cAClB8D,EAAQ,cAAeN,CAAc,EAErCM,EAAQ,cAAeJ,CAAc,CAEzC,CAAC,EAICC,GACFA,EAAe,iBAAiB,QAAS,IAAM,CAC7C,QAAQ,IAAI,yCAA0C3D,CAAW,EAC7DA,IAAgB,cAClB8D,EAAQ,cAAeN,CAAc,EAErCM,EAAQ,cAAeH,CAAc,CAEzC,CAAC,EAICC,GACFA,EAAQ,iBAAiB,QAAS,IAAM,CACtC,QAAQ,IAAI,yCAA0C5D,CAAW,EAC7DA,IAAgB,OAClB8D,EAAQ,cAAeN,CAAc,EAErCM,EAAQ,OAAQF,CAAO,CAE3B,CAAC,EAIC5Z,GACFA,EAAS,iBAAiB,QAAS,IAAM,CAGvC,GAFA4V,IAAU,kBAAiB,EAEvBI,EAAY,WAAW,SAAS,EAElC,OADFJ,IAAU,WAAU,EACVI,EAAW,CACjB,IAAK,gBACHJ,IAAU,mBAAkB,EAC5B,MACF,IAAK,cACHA,IAAU,iBAAgB,EAC1B,MACF,IAAK,cACHA,IAAU,iBAAgB,EAC1B,KACZ,CAEI,CAAC,CAEL,CA8CA,eAAea,IAAgB,CAC7B,GAAI,CACF,QAAQ,IAAI,4BAA4B,EACxC,MAAM1c,EAAY,MAAMllB,GAAY,EACpC,QAAQ,IAAI,0BAA2BklB,CAAS,EAGhDigB,GAAgBjgB,CAAS,EAGrBuQ,IACFA,EAAQ,aAAY,EAChBvQ,EAAU,OAAS,IACrBuQ,EAAQ,WAAWvQ,CAAS,EAC5B,QAAQ,IAAI,cAAeA,EAAU,OAAQ,gBAAgB,IAKjE,MAAMkgB,EAAU,SAAS,eAAe,gBAAgB,EACpDA,IACFA,EAAQ,YAAclgB,EAAU,OAGpC,OAASzwB,EAAO,CACd,QAAQ,MAAM,kCAAmCA,CAAK,CACxD,CACF,CAKA,SAASitC,GAAoBxwB,EAAS,CACpC,MAAMjX,EAAOiX,EAAQ,IAAI,MAAM,EACzBvR,EAAcuR,EAAQ,IAAI,aAAa,EACvCtR,EAAWsR,EAAQ,IAAI,UAAU,EACjC/K,EAAM+K,EAAQ,IAAI,KAAK,GAAKA,EAAQ,IAAI,WAAW,EACnD9K,EAAM8K,EAAQ,IAAI,KAAK,GAAKA,EAAQ,IAAI,UAAU,EAIxD,QAAQ,IAAI,2BAA4B,CAAE,KAAAjX,EAAM,YAAA0F,EAAa,SAAAC,EAAU,IAAAuG,EAAK,IAAAC,EAAK,CAInF,CAEA,SAAS++B,GAAgBjgB,EAAW,CAClC,MAAMvW,EAAY,SAAS,eAAe,gBAAgB,EAC1D,GAAI,CAACA,EAAW,OAGhB,MAAM02B,EAAc,SAAS,eAAe,uBAAuB,EAKnE,GAJIA,IACFA,EAAY,YAAcngB,EAAU,QAGlCA,EAAU,SAAW,EAAG,CAC1BvW,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAMtB,MACF,CAGA,MAAM22B,EAAiB,CACrB,MAAS,KACT,OAAU,KACV,OAAU,KACV,OAAU,KACV,QAAW,KACX,MAAS,IACb,EAEE32B,EAAU,UAAYuW,EAAU,IAAIzgB,GAAO,CACzC,MAAM8V,EAAQ+qB,EAAe7gC,EAAI,QAAQ,GAAK,KAC9C,MAAO;AAAA;AAAA,oBAESA,EAAI,EAAE,eAAeA,EAAI,SAAS,eAAeA,EAAI,QAAQ;AAAA;AAAA;AAAA,+BAGlD8V,CAAK,IAAI6e,EAAW30B,EAAI,IAAI,CAAC;AAAA,uDACLA,EAAI,SAAS,QAAQ,CAAC,CAAC,KAAKA,EAAI,UAAU,QAAQ,CAAC,CAAC;AAAA;AAAA,qCAEtEA,EAAI,QAAQ,KAAKA,EAAI,QAAQ;AAAA;AAAA,UAExDA,EAAI,YAAc,8CAA8C20B,EAAW30B,EAAI,WAAW,CAAC,WAAa,EAAE;AAAA;AAAA,KAGlH,CAAC,EAAE,KAAK,EAAE,EAGVkK,EAAU,iBAAiB,gBAAgB,EAAE,QAAQ42B,GAAQ,CAC3DA,EAAK,iBAAiB,QAAUxmC,GAAM,CACpCA,EAAE,eAAc,EAChB,MAAMoH,EAAM,WAAWo/B,EAAK,QAAQ,GAAG,EACjCn/B,EAAM,WAAWm/B,EAAK,QAAQ,GAAG,EACjC1zC,EAAK,SAAS0zC,EAAK,QAAQ,EAAE,EAGnC9P,GAAS,OAAOtvB,EAAKC,EAAK,EAAE,EAG5BqvB,GAAS,aAAa5jC,CAAE,CAC1B,CAAC,CACH,CAAC,CACH,CAUA,eAAeixC,IAAwB,CACrC,MAAMD,EAAiB,SAAS,eAAe,kBAAkB,EAC3D2C,EAAQ,SAAS,eAAe,kBAAkB,EAClDC,EAAc,SAAS,eAAe,sBAAsB,EAClE,GAAI,GAAC5C,GAAkB,CAAC2C,GAExB,IAAI,CACF,MAAME,EAAQ,MAAMngC,GAAa,EAEjCigC,EAAM,UAAYE,EAAM,IAAKnmC,GAAM,CAEjC,MAAM4rB,EADWrmB,GAAmBvF,EAAE,IAAI,EAEtC;AAAA,iCACuB65B,EAAW75B,EAAE,IAAI,CAAC;AAAA;AAAA;AAAA,sBAIzC,GACJ,MAAO;AAAA;AAAA;AAAA,8DAGiD65B,EAAW75B,EAAE,IAAI,CAAC,KAAK65B,EAAW75B,EAAE,IAAI,CAAC;AAAA;AAAA,kEAErCA,EAAE,KAAK;AAAA,sCACnC4rB,CAAQ;AAAA;AAAA,OAG1C,CAAC,EAAE,KAAK,EAAE,EACV0X,EAAe,UAAU,OAAO,QAAQ,EAGxC2C,EAAM,iBAAiB,kBAAkB,EAAE,QAASG,GAAS,CAC3DA,EAAK,iBAAiB,QAAU5mC,GAAM,CACpCA,EAAE,eAAc,EAChB6mC,GAAiBD,EAAK,QAAQ,KAAK,CACrC,CAAC,CACH,CAAC,EAGDH,EAAM,iBAAiB,kBAAkB,EAAE,QAASxqB,GAAQ,CAC1DA,EAAI,iBAAiB,QAAS,MAAOjc,GAAM,CACzCA,EAAE,eAAc,EAChB,MAAMgG,EAAYiW,EAAI,QAAQ,MAC9B,GAAK,QAAQ,0BAA0BjW,CAAS;;AAAA,sEAA6E,EAC7H,GAAI,CACF,MAAM+jB,EAAU,MAAM9jB,GAAWD,CAAS,EAC1C88B,GAAY,WAAW/Y,CAAO,OAAOA,IAAY,EAAI,GAAK,GAAG,UAAU/jB,CAAS,uCAAuC,EACvH,MAAM+9B,GAAqB,CAC7B,OAASpmC,EAAK,CACZ,QAAQ,MAAM,gCAAiCA,CAAG,EAClDolC,EAAU,oBAAoB/8B,CAAS,MAAMrI,EAAI,OAAO,EAAE,CAC5D,CACF,CAAC,CACH,CAAC,CACH,OAASjI,EAAO,CACd,QAAQ,MAAM,oCAAqCA,CAAK,EACxD+wC,EAAM,UAAY,wEAClB3C,EAAe,UAAU,OAAO,QAAQ,CAC1C,CAGI4C,GAAe,CAACA,EAAY,SAC9BA,EAAY,OAAS,GACrBA,EAAY,iBAAiB,QAASI,EAA0B,GAEpE,CAOA,eAAeA,IAA6B,CAC1C,GAAK,QACH;;AAAA,8IAGJ,EAEE,GAAI,CACF,MAAMrxC,EAAU,MAAM0Q,GAAoB,EACpCG,EAAQ7Q,EAAQ,OAAO,CAAC8Q,EAAG,IAAMA,EAAI,EAAE,MAAO,CAAC,EACrDu8B,GAAY,WAAWx8B,CAAK,OAAOA,IAAU,EAAI,GAAK,GAAG,WAAW7Q,EAAQ,MAAM,SAASA,EAAQ,SAAW,EAAI,GAAK,GAAG,GAAG,EAC7H,MAAMsuC,GAAqB,EAEvB,QAAQ,qEAAqE,GAC/E,OAAO,SAAS,OAAM,CAE1B,OAASpmC,EAAK,CACZ,QAAQ,MAAM,0BAA2BA,CAAG,EAC5ColC,EAAU,kCAAoCplC,EAAI,OAAO,CAC3D,CACF,CAUA,eAAekpC,GAAiB7gC,EAAW,CACzC,MAAM+gC,EAAa,SAAS,eAAe,wBAAwB,EAC7DC,EAAY,SAAS,eAAe,oBAAoB,EACxDC,EAAY,SAAS,eAAe,oBAAoB,EAG9DF,EAAW,YAAc,UAAU/gC,CAAS,GAC5CghC,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOtBC,EAAU,YAAc,GAGV,IAAIrM,GAAM,SAAS,eAAe,mBAAmB,CAAC,EAC9D,KAAI,EAEV,GAAI,CACF,KAAM,CAAE,QAAArjC,EAAS,KAAAC,CAAI,EAAK,MAAMiP,GAAgBT,CAAS,EAEzD,GAAIxO,EAAK,SAAW,EAAG,CACrBwvC,EAAU,UAAY,gEACtBC,EAAU,YAAc,SACxB,MACF,CAGA,MAAMC,EAAc3vC,EAAQ,IAAI,GAAK,2BAA2B8iC,EAAW,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EACvF8M,EAAW3vC,EAAK,IAAIkE,GASjB,OAROnE,EAAQ,IAAI+I,GAAK,CAC7B,IAAI47B,EAAMxgC,EAAI4E,CAAC,EACf,GAAI47B,GAAQ,KAA2B,MAAO,8CAC9CA,EAAM,OAAOA,CAAG,EAEhB,MAAMkL,EAAUlL,EAAI,OAAS,IAAMA,EAAI,UAAU,EAAG,GAAG,EAAI,MAAQA,EACnE,MAAO,OAAO7B,EAAW+M,CAAO,CAAC,OACnC,CAAC,EAAE,KAAK,EAAE,CACS,OACpB,EAAE,KAAK,EAAE,EAEVJ,EAAU,UAAY;AAAA;AAAA;AAAA;AAAA,kBAIRE,CAAW;AAAA;AAAA,mBAEVC,CAAQ;AAAA;AAAA;AAAA,MAKvBF,EAAU,YAAc,GAAGzvC,EAAK,MAAM,GAAGA,EAAK,QAAU,IAAM,IAAM,EAAE,YAAYD,EAAQ,MAAM,YAElG,OAAS7B,EAAO,CACd,QAAQ,MAAM,sCAAuCA,CAAK,EAC1DsxC,EAAU,UAAY,6DAA6D3M,EAAW3kC,EAAM,OAAO,CAAC,QAC9G,CACF,CAMA,eAAeivC,IAAe,CAC5B,GAAI,CACF,MAAMt/B,GAAiB,uBAAuB,EAC9Cy9B,GAAY,gCAAgC,CAC9C,OAASptC,EAAO,CACd,QAAQ,MAAM,uBAAwBA,CAAK,EAC3CqtC,EAAU,kBAAoBrtC,EAAM,OAAO,CAC7C,CACF,CAGA,eAAe8vC,IAAsB,CACnC,GAAI,CACH,MAAM7e,EAAU,MAAMlhB,GAAe,EAG/BH,EAAO,IAAI,KAAK,CAAC,KAAK,UAAUqhB,EAAS,KAAM,CAAC,CAAC,EAAG,CAAE,KAAM,kBAAkB,CAAE,EAChFphB,EAAM,IAAI,gBAAgBD,CAAI,EAC9BE,EAAI,SAAS,cAAc,GAAG,EACpCA,EAAE,KAAOD,EACTC,EAAE,SAAW,oBACbA,EAAE,MAAK,EACP,IAAI,gBAAgBD,CAAG,EAExBu9B,GAAY,YAAYnc,EAAQ,SAAS,MAAM,cAAc,CAC9D,OAAQjxB,EAAO,CACZ,QAAQ,MAAM,+BAAgCA,CAAK,EACnDqtC,EAAU,0BAA4BrtC,EAAM,OAAO,CACrD,CACF,CAMA,eAAegwC,IAAmB,CAChC,GAAI,CACF,MAAMpiC,EAAS,MAAMqC,GAAiB,EAGhC0hC,EAAgB,SAAS,eAAe,gBAAgB,EAC1DA,IACFA,EAAc,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA,uCAKO/jC,EAAO,MAAQ,aAAe,WAAW,KAAKA,EAAO,MAAQ,MAAQ,IAAI;AAAA;AAAA;AAAA;AAAA,uCAIzEmqB,EAAQ,EAAK,aAAe,YAAY,KAAKA,EAAQ,EAAK,MAAQ,SAAS;AAAA;AAAA;AAAA;AAAA,0BAIxFnqB,EAAO,cAAgB,KAAK;AAAA;AAAA;AAAA;AAAA,oBAIlCA,EAAO,OAAO,IAAI9C,GAAK,yCAAyCA,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA;AAAA;AAAA,mDAIrD8C,EAAO,aAAa;AAAA;AAAA;AAAA;AAAA,SAQ/C,IAAIs3B,GAAM,SAAS,eAAe,aAAa,CAAC,EACxD,KAAI,CAElB,OAASllC,EAAO,CACd,QAAQ,MAAM,8BAA+BA,CAAK,EAClDqtC,EAAU,sBAAsB,CAClC,CACF,CAWA,SAASuE,GAAeC,EAAS,CAC/B,OAAOA,EAAQ,QAAQ,OAAQ,EAAE,EAAE,QAAQ,OAAQ,EAAE,EAClD,MAAM,GAAG,EACT,IAAIC,GAAQ,CACX,KAAM,CAACpgC,EAAKC,CAAG,EAAImgC,EAAK,OAAO,MAAM,KAAK,EAAE,IAAI,MAAM,EACtD,MAAO,CAACpgC,EAAKC,CAAG,CAClB,CAAC,CACL,CASA,SAASogC,GAAgBxlC,EAAK,CAQ5B,MAAO,CAAE,KAAM,UAAW,YAPZA,EAAI,KAAI,EACnB,QAAQ,oBAAqB,EAAE,EAC/B,QAAQ,SAAU,EAAE,EAEG,MAAM,KAAK,EACX,IAAIqlC,EAAc,CAEA,CAC9C,CASA,SAASI,GAAqBzlC,EAAK,CAajC,MAAO,CAAE,KAAM,eAAgB,YAZjBA,EAAI,KAAI,EACnB,QAAQ,yBAA0B,EAAE,EACpC,QAAQ,SAAU,EAAE,EAEM,MAAM,OAAO,EAEV,IAAI0lC,GAClBA,EAAQ,QAAQ,OAAQ,EAAE,EAAE,QAAQ,OAAQ,EAAE,EAClC,MAAM,KAAK,EACpB,IAAIL,EAAc,CACtC,CAEmD,CACtD,CAOA,SAASM,GAAS3lC,EAAK,CACrB,GAAI,CAACA,EAAK,OAAO,KACjB,MAAM4lC,EAAU5lC,EAAI,KAAI,EAAG,YAAW,EACtC,OAAI4lC,EAAQ,WAAW,cAAc,EAAUH,GAAqBzlC,CAAG,EACnE4lC,EAAQ,WAAW,SAAS,EAAUJ,GAAgBxlC,CAAG,GAC7D,QAAQ,KAAK,8BAA+B4lC,EAAQ,UAAU,EAAG,EAAE,CAAC,EAC7D,KACT,CASA,SAASC,GAAqBC,EAAa,CACzC,GAAI,CAACA,GAAa,SAAW,CAACA,GAAa,MAAM,SAC/C,eAAQ,KAAK,qDAAqD,EAC3D,KAGT,KAAM,CAAE,SAAAC,EAAU,WAAAC,EAAY,cAAAC,CAAa,EAAKH,EAAY,KACtDroB,EAAWkoB,GAASI,CAAQ,EAElC,MAAO,CACL,KAAM,oBACN,SAAU,CAAC,CACT,KAAM,UACN,WAAY,CACV,WAAYC,EACZ,cAAeC,CACvB,EACM,SAAUxoB,CAChB,CAAK,CACL,CACA,CAUA,SAASyoB,GAAe1mC,EAAO,CAC7B,GAAI,CAAC,MAAM,QAAQA,CAAK,GAAKA,EAAM,SAAW,EAAG,OAAO,KAExD,MAAMoB,EAAW,GACjB,UAAWulC,KAAQ3mC,EAAO,CAExB,MAAMQ,EAAMmmC,EAAK,SAAWA,EAAK,SAC3B1oB,EAAWkoB,GAAS3lC,CAAG,EAC7B,GAAI,CAACyd,EAAU,SAGf,MAAMD,EAAa,CAAE,WAAY,gBAAgB,EACjD,SAAW,CAAC5gB,EAAKjB,CAAK,IAAK,OAAO,QAAQwqC,CAAI,EACxCvpC,IAAQ,WAAaA,IAAQ,aACjC4gB,EAAW5gB,CAAG,EAAIjB,GAGpBiF,EAAS,KAAK,CAAE,KAAM,UAAW,WAAA4c,EAAY,SAAAC,EAAU,CACzD,CAEA,OAAI7c,EAAS,SAAW,EAAU,KAC3B,CAAE,KAAM,oBAAqB,SAAAA,CAAQ,CAC9C,CAOA,eAAewgC,IAAuB,CACpC,MAAMgF,EAAY,oBAEZC,EAAgB,CACpB,YAAa,UACb,YAAa,IACb,UAAW,uBACX,gBAAiB,kBACrB,EAGQC,EAAa7R,GAAS,cAAc,CAAc,GAAK,KAK7D,SAAS8R,EAAoB9mB,EAAO,CAClC,GAAI,CAACA,EAAO,OACZ,MAAMvQ,EAASuQ,EAAM,UAAS,EACxB5J,EAAW,GACjB3G,EAAO,QAASC,GAAU,CACpBA,EAAM,IAAI,OAAO,IAAM,qBACzB0G,EAAS,KAAK1G,CAAK,CAEvB,CAAC,EACD0G,EAAS,QAAS1G,GAAUD,EAAO,OAAOC,CAAK,CAAC,CAClD,CAKA,SAASq3B,EAAer3B,EAAO,CAC7B,GAAI,CAACA,GAAS,CAACslB,EAAS,OACxB,MAAMje,EAASrH,EAAM,UAAS,EAAG,UAAS,EACtCqH,GAAUA,EAAO,CAAC,IAAM,KAC1Bie,EAAQ,OAAM,EAAG,QAAO,EAAG,IAAIje,EAAQ,CACrC,QAAS,CAAC,GAAI,GAAI,GAAI,EAAE,EACxB,SAAU,GAClB,CAAO,CAEL,CAEA,GAAI,CAEF,MAAM8Y,EAAS,MAAMjwB,GAAc+mC,CAAS,EAC5C,GAAI9W,EAAQ,CACV,QAAQ,IAAI,iDAAiD,EAC7D,MAAMngB,EAAQslB,GAAS,gBAAgBnF,EAAQ,oBAAqB+W,EAAeC,CAAU,EAC7FE,EAAer3B,CAAK,CACtB,CAGA,GAAIqc,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,8CAA8C,EAC1D,MAAM+U,EAAc,MAAMzU,GAAmB,EAGvC3M,EAAUmhB,GAAqBC,CAAW,EAChD,GAAI,CAACphB,EAAS,CACZ,QAAQ,KAAK,iDAAiD,EAC9D,MACF,CAEA,QAAQ,IAAI,2BAA4BA,EAAQ,SAAS,CAAC,GAAG,YAAY,cACvE,IAAKA,EAAQ,SAAS,CAAC,GAAG,UAAU,aAAa,OAAQ,YAAY,EAGvE,MAAMvlB,GAAeinC,EAAW1hB,CAAO,EAGnC4K,GACFiX,EAAoBD,GAAc7R,GAAS,iBAAiB,EAG9D,MAAMtlB,EAAQslB,GAAS,gBAAgB/P,EAAS,oBAAqB2hB,EAAeC,CAAU,EAC9FE,EAAer3B,CAAK,EACpB,QAAQ,IAAI,yCAAyC,CAEvD,MAAYmgB,GACV,QAAQ,IAAI,oEAAoE,CAGpF,OAAS77B,EAAO,CACd,QAAQ,MAAM,0CAA2CA,CAAK,CAChE,CACF,CAQA,SAASgzC,GAAiBlxC,EAAM,CAC9B,GAAI,CAAC,MAAM,QAAQA,CAAI,GAAKA,EAAK,SAAW,EAAG,OAAO,KACtD,MAAMqL,EAAW,GACjB,UAAWhB,KAAKrK,EAAM,CACpB,MAAMyK,EAAMJ,EAAE,SAAWA,EAAE,cAAgBA,EAAE,KACvC6d,EAAWkoB,GAAS3lC,CAAG,EACxByd,GACL7c,EAAS,KAAK,CACZ,KAAM,UACN,WAAY,CAAE,WAAY,WAAY,WAAYhB,EAAE,YAAc,IAAI,EACtE,SAAA6d,CACN,CAAK,CACH,CACA,OAAI7c,EAAS,SAAW,EAAU,KAC3B,CAAE,KAAM,oBAAqB,SAAAA,CAAQ,CAC9C,CAYA,eAAeygC,IAAc,CAK3B,MAAMqF,EAAe,CACnB,YAAa,UACb,YAAa,IACb,UAAW,wBACX,gBAAiB,kBACrB,EAEQJ,EAAa7R,GAAS,cAAc,CAAc,GAAK,KACvDkS,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EACxDC,EAAenS,GAAS,gBAAgBkS,EAAc,WAAYD,EAAcJ,CAAU,EAChG,GAAI,CAACM,EAAc,CACjB,QAAQ,KAAK,uCAAuC,EACpD,MACF,CACAA,EAAa,WAAW,EAAK,EAQ7B,MAAMC,EAA2B,EACjCD,EAAa,SAAS,CAAC12B,EAASgF,IAAe,CAC7C,MAAM+O,EAAS,CAEb,IAAI5V,EAAM,CACR,OAAQ,IAAIC,EAAO,CAAE,MAAO,yBAA0B,MAAO,IAAK,CAC1E,CAAO,EAED,IAAID,EAAM,CACR,OAAQ,IAAIC,EAAO,CAAE,MAAO,UAAW,MAAO,IAAK,SAAU,CAAC,EAAG,CAAC,CAAC,CAAE,EACrE,KAAQ,IAAIC,EAAK,CAAE,MAAO,uBAAuB,CAAE,CAC3D,CAAO,CACP,EAEI,GAAI2G,GAAc2xB,EAA0B,CAC1C,MAAMC,EAAS52B,EAAQ,IAAI,YAAY,EACnC42B,GAAU,MAAQ,OAAOA,CAAM,EAAE,OAAS,GAC5C7iB,EAAO,KAAK,IAAI5V,EAAM,CACpB,KAAM,IAAI04B,GAAO,CACf,KAAM,OAAOD,CAAM,EACnB,KAAM,6BACN,KAAQ,IAAIv4B,EAAK,CAAE,MAAO,SAAS,CAAE,EACrC,OAAQ,IAAID,EAAO,CAAE,MAAO,yBAA0B,MAAO,EAAG,EAChE,SAAU,EACtB,CAAW,CACX,CAAS,CAAC,CAEN,CACA,OAAO2V,CACT,CAAC,EAED2iB,EAAa,GAAG,iBAAkB,IAAM,CAClCA,EAAa,WAAU,GAAMA,EAAa,UAAS,EAAG,YAAW,EAAG,SAAW,GACjF9F,EAAU,wEAAwE,CAEtF,CAAC,EAED,SAASkG,EAAYtiB,EAAS,CAC5B,MAAMvL,EAAc,IAAIoM,KAAU,aAAab,EAAS,CAAE,kBAAmB,YAAa,EAC1FkiB,EAAa,UAAS,EAAG,MAAK,EAC9BA,EAAa,UAAS,EAAG,YAAYztB,CAAW,CAClD,CAEA,GAAI,CAEF,MAAMrZ,EADUywB,GAAU,GACE,aAAe,KAKrCjB,EAAS,MAAMpvB,GAAgBJ,CAAU,EAC/C,GAAIwvB,EAAQ,CACV,MAAM5K,EAAU+hB,GAAiBnX,CAAM,EACnC5K,GAASsiB,EAAYtiB,CAAO,EAChC,QAAQ,IAAI,6BAA8B4K,EAAO,OAAQ,kBAAmBxvB,EAAY,GAAG,EAC3F,MACF,CAIA,GAAI,CAAC0rB,EAAQ,GAAM,CAACuF,KAAqB,CACvC,QAAQ,IAAI,mEAAoEjxB,CAAU,EAC1F,MACF,CACA,QAAQ,IAAI,6CAA8CA,EAAY,MAAM,EAC5E,MAAMgmC,EAAc,MAAMlU,GAAU,EACpC,GAAI,CAACkU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,qCAAsCA,CAAW,EAC9D,MACF,CACA,MAAMvwC,EAAOuwC,EAAY,KACzB,QAAQ,IAAI,2BAA4BvwC,EAAK,OAAQ,OAAO,EAE5D,MAAMsK,GAAYtK,EAAMuK,CAAU,EAElC,MAAM4kB,EAAU+hB,GAAiBlxC,CAAI,EACjCmvB,GAASsiB,EAAYtiB,CAAO,EAChC,QAAQ,IAAI,yBAA0BA,GAAS,SAAS,QAAU,EAAG,gBAAgB,CACvF,OAASjxB,EAAO,CACd,QAAQ,MAAM,iCAAkCA,CAAK,CACvD,CACF,CAUA,eAAe6tC,IAAqB,CAElC,MAAM2F,EAAY,CAChB,YAAa,UACb,YAAa,IACb,UAAW,wBACX,gBAAiB,kBACrB,EAEQX,EAAa7R,GAAS,cAAc,CAAc,GAAK,KAC7D,QAAQ,IAAI,yCAA0C6R,EAAaA,EAAW,IAAI,OAAO,EAAI,MAAM,EAInG,MAAMK,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EACxDO,EAAazS,GAAS,gBAAgBkS,EAAc,QAASM,EAAWX,CAAU,EACxF,GAAI,CAACY,EAAY,CACf,QAAQ,KAAK,oCAAoC,EACjD,MACF,CACAA,EAAW,WAAW,EAAK,EAG3BA,EAAW,GAAG,iBAAkB,IAAM,CAChCA,EAAW,WAAU,GAAMA,EAAW,UAAS,EAAG,YAAW,EAAG,SAAW,GAC7EpG,EAAU,sFAAsF,CAEpG,CAAC,EAKD,SAASqG,EAAgBziB,EAAS,CAChC,MAAMvL,EAAc,IAAIoM,KAAU,aAAab,EAAS,CACtD,kBAAmB,WACzB,CAAK,EACDwiB,EAAW,UAAS,EAAG,MAAK,EAC5BA,EAAW,UAAS,EAAG,YAAY/tB,CAAW,CAChD,CAEA,GAAI,CAEF,MAAMmW,EAAS,MAAM3vB,GAAsB,EAC3C,GAAI2vB,EAAQ,CACV,MAAM5K,EAAUwhB,GAAe5W,CAAM,EACjC5K,IACF,QAAQ,IAAI,iDAAkDA,EAAQ,SAAS,OAAQ,OAAO,EAC9FyiB,EAAgBziB,CAAO,EAE3B,CAGA,GAAI8G,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,4CAA4C,EACxD,MAAM+U,EAAc,MAAMvU,GAAiB,EAE3C,GAAI,CAACuU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,gDAAiDA,CAAW,EACzE,MACF,CAEA,MAAMtmC,EAAQsmC,EAAY,KAC1B,QAAQ,IAAI,kCAAmCtmC,EAAM,OAAQ,SAAS,EAGtE,MAAMD,GAAmBC,CAAK,EAG9B,MAAMklB,EAAUwhB,GAAe1mC,CAAK,EACpC,GAAI,CAACklB,EAAS,CACZ,QAAQ,KAAK,0CAA0C,EACvD,MACF,CAEAyiB,EAAgBziB,CAAO,EACvB,QAAQ,IAAI,0CAA2CA,EAAQ,SAAS,OAAQ,OAAO,CAEzF,MAAY4K,GACV,QAAQ,IAAI,kEAAkE,CAGlF,OAAS77B,EAAO,CACd,QAAQ,MAAM,wCAAyCA,CAAK,CAC9D,CACF,CASA,SAAS2zC,GAAiBnlC,EAAS,CACjC,GAAI,CAAC,MAAM,QAAQA,CAAO,GAAKA,EAAQ,SAAW,EAAG,OAAO,KAG5D,MAAMy1B,EAAO,IAAI,IACX92B,EAAW,GACjB,UAAWymC,KAAUplC,EAAS,CAC5B,MAAMpR,EAAKw2C,EAAO,IAAMA,EAAO,UAAYA,EAAO,UAClD,GAAIx2C,GAAM,KAAM,CACd,GAAI6mC,EAAK,IAAI7mC,CAAE,EAAG,SAClB6mC,EAAK,IAAI7mC,CAAE,CACb,CAKA,IAAI4sB,EAAW,KACf,GAAI4pB,EAAO,MAAQA,EAAO,KAAK,MAAQA,EAAO,KAAK,YACjD5pB,EAAW,CAAE,KAAM4pB,EAAO,KAAK,KAAM,YAAaA,EAAO,KAAK,WAAW,UAChEA,EAAO,aAAeA,EAAO,YAAY,MAAQA,EAAO,YAAY,YAC7E5pB,EAAW,CAAE,KAAM4pB,EAAO,YAAY,KAAM,YAAaA,EAAO,YAAY,WAAW,MAClF,CACL,MAAMrnC,EAAMqnC,EAAO,UAAYA,EAAO,cAAgBA,EAAO,SAAWA,EAAO,IAC/E5pB,EAAWkoB,GAAS3lC,CAAG,CACzB,CACA,GAAI,CAACyd,EAAU,SAGf,MAAME,EAAW,IAAI,IAAI,CAAC,UAAW,WAAY,OAAQ,eAAgB,MAAO,eAAgB,cAAe,YAAY,CAAC,EACtHH,EAAa,CAAE,WAAY,QAAQ,EACzC,SAAW,CAAC5gB,EAAKjB,CAAK,IAAK,OAAO,QAAQ0rC,CAAM,EAC1C1pB,EAAS,IAAI/gB,CAAG,IACpB4gB,EAAW5gB,CAAG,EAAIjB,GAGpBiF,EAAS,KAAK,CAAE,KAAM,UAAW,WAAA4c,EAAY,SAAAC,EAAU,CACzD,CAEA,OAAI7c,EAAS,SAAW,EAAU,KAC3B,CAAE,KAAM,oBAAqB,SAAAA,CAAQ,CAC9C,CAUA,eAAe2gC,IAAc,CAE3B,MAAM+F,EAAc,CAClB,YAAa,UACb,YAAa,IACb,UAAW,wBACX,gBAAiB,kBACrB,EAEQC,EAAe9S,GAAS,cAAc,CAAiB,GAAK,KAClE,QAAQ,IAAI,oCAAqC8S,EAAeA,EAAa,IAAI,OAAO,EAAI,MAAM,EAIlG,MAAMZ,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EAI9D,GADA9R,GAAeJ,GAAS,gBAAgBkS,EAAc,UAAWW,EAAaC,CAAY,EACtF,CAAC1S,GAAc,CACjB,QAAQ,KAAK,sCAAsC,EACnD,MACF,CACAA,GAAa,WAAW,EAAK,EAG7BA,GAAa,GAAG,iBAAkB,IAAM,CAClCA,GAAa,WAAU,GAAMA,GAAa,UAAS,EAAG,YAAW,EAAG,SAAW,GACjFiM,EAAU,gFAAgF,CAE9F,CAAC,EAKD,SAAS0G,EAAkB9iB,EAAS,CAClC,MAAMvL,EAAc,IAAIoM,KAAU,aAAab,EAAS,CACtD,kBAAmB,WACzB,CAAK,EACDmQ,GAAa,UAAS,EAAG,MAAK,EAC9BA,GAAa,UAAS,EAAG,YAAY1b,CAAW,CAClD,CAEA,GAAI,CAEF,MAAMmW,EAAS,MAAMntB,GAAe,EACpC,GAAImtB,EAAQ,CACV,MAAM5K,EAAU0iB,GAAiB9X,CAAM,EACnC5K,IACF,QAAQ,IAAI,yCAA0CA,EAAQ,SAAS,OAAQ,SAAS,EACxF8iB,EAAkB9iB,CAAO,EAE7B,CAGA,GAAI8G,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,oCAAoC,EAChD,MAAM+U,EAAc,MAAMtU,GAAkB,EAE5C,GAAI,CAACsU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,iDAAkDA,CAAW,EAC1E,MACF,CAEA,MAAM7jC,EAAU6jC,EAAY,KAC5B,QAAQ,IAAI,0BAA2B7jC,EAAQ,OAAQ,SAAS,EAG5DA,EAAQ,OAAS,GACnB,QAAQ,IAAI,2BAA4B,OAAO,KAAKA,EAAQ,CAAC,CAAC,CAAC,EAIjE,MAAMD,GAAYC,CAAO,EAGzB,MAAMyiB,EAAU0iB,GAAiBnlC,CAAO,EACxC,GAAI,CAACyiB,EAAS,CACZ,QAAQ,KAAK,4CAA4C,EACzD,MACF,CAEA8iB,EAAkB9iB,CAAO,EACzB,QAAQ,IAAI,kCAAmCA,EAAQ,SAAS,OAAQ,SAAS,CAEnF,MAAY4K,GACV,QAAQ,IAAI,0DAA0D,CAG1E,OAAS77B,EAAO,CACd,QAAQ,MAAM,gCAAiCA,CAAK,CACtD,CACF,CASA,SAASg0C,GAAoBhlC,EAAY,CACvC,GAAI,CAAC,MAAM,QAAQA,CAAU,GAAKA,EAAW,SAAW,EAAG,OAAO,KAElE,MAAMilC,EAAW,CAAC,UAAW,WAAY,OAAQ,MAAO,WAAW,EAE7D9mC,EAAW,GACjB,UAAW+1B,KAAMl0B,EAAY,CAC3B,MAAM+tB,EAAMmG,EAAG,SAAWA,EAAG,UAAYA,EAAG,MAAQA,EAAG,KAAOA,EAAG,UAEjE,IAAIlZ,EAOJ,GANI,OAAO+S,GAAQ,UAAYA,IAAQ,MAAQA,EAAI,KAEjD/S,EAAW+S,EAEX/S,EAAWkoB,GAASnV,CAAG,EAErB,CAAC/S,EAAU,SAEf,MAAMD,EAAa,CAAE,WAAY,oBAAoB,EACrD,SAAW,CAAC5gB,EAAKjB,CAAK,IAAK,OAAO,QAAQg7B,CAAE,EACtC+Q,EAAS,SAAS9qC,CAAG,GAErB,OAAOjB,GAAU,UAAYA,IAAU,OAC3C6hB,EAAW5gB,CAAG,EAAIjB,GAGpBiF,EAAS,KAAK,CAAE,KAAM,UAAW,WAAA4c,EAAY,SAAAC,EAAU,CACzD,CAEA,OAAI7c,EAAS,SAAW,EAAU,KAC3B,CAAE,KAAM,oBAAqB,SAAAA,CAAQ,CAC9C,CAUA,eAAe4gC,IAAyB,CAEtC,MAAMmG,EAAiB,CACrB,YAAa,UACb,YAAa,EACb,UAAW,wBACX,gBAAiB,kBACrB,EAEQC,EAAiBnT,GAAS,cAAc,CAAmB,GAAK,KACtE,QAAQ,IAAI,iDAAkDmT,EAAiBA,EAAe,IAAI,OAAO,EAAI,MAAM,EAGnH,MAAMjB,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EACxDkB,EAAkBpT,GAAS,gBAAgBkS,EAAc,sBAAuBgB,EAAgBC,CAAc,EACpH,GAAI,CAACC,EAAiB,CACpB,QAAQ,KAAK,kDAAkD,EAC/D,MACF,CACAA,EAAgB,WAAW,EAAK,EAGhCA,EAAgB,GAAG,iBAAkB,IAAM,CACrCA,EAAgB,WAAU,GAAMA,EAAgB,UAAS,EAAG,YAAW,EAAG,SAAW,GACvF/G,EAAU,+FAA+F,CAE7G,CAAC,EAKD,SAASgH,EAAqBpjB,EAAS,CACrC,MAAMvL,EAAc,IAAIoM,KAAU,aAAab,EAAS,CACtD,kBAAmB,WACzB,CAAK,EACDmjB,EAAgB,UAAS,EAAG,MAAK,EACjCA,EAAgB,UAAS,EAAG,YAAY1uB,CAAW,CACrD,CAEA,GAAI,CAEF,MAAMmW,EAAS,MAAMvsB,GAA0B,EAC/C,GAAIusB,EAAQ,CACV,MAAM5K,EAAU+iB,GAAoBnY,CAAM,EACtC5K,IACF,QAAQ,IAAI,qDAAsDA,EAAQ,SAAS,OAAQ,YAAY,EACvGojB,EAAqBpjB,CAAO,EAEhC,CAGA,GAAI8G,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,gDAAgD,EAC5D,MAAM+U,EAAc,MAAMrU,GAAqB,EAE/C,GAAI,CAACqU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,oDAAqDA,CAAW,EAC7E,MACF,CAEA,MAAMrjC,EAAaqjC,EAAY,KAC/B,QAAQ,IAAI,sCAAuCrjC,EAAW,OAAQ,SAAS,EAG3EA,EAAW,OAAS,GACtB,QAAQ,IAAI,8BAA+B,OAAO,KAAKA,EAAW,CAAC,CAAC,CAAC,EAIvE,MAAMD,GAAuBC,CAAU,EAGvC,MAAMiiB,EAAU+iB,GAAoBhlC,CAAU,EAC9C,GAAI,CAACiiB,EAAS,CACZ,QAAQ,KAAK,wDAAwD,EACrE,MACF,CAEAojB,EAAqBpjB,CAAO,EAC5B,QAAQ,IAAI,8CAA+CA,EAAQ,SAAS,OAAQ,YAAY,CAElG,MAAY4K,GACV,QAAQ,IAAI,sEAAsE,CAGtF,OAAS77B,EAAO,CACd,QAAQ,MAAM,4CAA6CA,CAAK,CAClE,CACF,CAWA,SAASs0C,GAAiBxyC,EAAMorC,EAAW,CACzC,GAAI,CAAC,MAAM,QAAQprC,CAAI,GAAKA,EAAK,SAAW,EAAG,OAAO,KAEtD,MAAMwrC,EAAY,IAAIC,GAChBgH,EAAgB,IAAIziB,GAIpBmiB,EAAW,CAAC,OAAQ,WAAY,MAAO,UAAW,WAAY,OAAQ,MAAM,EAE5E9mC,EAAW,GACjB,UAAWnH,KAAOlE,EAAM,CACtB,MAAMi7B,EAAM/2B,EAAI,MAAQA,EAAI,UAAYA,EAAI,KAAOA,EAAI,SAAWA,EAAI,UAAYA,EAAI,MAAQA,EAAI,KAClG,GAAI,CAAC+2B,EAAK,SAEV,IAAIyX,EACJ,GAAI,CACF,GAAI,OAAOzX,GAAQ,UAAYA,IAAQ,MAAQA,EAAI,KAAM,CAEvD5vB,EAAS,KAAK,CACZ,KAAM,UACN,WAAYsnC,GAAazuC,EAAKiuC,EAAU/G,CAAS,EACjD,SAAUnQ,CACpB,CAAS,EACD,QACF,CACAyX,EAASlH,EAAU,aAAavQ,CAAG,CACrC,OAAS90B,EAAK,CACZ,QAAQ,KAAK,iCAAiCilC,CAAS,IAAKjlC,EAAK80B,GAAK,SAAQ,EAAG,MAAM,EAAG,EAAE,CAAC,EAC7F,QACF,CAEA,MAAM/S,EAAW,KAAK,MAAMuqB,EAAc,cAAcC,CAAM,CAAC,EAC/DrnC,EAAS,KAAK,CACZ,KAAM,UACN,WAAYsnC,GAAazuC,EAAKiuC,EAAU/G,CAAS,EACjD,SAAAljB,CACN,CAAK,CACH,CAEA,OAAI7c,EAAS,SAAW,EAAU,KAC3B,CAAE,KAAM,oBAAqB,SAAAA,CAAQ,CAC9C,CAKA,SAASsnC,GAAazuC,EAAKkkB,EAAUgjB,EAAW,CAC9C,MAAMjhC,EAAQ,CAAE,WAAYihC,CAAS,EACrC,SAAW,CAAC/jC,EAAKjB,CAAK,IAAK,OAAO,QAAQlC,CAAG,EACvCkkB,EAAS,SAAS/gB,CAAG,GACrB,OAAOjB,GAAU,UAAYA,IAAU,OAC3C+D,EAAM9C,CAAG,EAAIjB,GAEf,OAAO+D,CACT,CASA,eAAe+hC,IAAwB,CACrC,MAAM0G,EAAgB,CACpB,YAAa,UACb,YAAa,GACb,gBAAiB,gBACjB,UAAW,eACf,EAEQC,EAAe3T,GAAS,qBAAqB,yBAAyB,EAC5E,QAAQ,IAAI,uCAAwC2T,EAAeA,EAAa,IAAI,OAAO,EAAI,MAAM,EAGrG,MAAMzB,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EACxD0B,EAAgB5T,GAAS,gBAAgBkS,EAAc,qBAAsBwB,EAAeC,CAAY,EAC9G,GAAI,CAACC,EAAe,CAClB,QAAQ,KAAK,iDAAiD,EAC9D,MACF,CAWA,GAVAA,EAAc,WAAW,EAAK,EAG9BA,EAAc,GAAG,iBAAkB,IAAM,CACnCA,EAAc,WAAU,GAAMA,EAAc,UAAS,EAAG,YAAW,EAAG,SAAW,GACnFvH,EAAU,+EAA+E,CAE7F,CAAC,EAGG,CAACtV,EAAQ,GAAM,CAACuF,KAAqB,CACvC,QAAQ,IAAI,wEAAwE,EACpF,MACF,CAEA,GAAI,CACF,QAAQ,IAAI,+CAA+C,EAC3D,MAAM+U,EAAc,MAAMpU,GAAoB,EAE9C,GAAI,CAACoU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,mDAAoDA,CAAW,EAC5E,MACF,CAEA,MAAMvwC,EAAOuwC,EAAY,KACzB,QAAQ,IAAI,qCAAsCvwC,EAAK,OAAQ,MAAM,EACjEA,EAAK,OAAS,GAChB,QAAQ,IAAI,wBAAyB,OAAO,KAAKA,EAAK,CAAC,CAAC,CAAC,EAG3D,MAAMmvB,EAAUqjB,GAAiBxyC,EAAM,oBAAoB,EAC3D,GAAI,CAACmvB,EAAS,CACZ,QAAQ,KAAK,6CAA6C,EAC1D,MACF,CAEA,MAAM9jB,EAAW,IAAI2kB,KAAU,aAAab,EAAS,CAAE,kBAAmB,YAAa,EACvF2jB,EAAc,UAAS,EAAG,MAAK,EAC/BA,EAAc,UAAS,EAAG,YAAYznC,CAAQ,EAC9C,QAAQ,IAAI,mCAAoCA,EAAS,OAAQ,UAAU,CAE7E,OAASnN,EAAO,CACd,QAAQ,MAAM,2CAA4CA,CAAK,CACjE,CACF,CAYA,eAAeiuC,IAAe,CAI5B,MAAM4G,EAAa,CACjB,YAAiB,UACjB,YAAiB,IACjB,gBAAiB,UACjB,gBAAiB,IACjB,UAAiB,gBACjB,gBAAiB,eACrB,EAEQV,EAAiBnT,GAAS,cAAc,CAAmB,GAAK,KACtE,QAAQ,IAAI,8BAA+BmT,EAAiBA,EAAe,IAAI,OAAO,EAAI,MAAM,EAIhG,MAAMjB,EAAe,CAAE,KAAM,oBAAqB,SAAU,EAAE,EACxD4B,EAAa9T,GAAS,gBAAgBkS,EAAc,YAAa2B,EAAYV,CAAc,EACjG,GAAI,CAACW,EAAY,CACf,QAAQ,KAAK,wCAAwC,EACrD,MACF,CACAA,EAAW,WAAW,EAAK,EAG3BA,EAAW,GAAG,iBAAkB,IAAM,CAChCA,EAAW,WAAU,GAAMA,EAAW,UAAS,EAAG,YAAW,EAAG,SAAW,GAC7EzH,EAAU,2EAA2E,CAEzF,CAAC,EAGD,SAAS0H,EAAgBjzC,EAAM,CAC7B,MAAMmvB,EAAUqjB,GAAiBxyC,EAAM,UAAU,EACjD,GAAI,CAACmvB,EACH,eAAQ,KAAK,8CAA8C,EACpD,EAET,MAAM9jB,EAAW,IAAI2kB,KAAU,aAAab,EAAS,CAAE,kBAAmB,YAAa,EACvF,OAAA6jB,EAAW,UAAS,EAAG,MAAK,EAC5BA,EAAW,UAAS,EAAG,YAAY3nC,CAAQ,EACpCA,EAAS,MAClB,CAEA,GAAI,CAEF,MAAM0uB,EAAS,MAAMpsB,GAAgB,EACrC,GAAIosB,EAAQ,CACV,MAAM1tB,EAAI4mC,EAAgBlZ,CAAM,EAChC,QAAQ,IAAI,2CAA4C1tB,EAAG,UAAU,CACvE,CAGA,GAAI4pB,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,sCAAsC,EAClD,MAAM+U,EAAc,MAAMnU,GAAW,EAErC,GAAI,CAACmU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,0CAA2CA,CAAW,EACnE,MACF,CAEA,MAAMvwC,EAAOuwC,EAAY,KACzB,QAAQ,IAAI,4BAA6BvwC,EAAK,OAAQ,MAAM,EACxDA,EAAK,OAAS,GAChB,QAAQ,IAAI,wBAAyB,OAAO,KAAKA,EAAK,CAAC,CAAC,CAAC,EAI3D,MAAMyN,GAAazN,CAAI,EAEvB,MAAMqM,EAAI4mC,EAAgBjzC,CAAI,EAC9B,QAAQ,IAAI,oCAAqCqM,EAAG,UAAU,CAEhE,MAAY0tB,GACV,QAAQ,IAAI,4DAA4D,CAG5E,OAAS77B,EAAO,CACd,QAAQ,MAAM,kCAAmCA,CAAK,CACxD,CACF,CAMA,SAASkuC,IAAwB,CAI/BlN,GAAS,YACP,0BACA,2BACA,sDACA,iCACA,CAAE,WAAY,YAAa,QAAS,GAAO,WAAY,EAAI,CAC/D,EAWEA,GAAS,YACP,0BACA,4BACA,sCACA,aACA,CACE,WAAY,KACZ,MAAO,cACP,QAAS,GACT,QAAS,GACT,OAAQ,IACR,WAAY,GACZ,aACE,qGAEF,UAAW,0EACjB,CACA,CACA,CAQA,eAAe0M,IAAa,CAC1B,MAAMiF,EAAY,mBAMlB,SAASqC,EAAuBv5B,EAAQ,CAGtC,MAAMrF,EAAS,CAAC,GAAGqF,CAAM,EAAE,KAAK,CAAC3L,EAAG4F,IAAMA,EAAE,GAAK5F,EAAE,EAAE,EACrD,UAAW4L,KAAStF,EAClB4qB,GAAS,cAActlB,EAAM,GAAIA,EAAM,KAAMA,EAAM,aAAe,EAAE,EAEtE,QAAQ,IAAI,gBAAiBD,EAAO,OAAQ,qBAAqB,CACnE,CAEA,GAAI,CAEF,MAAMogB,EAAS,MAAMjwB,GAAc+mC,CAAS,EAO5C,GANI9W,IACF,QAAQ,IAAI,kDAAmDA,EAAO,OAAQ,SAAS,EACvFmZ,EAAuBnZ,CAAM,GAI3B9D,EAAQ,GAAMuF,KAAqB,CACrC,QAAQ,IAAI,6CAA6C,EACzD,MAAM+U,EAAc,MAAMxU,GAAS,EAEnC,GAAI,CAACwU,GAAa,SAAW,CAAC,MAAM,QAAQA,GAAa,IAAI,EAAG,CAC9D,QAAQ,KAAK,wCAAyCA,CAAW,EACjE,MACF,CAEA,MAAM52B,EAAS42B,EAAY,KAO3B,GANA,QAAQ,IAAI,mCAAoC52B,EAAO,OAAQ,SAAS,EAGxE,MAAM/P,GAAeinC,EAAWl3B,CAAM,EAGlCogB,EAAQ,CAEV,MAAMoZ,EAAgBjU,GAAS,gBAAe,GAAI,UAAS,EAC3D,GAAIiU,EAAe,CACjB,MAAM7yB,EAAW,GACjB6yB,EAAc,QAASv5B,GAAU,CAC3BA,EAAM,IAAI,SAAS,IAAM,QAC3B0G,EAAS,KAAK1G,CAAK,CAEvB,CAAC,EACD0G,EAAS,QAAS1G,GAAUu5B,EAAc,OAAOv5B,CAAK,CAAC,CACzD,CACF,CAEAs5B,EAAuBv5B,CAAM,EAC7B,QAAQ,IAAI,2CAA2C,CAEzD,MAAYogB,GACV,QAAQ,IAAI,mEAAmE,CAGnF,OAAS77B,EAAO,CACd,QAAQ,MAAM,yCAA0CA,CAAK,CAC/D,CACF,CAMA,eAAeuuC,IAAW,CACxB,GAAI,CAACxW,EAAQ,EAAI,CACf,QAAQ,IAAI,6BAA6B,EACzC,MACF,CAaA,QAAQ,IAAI,0DAA0D,CACxE,CAOA,MAAMmd,GAAqB,GAGrBC,GAAe,CACnB,YAAa,UACb,YAAa,EACb,UAAW,sBACb,EAKA,SAASC,GAAoBlwC,EAAS,CACpCmwC,GAAW,QAASnwC,CAAO,EAC3B,MAAMsV,EAAK,SAAS,eAAe,mBAAmB,EAClDA,IACFA,EAAG,cAAc,eAAe,EAAE,YAActV,EAChDsV,EAAG,UAAU,OAAO,QAAQ,EAC5B,WAAW,IAAMA,EAAG,UAAU,IAAI,QAAQ,EAAG,GAAI,EAErD,CAUA,SAAS86B,GAAmBC,EAAcC,EAAc/hB,EAAK,CAC3D,MAAMgiB,EAAc,MAAM,QAAQF,CAAY,EAAIA,EAAe,CAACA,CAAY,EAE9E,IAAIG,EAAgB,EACpB,UAAW/S,KAAM8S,EAAa,CAC5B,GAAI,CAAC9S,GAAMA,EAAG,OAAS,qBAAuB,CAACA,EAAG,UAAU,OAAQ,SAEpE,MAAMxP,EAAYwP,EAAG,SACjBA,EAAG,SAAS,QAAQ,YAAa,EAAE,EACnC6S,EAEE95B,EAAQslB,GAAS,gBAAgB2B,EAAIxP,EAAWgiB,EAAY,EAC9Dz5B,IAGFA,EAAM,IAAI,YAAa,EAAI,EAC3BA,EAAM,IAAI,UAAW,KAAK,EAC1Bw5B,GAAmB,KAAKx5B,CAAK,EAC7Bg6B,GAAiB/S,EAAG,SAAS,OAM7BgT,GAAYhT,EAAIxP,EAAWzX,CAAK,EAAE,MAAOzT,GACvC,QAAQ,KAAK,yDAA0DA,CAAG,CAClF,EAEE,CAEA,GAAIytC,IAAkB,EAAG,CACvBN,GAAoB,gCAAgC,EACpD,MACF,CAEA,QAAQ,IAAI,IAAI3hB,CAAG,WAAWiiB,CAAa,oBAAoBD,EAAY,MAAM,WAAW,EAG5F,MAAMG,EAAYV,GAAmBA,GAAmB,OAAS,CAAC,EAClE,GAAIU,EAAW,CACb,MAAM7yB,EAAS6yB,EAAU,UAAS,EAAG,UAAS,EAC9C5U,GAAS,OAAM,EAAG,QAAO,EAAG,IAAIje,EAAQ,CAAE,QAAS,CAAC,GAAI,GAAI,GAAI,EAAE,EAAG,QAAS,GAAI,CACpF,CAEA8yB,GAAyB,CAC3B,CAMA,MAAMC,GAAgB,IAAIvI,GAM1B,SAASwI,GAAkB/rB,EAAU,CACnC,OAAO8rB,GAAc,cAAc9rB,EAAU,CAC3C,eAAgB,YAChB,kBAAmB,WACvB,CAAG,CACH,CAeA,eAAe2rB,GAAYhT,EAAIqT,EAAat6B,EAAO,CACjD,MAAM3O,EAAe41B,GAAI,UAAU,QAAU,EAC7C,GAAI51B,IAAiB,EAAG,OAGxB,KAAM,CAAE,GAAIG,CAAQ,EAAK,MAAMP,GAAqB,CAClD,SAAUqpC,GAAe,mBACzB,WAAY,QACZ,aAAAjpC,CACJ,CAAG,EACD2O,EAAM,IAAI,oBAAqBxO,CAAQ,EAIvC,MAAM+oC,EADav6B,EAAM,UAAS,EAAG,YAAW,EAClB,IAAKrO,GAAM,CACvC,MAAM4O,EAAO5O,EAAE,YAAW,EAC1B,MAAO,CACL,aAAc4O,EAAO85B,GAAkB95B,CAAI,EAAI,GAC/C,WAAYwuB,GAAuBp9B,EAAE,eAAe,CAC1D,CACE,CAAC,EACD,MAAMJ,GAA0BC,EAAU+oC,CAAU,EAGpDhR,GAAuB,CACrB,SAAA/3B,EACA,SAAU8oC,EACV,GAAArT,EACA,SAAU,MAAO1iC,GAAW,CAC1B,GAAI,CACF,MAAMi2C,GAAwBhpC,EAAUwO,EAAOzb,CAAM,CACvD,OAASgI,EAAK,CACZ,QAAQ,MAAM,+CAAgDA,CAAG,EACjEolC,EAAU,sCAAwCplC,EAAI,OAAO,CAC/D,CACF,CACJ,CAAG,CACH,CAGA,SAASwiC,GAAuBx+B,EAAO,CACrC,MAAMgd,EAAM,GACZ,SAAW,CAAC9Z,EAAGb,CAAC,IAAK,OAAO,QAAQrC,GAAS,EAAE,EACzCkD,IAAM,aACV8Z,EAAI9Z,CAAC,EAAIb,GAEX,OAAO2a,CACT,CAQA,eAAeitB,GAAwBhpC,EAAUwO,EAAOzb,EAAQ,CAC9D,GAAI,CAACA,GAAUA,EAAO,SAAW,SAAU,CACzCyb,GAAO,IAAI,wBAAyB,OAAO,EAC3Cy6B,GAAyBz6B,CAAK,EAC9B,MACF,CAEA,KAAM,CAAE,OAAAlc,EAAQ,WAAAsN,EAAY,QAAA22B,CAAO,EAAKxjC,EACxC,GAAI,CAAC6M,GAAcA,IAAe,QAAS,CACzC,MAAMU,GAAqBN,EAAU,CAAE,WAAY,QAAS,QAAS,KAAM,OAAQ,QAAS,EAC5FwO,GAAO,IAAI,wBAAyB,OAAO,EAC3Cy6B,GAAyBz6B,CAAK,EAC9B,MACF,CAIA,MAAMzN,GAA+Bf,EAAWjB,GAC9C23B,GAAkB33B,EAAOw3B,CAAO,CACpC,EAEE,MAAMj2B,GAAqBN,EAAU,CAAE,WAAAJ,EAAY,QAAA22B,EAAS,OAAQ,SAAU,EAC9E/nB,GAAO,IAAI,wBAAyB,QAAQ,EAC5CA,GAAO,IAAI,4BAA6B5O,CAAU,EAClDqpC,GAAyBz6B,CAAK,EAE1Blc,IAAW,UACb,MAAM42C,GAAUlpC,EAAUwO,CAAK,CAEnC,CAUA,eAAe06B,GAAUlpC,EAAUwO,EAAO,CACxCA,GAAO,IAAI,wBAAyB,WAAW,EAC/Cy6B,GAAyBz6B,CAAK,EAC9B,GAAI,CACF,MAAMlO,GAAqBN,EAAU,CAAE,OAAQ,WAAW,CAAE,EAE5D,MAAMmpC,EAAM,MAAMtoC,GAAkBb,CAAQ,EACtCC,EAAW,MAAMa,GAA0Bd,CAAQ,EAQnDywB,EAAO,CACX,eARcb,GAAU,GAQC,SAAW,KACpC,OAAQ,CACN,iBAAkBuZ,EAAI,iBACtB,SAAkBA,EAAI,SACtB,cAAkBlpC,EAAS,MACnC,EACM,SAAUA,EAAS,IAAKE,IAAO,CAC7B,YAAaA,EAAE,YACf,KAAaA,EAAE,aACf,MAAaA,EAAE,UACvB,EAAQ,CACR,EAOI,QAAQ,IAAI,WAAY,CACtB,SAAU,UAAUgpC,EAAI,WAAW,yCACnC,YAAaA,EAAI,YACjB,KAAA1Y,CACN,CAAK,EAED,MAAMnwB,GAAqBN,EAAU,CACnC,OAAQ,SACR,eAAgB,IAAI,KAAI,EAAG,YAAW,CAC5C,CAAK,EACDwO,GAAO,IAAI,wBAAyB,QAAQ,EAC5Cy6B,GAAyBz6B,CAAK,EAE9B+xB,GACE,8GAEN,CACE,OAASxlC,EAAK,CACZ,QAAQ,MAAM,wBAAyBA,CAAG,EAC1CyT,GAAO,IAAI,wBAAyB,QAAQ,EAC5Cy6B,GAAyBz6B,CAAK,EAC9B2xB,EAAU,8BAAgCplC,EAAI,OAAO,CACvD,CACF,CAIA,OAAO,iBAAiB,oBAAsBqC,GAAM,CAClD2hC,GAAmB3hC,EAAE,QAAU,EAAE,CACnC,CAAC,EAKD,OAAO,iBAAiB,2BAA6BA,GAAM,CACzD,KAAM,CAAE,SAAA4C,EAAU,OAAAU,EAAQ,MAAA8N,CAAK,EAAKpR,EAAE,QAAU,GAC5CsD,IAAW,UACbwoC,GAAUlpC,EAAUwO,CAAK,EAAE,MAAOzT,GAChC,QAAQ,MAAM,iCAAkCA,CAAG,CACzD,CAEA,CAAC,EAOD,SAASkuC,GAAyBz6B,EAAO,CACvC,GAAI,CAACA,GAAS,CAACslB,EAAS,OACxB,MAAMsV,EAAWtV,EAAQ,OAAM,GAC3B,YAAW,GACX,SAAQ,GACR,KAAMp2B,GAAMA,GAAG,aAAa,OAAS,iBACtBA,GAAG,SAAS,WAAW,SAAS,kBAAkB,CAAC,EAClE0rC,GAAY,OAAOA,EAAS,WAAc,YAC5CA,EAAS,UAAS,CAEtB,CAKA,SAAST,IAA4B,CACnC,MAAMU,EAAS,SAAS,eAAe,sBAAsB,EAC7D,GAAI,CAACA,EAAQ,OAEb,GAAIrB,GAAmB,SAAW,EAAG,CACnCqB,EAAO,UAAY,GACnBA,EAAO,UAAU,IAAI,QAAQ,EAC7B,MACF,CAEAA,EAAO,UAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,YAWnB,MAAMC,EAASD,EAAO,cAAc,uBAAuB,EAC3DrB,GAAmB,QAAQ,CAACtf,EAAG9e,IAAQ,CACrC,MAAMhB,EAAK,SAAS,cAAc,IAAI,EACtCA,EAAG,UAAY,yEACfA,EAAG,UAAY,qCAAqC6uB,EAAW/O,EAAE,IAAI,OAAO,CAAC,CAAC;AAAA;AAAA,uGAEqBA,EAAE,UAAS,EAAG,YAAW,EAAG,MAAM;AAAA,yGAChC9e,CAAG;AAAA;AAAA;AAAA,eAIxG0/B,EAAO,YAAY1gC,CAAE,CACvB,CAAC,EACDygC,EAAO,UAAU,OAAO,QAAQ,EAGhCA,EAAO,iBAAiB,mBAAmB,EAAE,QAAQhwB,GAAO,CAC1DA,EAAI,iBAAiB,QAAS,IAAM,CAClCkwB,GAAoB,OAAOlwB,EAAI,QAAQ,SAAS,CAAC,CACnD,CAAC,CACH,CAAC,EAGDgwB,EAAO,cAAc,yBAAyB,GAAG,iBAAiB,QAAS,IAAM,CAC/EG,GAAoB,CACtB,CAAC,CACH,CAKA,SAASD,GAAoB3/B,EAAK,CAChC,GAAIA,EAAM,GAAKA,GAAOo+B,GAAmB,OAAQ,OACjD,MAAMx5B,EAAQw5B,GAAmBp+B,CAAG,EAC9B6/B,EAAe3V,GAAS,gBAAe,EACzC2V,GACFA,EAAa,UAAS,EAAG,OAAOj7B,CAAK,EAEvCw5B,GAAmB,OAAOp+B,EAAK,CAAC,EAChC++B,GAAyB,EACzB,QAAQ,IAAI,8BAA+Bn6B,EAAM,IAAI,OAAO,CAAC,CAC/D,CAKA,SAASg7B,IAAuB,CAC9B,MAAMC,EAAe3V,GAAS,gBAAe,EAC7C,GAAI2V,EACF,UAAWj7B,KAASw5B,GAClByB,EAAa,UAAS,EAAG,OAAOj7B,CAAK,EAGzCw5B,GAAmB,OAAS,EAC5BW,GAAyB,EACzB,QAAQ,IAAI,0CAA0C,CACxD,CASA,SAASe,GAAsBrN,EAAO,CACpC,MAAMluB,EAAM,GACZ,UAAWhO,KAAKk8B,EAAO,CACrB,MAAM/jB,EAAMnY,EAAE,KAAK,MAAM,GAAG,EAAE,IAAG,EAAG,YAAW,EAC/CgO,EAAImK,CAAG,EAAInY,CACb,CACA,OAAOgO,CACT,CAEA,eAAeg0B,GAAsB/yB,EAAK,CACxC,MAAMitB,EAAQjtB,EAAI,OAAO,MACzB,GAAI,CAACitB,GAASA,EAAM,SAAW,EAAG,OAElC,MAAMsN,EAAgB,IAAM,KAAO,KAC7BC,EAAY,MAAM,KAAKvN,CAAK,EAAE,OAAO,CAAC14B,EAAGxD,IAAMwD,EAAIxD,EAAE,KAAM,CAAC,EAClE,GAAIypC,EAAYD,EAAe,CAC7B,MAAME,GAAUD,EAAa,SAAc,QAAQ,CAAC,EACpD1B,GACE,oBAAoB2B,CAAM,+CAChC,EACIz6B,EAAI,OAAO,MAAQ,GACnB,MACF,CAEA,GAAI,CACF,IAAI2U,EACA+kB,EACJ,MAAMgB,EAAQJ,GAAsBrN,CAAK,EAEzC,GAAIyN,EAAM,IAAK,CACb,MAAMC,EAAOD,EAAM,IACnBhB,EAAciB,EAAK,KAAK,QAAQ,UAAW,EAAE,EAC7C,QAAQ,IAAI,0BAA2BA,EAAK,KAAM,KAAOA,EAAK,KAAO,MAAM,QAAQ,CAAC,EAAI,MAAM,EAE9FhmB,EAAU,MADE,MAAMmb,GAAM,GACJ,MAAM6K,EAAK,YAAW,CAAE,CAE9C,SAAWD,EAAM,IAAK,CACpBhB,EAAcgB,EAAM,IAAI,KAAK,QAAQ,UAAW,EAAE,EAGlD,MAAME,EADW,CAAC,MAAO,MAAO,KAAK,EACZ,OAAO1xB,GAAO,CAACwxB,EAAMxxB,CAAG,CAAC,EAClD,GAAI0xB,EAAQ,OAAS,EAAG,CACtB9B,GAAoB,6BAA+B8B,EAAQ,IAAI5sC,GAAK,IAAMA,CAAC,EAAE,KAAK,IAAI,EAClF,qDAAqD,EACzDgS,EAAI,OAAO,MAAQ,GACnB,MACF,CAEA,MAAM66B,EAAS,GACfA,EAAO,IAAM,MAAMH,EAAM,IAAI,YAAW,EACxCG,EAAO,IAAM,MAAMH,EAAM,IAAI,YAAW,EACxCG,EAAO,IAAM,MAAM,IAAI,SAASH,EAAM,GAAG,EAAE,KAAI,EAC3CA,EAAM,MAAKG,EAAO,IAAM,MAAM,IAAI,SAASH,EAAM,GAAG,EAAE,KAAI,GAE9D,QAAQ,IAAI,mCACV,OAAO,KAAKA,CAAK,EAAE,IAAI1sC,GAAK,IAAMA,CAAC,EAAE,KAAK,IAAI,EAC9C,KAAO0sC,EAAM,IAAI,KAAO,MAAM,QAAQ,CAAC,EAAI,WAAW,EAGxD/lB,EAAU,MADE,MAAMmb,GAAM,GACJ+K,CAAM,CAE5B,KAAO,CACL/B,GAAoB,+CAA+C,EACnE94B,EAAI,OAAO,MAAQ,GACnB,MACF,CAEAg5B,GAAmBrkB,EAAS+kB,EAAa,WAAW,CACtD,OAASh2C,EAAO,CACd,QAAQ,MAAM,sBAAuBA,CAAK,EAC1Co1C,GAAoB,8BAAgCp1C,EAAM,OAAO,CACnE,CAEAsc,EAAI,OAAO,MAAQ,EACrB,CAMA,eAAekzB,GAAoBlzB,EAAK,CACtC,MAAM26B,EAAO36B,EAAI,OAAO,QAAQ,CAAC,EACjC,GAAI,CAAC26B,EAAM,OAIX,MAAMJ,EAAgB,IAAM,KAAO,KACnC,GAAII,EAAK,KAAOJ,EAAe,CAC7B,MAAME,GAAUE,EAAK,KAAQ,SAAc,QAAQ,CAAC,EACpD7B,GACE,mBAAmB2B,CAAM,8GAE/B,EACIz6B,EAAI,OAAO,MAAQ,GACnB,MACF,CAEA,GAAI,CACF,MAAMkS,EAAO,MAAMyoB,EAAK,KAAI,EAC5B,QAAQ,IAAI,0BAA2BA,EAAK,KAAM,KAAOA,EAAK,KAAO,MAAM,QAAQ,CAAC,EAAI,MAAM,EAE9F,MAAMprC,EAAS,KAAK,MAAM2iB,CAAI,EAG9B,IAAImU,EACJ,GAAI92B,EAAO,OAAS,oBAClB82B,EAAK92B,UACIA,EAAO,OAAS,UACzB82B,EAAK,CAAE,KAAM,oBAAqB,SAAU,CAAC92B,CAAM,CAAC,UAC3CA,EAAO,MAAQA,EAAO,YAE/B82B,EAAK,CAAE,KAAM,oBAAqB,SAAU,CAAC,CAAE,KAAM,UAAW,SAAU92B,EAAQ,WAAY,EAAE,CAAE,CAAC,MAC9F,CACLupC,GAAoB,0CAA0C,EAC9D94B,EAAI,OAAO,MAAQ,GACnB,MACF,CAEA,MAAM05B,EAAciB,EAAK,KAAK,QAAQ,iBAAkB,EAAE,EAC1D3B,GAAmB3S,EAAIqT,EAAa,eAAe,CACrD,OAASh2C,EAAO,CACd,QAAQ,MAAM,0BAA2BA,CAAK,EAC9C,MAAM+2C,GAAUE,EAAK,MAAQ,KAAO,OAAO,QAAQ,CAAC,EACpD7B,GACE,qBAAqB6B,EAAK,IAAI,MAAMF,CAAM,SAAS/2C,EAAM,OAAO,EACtE,CACE,CAEAsc,EAAI,OAAO,MAAQ,EACrB,CAMA,eAAeqzB,GAAgBrzB,EAAK,CAClC,MAAM26B,EAAO36B,EAAI,OAAO,QAAQ,CAAC,EACjC,GAAI,CAAC26B,EAAM,OAEX,MAAMJ,EAAgB,IAAM,KAAO,KACnC,GAAII,EAAK,KAAOJ,EAAe,CAC7B,MAAME,GAAUE,EAAK,KAAQ,SAAc,QAAQ,CAAC,EACpD7B,GACE,mBAAmB2B,CAAM,yCAC/B,EACIz6B,EAAI,OAAO,MAAQ,GACnB,MACF,CAEA,GAAI,CACF,MAAMkS,EAAO,MAAMyoB,EAAK,KAAI,EAC5B,QAAQ,IAAI,sBAAuBA,EAAK,KAAM,KAAOA,EAAK,KAAO,MAAM,QAAQ,CAAC,EAAI,MAAM,EAG1F,MAAM9pC,EADY,IAAIiqC,GAAI,CAAE,cAAe,EAAK,CAAE,EACvB,aAAa5oB,EAAM,CAC5C,kBAAmB,WACzB,CAAK,EAED,GAAI,CAACrhB,GAAYA,EAAS,SAAW,EAAG,CACtCioC,GAAoB,oCAAoC,EACxD94B,EAAI,OAAO,MAAQ,GACnB,MACF,CAGA,MAAMi4B,EAAgB,IAAIziB,GACpB6Q,EAAK,KAAK,MAAM4R,EAAc,cAAcpnC,EAAU,CAC1D,kBAAmB,YACnB,eAAgB,WACtB,CAAK,CAAC,EAEI6oC,EAAciB,EAAK,KAAK,QAAQ,UAAW,EAAE,EACnD3B,GAAmB3S,EAAIqT,EAAa,WAAW,CACjD,OAASh2C,EAAO,CACd,QAAQ,MAAM,sBAAuBA,CAAK,EAC1C,MAAM+2C,GAAUE,EAAK,MAAQ,KAAO,OAAO,QAAQ,CAAC,EACpD7B,GACE,qBAAqB6B,EAAK,IAAI,MAAMF,CAAM,SAAS/2C,EAAM,OAAO,EACtE,CACE,CAEAsc,EAAI,OAAO,MAAQ,EACrB,CAWA,SAASszB,IAAkB,CACzB,MAAM11B,EAAY,SAAS,cAAc,gBAAgB,EACzD,GAAI,CAACA,EAAW,OAEhB,IAAIm9B,EAAc,EAElBn9B,EAAU,iBAAiB,YAAc5P,GAAM,CAC7CA,EAAE,eAAc,EAChB+sC,IACAn9B,EAAU,UAAU,IAAI,WAAW,CACrC,CAAC,EAEDA,EAAU,iBAAiB,WAAa5P,GAAM,CAC5CA,EAAE,eAAc,CAClB,CAAC,EAED4P,EAAU,iBAAiB,YAAc5P,GAAM,CAC7CA,EAAE,eAAc,EAChB+sC,IACIA,GAAe,IACjBA,EAAc,EACdn9B,EAAU,UAAU,OAAO,WAAW,EAE1C,CAAC,EAEDA,EAAU,iBAAiB,OAAS5P,GAAM,CACxCA,EAAE,eAAc,EAChB+sC,EAAc,EACdn9B,EAAU,UAAU,OAAO,WAAW,EAEtC,MAAMqvB,EAAQj/B,EAAE,cAAc,MAC9B,GAAI,CAACi/B,GAASA,EAAM,SAAW,EAAG,OAGlC,MAAMyN,EAAQJ,GAAsBrN,CAAK,EACnC+N,EAAO,OAAO,KAAKN,CAAK,EAE9B,GAAIA,EAAM,KAAOA,EAAM,IAAK,CAE1B,MAAMO,EAAU,CAAE,OAAQ,CAAE,MAAAhO,EAAO,MAAO,GAAI,EAC9C,OAAO,eAAegO,EAAQ,OAAQ,QAAS,CAAE,SAAU,GAAM,EACjElI,GAAsBkI,CAAO,CAC/B,SAAWP,EAAM,SAAWA,EAAM,KAAM,CAEtC,MAAMO,EAAU,CAAE,OAAQ,CAAE,MAAO,CADtBP,EAAM,SAAWA,EAAM,IACI,EAAG,MAAO,GAAI,EACtD,OAAO,eAAeO,EAAQ,OAAQ,QAAS,CAAE,SAAU,GAAM,EACjE/H,GAAoB+H,CAAO,CAC7B,SAAWP,EAAM,IAAK,CACpB,MAAMO,EAAU,CAAE,OAAQ,CAAE,MAAO,CAACP,EAAM,GAAG,EAAG,MAAO,GAAI,EAC3D,OAAO,eAAeO,EAAQ,OAAQ,QAAS,CAAE,SAAU,GAAM,EACjE5H,GAAgB4H,CAAO,CACzB,MACEnC,GACE,6BAA+BkC,EAAK,IAAIhtC,GAAK,IAAMA,CAAC,EAAE,KAAK,IAAI,EAC7D,oDACV,CAEE,CAAC,EAED,QAAQ,IAAI,wCAAwC,CACtD,CAMA,SAASq6B,EAAWnW,EAAM,CACxB,MAAMC,EAAM,SAAS,cAAc,KAAK,EACxC,OAAAA,EAAI,YAAcD,EACXC,EAAI,SACb,CAMA,MAAM+oB,GAAkB,GAElBC,GAAa,CACjB,MAAS,CAAE,KAAM,mBAA2B,MAAO,6BAA6B,EAChF,QAAS,CAAE,KAAM,+BAAgC,MAAO,yBAAyB,EACjF,QAAS,CAAE,KAAM,uBAA4B,MAAO,yBAAyB,EAC7E,KAAS,CAAE,KAAM,sBAA4B,MAAO,yBAAyB,CAC/E,EASA,SAASpC,GAAWv1C,EAAM0uB,EAAM,CAC9B,MAAMkpB,EAAMD,GAAW33C,CAAI,GAAK23C,GAAW,MAGzB33C,IAAS,QAAU,QAAQ,MACzCA,IAAS,UAAY,QAAQ,KAC7B,QAAQ,KACF,QAAS0uB,CAAI,EAEvB,MAAMmpB,EAAM,SAAS,eAAe,aAAa,EACjD,GAAI,CAACA,EAAK,OAGV,MAAMC,EAAcD,EAAI,cAAc,aAAa,EAC/CC,GAAaA,EAAY,OAAM,EAGnC,MAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,8CAElB,MAAMj0C,EADM,IAAI,KAAI,EACH,mBAAmB,GAAI,CAAE,KAAM,UAAW,OAAQ,UAAW,OAAQ,SAAS,CAAE,EAYjG,IAXAi0C,EAAM,UACJ,4DACkBH,EAAI,IAAI,qCAAqCA,EAAI,KAAK,oDACxB/S,EAAWnW,CAAI,CAAC,8DACd5qB,CAAI,iBAIxD+zC,EAAI,QAAQE,CAAK,EAGVF,EAAI,SAAS,OAASH,IAC3BG,EAAI,iBAAiB,OAAM,CAE/B,CAGA,SAAS5I,IAAiB,CACxB,MAAMxoB,EAAM,SAAS,eAAe,mBAAmB,EACnDA,GACFA,EAAI,iBAAiB,QAAS,IAAM,CAClC,MAAMoxB,EAAM,SAAS,eAAe,aAAa,EAC7CA,IACFA,EAAI,UAAY,iFAEpB,CAAC,CAEL,CAUA,SAAS5K,IAAkB,CACzB,MAAM+K,EAAW,SAAS,eAAe,aAAa,EAChDppB,EAAW,SAAS,eAAe,YAAY,EAC/CqpB,EAAW,SAAS,eAAe,cAAc,EACjDC,EAAW,SAAS,eAAe,UAAU,EAEnD,GAAI,CAACnX,GAAW,YAAa,CACvBnS,IAAUA,EAAS,YAAc,UACrC,MACF,CAGAmS,GAAW,GAAG,WAAanB,GAAQ,CAC7BhR,IAAUA,EAAS,YAAc,GAAGsQ,GAAYU,EAAI,GAAG,CAAC,KAAKV,GAAYU,EAAI,GAAG,CAAC,IACjFqY,IAAUA,EAAM,YAAc3Y,GAAeM,EAAI,QAAQ,GACzDsY,IAAUA,EAAO,YAAc,GAAGtY,EAAI,YAAc,KAAOA,EAAI,WAAa,GAAG,QAC/EoY,IACFA,EAAQ,UAAU,IAAI,QAAQ,EAC9BA,EAAQ,UAAU,OAAO,eAAgB,eAAgB,cAAc,EACvEA,EAAQ,UAAU,IAAI,WAAazY,GAAgBK,EAAI,QAAQ,CAAC,GAElEsB,GAAS,oBAAoBtB,EAAI,IAAKA,EAAI,IAAKA,EAAI,QAAQ,CAC7D,CAAC,EAGDmB,GAAW,GAAG,QAAUvkB,GAAQ,CAC9B0kB,GAAS,iBAAiB1kB,EAAI,MAAM,IAAKA,EAAI,MAAM,GAAG,CACxD,CAAC,EAEDukB,GAAW,GAAG,QAAU54B,GAAQ,CAC9B,QAAQ,KAAK,QAASA,GAAK,SAAWA,CAAG,EACrCA,GAAOA,EAAI,OAAS,GACtBolC,EAAU,gEAAgE,CAE9E,CAAC,EAGDrM,EAAQ,WAAW,SAAY,CAC7B,GAAI,CACF,MAAMtB,EAAM,MAAMmB,GAAW,mBAAkB,EAC/CG,EAAQ,SAAStB,EAAI,IAAKA,EAAI,IAAK,EAAE,CACvC,OAASz3B,EAAK,CACZolC,EAAU,iCAAmCplC,GAAK,SAAWA,EAAI,CACnE,CACF,CAAC,EAGD+4B,EAAQ,kBAAkB,MAAOpqB,GAAU,CACzC,GAAIA,EACF,GAAI,CACF,MAAM1M,GACN82B,EAAQ,iBAAgB,EACxBA,EAAQ,kBAAkB,EAAI,EAC9B8W,GAAS,UAAU,IAAI,WAAW,EAClC,MAAMjX,GAAW,eAAe,CAAE,KAAM,SAAS,IAAI,OAAO,gBAAgB,GAAI,EAChFuM,GAAY,6BAA6B,CAC3C,OAASnlC,EAAK,CACZ+4B,EAAQ,kBAAkB,EAAK,EAC/B8W,GAAS,UAAU,OAAO,WAAW,EACrCzK,EAAU,+BAAiCplC,GAAK,SAAWA,EAAI,CACjE,KAEA,IAAI,CACF,MAAM3H,EAAM,MAAMugC,GAAW,cAAa,EAG1C,GAFAG,EAAQ,kBAAkB,EAAK,EAC/B8W,GAAS,UAAU,OAAO,WAAW,EACjCx3C,EAAK,CACP,MAAM4hC,EAAM,gBAAgB5hC,EAAI,UAAU,YAAY4+B,GAAe5+B,EAAI,SAAS,CAAC,IAChFA,EAAI,OAAS,YAAc,4BAC9B8sC,GAAYlL,CAAG,CACjB,CACF,OAASj6B,EAAK,CACZolC,EAAU,8BAAgCplC,GAAK,SAAWA,EAAI,CAChE,CAEJ,CAAC,EAGD,MAAMgwC,EAAU,SAAY,CAC1B,GAAKlgB,EAAQ,EACb,GAAI,CACF,MAAM7tB,GACN,MAAMiC,EAAI,MAAM00B,GAAW,YAAW,EAClC10B,EAAE,QAAQ,QAAQ,IAAI,gBAAgBA,EAAE,MAAM,mBAAmB,CACvE,OAAS7B,EAAG,CACV,QAAQ,KAAK,2BAA4BA,CAAC,CAC5C,CACF,EACA2tC,EAAO,EACPngB,GAAiBwW,GAAY,CAAOA,GAAS2J,EAAO,CAAI,CAAC,CAC3D,CAMA,SAAS5K,EAAUnoC,EAAS,CAC1BmwC,GAAW,QAASnwC,CAAO,EAC3B,MAAMsV,EAAK,SAAS,eAAe,eAAe,EAC9CA,IACFA,EAAG,cAAc,eAAe,EAAE,YAActV,EAChDsV,EAAG,UAAU,OAAO,QAAQ,EAC5B,WAAW,IAAMA,EAAG,UAAU,IAAI,QAAQ,EAAG,GAAI,EAErD,CAEA,SAAS4yB,GAAYloC,EAAS,CAC5BmwC,GAAW,UAAWnwC,CAAO,EAC7B,MAAMsV,EAAK,SAAS,eAAe,iBAAiB,EAChDA,IACFA,EAAG,cAAc,eAAe,EAAE,YAActV,EAChDsV,EAAG,UAAU,OAAO,QAAQ,EAC5B,WAAW,IAAMA,EAAG,UAAU,IAAI,QAAQ,EAAG,GAAI,EAErD,CAEA,SAASizB,GAAYvoC,EAAS,CAC5BmwC,GAAW,UAAWnwC,CAAO,EAC7B,MAAMsV,EAAK,SAAS,eAAe,iBAAiB,EAChDA,IACFA,EAAG,cAAc,eAAe,EAAE,YAActV,EAChDsV,EAAG,UAAU,OAAO,QAAQ,EAC5B,WAAW,IAAMA,EAAG,UAAU,IAAI,QAAQ,EAAG,GAAI,EAErD,CAMA,SAASg0B,IAAoB,CAC3B,MAAMne,EAAS,SAAS,eAAe,uBAAuB,EAC9D,GAAI,CAACA,EAAQ,OAGC,aAAa,QAAQ,gBAAgB,IACrC,SACZ,SAAS,gBAAgB,UAAU,IAAI,gBAAgB,EACvDA,EAAO,QAAU,IAGnBA,EAAO,iBAAiB,SAAU,IAAM,CACtC,SAAS,gBAAgB,UAAU,OAAO,iBAAkBA,EAAO,OAAO,EAC1E,aAAa,QAAQ,iBAAkBA,EAAO,OAAO,EACrD,QAAQ,IAAI,4BAA6BA,EAAO,QAAU,KAAO,KAAK,CACxE,CAAC,CACH,CAMA,SAASqe,IAAe,CACtB,MAAMre,EAAS,SAAS,eAAe,kBAAkB,EACzD,GAAI,CAACA,EAAQ,OAEb,SAAS6nB,EAAU1oB,EAAI,CACrB,SAAS,gBAAgB,UAAU,OAAO,YAAaA,CAAE,EAEzD,SAAS,gBAAgB,aAAa,gBAAiBA,EAAK,OAAS,OAAO,CAC9E,CAGc,aAAa,QAAQ,WAAW,IAChC,SACZa,EAAO,QAAU,GACjB6nB,EAAU,EAAI,GAGhB7nB,EAAO,iBAAiB,SAAU,IAAM,CACtC6nB,EAAU7nB,EAAO,OAAO,EACxB,aAAa,QAAQ,YAAaA,EAAO,OAAO,EAChD,QAAQ,IAAI,uBAAwBA,EAAO,QAAU,KAAO,KAAK,CACnE,CAAC,CACH,CAMA,SAASoe,IAAwB,CAC/B,MAAMpe,EAAS,SAAS,eAAe,2BAA2B,EAC5DtK,EAAQ,SAAS,eAAe,0BAA0B,EAChE,GAAI,CAACsK,EAAQ,OAEb,SAAS8nB,GAAc,CACjBpyB,IAAOA,EAAM,YAAcsK,EAAO,QAAU,WAAa,SAC/D,CAGA,MAAM/jB,EAAQ,aAAa,QAAQ,oBAAoB,EACnDA,IAAU,aACZ+jB,EAAO,QAAU,IAEnB8nB,EAAW,EAGXnX,GAAS,iBAAiB10B,GAAS,QAAQ,EAE3C+jB,EAAO,iBAAiB,SAAU,IAAM,CACtC,MAAM7G,EAAS6G,EAAO,QAAU,WAAa,SAC7C,aAAa,QAAQ,qBAAsB7G,CAAM,EACjD2uB,EAAW,EACXnX,GAAS,iBAAiBxX,CAAM,EAChC,QAAQ,IAAI,iCAAkCA,CAAM,CACtD,CAAC,CACH,CAMA,SAASmlB,IAAqB,CAC5B,MAAM9J,EAAS,SAAS,eAAe,wBAAwB,EAC/D,GAAI,CAACA,EAAQ,OAGb,MAAMv4B,EAAQ,aAAa,QAAQ,iBAAiB,GAAK,OACzDu4B,EAAO,MAAQv4B,EAEfu4B,EAAO,iBAAiB,SAAU,IAAM,CACtC,MAAM17B,EAAM07B,EAAO,MACnB,aAAa,QAAQ,kBAAmB17B,CAAG,EAC3C63B,GAAS,WAAW73B,CAAG,EACvB,QAAQ,IAAI,+BAAgCA,CAAG,CACjD,CAAC,EAKD63B,GAAS,OAAM,GAAI,GAAG,gBAAkB1kB,GAAQ,CAC9C,GAAIA,GAAK,KAAOuoB,EAAO,QAAUvoB,EAAI,IAAK,CACxCuoB,EAAO,MAAQvoB,EAAI,IACnB,GAAI,CAAE,aAAa,QAAQ,kBAAmBA,EAAI,GAAG,CAAG,MAAQ,CAAC,CACnE,CACF,CAAC,CACH,CAOA,SAASsyB,IAAuB,CAC9B,MAAMwJ,EAAY,SAAS,eAAe,kBAAkB,EACtD1hB,EAAY,SAAS,eAAe,iBAAiB,EACrD2hB,EAAY,SAAS,eAAe,iBAAiB,EAC3D,GAAI,CAACD,GAAW,CAAC1hB,GAAY,CAAC2hB,EAAW,OAGzC,SAASC,EAAS34C,EAAO,CACvB,OAAKA,EACDA,EAAQ,KAAO,MAAqBA,EAAQ,MAAM,QAAQ,CAAC,EAAI,MAC/DA,EAAQ,KAAO,KAAO,MAAcA,GAAS,KAAO,OAAO,QAAQ,CAAC,EAAI,OACpEA,GAAS,KAAO,KAAO,OAAO,QAAQ,CAAC,EAAI,MAHhC,MAIrB,CAIA,IAAI44C,EAAkB,KAGtB,eAAexjB,GAAU,CACvB,GAAIwjB,EAAiB,OAAOA,EAM5B,MAAMC,EAAW,CAAC,CAAC,UAAU,eAAe,WAC5C,OAAAJ,EAAQ,UAAYI,EAChB,oDACA,wEAEJD,GAAmB,SAAY,CAC7B,GAAI,CACF,MAAMtH,EAAQ,MAAMnY,GAAiB,EAErC,GAAI,CAACmY,EAAO,CACVmH,EAAQ,UAAY;AAAA;AAAA;AAAA,oBAIpB,MACF,CAEA,MAAMxnC,EAAQqgC,EAAM,OACdnvC,EAAOmvC,EAAM,WAChB,OAAQ,GAAM,EAAE,MAAQ,CAAC,EACzB,IAAK,GAAM;AAAA;AAAA,oBAEFtM,EAAW,EAAE,KAAK,CAAC;AAAA,qCACF,EAAE,MAAM,eAAc,CAAE,MAAM,EAAE,MAAM,gBAAgB;AAAA,qCACtD2T,EAAS,EAAE,QAAQ,CAAC;AAAA;AAAA;AAAA,sCAGnB3T,EAAW,EAAE,GAAG,CAAC,iBAAiBA,EAAW,EAAE,KAAK,CAAC;AAAA,uCACpDA,EAAW,EAAE,KAAK,CAAC;AAAA;AAAA;AAAA;AAAA,kBAIxC,EAAE,KAAK,EAAE,EAEnB,IAAI8T,EAAc,GAClB,MAAMC,EAAM,MAAMxf,GAAkB,EACpC,GAAIwf,GAAOA,EAAI,MAAQ,EAAG,CACxB,MAAMC,GAAQD,EAAI,MAAQA,EAAI,MAAS,KAAK,QAAQ,CAAC,EACrDD,EAAc;AAAA;AAAA,mCAEWH,EAASI,EAAI,KAAK,CAAC,OAAOJ,EAASI,EAAI,KAAK,CAAC,eAAeC,CAAG;AAAA,mBAE1F,CAEA,GAAI/nC,EAAM,QAAU,EAAG,CACrBwnC,EAAQ,UAAY;AAAA;AAAA;AAAA,oBAGVK,CAAW,GACrB/hB,EAAS,SAAW,GACpB,MACF,CAEA0hB,EAAQ,UAAY;AAAA;AAAA,sBAENxnC,EAAM,MAAM,eAAc,CAAE,4BAA4B0nC,EAAS1nC,EAAM,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBASjF9O,CAAI;AAAA,oBACL22C,CAAW,GACvB/hB,EAAS,SAAW,GAGpB0hB,EAAQ,iBAAiB,qBAAqB,EAAE,QAAS7xB,GAAQ,CAC/DA,EAAI,iBAAiB,QAAS,MAAOjc,GAAM,CACzCA,EAAE,eAAc,EAChB,MAAM2uB,EAAY1S,EAAI,QAAQ,MACxBR,EAAYQ,EAAI,QAAQ,OAAS0S,EACvC,GAAI,CAAC,QAAQ,iBAAiBlT,CAAK;;AAAA,mFAAgG,EACjI,OAEFQ,EAAI,SAAW,GACJ,MAAMyS,GAA0BC,CAAS,EAElD,QAAQ,IAAI,qCAAqClT,CAAK,EAAE,EAExD,QAAQ,KAAK,6CAA6CA,CAAK,EAAE,EAEnE,MAAMgP,EAAO,CACf,CAAC,CACH,CAAC,CACH,QAAC,CACCwjB,EAAkB,IACpB,CACF,GAAC,EAEMA,CACT,CAGA7hB,EAAS,iBAAiB,QAAS,SAAY,CAC7C,GAAI,CAAC,QAAQ,6FAA6F,EACxG,OAEFA,EAAS,SAAW,GACT,MAAMqC,GAAe,EAE9B,QAAQ,IAAI,gCAAgC,EAE5C,QAAQ,KAAK,oCAAoC,EAEnD,MAAMhE,EAAO,CACf,CAAC,EAGDsjB,EAAU,iBAAiB,oBAAqBtjB,CAAO,EAKvDwD,GAAgC,IAAM,CACpC,QAAQ,IAAI,gEAAgE,EAC5ExD,EAAO,CACT,CAAC,EAIDA,EAAO,CACT,CAMA,SAAS8Z,IAA4B,CACnC,MAAM+J,EAAa,SAAS,eAAe,oBAAoB,EACzDC,EAAa,SAAS,eAAe,wBAAwB,EACnE,GAAI,CAACD,GAAc,CAACC,EAAS,OAE7B,MAAM1U,EAAQe,GAAM,oBAAoB2T,CAAO,EAGzCC,EAAgB,SAAS,eAAe,4BAA4B,EACpEC,EAAgB,SAAS,eAAe,gCAAgC,EACxEC,EAAgB,SAAS,eAAe,4BAA4B,EACpEC,EAAgB,SAAS,eAAe,6BAA6B,EACrEC,EAAgB,SAAS,eAAe,4BAA4B,EACpEC,EAAgB,SAAS,eAAe,iCAAiC,EACzEC,EAAiB,SAAS,eAAe,4BAA4B,EAErEC,EAAgB,SAAS,eAAe,wBAAwB,EAChEC,EAAgB,SAAS,eAAe,kBAAkB,EAC1DC,EAAgB,SAAS,eAAe,kBAAkB,EAC1DC,EAAgB,SAAS,eAAe,mBAAmB,EAC3DC,EAAgB,SAAS,eAAe,yBAAyB,EACjEC,EAAgB,SAAS,eAAe,kBAAkB,EAE1DC,EAAoB,SAAS,eAAe,mBAAmB,EAC/DC,EAAoB,SAAS,eAAe,uBAAuB,EACnEC,EAAoB,SAAS,eAAe,oBAAoB,EAChEC,EAAoB,SAAS,eAAe,wBAAwB,EACpEC,EAAoB,SAAS,eAAe,4BAA4B,EAExEC,EAAkB,SAAS,eAAe,sBAAsB,EAChEC,EAAkB,SAAS,eAAe,0BAA0B,EACpEC,EAAkB,SAAS,eAAe,yBAAyB,EACnEC,EAAkB,SAAS,eAAe,qBAAqB,EAC/DC,EAAkB,SAAS,eAAe,yBAAyB,EACnEC,EAAkB,SAAS,eAAe,sBAAsB,EAEhEC,EAAa,SAAS,eAAe,oBAAoB,EACzDC,EAAa,SAAS,eAAe,qBAAqB,EAGhE,IAAIC,EAAoB,KAGxB,SAASlC,GAAS5iC,EAAG,CACnB,OAAKA,EACDA,EAAI,KAAO,MAAqBA,EAAI,MAAM,QAAQ,CAAC,EAAI,MACvDA,EAAI,KAAO,KAAO,MAAcA,GAAK,KAAO,OAAO,QAAQ,CAAC,EAAI,OAC5DA,GAAK,KAAO,KAAO,OAAO,QAAQ,CAAC,EAAI,MAHhC,MAIjB,CAGA,SAAS+kC,EAAYjd,EAAI,CACvB,GAAI,CAACA,GAAMA,EAAK,IAAM,MAAO,QAC7B,MAAM3sB,EAAI,KAAK,MAAM2sB,EAAK,GAAI,EAC9B,GAAI3sB,EAAI,GAAI,OAAOA,EAAI,KACvB,MAAM6pC,EAAI,KAAK,MAAM7pC,EAAI,EAAE,EACrB1E,GAAI0E,EAAI,GACd,OAAI6pC,EAAI,GAAW,GAAGA,CAAC,QAAQvuC,EAAC,KAEzB,GADG,KAAK,MAAMuuC,EAAI,EAAE,CAChB,MAAMA,EAAI,EAAE,MACzB,CAGA,SAASC,IAAoB,CAC3B,OAAIhB,EAAc,QACT3Y,GAAS,qBAAoB,GAAM,KAExC4Y,EAAkB,QACb5Y,GAAS,6BAA6B,QAAU,KAErD6Y,EAAe,QACV1d,GAEF,IACT,CAGA,SAASye,GAAiB,CACxB,MAAM1f,EAAUme,EAAc,MACxBze,EAAU,SAAS0e,EAAa,MAAO,EAAE,EACzCze,EAAU,SAAS0e,EAAa,MAAO,EAAE,EAE/C,GAAI,OAAO,MAAM3e,CAAI,GAAK,OAAO,MAAMC,CAAI,GAAKD,EAAOC,EAAM,CAC3D4e,EAAW,YAAc,qBACzBC,EAAY,UAAU,QAAQ,aAAc,eAAe,EAC3DR,EAAS,SAAW,GACpB,MACF,CAEA,MAAMn2B,GAAS43B,GAAiB,EAChC,GAAI,CAAC53B,GAAQ,CACX02B,EAAW,YAAc,kCACzBC,EAAY,UAAU,QAAQ,aAAc,eAAe,EAC3DR,EAAS,SAAW,GACpB,MACF,CAEA,MAAM2B,EAAathB,GAAkB2B,CAAO,GAAG,SAAW,GACpD4f,EAAU,KAAK,IAAIjgB,EAAMggB,CAAU,EACnCrqC,GAAQmqB,GAAW5X,GAAQ6X,EAAMkgB,CAAO,EACxCn7C,GAAQ28B,GAAmB9rB,EAAK,EAEtC,IAAIuqC,GAAc,GACdD,EAAUjgB,IACZkgB,GAAc,uCAAuClgB,CAAI,kCAAkCggB,CAAU,oBAAoBA,CAAU,YAEjIrqC,GAAQ,MACVuqC,IAAe,yJAGjBtB,EAAW,UACT,WAAWjpC,GAAM,eAAc,CAAE,sBAC7B8nC,GAAS34C,EAAK,CAAC,GACnBo7C,GAEFrB,EAAY,UAAU,OAAO,gBAAiB,CAAC,CAACqB,EAAW,EAC3DrB,EAAY,UAAU,OAAO,aAAc,CAACqB,EAAW,EAEvD7B,EAAS,SAAW,CAACM,EAAS,SAAWhpC,KAAU,CACrD,CAGA,SAASwqC,IAAkB,CACZha,GAAS,qBAAoB,EAExC8Y,EAAa,YAAc,WAE3BA,EAAa,YAAc,GAGhB9Y,GAAS,0BAAyB,GAE7C+Y,EAAiB,YAAc,GAC/BH,EAAkB,SAAW,KAE7BG,EAAiB,YAAc,0CAC/BH,EAAkB,SAAW,GACzBA,EAAkB,UAASD,EAAc,QAAU,IAE3D,CAGA,SAASsB,IAAa,CACpBnC,EAAS,UAAU,OAAO,QAAQ,EAClCC,EAAa,UAAU,IAAI,QAAQ,EACnCC,EAAS,UAAU,IAAI,QAAQ,EAE/BE,EAAS,UAAU,OAAO,QAAQ,EAClCD,EAAU,UAAU,OAAO,QAAQ,EACnCA,EAAU,YAAc,SACxBE,EAAa,UAAU,IAAI,QAAQ,EACnCC,EAAe,SAAW,GAE1BI,EAAS,QAAU,GACnBN,EAAS,SAAW,GAEpBsB,EAAoB,IACtB,CAIA5B,EAAW,iBAAiB,QAAS,IAAM,CACzCqC,GAAU,EACVD,GAAe,EACfJ,EAAc,EACdzW,EAAM,KAAI,CACZ,CAAC,EAGDkV,EAAc,iBAAiB,SAAUuB,CAAc,EACvDtB,EAAa,iBAAiB,QAASsB,CAAc,EACrDrB,EAAa,iBAAiB,QAASqB,CAAc,EACrDjB,EAAc,iBAAiB,SAAUiB,CAAc,EACvDhB,EAAkB,iBAAiB,SAAUgB,CAAc,EAC3Df,EAAe,iBAAiB,SAAUe,CAAc,EACxDpB,EAAS,iBAAiB,SAAUoB,CAAc,EAGlD1B,EAAS,iBAAiB,QAAS,SAAY,CAC7C,MAAMhe,EAAUme,EAAc,MACxBze,EAAU,SAAS0e,EAAa,MAAO,EAAE,EACzCze,EAAU,SAAS0e,EAAa,MAAO,EAAE,EACzCx2B,GAAU43B,GAAiB,EACjC,GAAI,CAAC53B,GAAQ,OAGb+1B,EAAS,UAAU,IAAI,QAAQ,EAC/BC,EAAa,UAAU,OAAO,QAAQ,EACtCG,EAAS,UAAU,IAAI,QAAQ,EAC/BD,EAAU,YAAc,kBACxBG,EAAe,SAAW,GAE1BY,EAAY,MAAM,MAAQ,KAC1BA,EAAY,aAAa,gBAAiB,GAAG,EAC7CC,EAAgB,YAAc,KAC9BC,EAAe,YAAc,eAC7BC,EAAW,YAAc,IACzBC,EAAe,YAAc,IAC7BC,EAAY,YAAc,IAE1BG,EAAoB,IAAIvf,GAAsB,CAC5C,QAAAC,EACA,WAAYnY,GACZ,QAAY6X,EACZ,QAAYC,EACZ,WAAahqB,GAAM,CACjB,GAAIA,EAAE,MAAQ,EAAG,CACf,MAAM8nC,GAAM,KAAK,IAAI,IAAK,KAAK,MAAO9nC,EAAE,KAAOA,EAAE,MAAS,GAAG,CAAC,EAC9DmpC,EAAY,MAAM,MAAQrB,GAAM,IAChCqB,EAAY,aAAa,gBAAiB,OAAOrB,EAAG,CAAC,EACrDsB,EAAgB,YAActB,GAAM,IACpCuB,EAAe,YAAc,GAAGrpC,EAAE,KAAK,gBAAgB,OAAOA,EAAE,MAAM,eAAc,CAAE,QACxF,CACAspC,EAAW,YAAkBtpC,EAAE,GAAG,eAAc,EAChDupC,EAAe,YAAcvpC,EAAE,OAAO,eAAc,EACpDwpC,EAAY,YAAiBxpC,EAAE,OAAS,KAAO4pC,EAAY5pC,EAAE,KAAK,EAAI,GACxE,CACN,CAAK,EAED,IAAI5Q,EACJ,GAAI,CACFA,EAAS,MAAMu6C,EAAkB,MAAK,CACxC,OAASvyC,EAAK,CACZ,QAAQ,MAAM,4BAA6BA,CAAG,EAC9ChI,EAAS,CAAE,MAAO,QAAS,KAAM,EAAG,MAAO,EAAG,GAAI,EAAG,OAAQ,CAAC,CAChE,CAGA84C,EAAa,UAAU,IAAI,QAAQ,EACnCC,EAAS,UAAU,OAAO,QAAQ,EAClCC,EAAU,UAAU,IAAI,QAAQ,EAChCE,EAAa,UAAU,OAAO,QAAQ,EACtCC,EAAe,SAAW,GAEtBn5C,EAAO,QAAU,aACnBq6C,EAAU,YAAc,qBACxBC,EAAW,UAAY,yBAAyBt6C,EAAO,KAAK,gBAAgB,gBAAgBA,EAAO,MAAM,eAAc,CAAE,cACpHA,EAAO,GAAG,eAAc,CAAE,cAAcA,EAAO,OAAO,eAAc,CAAE,YAClEA,EAAO,QAAU,SAC1Bq6C,EAAU,YAAc,kBACxBC,EAAW,YAAc,6BAEzBD,EAAU,YAAc,oBACxBC,EAAW,UAAY,WAAWt6C,EAAO,GAAG,eAAc,CAAE,0BACzDA,EAAO,OAAS,EAAI,KAAKA,EAAO,OAAO,eAAc,CAAE,UAAY,IACpE,aAAaw6C,EAAYx6C,EAAO,SAAS,CAAC,IAEhD,CAAC,EAGDg5C,EAAU,iBAAiB,QAAS,IAAM,CACpCuB,GACFA,EAAkB,OAAM,CAE5B,CAAC,EAGD3B,EAAQ,iBAAiB,kBAAmB,IAAM,CAC5C2B,GAAmBA,EAAkB,OAAM,EAC/CS,GAAU,CACZ,CAAC,CACH,CAoBA,SAASnM,IAAkB,CACzB,MAAMlS,EAAaE,GAAU,EACvBoe,EAAa,SAAS,eAAe,UAAU,EAC/CC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAa,SAAS,eAAe,gBAAgB,EACrDC,EAAa,SAAS,eAAe,iBAAiB,EACtDC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAa,SAAS,eAAe,kBAAkB,EACvDC,EAAa,SAAS,eAAe,sBAAsB,EAEjE,GAAI,CAACP,GAAW,CAACC,GAAY,CAACC,GAAU,CAACC,GAAW,CAACC,GAAY,CAACC,EAAY,CAC5E,QAAQ,KAAK,gFAAgF,EAC7F,MACF,CAIA,GAFwB,CAAC,CAAC3e,GAAW,CAAC,CAACA,EAAQ,QAE1B,CAEnB,MAAMoZ,EAAc,CAACpZ,EAAQ,MAAOA,EAAQ,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EAAE,KAAI,GACjEA,EAAQ,UAAY,qBAClCtK,GAAWsK,EAAQ,WAAaA,EAAQ,UAAY,KAAK,KAAI,EAAG,OAAO,CAAC,EAAE,YAAW,EAC3Fue,EAAS,YAAc7oB,EACvB6oB,EAAS,MAAM,WAAa,6BAC5BC,EAAO,YAAcpF,EACrBqF,EAAQ,YAAcze,EAAQ,OAAS,GAEvC,MAAM8e,EAAO,GACT9e,EAAQ,aAAe,MAAM8e,EAAK,KAAK,YAAY/W,EAAW,OAAO/H,EAAQ,WAAW,CAAC,CAAC,EAAE,EAC5FA,EAAQ,WAAe,MAAM8e,EAAK,KAAK,UAAU/W,EAAW,OAAO/H,EAAQ,SAAS,CAAC,CAAC,EAAE,EACxFA,EAAQ,aAAqB8e,EAAK,KAAK/W,EAAW/H,EAAQ,WAAW,CAAC,EAC1E0e,EAAS,UAAYI,EAAK,KAAK,KAAK,GAAK,mBAEzCH,EAAW,UAAU,OAAO,QAAQ,EACpCA,EAAW,iBAAiB,QAAS,IAAMI,GAAc/e,CAAO,EAAG,CAAE,KAAM,GAAO,EAClF4e,GAAY,UAAU,IAAI,QAAQ,EAClCC,GAAY,UAAU,IAAI,QAAQ,EAClCP,EAAQ,gBAAgB,YAAY,EACpCA,EAAQ,aAAa,QAAS,UAAUlF,CAAW,EAAE,CACvD,MAAW,OAAO,OAAO,eAAmB,KAE1CmF,EAAS,UAAY,oCACrBA,EAAS,MAAM,WAAa,oCAC5BC,EAAO,YAAc,sBACrBC,EAAQ,YAAc,GACtBC,EAAS,YAAc,GAEvBC,EAAW,UAAU,IAAI,QAAQ,EACjCC,GAAY,UAAU,IAAI,QAAQ,EAClCC,GAAY,UAAU,OAAO,QAAQ,EACrCP,EAAQ,QAAQ,MAAQ,aACxBA,EAAQ,aAAa,QAAS,8BAA8B,IAG5DC,EAAS,UAAY,oCACrBA,EAAS,MAAM,WAAa,oCAC5BC,EAAO,YAAc,gBACrBC,EAAQ,YAAc,GACtBC,EAAS,YAAc,GAEvBC,EAAW,UAAU,IAAI,QAAQ,EACjCC,GAAY,UAAU,OAAO,QAAQ,EACrCC,GAAY,UAAU,IAAI,QAAQ,EAClCP,EAAQ,QAAQ,MAAQ,kBACxBA,EAAQ,aAAa,QAAS,sBAAsB,EAExD,CAgBA,eAAeS,GAAc/e,EAAS,CACpC,GAAI,CAAC,QAAQ,2BAA2BA,GAAS,WAAaA,GAAS,UAAY,MAAM,GAAG,EAC1F,OAIF,MAAMgf,EAAc,SAAS,OAC1B,MAAM,GAAG,EACT,IAAKhxC,GAAMA,EAAE,KAAI,CAAE,EACnB,KAAMA,GAAMA,EAAE,WAAW,iBAAiB,CAAC,GAC1C,MAAM,GAAG,EAAE,CAAC,EAChB,GAAIgxC,EACF,GAAI,CAEF,MAAM,MAAM,6CAA+C,mBAAmBA,CAAW,EAAG,CAC1F,OAAQ,MACR,KAAM,UACN,YAAa,UACb,MAAO,UACf,CAAO,CACH,OAAS3zC,EAAK,CACZ,QAAQ,KAAK,gDAAiDA,CAAG,CACnE,CAKF,MAAM4zC,EAAO,gCACb,SAAS,OAAS,4BAA4BA,CAAI,qCAClD,SAAS,OAAS,4BAA4BA,CAAI,oCAClD,SAAS,OAAS,4BAA4BA,CAAI,WAGlD,OAAO,SAAS,KAAO,2BACzB,CAOI,SAAS,aAAe,UAC1B,SAAS,iBAAiB,mBAAoBhP,EAAO,EAErDA,GAAO","names":["FUNCTION","CHANNEL","GET","HAS","SET","isArray","SharedArrayBuffer","window","notify","wait","waitAsync","postPatched","buffer","onmessage","w","ids","resolvers","postMessage","listener","event","details","id","sb","data","rest","resolve","buff","i","as","Int32Array","Map","Uint16Array","I32_BYTES","UI16_BYTES","waitInterrupt","delay","handler","buffers","context","syncResult","fn","uid","coincident","self","parse","stringify","transform","interrupt","sendMessage","post","transfer","args","decoder","waitFor","isAsync","seppuku","_","action","deadlock","length","bytes","actions","callback","type","results","error","result","serialized","ui16a","createMutex","promise","res","normalizeDatabaseFile","dbFile","convertStreamTo","bufferOrStream","reader","chunks","streamDone","chunk","arrayLength","offset","SQLiteMemoryDriver","sqlite3InitModule","config","databasePath","flags","__vitePreload","statement","statements","tx","prepared","stmt","newStmt","columns","rows","size","database","dataPointer","resultCode","pointer","readOnly","verbose","db","statementData","opMap","_ctx","opId","_db","table","rowid","cb","debounce","func","options","lastArgs","lastThis","maxWait","timerId","lastCallTime","lastInvokeTime","leading","maxing","trailing","invokeFunc","time","thisArg","leadingEdge","timerExpired","remainingWait","timeSinceLastCall","timeSinceLastInvoke","timeWaiting","shouldInvoke","trailingEdge","cancel","flush","debounced","isInvoking","getQueryKey","getDatabaseKey","clientKey","sessionKey","SQLocalProcessor","driver","reason","dbKey","message","change","_transfer","response","partOfTransaction","sql","name","queryKey","errored","proxy","sqlTag","queryTemplate","params","isArrayOfArrays","row","convertRowsToObjects","checkedRows","rowObj","column","columnIndex","isDrizzleStatement","isStatement","normalizeStatement","drizzleStatement","exec","normalizeSql","maybeQueryTemplate","mutationLock","mode","bypass","mutation","SQLiteKvvfsDriver","storageType","memdb","_a","_b","SQLocal","queries","reject","userCallback","method","transactionKey","resultIndex","passStatements","query","passStatement","transaction","err","value","gotFirstValue","isListening","updateCount","watchedTables","subObservers","errObservers","runStatement","updateOrder","usedTables","readTables","writtenTables","observer","onEffect","onData","onError","funcName","key","attachFunction","databaseFile","beforeUnlock","clientConfig","onInit","onConnect","processor","commonConfig","DATABASE_PATH","BROADCAST_CHANNEL","channel","isReady","readyResolve","readyReject","dbReady","changeListeners","onDatabaseChange","payload","e","broadcastChange","initSchema","testResult","tablesAfterLocations","cols","c","allTables","t","addLocation","longitude","latitude","description","category","tableCheck","newId","verifyResult","getLocations","limit","getLocationCount","saveRemoteData","json","getRemoteData","parsed","saveCollectorZones","zones","z","props","getLocalCollectorZones","r","saveUpnGrid","districtId","saved","wkt","numOrNull","getLocalUpnGrid","uuidv4","createExternalImport","opts","filename","targetType","featureCount","clientImportId","addExternalImportFeatures","importId","features","inserted","f","propsJson","cuuid","updateExternalImport","patch","cur","mappingJson","status","errorCount","lastUploadedAt","getExternalImport","getExternalImportFeatures","remapImportedFeatureProperties","remap","n","before","after","v","saveParcels","parcels","p","getLocalParcels","updateParcel","parcelId","insertNewParcel","geometryWkt","saveBuildingFootprints","footprints","first","types","k","rawWkt","rawId","getLocalBuildingFootprints","saveOSMRoads","roads","getLocalOSMRoads","exportDatabase","downloadDatabase","blob","url","a","exportToGeoJSON","loc","getDatabaseStatus","tables","locationCount","CACHED_LAYER_TABLES","isCachedLayerTable","tableName","clearTable","count","clearAllCachedLayers","existing","existingNames","total","s","getTableStats","getTableContent","testDatabase","version","createGpsTrail","meta","uuid","startedAt","addGpsTrailPoint","trailId","point","seq","lon","lat","altitude","accuracy","altitudeAccuracy","heading","speed","satellites","timestamp","recordedAt","finishGpsTrail","summary","endedAt","pointCount","distanceM","getUnsyncedGpsTrails","getGpsTrailPoints","markGpsTrailSynced","remoteId","M_TO_FT","M_TO_MI","SQM_TO_SQFT","SQM_TO_ACRE","SQM_TO_SQMI","getSystem","formatLength","metres","ft","formatLengthFull","mi","formatArea","sqMetres","acres","formatAreaFull","sqft","sqmi","formatCircleExtent","radiusMetres","segmentIntersection","p1","p2","p3","p4","eps","dx1","dy1","dx2","dy2","denom","dx3","dy3","u","signedArea","ring","area","pointInRing","pt","inside","j","xi","yi","xj","yj","dist2","b","findIntersections","line","hits","li","ri","ix","isDup","h","insertPointsIntoRing","sorted","expanded","indices","insertIdx","snapDist","ringSlice","i0","i1","start","end","idx","cuttingLineSlice","hit0","hit1","startSeg","endSeg","ensureWinding","ccw","closeRing","coords","last","extendLineOutsideRing","minX","minY","maxX","maxY","diag","p0","dx","dy","len","scale","pN","pN1","splitPolygonByLine","polygonCoords","lineCoords","exteriorRing","holes","extendedLine","expandedRing","idx0","idx1","iA","iB","cutForward","cutReverse","sliceAB","ringA","sliceBA","ringB","originalCCW","finalA","finalB","polyA","polyB","hole","centroid","holeCentroid","cx","cy","THEMES","container","ensureContainer","showToast","duration","parent","theme","el","dismiss","SPLIT_COLORS","HIGHLIGHT_STYLE","Style","Stroke","Fill","SKETCH_STYLE","CircleStyle","PolygonSplitInteraction","ol_interaction_Interaction","VectorSource","VectorLayer","map","active","sources","collect","layers","layer","hit","clone","best","bestDist","source","feat","geom","closest","distPx","LineString","ol_interaction_Draw","evt","cuttingLine","cuttingLineCoords","feature","coordsA","coordsB","featureA","PolygonGeom","featureB","splitFeatures","distToSegmentSq","segA","segB","lenSq","projX","projY","findClosestEdge","clickCoord","bestIdx","d","coordsEqual","tolSq","isVertexNearRing","findSharedBoundary","seedIdxA","seedIdxB","tolerance","nA","nB","a0","a1","b0","b1","a0NearB","a1NearB","b0NearA","b1NearA","reversed","startA","endA","startB","endB","safety","nextA","nextB","prevA","prevB","walkRing","fromIdx","toIdx","mergePolygons","polygonCoordsA","polygonCoordsB","clickCoordA","clickCoordB","holesA","holesB","seedA","seedB","shared","partA","partB","merged","mergedRing","areaA","areaB","areaMerged","expectedArea","finalRing","validHoles","HIGHLIGHT_A","HIGHLIGHT_B","LABEL_A","Text","LABEL_B","EDGE_STYLE","MERGE_STYLE","PolygonMergeInteraction","skipFeature","style","edge","edgeFeat","Feature","resolution","bestSeg","sourceA","sourceB","geomA","geomB","mergedFeature","evtData","afterEvt","isParcelA","isParcelB","toRemove","cloneA","cloneB","polygonArea","longestEdge","bestLen","bestI","along","perp","makeCuttingLine","origin","extent","centroidT","sx","sy","dividePolygon","edgeCoords","nVerts","perpMin","perpMax","pieces","remaining","remainingCount","remainingArea","targetArea","remRing","remN","rMin","rMax","lo","hi","bestPiece","bestRemaining","bestError","iter","mid","nudge","lineA","resultA","halfA","halfB","tA","tB","nearPiece","farPiece","nearArea","lineB","resultB","pieceColors","colors","hue","PolygonDivideInteraction","ext","center","newFeatures","MapView","targetId","cat","emoji","label","fontSize","baseLayers","LayerGroup","View","fromLonLat","layerSwitcher","LayerSwitcher","btn","baseUrl","_lsChromeScheduled","ScaleLine","searchNominatim","SearchNominatim","searchResult","lonLat","coordinate","Circle","mapLayers","overlayIdx","Select","clickCondition","ModifyFeature","UndoRedo","EditBar","extraBar","Bar","Button","Split","idFields","field","splitLineToggle","Toggle","splitPolyToggle","splitDivideToggle","splitSubBar","splitParentToggle","mergeToggle","editbarEl","breakEl","SnapGuides","VectorImageLayer","drawToolNames","interaction","snapToggleBtn","visible","TouchCursor","listeners","selected","Point","out","isCoord","visitRing","isPolygonRing","poly","walk","sub","system","Overlay","currentFeature","html","catColor","title","color","properties","geometry","geomType","skipKeys","areaSqm","getArea","areaFormatted","lengthM","getLength","lengthFormatted","toLonLat","parcelFeatures","zoneFeatures","otherByLayer","dataRows","names","tableRows","labelColor","border","exportContext","pdfRows","exportAnalysisPDF","gisBtn","arr","circleFeature","circleGeom","circlePoly","fromCircle","circleExtent","radius","intersectsCircle","fExtent","scanGroup","group","groupTitle","layerTitle","candidates","fType","radiusFormatted","polygonFeature","polyGeom","polyExtent","perimeterM","perimeterFormatted","intersectsPoly","typeB","flatB","stride","flatA","strideA","fieldsHtml","displayVal","escapedKey","escapedVal","form","formData","updatedProps","propsA","propsB","getLabel","labelA","labelB","close","chosenProps","labels","radios","updateHighlight","lbl","radio","input","keys","attributeKeys","clickedFeature","text","div","coordsEl","defaultBasemap","topoLayer","TileLayer","XYZ","cartoLightLayer","cartoDarkLayer","osmCycleLayer","OSM","satelliteLayer","googleLayer","osmLayer","baseGroup","matched","on","OPTIONS","target","panel","opt","syncSelection","open","resAtLat","halo","dot","radiusMeters","segments","zoom","toggle","next","customStyle","styles","locations","featureOrId","padding","hasOverlayFeature","hasParcelFeature","markerFeature","index","hoveredFeature","geojson","styleOptions","targetGroup","strokeColor","strokeWidth","strokeDash","fillColor","lineCasingColor","lineCasingWidth","pointRadius","pointFillColor","pointStrokeColor","pointStrokeWidth","GeoJSON","fillStyle","pointStyle","mainStroke","layerStyle","casingW","describeFromGeom","feats","initial","once","ev","desc","wmsSource","TileWMS","wmsLayer","xyzSource","xyzLayer","card","nameRow","nameHint","urlInput","layerName","dlg","inp","wmsSrc","wfsUrl","wfsSource","tag","labelSpan","chip","btnBar","chevronEl","content","ensureSubtitle","removeBtn","chipSpec","fresh","addBtn","visit","removed","child","panelContainer","ul","badge","footer","counts","totalOverlays","activeOverlays","HIDDEN_INTERNAL","refresh","hookLayer","added","legendUrl","wrapper","update","children","str","found","view","src","ex","MapTools","l","drawCircle","Draw","output","radiusLine","unByKey","drawLine","drawPolygon","drawPoint","mainBar","measureBar","circleBtn","lineBtn","areaBtn","clearBtn","swRegistration","registerServiceWorker","newWorker","showUpdateNotification","deferredPrompt","installButton","initInstallPrompt","buttonSelector","showManualInstallInstructions","outcome","isIOS","isSafari","offlineIndicator","offlineListeners","initOfflineDetection","indicatorSelector","updateOfflineUI","notifyOfflineListeners","isOffline","onOfflineChange","isOnline","applyUpdate","getActiveServiceWorker","timeoutMs","ready","timeout","registration","sw","onServiceWorkerControllerChange","requestFromServiceWorker","requestType","responseType","extra","readyTimeoutMs","timer","getTileCacheStats","clearTileCaches","clearTileCacheForProvider","cacheName","getStorageEstimate","usage","quota","initPWA","autoRegisterSW","BASEMAP_TEMPLATES","AVG_TILE_BYTES","ORIGIN_SHIFT","metersToLonLat","x","y","lonLatToTile","latRad","tileRangeForExtent","extent3857","minLon","minLat","maxLon","maxLat","tl","br","minTileX","maxTileX","minTileY","maxTileY","countTiles","minZ","maxZ","enumerateTiles","formatTileUrl","template","OfflineTileDownloader","baseMap","minZoom","maxZoom","concurrency","interBatchDelayMs","onProgress","tpl","tiles","done","ok","failed","cached","emit","phase","elapsedMs","etaMs","batch","GHANA_EXTENT_3857","lonLatToMeters","ne","estimatedSizeBytes","tileCount","API_BASE","FALLBACK_DISTRICT_ID","API_TOKEN","resolveDistrictId","session","API_CREDENTIALS","getSession","raw","REQUEST_TIMEOUT","PING_TIMEOUT","_serverReachable","checkServerReachable","force","controller","isServerReachable","withTimeout","ms","remotePost","endpoint","body","getDistrictBoundary","getLayers","getCollectorZones","getDistrictParcels","getBuildingFootprints","getContoursHillshade","getOSMRoads","getUpnGrid","pushGpsTrail","trail","points","EARTH_RADIUS_M","DEG2RAD","haversineMeters","lon1","lat1","lon2","lat2","dLat","dLon","formatCoord","decimals","formatDistance","meters","formatAccuracy","accuracyQuality","DEFAULTS","GeoTracker","set","pos","fix","trailMeta","synced","pushed","trails","trailRow","minIntervalMs","minDistanceM","heartbeatMs","maxAccuracyM","now","keep","stepM","elapsed","num","ch","sqlocalStorage","remote","remoteSync","geoTracker","KNOWN_COMMANDS","createEmbedBridge","mapView","embedConfig","highlightSource","highlightLayer","parcelsLayer","pendingSelectUpn","readyEmitted","send","emitError","code","emitReady","parcelPayload","outLon","outLat","getCenter","highlightFeature","_markerFeature","parcelFeature","msg","selectByUpn","upn","attachParcelsLayer","drain","scheduled","TARGET_TYPES","TARGET_FIELDS","dominantGeometryFamily","fc","polys","lines","max","attributeFingerprint","sampleSize","has","fp","detectTargetType","family","FIELD_CANDIDATES","normaliseKey","autoMapFields","sourceByNorm","mapping","col","cand","applyFieldMapping","sourceProps","targetCol","sourceKey","listSourceFields","seen","els","modal","state","cacheEls","onTargetChange","finish","renderFieldsTable","optionsHtml","escapeAttr","escapeHtml","current","select","sel","newType","onResult","openImportMappingModal","Modal","fieldsize","lib","char","fieldLength","fieldSize","require$$0","fields","multi","bytesPer","obj","inherit","isDef","o","memo","require$$1","require$$2","structure","field_meta","fieldDescLength","bytesPerRecord","headerLength","val","dbf","prj","coordinates","shpView","shxView","contentLength","fileLength","shpI","shxI","geometries","TYPE","shxOffset","writePolyLine","flattened","justCoords","noParts","parts","featureExtent","onlyParts","no","rings","require$$3","require$$4","pointWriter","require$$6","polyWriter","require$$7","writers","write_1","write","geometry_type","writer","shpLength","shxLength","shpBuffer","shxBuffer","writeHeader","writeExtent","dbfBuf","justType","gj","oftype","isType","justProps","JSZip","zip","files","fileName","generateOptions","download","shpWrite","PROJ_MAP","PROJ_WGS84","exportFeaturesToGis","rename","format","filenameBase","buildRenamedGeoJSON","downloadBlob","writeKml","writeShp","fmt","GeoJSONFormat","geomGeoJson","stripGeometryFromProps","outProps","clones","labelKey","KMLFormat","sanitised","sanitiseShpFieldNames","shpwrite.download","allKeys","used","base","candidate","suffix","newProps","onFormatChange","onExportClick","collectFeatures","ctx","tagWithSource","sourceLabel","unionAttributeKeys","skip","currentFormat","warn","openExportGisModal","def","_shpModule","getShp","mod","mapTools","embedBridge","EMBED_CONFIG","IS_EMBED_PERMIT","currentMode","showNoDistrictBlockerIfNeeded","overlay","initApp","savedBasemap","initGpsTracking","upnGridFeature","showLocationDetails","layerType","loadLocations","showSuccess","showError","wktFormat","WKT","wktString","showWarning","loadLayers","loadDistrictBoundary","loadUpnGrid","loadCollectorZones","loadParcels","loadBuildingFootprints","loadContoursHillshade","loadOSMRoads","loadExternalWMSLayers","initUI","statsContainer","refreshLocalDataStats","offline","syncData","initFieldworkMode","initMeasurementSystem","initDarkMode","initDefaultBasemap","initOfflineTileCache","initOfflineDownloadDialog","initAccountCard","initMessageLog","exportBtn","handleExport","localDataBtn","importShpBtn","shpFileInput","handleShapefileImport","importGeoJSONBtn","geojsonFileInput","handleGeoJSONImport","importKMLBtn","kmlFileInput","handleKMLImport","initMapDropZone","exportGeoJSONBtn","handleExportGeoJSON","statusBtn","handleShowStatus","fitBtn","addLocationBtn","measureCircleBtn","measureLineBtn","measureAreaBtn","drawBtn","modeButtons","setMode","activeBtn","renderLocations","countEl","mobileCount","categoryEmojis","item","tbody","clearAllBtn","stats","link","showTableContent","handleClearAllCachedLayers","modalTitle","modalBody","modalInfo","headerCells","bodyRows","display","statusContent","parseCoordRing","ringStr","pair","parseWKTPolygon","parseWKTMultiPolygon","polyStr","parseWKT","trimmed","apiResponseToGeoJSON","apiResponse","boundary","districtid","district_name","zonesToGeoJSON","zone","CACHE_KEY","boundaryStyle","adminGroup","removeBoundaryLayer","zoomToBoundary","upnGridToGeoJSON","upnGridStyle","emptyGeoJSON","upnGridLayer","UPN_LABEL_MAX_RESOLUTION","prefix","OlText","setFeatures","zoneStyle","zonesLayer","setZoneFeatures","parcelsToGeoJSON","parcel","parcelStyle","landUseGroup","setParcelFeatures","footprintsToGeoJSON","geomKeys","footprintStyle","physInfraGroup","footprintsLayer","setFootprintFeatures","wktRowsToGeoJSON","geojsonFormat","olGeom","flattenProps","contoursStyle","biophysGroup","contoursLayer","roadsStyle","roadsLayer","setRoadFeatures","createLayerGroupsOnMap","overlayLayers","importedFileLayers","IMPORT_STYLE","showFileImportError","logMessage","addImportedGeoJSON","geojsonInput","fallbackName","collections","totalFeatures","stageImport","lastLayer","refreshImportedLayersCard","wktFormat4326","geometryToWkt4326","displayName","stagedRows","handleImportModalResult","refreshLayerSwitcherChip","runUpload","imp","switcher","infoEl","listEl","removeImportedLayer","removeImportedLayers","overlayGroup","indexFilesByExtension","MAX_FILE_SIZE","totalSize","sizeMB","byExt","file","missing","shpObj","KML","dragCounter","exts","fakeEvt","MESSAGE_LOG_MAX","MSG_CONFIG","cfg","log","placeholder","entry","readout","accEl","satsEl","trySync","applyDark","updateLabel","statsEl","offcanvas","fmtBytes","refreshInFlight","swActive","storageNote","est","pct","triggerBtn","modalEl","formView","progressView","doneView","cancelBtn","startBtn","closeDoneBtn","headerCloseBtn","basemapSelect","minZoomInput","maxZoomInput","ackCheck","estimateEl","estimateBox","areaViewRadio","areaDistrictRadio","areaGhanaRadio","areaViewInfo","areaDistrictInfo","progressBar","progressPercent","progressCounts","progressOk","progressFailed","progressEta","doneTitle","doneDetail","currentDownloader","fmtDuration","m","getSelectedExtent","updateEstimate","tplMaxZoom","effMaxZ","warningHTML","updateAreaInfos","resetModal","menuBtn","avatarEl","nameEl","emailEl","detailEl","signoutBtn","signinLink","noSessNote","bits","handleSignOut","cookieToken","past"],"ignoreList":[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54],"sources":["../../node_modules/proxy-target/esm/types.js","../../node_modules/coincident/esm/channel.js","../../node_modules/proxy-target/esm/traps.js","../../node_modules/coincident/esm/bridge.js","../../node_modules/coincident/esm/index.js","../../node_modules/sqlocal/dist/lib/create-mutex.js","../../node_modules/sqlocal/dist/lib/normalize-database-file.js","../../node_modules/sqlocal/dist/drivers/sqlite-memory-driver.js","../../node_modules/sqlocal/dist/lib/debounce.js","../../node_modules/sqlocal/dist/lib/get-query-key.js","../../node_modules/sqlocal/dist/lib/get-database-key.js","../../node_modules/sqlocal/dist/processor.js","../../node_modules/sqlocal/dist/lib/sql-tag.js","../../node_modules/sqlocal/dist/lib/convert-rows-to-objects.js","../../node_modules/sqlocal/dist/lib/normalize-statement.js","../../node_modules/sqlocal/dist/lib/normalize-sql.js","../../node_modules/sqlocal/dist/lib/mutation-lock.js","../../node_modules/sqlocal/dist/drivers/sqlite-kvvfs-driver.js","../../node_modules/sqlocal/dist/client.js","../../src/database.js","../../src/units.js","../../src/geom/polygonSplit.js","../../src/toast.js","../../src/interactions/PolygonSplitInteraction.js","../../src/geom/polygonMerge.js","../../src/interactions/PolygonMergeInteraction.js","../../src/geom/polygonDivide.js","../../src/interactions/PolygonDivideInteraction.js","../../src/components/MapView.js","../../src/components/MapTools.js","../../src/pwa.js","../../src/offlineTiles.js","../../src/remotedb.js","../../src/geotracker/geo-utils.js","../../src/geotracker/GeoTracker.js","../../src/geotracker-lupmis.js","../../src/embed-bridge.js","../../src/import-detect.js","../../src/import-modal.js","../../node_modules/shp-write/src/types.js","../../node_modules/dbf/src/fieldsize.js","../../node_modules/dbf/src/lib.js","../../node_modules/dbf/src/fields.js","../../node_modules/dbf/src/structure.js","../../node_modules/dbf/index.js","../../node_modules/shp-write/src/prj.js","../../node_modules/shp-write/src/extent.js","../../node_modules/shp-write/src/fields.js","../../node_modules/shp-write/src/points.js","../../node_modules/shp-write/src/poly.js","../../node_modules/shp-write/src/write.js","../../node_modules/shp-write/src/geojson.js","../../node_modules/shp-write/src/zip.js","../../node_modules/shp-write/src/download.js","../../node_modules/shp-write/index.js","../../src/gis-export.js","../../src/export-gis-modal.js","../../main.js"],"sourcesContent":["export const ARRAY = 'array';\nexport const BIGINT = 'bigint';\nexport const BOOLEAN = 'boolean';\nexport const FUNCTION = 'function';\nexport const NULL = 'null';\nexport const NUMBER = 'number';\nexport const OBJECT = 'object';\nexport const STRING = 'string';\nexport const SYMBOL = 'symbol';\nexport const UNDEFINED = 'undefined';\n","// ⚠️ AUTOMATICALLY GENERATED - DO NOT CHANGE\nexport const CHANNEL = '64e10b34-2bf7-4616-9668-f99de5aa046e';\n\nexport const MAIN = 'M' + CHANNEL;\nexport const THREAD = 'T' + CHANNEL;\n","export const APPLY = 'apply';\nexport const CONSTRUCT = 'construct';\nexport const DEFINE_PROPERTY = 'defineProperty';\nexport const DELETE_PROPERTY = 'deleteProperty';\nexport const GET = 'get';\nexport const GET_OWN_PROPERTY_DESCRIPTOR = 'getOwnPropertyDescriptor';\nexport const GET_PROTOTYPE_OF = 'getPrototypeOf';\nexport const HAS = 'has';\nexport const IS_EXTENSIBLE = 'isExtensible';\nexport const OWN_KEYS = 'ownKeys';\nexport const PREVENT_EXTENSION = 'preventExtensions';\nexport const SET = 'set';\nexport const SET_PROTOTYPE_OF = 'setPrototypeOf';\n","// The goal of this file is to normalize SAB\n// at least in main -> worker() use cases.\n// This still cannot possibly solve the sync\n// worker -> main() use case if SharedArrayBuffer\n// is not available or usable.\n\nimport {CHANNEL} from './channel.js';\n\nconst {isArray} = Array;\n\nlet {SharedArrayBuffer, window} = globalThis;\nlet {notify, wait, waitAsync} = Atomics;\nlet postPatched = null;\n\n// This is needed for some version of Firefox\nif (!waitAsync) {\n waitAsync = buffer => ({\n value: new Promise(onmessage => {\n // encodeURIComponent('onmessage=({data:b})=>(Atomics.wait(b,0),postMessage(0))')\n let w = new Worker('data:application/javascript,onmessage%3D(%7Bdata%3Ab%7D)%3D%3E(Atomics.wait(b%2C0)%2CpostMessage(0))');\n w.onmessage = onmessage;\n w.postMessage(buffer);\n })\n });\n}\n\n// Monkey-patch SharedArrayBuffer if needed\ntry {\n new SharedArrayBuffer(4);\n}\ncatch (_) {\n SharedArrayBuffer = ArrayBuffer;\n\n const ids = new WeakMap;\n // patch only main -> worker():async use case\n if (window) {\n const resolvers = new Map;\n const {prototype: {postMessage}} = Worker;\n\n const listener = event => {\n const details = event.data?.[CHANNEL];\n if (!isArray(details)) {\n event.stopImmediatePropagation();\n const { id, sb } = details;\n resolvers.get(id)(sb);\n }\n };\n\n postPatched = function (data, ...rest) {\n const details = data?.[CHANNEL];\n if (isArray(details)) {\n const [id, sb] = details;\n ids.set(sb, id);\n this.addEventListener('message', listener);\n }\n return postMessage.call(this, data, ...rest);\n };\n\n waitAsync = sb => ({\n value: new Promise(resolve => {\n resolvers.set(ids.get(sb), resolve);\n }).then(buff => {\n resolvers.delete(ids.get(sb));\n ids.delete(sb);\n for (let i = 0; i < buff.length; i++) sb[i] = buff[i];\n return 'ok';\n })\n });\n }\n else {\n const as = (id, sb) => ({[CHANNEL]: { id, sb }});\n\n notify = sb => {\n postMessage(as(ids.get(sb), sb));\n };\n\n addEventListener('message', event => {\n const details = event.data?.[CHANNEL];\n if (isArray(details)) {\n const [id, sb] = details;\n ids.set(sb, id);\n }\n });\n }\n}\n\nexport {SharedArrayBuffer, isArray, notify, postPatched, wait, waitAsync};\n","/*! (c) Andrea Giammarchi - ISC */\n\nimport {FUNCTION} from 'proxy-target/types';\n\nimport {CHANNEL} from './channel.js';\nimport {GET, HAS, SET} from './shared/traps.js';\n\nimport {SharedArrayBuffer, isArray, notify, postPatched, wait, waitAsync} from './bridge.js';\n\n// just minifier friendly for Blob Workers' cases\nconst {Int32Array, Map, Uint16Array} = globalThis;\n\n// common constants / utilities for repeated operations\nconst {BYTES_PER_ELEMENT: I32_BYTES} = Int32Array;\nconst {BYTES_PER_ELEMENT: UI16_BYTES} = Uint16Array;\n\nconst waitInterrupt = (sb, delay, handler) => {\n while (wait(sb, 0, 0, delay) === 'timed-out')\n handler();\n};\n\n// retain buffers to transfer\nconst buffers = new WeakSet;\n\n// retain either main threads or workers global context\nconst context = new WeakMap;\n\nconst syncResult = {value: {then: fn => fn()}};\n\n// used to generate a unique `id` per each worker `postMessage` \"transaction\"\nlet uid = 0;\n\n/**\n * @typedef {Object} Interrupt used to sanity-check interrupts while waiting synchronously.\n * @prop {function} [handler] a callback invoked every `delay` milliseconds.\n * @prop {number} [delay=42] define `handler` invokes in terms of milliseconds.\n */\n\n/**\n * Create once a `Proxy` able to orchestrate synchronous `postMessage` out of the box.\n * @param {globalThis | Worker} self the context in which code should run\n * @param {{parse: (serialized: string) => any, stringify: (serializable: any) => string, transform?: (value:any) => any, interrupt?: () => void | Interrupt}} [JSON] an optional `JSON` like interface to `parse` or `stringify` content with extra `transform` ability.\n * @returns {ProxyHandler | ProxyHandler}\n */\nconst coincident = (self, {parse = JSON.parse, stringify = JSON.stringify, transform, interrupt} = JSON) => {\n // create a Proxy once for the given context (globalThis or Worker instance)\n if (!context.has(self)) {\n // ensure no SAB gets a chance to pass through this call\n const sendMessage = postPatched || self.postMessage;\n // ensure the CHANNEL and data are posted correctly\n const post = (transfer, ...args) => sendMessage.call(self, {[CHANNEL]: args}, {transfer});\n\n const handler = typeof interrupt === FUNCTION ? interrupt : interrupt?.handler;\n const delay = interrupt?.delay || 42;\n const decoder = new TextDecoder('utf-16');\n\n // automatically uses sync wait (worker -> main)\n // or fallback to async wait (main -> worker)\n const waitFor = (isAsync, sb) => isAsync ?\n waitAsync(sb, 0) :\n ((handler ? waitInterrupt(sb, delay, handler) : wait(sb, 0)), syncResult);\n\n // prevent Harakiri https://github.com/WebReflection/coincident/issues/18\n let seppuku = false;\n\n context.set(self, new Proxy(new Map, {\n // there is very little point in checking prop in proxy for this very specific case\n // and I don't want to orchestrate a whole roundtrip neither, as stuff would fail\n // regardless if from Worker we access non existent Main callback, and vice-versa.\n // This is here mostly to guarantee that if such check is performed, at least the\n // get trap goes through and then it's up to developers guarantee they are accessing\n // stuff that actually exists elsewhere.\n [HAS]: (_, action) => typeof action === 'string' && !action.startsWith('_'),\n\n // worker related: get any utility that should be available on the main thread\n [GET]: (_, action) => action === 'then' ? null : ((...args) => {\n // transaction id\n const id = uid++;\n\n // first contact: just ask for how big the buffer should be\n // the value would be stored at index [1] while [0] is just control\n let sb = new Int32Array(new SharedArrayBuffer(I32_BYTES * 2));\n\n // if a transfer list has been passed, drop it from args\n let transfer = [];\n if (buffers.has(args.at(-1) || transfer))\n buffers.delete(transfer = args.pop());\n\n // ask for invoke with arguments and wait for it\n post(transfer, id, sb, action, transform ? args.map(transform) : args);\n\n // helps deciding how to wait for results\n const isAsync = self !== globalThis;\n\n // warn users about possible deadlock still allowing them\n // to explicitly `proxy.invoke().then(...)` without blocking\n let deadlock = 0;\n if (seppuku && isAsync)\n deadlock = setTimeout(console.warn, 1000, `💀🔒 - Possible deadlock if proxy.${action}(...args) is awaited`);\n\n return waitFor(isAsync, sb).value.then(() => {\n clearTimeout(deadlock);\n\n // commit transaction using the returned / needed buffer length\n const length = sb[1];\n\n // filter undefined results\n if (!length) return;\n\n // calculate the needed ui16 bytes length to store the result string\n const bytes = UI16_BYTES * length;\n\n // round up to the next amount of bytes divided by 4 to allow i32 operations\n sb = new Int32Array(new SharedArrayBuffer(bytes + (bytes % I32_BYTES)));\n\n // ask for results and wait for it\n post([], id, sb);\n return waitFor(isAsync, sb).value.then(() => parse(\n decoder.decode(new Uint16Array(sb.buffer).slice(0, length)))\n );\n });\n }),\n\n // main thread related: react to any utility a worker is asking for\n [SET](actions, action, callback) {\n const type = typeof callback;\n if (type !== FUNCTION)\n throw new Error(`Unable to assign ${action} as ${type}`);\n // lazy event listener and logic handling, triggered once by setters actions\n if (!actions.size) {\n // maps results by `id` as they are asked for\n const results = new Map;\n // add the event listener once (first defined setter, all others work the same)\n self.addEventListener('message', async (event) => {\n // grub the very same library CHANNEL; ignore otherwise\n const details = event.data?.[CHANNEL];\n if (isArray(details)) {\n // if early enough, avoid leaking data to other listeners\n event.stopImmediatePropagation();\n const [id, sb, ...rest] = details;\n let error;\n // action available: it must be defined/known on the main thread\n if (rest.length) {\n const [action, args] = rest;\n if (actions.has(action)) {\n seppuku = true;\n try {\n // await for result either sync or async and serialize it\n const result = await actions.get(action)(...args);\n if (result !== void 0) {\n const serialized = stringify(transform ? transform(result) : result);\n // store the result for \"the very next\" event listener call\n results.set(id, serialized);\n // communicate the required SharedArrayBuffer length out of the\n // resulting serialized string\n sb[1] = serialized.length;\n }\n }\n catch (_) {\n error = _;\n }\n finally {\n seppuku = false;\n }\n }\n // unknown action should be notified as missing on the main thread\n else {\n error = new Error(`Unsupported action: ${action}`);\n }\n // unlock the wait lock later on\n sb[0] = 1;\n }\n // no action means: get results out of the well known `id`\n // wait lock automatically unlocked here as no `0` value would\n // possibly ever land at index `0`\n else {\n const result = results.get(id);\n results.delete(id);\n // populate the SharedArrayBuffer with utf-16 chars code\n for (let ui16a = new Uint16Array(sb.buffer), i = 0; i < result.length; i++)\n ui16a[i] = result.charCodeAt(i);\n }\n // release te worker waiting either the length or the result\n notify(sb, 0);\n if (error) throw error;\n }\n });\n }\n // store this action callback allowing the setter in the process\n return !!actions.set(action, callback);\n }\n }));\n }\n return context.get(self);\n};\n\ncoincident.transfer = (...args) => (buffers.add(args), args);\n\nexport default coincident;\n","export function createMutex() {\n let promise;\n let resolve;\n const lock = async () => {\n while (promise) {\n await promise;\n }\n promise = new Promise((res) => {\n resolve = res;\n });\n };\n const unlock = async () => {\n const res = resolve;\n promise = undefined;\n resolve = undefined;\n res?.();\n };\n return { lock, unlock };\n}\n//# sourceMappingURL=create-mutex.js.map","export async function normalizeDatabaseFile(dbFile, convertStreamTo) {\n let bufferOrStream;\n if (dbFile instanceof Blob) {\n bufferOrStream = dbFile.stream();\n }\n else {\n bufferOrStream = dbFile;\n }\n if (bufferOrStream instanceof ReadableStream && convertStreamTo) {\n const stream = bufferOrStream;\n const reader = stream.getReader();\n switch (convertStreamTo) {\n case 'callback':\n return async () => {\n const chunk = await reader.read();\n return chunk.value;\n };\n case 'buffer':\n const chunks = [];\n let streamDone = false;\n while (!streamDone) {\n const chunk = await reader.read();\n if (chunk.value)\n chunks.push(chunk.value);\n streamDone = chunk.done;\n }\n const arrayLength = chunks.reduce((length, chunk) => {\n return length + chunk.length;\n }, 0);\n const buffer = new Uint8Array(arrayLength);\n let offset = 0;\n chunks.forEach((chunk) => {\n buffer.set(chunk, offset);\n offset += chunk.length;\n });\n return buffer.buffer;\n }\n }\n else {\n return bufferOrStream;\n }\n}\n//# sourceMappingURL=normalize-database-file.js.map","import { normalizeDatabaseFile } from '../lib/normalize-database-file.js';\nexport class SQLiteMemoryDriver {\n constructor(sqlite3InitModule) {\n Object.defineProperty(this, \"sqlite3InitModule\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: sqlite3InitModule\n });\n Object.defineProperty(this, \"sqlite3\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"db\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"config\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"pointers\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: []\n });\n Object.defineProperty(this, \"writeCallbacks\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: new Set()\n });\n Object.defineProperty(this, \"storageType\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: 'memory'\n });\n }\n async init(config) {\n const { databasePath } = config;\n const flags = this.getFlags(config);\n if (!this.sqlite3InitModule) {\n const { default: sqlite3InitModule } = await import('@sqlite.org/sqlite-wasm');\n this.sqlite3InitModule = sqlite3InitModule;\n }\n if (!this.sqlite3) {\n this.sqlite3 = await this.sqlite3InitModule();\n }\n if (this.db) {\n await this.destroy();\n }\n this.db = new this.sqlite3.oo1.DB(databasePath, flags);\n this.config = config;\n this.initWriteHook();\n }\n onWrite(callback) {\n this.writeCallbacks.add(callback);\n return () => {\n this.writeCallbacks.delete(callback);\n };\n }\n async exec(statement) {\n if (!this.db)\n throw new Error('Driver not initialized');\n return this.execOnDb(this.db, statement);\n }\n async execBatch(statements) {\n if (!this.db)\n throw new Error('Driver not initialized');\n const results = [];\n this.db.transaction((tx) => {\n const prepared = new Map();\n try {\n for (let statement of statements) {\n let stmt = prepared.get(statement.sql);\n if (!stmt) {\n const newStmt = tx.prepare(statement.sql);\n prepared.set(statement.sql, newStmt);\n stmt = newStmt;\n }\n if (statement.params?.length) {\n stmt.bind(statement.params);\n }\n let columns = [];\n let rows = [];\n while (stmt.step()) {\n columns = stmt.getColumnNames([]);\n rows.push(stmt.get([]));\n }\n results.push({ columns, rows });\n stmt.reset();\n }\n }\n finally {\n prepared.forEach((stmt) => {\n stmt.finalize();\n });\n }\n });\n return results;\n }\n async isDatabasePersisted() {\n return false;\n }\n async getDatabaseSizeBytes() {\n const sizeResult = await this.exec({\n sql: `SELECT page_count * page_size AS size \n\t\t\t\tFROM pragma_page_count(), pragma_page_size()`,\n method: 'get',\n });\n const size = sizeResult?.rows?.[0];\n if (typeof size !== 'number') {\n throw new Error('Failed to query database size');\n }\n return size;\n }\n async createFunction(fn) {\n if (!this.db)\n throw new Error('Driver not initialized');\n switch (fn.type) {\n case 'callback':\n case 'scalar':\n this.db.createFunction({\n name: fn.name,\n xFunc: (_, ...args) => fn.func(...args),\n arity: -1,\n });\n break;\n case 'aggregate':\n this.db.createFunction({\n name: fn.name,\n xStep: (_, ...args) => fn.func.step(...args),\n xFinal: (_, ...args) => fn.func.final(...args),\n arity: -1,\n });\n break;\n }\n }\n async import(database) {\n if (!this.sqlite3 || !this.db || !this.config) {\n throw new Error('Driver not initialized');\n }\n const data = await normalizeDatabaseFile(database, 'buffer');\n const dataPointer = this.sqlite3.wasm.allocFromTypedArray(data);\n this.pointers.push(dataPointer);\n const resultCode = this.sqlite3.capi.sqlite3_deserialize(this.db, 'main', dataPointer, data.byteLength, data.byteLength, this.config.readOnly\n ? this.sqlite3.capi.SQLITE_DESERIALIZE_READONLY\n : this.sqlite3.capi.SQLITE_DESERIALIZE_RESIZEABLE);\n this.db.checkRc(resultCode);\n }\n async export() {\n if (!this.sqlite3 || !this.db) {\n throw new Error('Driver not initialized');\n }\n return {\n name: 'database.sqlite3',\n data: this.sqlite3.capi.sqlite3_js_db_export(this.db),\n };\n }\n async clear() { }\n async destroy() {\n this.closeDb();\n this.pointers.forEach((pointer) => this.sqlite3?.wasm.dealloc(pointer));\n this.pointers = [];\n this.writeCallbacks.clear();\n }\n getFlags(config) {\n const { readOnly, verbose } = config;\n const parts = [readOnly === true ? 'r' : 'cw', verbose === true ? 't' : ''];\n return parts.join('');\n }\n execOnDb(db, statement) {\n const statementData = {\n rows: [],\n columns: [],\n };\n const rows = db.exec({\n sql: statement.sql,\n bind: statement.params,\n returnValue: 'resultRows',\n rowMode: 'array',\n columnNames: statementData.columns,\n });\n switch (statement.method) {\n case 'run':\n break;\n case 'get':\n statementData.rows = rows[0] ?? [];\n break;\n case 'all':\n default:\n statementData.rows = rows;\n break;\n }\n return statementData;\n }\n initWriteHook() {\n if (!this.config?.reactive)\n return;\n if (!this.sqlite3 || !this.db) {\n throw new Error('Driver not initialized');\n }\n const opMap = {\n [this.sqlite3.capi.SQLITE_INSERT]: 'insert',\n [this.sqlite3.capi.SQLITE_UPDATE]: 'update',\n [this.sqlite3.capi.SQLITE_DELETE]: 'delete',\n };\n this.sqlite3.capi.sqlite3_update_hook(this.db, (_ctx, opId, _db, table, rowid) => {\n this.writeCallbacks.forEach((cb) => {\n cb({ table, rowid, operation: opMap[opId] });\n });\n }, 0);\n }\n closeDb() {\n if (this.db) {\n this.db.close();\n this.db = undefined;\n }\n }\n}\n//# sourceMappingURL=sqlite-memory-driver.js.map","/**\n * Lodash (Custom Build) \n * Build: `lodash modularize exports=\"es\" include=\"debounce\" -p -o ./`\n * Copyright JS Foundation and other contributors \n * Released under MIT license \n * Based on Underscore.js 1.8.3 \n * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors\n */\nexport function debounce(func, wait, options) {\n let lastArgs;\n let lastThis;\n let maxWait;\n let result;\n let timerId;\n let lastCallTime;\n let lastInvokeTime = 0;\n let leading = false;\n let maxing = false;\n let trailing = true;\n if (typeof func !== 'function') {\n throw new TypeError('Expected a function');\n }\n wait = Number(wait) || 0;\n if (typeof options === 'object' && options !== null) {\n leading = !!options.leading;\n maxing = 'maxWait' in options;\n maxWait = maxing ? Math.max(Number(options.maxWait) || 0, wait) : 0;\n trailing = 'trailing' in options ? !!options.trailing : trailing;\n }\n function invokeFunc(time) {\n const args = lastArgs;\n const thisArg = lastThis;\n lastArgs = lastThis = undefined;\n lastInvokeTime = time;\n result = func.apply(thisArg, args);\n return result;\n }\n function leadingEdge(time) {\n lastInvokeTime = time;\n timerId = setTimeout(timerExpired, wait);\n return leading ? invokeFunc(time) : result;\n }\n function remainingWait(time) {\n const timeSinceLastCall = time - (lastCallTime ?? 0);\n const timeSinceLastInvoke = time - lastInvokeTime;\n const timeWaiting = wait - timeSinceLastCall;\n return maxing\n ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke)\n : timeWaiting;\n }\n function shouldInvoke(time) {\n const timeSinceLastCall = time - (lastCallTime ?? 0);\n const timeSinceLastInvoke = time - lastInvokeTime;\n return (lastCallTime === undefined ||\n timeSinceLastCall >= wait ||\n timeSinceLastCall < 0 ||\n (maxing && timeSinceLastInvoke >= maxWait));\n }\n function timerExpired() {\n const time = Date.now();\n if (shouldInvoke(time)) {\n return trailingEdge(time);\n }\n timerId = setTimeout(timerExpired, remainingWait(time));\n }\n function trailingEdge(time) {\n timerId = undefined;\n if (trailing && lastArgs) {\n return invokeFunc(time);\n }\n lastArgs = lastThis = undefined;\n return result;\n }\n function cancel() {\n if (timerId !== undefined) {\n clearTimeout(timerId);\n }\n lastInvokeTime = 0;\n lastArgs = lastCallTime = lastThis = timerId = undefined;\n }\n function flush() {\n return timerId === undefined ? result : trailingEdge(Date.now());\n }\n function debounced() {\n const time = Date.now();\n const isInvoking = shouldInvoke(time);\n // @ts-ignore\n lastArgs = arguments;\n // @ts-ignore\n lastThis = this;\n lastCallTime = time;\n if (isInvoking) {\n if (timerId === undefined) {\n return leadingEdge(lastCallTime);\n }\n if (maxing) {\n timerId = setTimeout(timerExpired, wait);\n return invokeFunc(lastCallTime);\n }\n }\n if (timerId === undefined) {\n timerId = setTimeout(timerExpired, wait);\n }\n return result;\n }\n debounced.cancel = cancel;\n debounced.flush = flush;\n return debounced;\n}\n//# sourceMappingURL=debounce.js.map","export function getQueryKey() {\n return crypto.randomUUID();\n}\n//# sourceMappingURL=get-query-key.js.map","import { getQueryKey } from './get-query-key.js';\nexport function getDatabaseKey(databasePath, clientKey) {\n switch (databasePath) {\n case 'session':\n case ':sessionStorage:':\n // The sessionStorage DB can be shared between clients in the same tab\n let sessionKey = sessionStorage._sqlocal_session_key;\n if (!sessionKey) {\n sessionKey = getQueryKey();\n sessionStorage._sqlocal_session_key = sessionKey;\n }\n return `session:${sessionKey}`;\n case 'local':\n case ':localStorage:':\n // There's only one localStorage DB per origin\n return 'local';\n case ':memory:':\n // Each memory DB is unique to a client\n return `memory:${clientKey}`;\n default:\n // OPFS DBs are shared by path across same-origin tabs\n return `path:${databasePath}`;\n }\n}\n//# sourceMappingURL=get-database-key.js.map","import coincident from 'coincident';\nimport { createMutex } from './lib/create-mutex.js';\nimport { SQLiteMemoryDriver } from './drivers/sqlite-memory-driver.js';\nimport { debounce } from './lib/debounce.js';\nimport { getDatabaseKey } from './lib/get-database-key.js';\nexport class SQLocalProcessor {\n constructor(driver) {\n Object.defineProperty(this, \"driver\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"config\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: {}\n });\n Object.defineProperty(this, \"userFunctions\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: new Map()\n });\n Object.defineProperty(this, \"initMutex\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: createMutex()\n });\n Object.defineProperty(this, \"transactionMutex\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: createMutex()\n });\n Object.defineProperty(this, \"transactionKey\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: null\n });\n Object.defineProperty(this, \"proxy\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"dirtyTables\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: new Set()\n });\n Object.defineProperty(this, \"effectsChannel\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"reinitChannel\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"onmessage\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"init\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (reason) => {\n if (!this.config.databasePath || !this.config.clientKey)\n return;\n await this.initMutex.lock();\n try {\n try {\n await this.driver.init(this.config);\n }\n catch {\n console.warn(`Persistence failed, so ${this.config.databasePath} will not be saved. For origin private file system persistence, make sure your web server is configured to use the correct HTTP response headers (See https://sqlocal.dev/guide/setup#cross-origin-isolation).`);\n this.config.databasePath = ':memory:';\n this.driver = new SQLiteMemoryDriver();\n await this.driver.init(this.config);\n }\n const dbKey = getDatabaseKey(this.config.databasePath, this.config.clientKey);\n this.reinitChannel = new BroadcastChannel(`_sqlocal_reinit_(${dbKey})`);\n this.reinitChannel.onmessage = (event) => {\n const message = event.data;\n if (this.config.clientKey === message.clientKey)\n return;\n switch (message.type) {\n case 'reinit':\n this.init(message.reason);\n break;\n case 'close':\n this.driver.destroy();\n break;\n }\n };\n if (this.config.reactive) {\n this.effectsChannel = new BroadcastChannel(`_sqlocal_effects_(${dbKey})`);\n this.driver.onWrite(async (change) => {\n this.dirtyTables.add(change.table);\n await this.transactionMutex.lock();\n this.emitEffectsDebounced();\n await this.transactionMutex.unlock();\n });\n }\n await Promise.all(Array.from(this.userFunctions.values()).map((fn) => {\n return this.initUserFunction(fn);\n }));\n await this.execInitStatements();\n this.emitMessage({ type: 'event', event: 'connect', reason });\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey: null,\n });\n await this.destroy();\n }\n finally {\n await this.initMutex.unlock();\n }\n }\n });\n Object.defineProperty(this, \"postMessage\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (event, _transfer) => {\n const message = event instanceof MessageEvent ? event.data : event;\n await this.initMutex.lock();\n switch (message.type) {\n case 'config':\n this.editConfig(message);\n break;\n case 'query':\n case 'batch':\n case 'transaction':\n this.exec(message);\n break;\n case 'function':\n this.createUserFunction(message);\n break;\n case 'getinfo':\n this.getDatabaseInfo(message);\n break;\n case 'import':\n this.importDb(message);\n break;\n case 'export':\n this.exportDb(message);\n break;\n case 'delete':\n this.deleteDb(message);\n break;\n case 'destroy':\n this.destroy(message);\n break;\n }\n await this.initMutex.unlock();\n }\n });\n Object.defineProperty(this, \"emitMessage\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: (message, transfer = []) => {\n if (this.onmessage) {\n this.onmessage(message, transfer);\n }\n }\n });\n Object.defineProperty(this, \"emitEffects\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: () => {\n if (!this.effectsChannel || this.dirtyTables.size === 0)\n return;\n this.effectsChannel.postMessage({\n type: 'effects',\n tables: [...this.dirtyTables],\n });\n this.dirtyTables.clear();\n }\n });\n Object.defineProperty(this, \"emitEffectsDebounced\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: debounce(() => this.emitEffects(), 32, {\n maxWait: 180,\n })\n });\n Object.defineProperty(this, \"editConfig\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: (message) => {\n this.config = message.config;\n this.init('initial');\n }\n });\n Object.defineProperty(this, \"exec\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n try {\n const response = {\n type: 'data',\n queryKey: message.queryKey,\n data: [],\n };\n switch (message.type) {\n case 'query':\n const partOfTransaction = this.transactionKey !== null &&\n this.transactionKey === message.transactionKey;\n try {\n if (!partOfTransaction) {\n await this.transactionMutex.lock();\n }\n const statementData = await this.driver.exec(message);\n response.data.push(statementData);\n }\n finally {\n if (!partOfTransaction) {\n await this.transactionMutex.unlock();\n }\n }\n break;\n case 'batch':\n try {\n await this.transactionMutex.lock();\n const results = await this.driver.execBatch(message.statements);\n response.data.push(...results);\n }\n finally {\n await this.transactionMutex.unlock();\n }\n break;\n case 'transaction':\n if (message.action === 'begin') {\n await this.transactionMutex.lock();\n this.transactionKey = message.transactionKey;\n await this.driver.exec({ sql: 'BEGIN' });\n }\n if ((message.action === 'commit' || message.action === 'rollback') &&\n this.transactionKey !== null &&\n this.transactionKey === message.transactionKey) {\n const sql = message.action === 'commit' ? 'COMMIT' : 'ROLLBACK';\n await this.driver.exec({ sql });\n this.transactionKey = null;\n await this.transactionMutex.unlock();\n }\n break;\n }\n this.emitMessage(response);\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey: message.queryKey,\n });\n }\n }\n });\n Object.defineProperty(this, \"execInitStatements\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n if (this.config.onInitStatements) {\n for (let statement of this.config.onInitStatements) {\n await this.driver.exec(statement);\n }\n }\n }\n });\n Object.defineProperty(this, \"getDatabaseInfo\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n try {\n this.emitMessage({\n type: 'info',\n queryKey: message.queryKey,\n info: {\n databasePath: this.config.databasePath,\n storageType: this.driver.storageType,\n databaseSizeBytes: await this.driver.getDatabaseSizeBytes(),\n persisted: await this.driver.isDatabasePersisted(),\n },\n });\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n queryKey: message.queryKey,\n error,\n });\n }\n }\n });\n Object.defineProperty(this, \"createUserFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n const { functionName: name, functionType: type, queryKey } = message;\n let fn;\n if (this.userFunctions.has(name)) {\n this.emitMessage({\n type: 'error',\n error: new Error(`A user-defined function with the name \"${name}\" has already been created for this SQLocal instance.`),\n queryKey,\n });\n return;\n }\n switch (type) {\n case 'callback':\n fn = {\n type,\n name,\n func: (...args) => {\n this.emitMessage({ type: 'callback', name, args });\n },\n };\n break;\n case 'scalar':\n fn = {\n type,\n name,\n func: this.proxy[`_sqlocal_func_${name}`],\n };\n break;\n case 'aggregate':\n fn = {\n type,\n name,\n func: {\n step: this.proxy[`_sqlocal_func_${name}_step`],\n final: this.proxy[`_sqlocal_func_${name}_final`],\n },\n };\n break;\n }\n try {\n await this.initUserFunction(fn);\n this.emitMessage({\n type: 'success',\n queryKey,\n });\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey,\n });\n }\n }\n });\n Object.defineProperty(this, \"initUserFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (fn) => {\n await this.driver.createFunction(fn);\n this.userFunctions.set(fn.name, fn);\n }\n });\n Object.defineProperty(this, \"importDb\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n const { queryKey, database } = message;\n let errored = false;\n try {\n await this.driver.import(database);\n if (this.driver.storageType === 'memory') {\n await this.execInitStatements();\n }\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey,\n });\n errored = true;\n }\n finally {\n if (this.driver.storageType !== 'memory') {\n await this.init('overwrite');\n }\n }\n if (!errored) {\n this.emitMessage({\n type: 'success',\n queryKey,\n });\n }\n }\n });\n Object.defineProperty(this, \"exportDb\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n const { queryKey } = message;\n try {\n const { name, data } = await this.driver.export();\n this.emitMessage({\n type: 'buffer',\n queryKey,\n bufferName: name,\n buffer: data,\n }, [data]);\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey,\n });\n }\n }\n });\n Object.defineProperty(this, \"deleteDb\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n const { queryKey } = message;\n let errored = false;\n try {\n await this.driver.clear();\n }\n catch (error) {\n this.emitMessage({\n type: 'error',\n error,\n queryKey,\n });\n errored = true;\n }\n finally {\n await this.init('delete');\n }\n if (!errored) {\n this.emitMessage({\n type: 'success',\n queryKey,\n });\n }\n }\n });\n Object.defineProperty(this, \"destroy\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n await this.driver.exec({ sql: 'PRAGMA optimize' });\n await this.driver.destroy();\n if (this.effectsChannel) {\n this.emitEffectsDebounced.flush();\n this.effectsChannel.close();\n this.effectsChannel = undefined;\n }\n if (this.reinitChannel) {\n this.reinitChannel.close();\n this.reinitChannel = undefined;\n }\n if (message) {\n this.emitMessage({\n type: 'success',\n queryKey: message.queryKey,\n });\n }\n }\n });\n const isInWorker = typeof WorkerGlobalScope !== 'undefined' &&\n globalThis instanceof WorkerGlobalScope;\n const proxy = isInWorker ? coincident(globalThis) : globalThis;\n this.proxy = proxy;\n this.driver = driver;\n }\n}\n//# sourceMappingURL=processor.js.map","export function sqlTag(queryTemplate, ...params) {\n return {\n sql: queryTemplate.join('?'),\n params,\n };\n}\n//# sourceMappingURL=sql-tag.js.map","function isArrayOfArrays(rows) {\n return !rows.some((row) => !Array.isArray(row));\n}\nexport function convertRowsToObjects(rows, columns) {\n let checkedRows;\n if (isArrayOfArrays(rows)) {\n checkedRows = rows;\n }\n else {\n checkedRows = [rows];\n }\n return checkedRows.map((row) => {\n const rowObj = {};\n columns.forEach((column, columnIndex) => {\n rowObj[column] = row[columnIndex];\n });\n return rowObj;\n });\n}\n//# sourceMappingURL=convert-rows-to-objects.js.map","import { sqlTag } from './sql-tag.js';\nfunction isDrizzleStatement(statement) {\n return (typeof statement === 'object' &&\n statement !== null &&\n 'getSQL' in statement &&\n typeof statement.getSQL === 'function');\n}\nfunction isStatement(statement) {\n return (typeof statement === 'object' &&\n statement !== null &&\n 'sql' in statement === true &&\n typeof statement.sql === 'string' &&\n 'params' in statement === true);\n}\nexport function normalizeStatement(statement) {\n if (typeof statement === 'function') {\n statement = statement(sqlTag);\n }\n if (isDrizzleStatement(statement)) {\n try {\n if (!('toSQL' in statement && typeof statement.toSQL === 'function')) {\n throw 1;\n }\n const drizzleStatement = statement.toSQL();\n if (!isStatement(drizzleStatement)) {\n throw 2;\n }\n const exec = 'all' in statement && typeof statement.all === 'function'\n ? statement.all\n : undefined;\n return {\n ...drizzleStatement,\n exec: exec ? () => exec() : undefined,\n };\n }\n catch {\n throw new Error('The passed statement could not be parsed.');\n }\n }\n const sql = statement.sql;\n let params = [];\n if ('params' in statement) {\n params = statement.params;\n }\n else if ('parameters' in statement) {\n params = statement.parameters;\n }\n return { sql, params };\n}\n//# sourceMappingURL=normalize-statement.js.map","import { sqlTag } from './sql-tag.js';\nexport function normalizeSql(maybeQueryTemplate, params) {\n let statement;\n if (typeof maybeQueryTemplate === 'string') {\n statement = { sql: maybeQueryTemplate, params };\n }\n else {\n statement = sqlTag(maybeQueryTemplate, ...params);\n }\n return statement;\n}\n//# sourceMappingURL=normalize-sql.js.map","export async function mutationLock(mode, bypass, config, mutation) {\n if (!bypass && 'locks' in navigator) {\n return navigator.locks.request(`_sqlocal_mutation_(${config.databasePath})`, { mode }, mutation);\n }\n else {\n return mutation();\n }\n}\n//# sourceMappingURL=mutation-lock.js.map","import { SQLiteMemoryDriver } from './sqlite-memory-driver.js';\nexport class SQLiteKvvfsDriver extends SQLiteMemoryDriver {\n constructor(storageType, sqlite3InitModule) {\n super(sqlite3InitModule);\n Object.defineProperty(this, \"storageType\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: storageType\n });\n }\n async init(config) {\n const flags = this.getFlags(config);\n if (config.readOnly) {\n throw new Error(`SQLite storage type \"${this.storageType}\" does not support read-only mode.`);\n }\n if (!this.sqlite3InitModule) {\n const { default: sqlite3InitModule } = await import('@sqlite.org/sqlite-wasm');\n this.sqlite3InitModule = sqlite3InitModule;\n }\n if (!this.sqlite3) {\n this.sqlite3 = await this.sqlite3InitModule();\n }\n if (this.db) {\n await this.destroy();\n }\n this.db = new this.sqlite3.oo1.JsStorageDb({\n filename: this.storageType,\n flags,\n });\n this.config = config;\n this.initWriteHook();\n }\n async isDatabasePersisted() {\n return navigator.storage?.persisted();\n }\n async getDatabaseSizeBytes() {\n if (!this.db)\n throw new Error('Driver not initialized');\n return this.db.storageSize();\n }\n async import(database) {\n const memdb = new SQLiteMemoryDriver();\n await memdb.init({});\n await memdb.import(database);\n await this.clear();\n await memdb.exec({\n sql: `VACUUM INTO 'file:${this.storageType}?vfs=kvvfs'`,\n });\n await memdb.destroy();\n }\n async clear() {\n if (!this.db)\n throw new Error('Driver not initialized');\n this.db.clearStorage();\n }\n async destroy() {\n this.closeDb();\n this.writeCallbacks.clear();\n }\n}\n//# sourceMappingURL=sqlite-kvvfs-driver.js.map","var _a, _b;\nimport coincident from 'coincident';\nimport { SQLocalProcessor } from './processor.js';\nimport { sqlTag } from './lib/sql-tag.js';\nimport { convertRowsToObjects } from './lib/convert-rows-to-objects.js';\nimport { normalizeStatement } from './lib/normalize-statement.js';\nimport { getQueryKey } from './lib/get-query-key.js';\nimport { normalizeSql } from './lib/normalize-sql.js';\nimport { mutationLock } from './lib/mutation-lock.js';\nimport { normalizeDatabaseFile } from './lib/normalize-database-file.js';\nimport { SQLiteMemoryDriver } from './drivers/sqlite-memory-driver.js';\nimport { SQLiteKvvfsDriver } from './drivers/sqlite-kvvfs-driver.js';\nimport { getDatabaseKey } from './lib/get-database-key.js';\nexport class SQLocal {\n constructor(config) {\n Object.defineProperty(this, \"config\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"clientKey\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"processor\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"isDestroyed\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: false\n });\n Object.defineProperty(this, \"bypassMutationLock\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: false\n });\n Object.defineProperty(this, \"transactionQueryKeyQueue\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: []\n });\n Object.defineProperty(this, \"userCallbacks\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: new Map()\n });\n Object.defineProperty(this, \"queriesInProgress\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: new Map()\n });\n Object.defineProperty(this, \"proxy\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"reinitChannel\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"effectsChannel\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: void 0\n });\n Object.defineProperty(this, \"processMessageEvent\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: (event) => {\n const message = event instanceof MessageEvent ? event.data : event;\n const queries = this.queriesInProgress;\n switch (message.type) {\n case 'success':\n case 'data':\n case 'buffer':\n case 'info':\n case 'error':\n if (message.queryKey && queries.has(message.queryKey)) {\n const [resolve, reject] = queries.get(message.queryKey);\n if (message.type === 'error') {\n reject(message.error);\n }\n else {\n resolve(message);\n }\n queries.delete(message.queryKey);\n }\n else if (message.type === 'error') {\n throw message.error;\n }\n break;\n case 'callback':\n const userCallback = this.userCallbacks.get(message.name);\n if (userCallback) {\n userCallback(...(message.args ?? []));\n }\n break;\n case 'event':\n this.config.onConnect?.(message.reason);\n break;\n }\n }\n });\n Object.defineProperty(this, \"createQuery\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (message) => {\n return mutationLock('shared', this.bypassMutationLock ||\n message.type === 'import' ||\n message.type === 'delete', this.config, async () => {\n if (this.isDestroyed === true) {\n throw new Error('This SQLocal client has been destroyed. You will need to initialize a new client in order to make further queries.');\n }\n const queryKey = getQueryKey();\n switch (message.type) {\n case 'import':\n this.processor.postMessage({\n ...message,\n queryKey,\n }, [message.database]);\n break;\n default:\n this.processor.postMessage({\n ...message,\n queryKey,\n });\n break;\n }\n return new Promise((resolve, reject) => {\n this.queriesInProgress.set(queryKey, [resolve, reject]);\n });\n });\n }\n });\n Object.defineProperty(this, \"broadcast\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: (message) => {\n this.reinitChannel.postMessage(message);\n }\n });\n Object.defineProperty(this, \"exec\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (sql, params, method = 'all', transactionKey) => {\n const message = await this.createQuery({\n type: 'query',\n transactionKey,\n sql,\n params,\n method,\n });\n const data = {\n rows: [],\n columns: [],\n };\n if (message.type === 'data') {\n data.rows = message.data[0]?.rows ?? [];\n data.columns = message.data[0]?.columns ?? [];\n }\n return data;\n }\n });\n Object.defineProperty(this, \"execBatch\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (statements) => {\n const message = await this.createQuery({\n type: 'batch',\n statements,\n });\n const data = new Array(statements.length).fill({\n rows: [],\n columns: [],\n });\n if (message.type === 'data') {\n message.data.forEach((result, resultIndex) => {\n data[resultIndex] = result;\n });\n }\n return data;\n }\n });\n Object.defineProperty(this, \"sql\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (queryTemplate, ...params) => {\n const statement = normalizeSql(queryTemplate, params);\n const { rows, columns } = await this.exec(statement.sql, statement.params, 'all');\n const resultRecords = convertRowsToObjects(rows, columns);\n return resultRecords;\n }\n });\n Object.defineProperty(this, \"batch\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (passStatements) => {\n const statements = passStatements(sqlTag);\n const data = await this.execBatch(statements);\n return data.map(({ rows, columns }) => {\n const resultRecords = convertRowsToObjects(rows, columns);\n return resultRecords;\n });\n }\n });\n Object.defineProperty(this, \"beginTransaction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n const transactionKey = getQueryKey();\n await this.createQuery({\n type: 'transaction',\n transactionKey,\n action: 'begin',\n });\n const query = async (passStatement) => {\n const statement = normalizeStatement(passStatement);\n if (statement.exec) {\n this.transactionQueryKeyQueue.push(transactionKey);\n return statement.exec();\n }\n const { rows, columns } = await this.exec(statement.sql, statement.params, 'all', transactionKey);\n const resultRecords = convertRowsToObjects(rows, columns);\n return resultRecords;\n };\n const sql = async (queryTemplate, ...params) => {\n const statement = normalizeSql(queryTemplate, params);\n const resultRecords = await query(statement);\n return resultRecords;\n };\n const commit = async () => {\n await this.createQuery({\n type: 'transaction',\n transactionKey,\n action: 'commit',\n });\n };\n const rollback = async () => {\n await this.createQuery({\n type: 'transaction',\n transactionKey,\n action: 'rollback',\n });\n };\n return {\n query,\n sql,\n commit,\n rollback,\n };\n }\n });\n Object.defineProperty(this, \"transaction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (transaction) => {\n return mutationLock('exclusive', false, this.config, async () => {\n let tx;\n this.bypassMutationLock = true;\n try {\n tx = await this.beginTransaction();\n const result = await transaction({\n sql: tx.sql,\n query: tx.query,\n });\n await tx.commit();\n return result;\n }\n catch (err) {\n await tx?.rollback();\n throw err;\n }\n finally {\n this.bypassMutationLock = false;\n }\n });\n }\n });\n Object.defineProperty(this, \"reactiveQuery\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: (passStatement) => {\n let value = [];\n let gotFirstValue = false;\n let isListening = false;\n let updateCount = 0;\n const statement = normalizeStatement(passStatement);\n const watchedTables = new Set();\n const subObservers = new Set();\n const errObservers = new Set();\n const runStatement = async () => {\n try {\n const updateOrder = ++updateCount;\n if (watchedTables.size === 0) {\n const usedTables = await this.sql(\"SELECT name, wr FROM tables_used(?) WHERE type = 'table'\", statement.sql);\n const readTables = new Set();\n const writtenTables = new Set();\n usedTables.forEach((table) => {\n if (typeof table.name !== 'string')\n return;\n table.wr\n ? writtenTables.add(table.name)\n : readTables.add(table.name);\n });\n if (readTables.size === 0) {\n throw new Error('The passed SQL does not read any tables.');\n }\n if (Array.from(writtenTables).some((table) => readTables.has(table))) {\n throw new Error('The passed SQL would mutate one or more of the tables that it reads. Doing this in a reactive query would create an infinite loop.');\n }\n readTables.forEach((name) => watchedTables.add(name));\n }\n const results = statement.exec\n ? await statement.exec()\n : await this.sql(statement.sql, ...statement.params);\n if (updateOrder === updateCount) {\n value = results;\n gotFirstValue = true;\n subObservers.forEach((observer) => observer(value));\n }\n }\n catch (err) {\n errObservers.forEach((observer) => {\n observer(err instanceof Error ? err : new Error(String(err)));\n });\n }\n };\n const onEffect = (message) => {\n if (message.data.tables.some((table) => watchedTables.has(table))) {\n runStatement();\n }\n };\n return {\n get value() {\n return value;\n },\n subscribe: (onData, onError) => {\n if (!this.effectsChannel) {\n throw new Error('This SQLocal instance is not configured for reactive queries. Set the \"reactive\" option to enable them.');\n }\n if (!onError) {\n onError = (err) => {\n throw err;\n };\n }\n subObservers.add(onData);\n errObservers.add(onError);\n if (!isListening) {\n this.effectsChannel.addEventListener('message', onEffect);\n isListening = true;\n runStatement();\n }\n else if (gotFirstValue) {\n onData(value);\n }\n return {\n unsubscribe: () => {\n subObservers.delete(onData);\n errObservers.delete(onError);\n if (subObservers.size !== 0)\n return;\n this.effectsChannel?.removeEventListener('message', onEffect);\n isListening = false;\n },\n };\n },\n };\n }\n });\n Object.defineProperty(this, \"createCallbackFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (funcName, func) => {\n await this.createQuery({\n type: 'function',\n functionName: funcName,\n functionType: 'callback',\n });\n this.userCallbacks.set(funcName, func);\n }\n });\n Object.defineProperty(this, \"createScalarFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (funcName, func) => {\n const key = `_sqlocal_func_${funcName}`;\n const attachFunction = () => {\n this.proxy[key] = func;\n };\n if (this.proxy === globalThis) {\n attachFunction();\n }\n await this.createQuery({\n type: 'function',\n functionName: funcName,\n functionType: 'scalar',\n });\n if (this.proxy !== globalThis) {\n attachFunction();\n }\n }\n });\n Object.defineProperty(this, \"createAggregateFunction\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (funcName, func) => {\n const key = `_sqlocal_func_${funcName}`;\n const attachFunction = () => {\n this.proxy[`${key}_step`] = func.step;\n this.proxy[`${key}_final`] = func.final;\n };\n if (this.proxy === globalThis) {\n attachFunction();\n }\n await this.createQuery({\n type: 'function',\n functionName: funcName,\n functionType: 'aggregate',\n });\n if (this.proxy !== globalThis) {\n attachFunction();\n }\n }\n });\n Object.defineProperty(this, \"getDatabaseInfo\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n const message = await this.createQuery({ type: 'getinfo' });\n if (message.type === 'info') {\n return message.info;\n }\n else {\n throw new Error('The database failed to return valid information.');\n }\n }\n });\n Object.defineProperty(this, \"getDatabaseFile\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n const message = await this.createQuery({ type: 'export' });\n if (message.type === 'buffer') {\n return new File([message.buffer], message.bufferName, {\n type: 'application/x-sqlite3',\n });\n }\n else {\n throw new Error('The database failed to export.');\n }\n }\n });\n Object.defineProperty(this, \"overwriteDatabaseFile\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (databaseFile, beforeUnlock) => {\n await mutationLock('exclusive', false, this.config, async () => {\n try {\n this.broadcast({\n type: 'close',\n clientKey: this.clientKey,\n });\n const database = await normalizeDatabaseFile(databaseFile, 'buffer');\n await this.createQuery({\n type: 'import',\n database,\n });\n if (typeof beforeUnlock === 'function') {\n this.bypassMutationLock = true;\n await beforeUnlock();\n }\n this.broadcast({\n type: 'reinit',\n clientKey: this.clientKey,\n reason: 'overwrite',\n });\n }\n finally {\n this.bypassMutationLock = false;\n }\n });\n }\n });\n Object.defineProperty(this, \"deleteDatabaseFile\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async (beforeUnlock) => {\n await mutationLock('exclusive', false, this.config, async () => {\n try {\n this.broadcast({\n type: 'close',\n clientKey: this.clientKey,\n });\n await this.createQuery({\n type: 'delete',\n });\n if (typeof beforeUnlock === 'function') {\n this.bypassMutationLock = true;\n await beforeUnlock();\n }\n this.broadcast({\n type: 'reinit',\n clientKey: this.clientKey,\n reason: 'delete',\n });\n }\n finally {\n this.bypassMutationLock = false;\n }\n });\n }\n });\n Object.defineProperty(this, \"destroy\", {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n await this.createQuery({ type: 'destroy' });\n if (typeof globalThis.Worker !== 'undefined' &&\n this.processor instanceof Worker) {\n this.processor.removeEventListener('message', this.processMessageEvent);\n this.processor.terminate();\n }\n this.queriesInProgress.clear();\n this.userCallbacks.clear();\n this.reinitChannel.close();\n this.effectsChannel?.close();\n this.isDestroyed = true;\n }\n });\n Object.defineProperty(this, _a, {\n enumerable: true,\n configurable: true,\n writable: true,\n value: () => {\n this.destroy();\n }\n });\n Object.defineProperty(this, _b, {\n enumerable: true,\n configurable: true,\n writable: true,\n value: async () => {\n await this.destroy();\n }\n });\n const clientConfig = typeof config === 'string' ? { databasePath: config } : config;\n const { onInit, onConnect, processor, ...commonConfig } = clientConfig;\n const { databasePath } = commonConfig;\n this.config = clientConfig;\n this.clientKey = getQueryKey();\n const dbKey = getDatabaseKey(databasePath, this.clientKey);\n this.reinitChannel = new BroadcastChannel(`_sqlocal_reinit_(${dbKey})`);\n if (commonConfig.reactive) {\n this.effectsChannel = new BroadcastChannel(`_sqlocal_effects_(${dbKey})`);\n }\n if (typeof processor !== 'undefined') {\n this.processor = processor;\n }\n else if (databasePath === 'local' || databasePath === ':localStorage:') {\n const driver = new SQLiteKvvfsDriver('local');\n this.processor = new SQLocalProcessor(driver);\n }\n else if (databasePath === 'session' ||\n databasePath === ':sessionStorage:') {\n const driver = new SQLiteKvvfsDriver('session');\n this.processor = new SQLocalProcessor(driver);\n }\n else if (typeof globalThis.Worker !== 'undefined' &&\n databasePath !== ':memory:') {\n this.processor = new Worker(new URL('./worker', import.meta.url), {\n type: 'module',\n });\n }\n else {\n const driver = new SQLiteMemoryDriver();\n this.processor = new SQLocalProcessor(driver);\n }\n if (this.processor instanceof SQLocalProcessor) {\n this.processor.onmessage = (message) => this.processMessageEvent(message);\n this.proxy = globalThis;\n }\n else {\n this.processor.addEventListener('message', this.processMessageEvent);\n this.proxy = coincident(this.processor);\n }\n this.processor.postMessage({\n type: 'config',\n config: {\n ...commonConfig,\n clientKey: this.clientKey,\n onInitStatements: onInit?.(sqlTag) ?? [],\n },\n });\n }\n}\n_a = Symbol.dispose, _b = Symbol.asyncDispose;\n//# sourceMappingURL=client.js.map","/**\n * Database Module\n *\n * Uses SQLocal directly with BroadcastChannel for cross-tab coordination.\n *\n * Why this approach instead of SharedWorker?\n * - SQLocal already uses its own internal worker for OPFS access\n * - Wrapping it in another SharedWorker adds complexity and causes issues\n * - BroadcastChannel provides simple cross-tab communication\n * - Each tab has its own SQLocal instance but they share the same OPFS database file\n *\n * Usage:\n * import { sql, dbReady, addLocation, getLocations } from './database.js';\n *\n * await dbReady;\n * await addLocation('Point A', -1.5, 7.5);\n * const locations = await getLocations();\n */\n\nimport { SQLocal } from 'sqlocal';\n\n// Database configuration\nconst DATABASE_PATH = 'lupmis2.db';\nconst BROADCAST_CHANNEL = 'lupmis-db-sync';\n\n// Create SQLocal instance\nconst db = new SQLocal(DATABASE_PATH);\n\n// Get the sql tagged template function\nconst { sql } = db;\n\nconsole.log('[Database] SQLocal instance created for:', DATABASE_PATH);\n\n// Export sql for direct queries\nexport { sql };\n\n// Create broadcast channel for cross-tab coordination\nconst channel = new BroadcastChannel(BROADCAST_CHANNEL);\n\n// Track if database is ready\nlet isReady = false;\nlet readyResolve;\nlet readyReject;\n\nexport const dbReady = new Promise((resolve, reject) => {\n readyResolve = resolve;\n readyReject = reject;\n});\n\n// Database change listeners\nconst changeListeners = new Set();\n\n/**\n * Subscribe to database changes (from any tab)\n * @param {Function} listener - Called with { table, action, id }\n * @returns {Function} Unsubscribe function\n */\nexport function onDatabaseChange(listener) {\n changeListeners.add(listener);\n return () => changeListeners.delete(listener);\n}\n\n// Handle messages from other tabs\nchannel.onmessage = (event) => {\n const { type, payload } = event.data;\n if (type === 'DB_CHANGE') {\n // Notify local listeners about changes from other tabs\n for (const listener of changeListeners) {\n try {\n listener(payload);\n } catch (e) {\n console.error('[Database] Change listener error:', e);\n }\n }\n }\n};\n\n/**\n * Broadcast a database change to other tabs\n */\nfunction broadcastChange(table, action, id = null) {\n channel.postMessage({\n type: 'DB_CHANGE',\n payload: { table, action, id, timestamp: Date.now() }\n });\n\n // Also notify local listeners\n for (const listener of changeListeners) {\n try {\n listener({ table, action, id, timestamp: Date.now(), local: true });\n } catch (e) {\n console.error('[Database] Change listener error:', e);\n }\n }\n}\n\n// ============================================================================\n// Database Initialization\n// ============================================================================\n\n/**\n * Initialize the database schema\n */\nexport async function initSchema() {\n try {\n console.log('[Database] Initializing schema...');\n\n // Test connection\n const testResult = await sql`SELECT sqlite_version() as version`;\n console.log('[Database] SQLite version:', testResult[0]?.version);\n\n // Create locations table\n console.log('[Database] Creating locations table...');\n await sql`\n CREATE TABLE IF NOT EXISTS locations (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n longitude REAL NOT NULL,\n latitude REAL NOT NULL,\n description TEXT,\n category TEXT DEFAULT 'default',\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n updated_at TEXT DEFAULT CURRENT_TIMESTAMP,\n synced INTEGER DEFAULT 0\n )\n `;\n\n // Verify table exists\n const tablesAfterLocations = await sql`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;\n console.log('[Database] Locations table exists:', tablesAfterLocations.length > 0);\n\n // Create sync_log table\n console.log('[Database] Creating sync_log table...');\n await sql`\n CREATE TABLE IF NOT EXISTS sync_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n table_name TEXT NOT NULL,\n record_id INTEGER NOT NULL,\n action TEXT NOT NULL,\n timestamp TEXT DEFAULT CURRENT_TIMESTAMP,\n synced INTEGER DEFAULT 0\n )\n `;\n\n // Create remote_data cache table\n console.log('[Database] Creating remote_data table...');\n await sql`\n CREATE TABLE IF NOT EXISTS remote_data (\n key TEXT PRIMARY KEY,\n data TEXT NOT NULL,\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // Create collector_zones table for caching zone data\n console.log('[Database] Creating collector_zones table...');\n await sql`\n CREATE TABLE IF NOT EXISTS collector_zones (\n id INTEGER PRIMARY KEY,\n zone_name TEXT,\n geometry_wkt TEXT,\n properties TEXT,\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // Create parcels table — mirrors the server's spatial.lu_parcels structure\n // (land-use parcels). Attribute columns match the server 1:1 so the local\n // data viewer shows real fields rather than a JSON blob.\n // status — local-only flag: 'verified' = downloaded from the API,\n // 'new' = drawn locally and pending server verification.\n // fetched_at — local-only cache timestamp.\n // Migrate older databases that used the previous JSON-blob schema\n // (id, geometry_wkt, properties, status, fetched_at): if the new `upn`\n // column is missing, drop the cached table so it is recreated with the\n // lu_parcels columns. Cached server parcels re-download on next load.\n console.log('[Database] Creating parcels table...');\n try {\n const cols = await sql`PRAGMA table_info(parcels)`;\n if (cols.length > 0 && !cols.some((c) => c.name === 'upn')) {\n console.log('[Database] Migrating parcels table to lu_parcels structure (dropping old cache)...');\n await sql`DROP TABLE parcels`;\n }\n } catch (e) {\n console.warn('[Database] parcels migration check failed:', e);\n }\n await sql`\n CREATE TABLE IF NOT EXISTS parcels (\n id INTEGER PRIMARY KEY,\n upn TEXT,\n style INTEGER,\n landuse TEXT,\n zone_code TEXT,\n zone_name TEXT,\n sector TEXT,\n block TEXT,\n parcel_no TEXT,\n prop_no TEXT,\n st_name TEXT,\n prop_add TEXT,\n fac_name TEXT,\n min_height INTEGER,\n max_height INTEGER,\n eff_date TEXT,\n lp_name TEXT,\n locality TEXT,\n mmda TEXT,\n last_update TEXT,\n remarks TEXT,\n geometry_wkt TEXT,\n created_at TEXT,\n updated_at TEXT,\n districtid INTEGER,\n status TEXT DEFAULT 'verified',\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // Create building_footprints table for caching footprint data\n console.log('[Database] Creating building_footprints table...');\n await sql`\n CREATE TABLE IF NOT EXISTS building_footprints (\n id INTEGER PRIMARY KEY,\n geometry_wkt TEXT,\n properties TEXT,\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // Create osm_roads table for caching the OSM road network\n console.log('[Database] Creating osm_roads table...');\n await sql`\n CREATE TABLE IF NOT EXISTS osm_roads (\n osm_id INTEGER PRIMARY KEY,\n geometry_wkt TEXT,\n properties TEXT,\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // UPN-grid table — district sub-division grid (one cell per UPN prefix).\n // The grid is static per district, so the cache is populated once and only\n // refreshed when the user is associated with a different district. The\n // districtid column lets getLocalUpnGrid() detect that mismatch.\n console.log('[Database] Creating upn_grid table...');\n await sql`\n CREATE TABLE IF NOT EXISTS upn_grid (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n districtid INTEGER,\n upn_prefix TEXT,\n geometry_wkt TEXT,\n fetched_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n // ── GPS trails ──────────────────────────────────────────────────────\n // Recorded field-movement tracks. These are the local store for the\n // reusable GeoTracker module (src/geotracker/). `client_uuid` lets the\n // server de-duplicate re-synced trails; `satellites` is nullable because\n // the web Geolocation API does not expose it (only native builds do).\n console.log('[Database] Creating gps_trails table...');\n await sql`\n CREATE TABLE IF NOT EXISTS gps_trails (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n client_uuid TEXT UNIQUE,\n name TEXT,\n district_id TEXT,\n started_at TEXT NOT NULL,\n ended_at TEXT,\n status TEXT NOT NULL DEFAULT 'recording',\n point_count INTEGER NOT NULL DEFAULT 0,\n distance_m REAL NOT NULL DEFAULT 0,\n synced INTEGER NOT NULL DEFAULT 0,\n remote_id TEXT,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP\n )\n `;\n\n console.log('[Database] Creating gps_trail_points table...');\n await sql`\n CREATE TABLE IF NOT EXISTS gps_trail_points (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n trail_id INTEGER NOT NULL,\n seq INTEGER NOT NULL,\n longitude REAL NOT NULL,\n latitude REAL NOT NULL,\n altitude REAL,\n accuracy REAL,\n altitude_accuracy REAL,\n heading REAL,\n speed REAL,\n satellites INTEGER,\n recorded_at TEXT NOT NULL\n )\n `;\n\n // ── External imports ────────────────────────────────────────────────\n // Staging for shapefile / GeoJSON / KML imports before they are uploaded\n // to the server. See LUPMIS2_Import_Upload_Design.docx §4.\n // external_imports — one row per imported file (the dataset)\n // external_import_features — staged features (rows pending upload)\n //\n // Status state machine (aligns with the database team's staged-upload\n // model — uploads land in spatial.lu_parcels_upload_tmp first, then a\n // supervisor promotes them to the live spatial.lu_parcels via the\n // migrated flag):\n //\n // 'imported' → 'mapped' → 'uploading' → 'submitted' → 'migrated'\n // ↘ 'failed'\n //\n // 'other' is a terminal display-only state (user chose \"Other / view only\").\n // 'submitted' = row exists in upload_tmp, awaiting supervisor review.\n // 'migrated' = supervisor approved & promoted to the live table.\n console.log('[Database] Creating external_imports table...');\n await sql`\n CREATE TABLE IF NOT EXISTS external_imports (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n filename TEXT NOT NULL,\n target_type TEXT NOT NULL DEFAULT 'other',\n mapping_json TEXT,\n status TEXT NOT NULL DEFAULT 'imported',\n feature_count INTEGER NOT NULL DEFAULT 0,\n error_count INTEGER NOT NULL DEFAULT 0,\n client_import_id TEXT UNIQUE,\n created_at TEXT DEFAULT CURRENT_TIMESTAMP,\n last_uploaded_at TEXT\n )\n `;\n\n console.log('[Database] Creating external_import_features table...');\n await sql`\n CREATE TABLE IF NOT EXISTS external_import_features (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n import_id INTEGER NOT NULL REFERENCES external_imports(id) ON DELETE CASCADE,\n client_uuid TEXT UNIQUE,\n geometry_wkt TEXT NOT NULL,\n properties_json TEXT,\n upload_status TEXT NOT NULL DEFAULT 'pending',\n server_id INTEGER,\n error_message TEXT\n )\n `;\n\n // Create indexes\n await sql`CREATE INDEX IF NOT EXISTS idx_locations_category ON locations(category)`;\n await sql`CREATE INDEX IF NOT EXISTS idx_locations_synced ON locations(synced)`;\n await sql`CREATE INDEX IF NOT EXISTS idx_gps_trails_synced ON gps_trails(synced, status)`;\n await sql`CREATE INDEX IF NOT EXISTS idx_gps_trail_points_trail ON gps_trail_points(trail_id, seq)`;\n await sql`CREATE INDEX IF NOT EXISTS idx_external_imports_status ON external_imports(status)`;\n await sql`CREATE INDEX IF NOT EXISTS idx_external_import_features_import ON external_import_features(import_id, upload_status)`;\n\n // Final verification\n const allTables = await sql`SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;\n console.log('[Database] All tables:', allTables.map(t => t.name));\n\n isReady = true;\n readyResolve(true);\n console.log('[Database] ✓ Schema initialized');\n\n } catch (error) {\n console.error('[Database] ✗ Schema init failed:', error);\n readyReject(error);\n throw error;\n }\n}\n\n// ============================================================================\n// Location Operations\n// ============================================================================\n\n/**\n * Add a new location\n */\nexport async function addLocation(name, longitude, latitude, options = {}) {\n const { description = null, category = 'default' } = options;\n\n console.log('[Database] Adding location:', name, longitude, latitude, category);\n\n try {\n // Check table exists first\n const tableCheck = await sql`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;\n console.log('[Database] Table check before insert:', tableCheck);\n\n if (tableCheck.length === 0) {\n console.error('[Database] ✗ locations table does not exist!');\n throw new Error('locations table does not exist');\n }\n\n // Insert - using explicit values\n console.log('[Database] Executing INSERT...');\n await sql`\n INSERT INTO locations (name, longitude, latitude, description, category)\n VALUES (${name}, ${longitude}, ${latitude}, ${description}, ${category})\n `;\n console.log('[Database] INSERT completed');\n\n // Get the ID\n const idResult = await sql`SELECT last_insert_rowid() as id`;\n const newId = idResult[0]?.id;\n console.log('[Database] New ID:', newId);\n\n // Verify it was actually inserted\n const verifyResult = await sql`SELECT * FROM locations WHERE id = ${newId}`;\n console.log('[Database] Verify insert:', verifyResult);\n\n if (verifyResult.length === 0) {\n console.error('[Database] ✗ Insert verification failed - row not found!');\n throw new Error('Insert verification failed');\n }\n\n // Log for sync\n await sql`\n INSERT INTO sync_log (table_name, record_id, action)\n VALUES ('locations', ${newId}, 'INSERT')\n `;\n\n // Broadcast to other tabs\n broadcastChange('locations', 'INSERT', newId);\n\n console.log('[Database] ✓ Location added:', newId);\n return { id: newId };\n\n } catch (error) {\n console.error('[Database] ✗ Failed to add location:', error);\n throw error;\n}\n}\n\n/**\n * Get all locations\n */\nexport async function getLocations(options = {}) {\n const { category = null, limit = 1000 } = options;\n\n try {\n // First check if table exists\n const tableCheck = await sql`SELECT name FROM sqlite_master WHERE type='table' AND name='locations'`;\n console.log('[Database] getLocations - table exists:', tableCheck.length > 0);\n\n if (tableCheck.length === 0) {\n console.warn('[Database] locations table does not exist yet');\n return [];\n }\n\n let results;\n if (category) {\n results = await sql`\n SELECT * FROM locations\n WHERE category = ${category}\n ORDER BY created_at DESC\n LIMIT ${limit}\n `;\n } else {\n results = await sql`\n SELECT * FROM locations\n ORDER BY created_at DESC\n LIMIT ${limit}\n `;\n}\n\n console.log('[Database] getLocations returned', results.length, 'rows');\n return results;\n\n } catch (error) {\n console.error('[Database] getLocations error:', error);\n return [];\n }\n}\n\nexport async function getLocation(id) {\n try {\n const results = await sql`SELECT * FROM locations WHERE id = ${id}`;\n return results[0] || null;\n } catch (error) {\n console.error('[Database] getLocation error:', error);\n return null;\n}\n}\n\n/**\n * Update a location\n */\nexport async function updateLocation(id, updates) {\n const { name, longitude, latitude, description, category } = updates;\n\n try {\n const location = await getLocation(id);\n if (!location) {\n throw new Error(`Location ${id} not found`);\n }\n\n await sql`\n UPDATE locations\n SET\n name = ${name ?? location.name},\n longitude = ${longitude ?? location.longitude},\n latitude = ${latitude ?? location.latitude},\n description = ${description ?? location.description},\n category = ${category ?? location.category},\n updated_at = CURRENT_TIMESTAMP,\n synced = 0\n WHERE id = ${id}\n `;\n\n // Log for sync\n await sql`\n INSERT INTO sync_log (table_name, record_id, action)\n VALUES ('locations', ${id}, 'UPDATE')\n `;\n\n // Broadcast to other tabs\n broadcastChange('locations', 'UPDATE', id);\n console.log('[Database] ✓ Location updated:', id);\n\n } catch (error) {\n console.error('[Database] ✗ updateLocation error:', error);\n throw error;\n}\n}\n\n/**\n * Delete a location\n */\nexport async function deleteLocation(id) {\n try {\n await sql`\n INSERT INTO sync_log (table_name, record_id, action)\n VALUES ('locations', ${id}, 'DELETE')\n `;\n\n await sql`DELETE FROM locations WHERE id = ${id}`;\n\n // Broadcast to other tabs\n broadcastChange('locations', 'DELETE', id);\n console.log('[Database] ✓ Location deleted:', id);\n\n } catch (error) {\n console.error('[Database] ✗ deleteLocation error:', error);\n throw error;\n}\n}\n\n/**\n * Get location count\n */\nexport async function getLocationCount() {\n try {\n const result = await sql`SELECT COUNT(*) as count FROM locations`;\n return result[0]?.count ?? 0;\n } catch (error) {\n console.error('[Database] getLocationCount error:', error);\n return 0;\n}\n}\n\n// ============================================================================\n// Sync Operations\n// ============================================================================\n\n/**\n * Get unsynced changes\n */\nexport async function getUnsyncedChanges() {\n return sql`SELECT * FROM sync_log WHERE synced = 0 ORDER BY timestamp ASC`;\n}\n\n/**\n * Mark changes as synced\n */\nexport async function markSynced(syncLogIds) {\n if (!syncLogIds.length) return;\n for (const id of syncLogIds) {\n await sql`UPDATE sync_log SET synced = 1 WHERE id = ${id}`;\n}\n}\n\n/**\n * Get locations that need syncing\n */\nexport async function getUnsyncedLocations() {\n return sql`SELECT * FROM locations WHERE synced = 0`;\n}\n\n/**\n * Mark locations as synced\n */\nexport async function markLocationsSynced(ids) {\n if (!ids.length) return;\n for (const id of ids) {\n await sql`UPDATE locations SET synced = 1 WHERE id = ${id}`;\n}\n}\n\n// ============================================================================\n// Remote Data Cache\n// ============================================================================\n\n/**\n * Save remote API data to the local cache.\n * Uses INSERT OR REPLACE so the same key is always overwritten.\n *\n * @param {string} key - Unique identifier (e.g. 'district_boundary')\n * @param {Object|Array} data - JSON-serialisable data to cache\n */\nexport async function saveRemoteData(key, data) {\n try {\n const json = JSON.stringify(data);\n await sql`\n INSERT OR REPLACE INTO remote_data (key, data, fetched_at)\n VALUES (${key}, ${json}, CURRENT_TIMESTAMP)\n `;\n console.log('[Database] ✓ Remote data cached:', key);\n } catch (error) {\n console.error('[Database] ✗ Failed to cache remote data:', key, error);\n throw error;\n }\n}\n\n/**\n * Retrieve cached remote data by key.\n *\n * @param {string} key - Unique identifier (e.g. 'district_boundary')\n * @returns {Promise} Parsed data, or null if not cached\n */\nexport async function getRemoteData(key) {\n try {\n const rows = await sql`SELECT data, fetched_at FROM remote_data WHERE key = ${key}`;\n if (rows.length === 0) return null;\n const parsed = JSON.parse(rows[0].data);\n console.log('[Database] ✓ Remote data loaded from cache:', key, '(fetched', rows[0].fetched_at + ')');\n return parsed;\n } catch (error) {\n console.error('[Database] ✗ Failed to read cached remote data:', key, error);\n return null;\n }\n}\n\n// ============================================================================\n// Collector Zones\n// ============================================================================\n\n/**\n * Save collector zones to the local table.\n * Replaces all existing rows.\n *\n * @param {Array} zones - Array of zone objects from the API\n */\nexport async function saveCollectorZones(zones) {\n try {\n await sql`DELETE FROM collector_zones`;\n for (const z of zones) {\n const props = JSON.stringify(z);\n await sql`\n INSERT INTO collector_zones (id, zone_name, geometry_wkt, properties, fetched_at)\n VALUES (${z.colzonenr || z.id}, ${z.colzonename || z.zone_name || ''}, ${z.polygon || z.boundary || ''}, ${props}, CURRENT_TIMESTAMP)\n `;\n }\n console.log('[Database] ✓ Saved', zones.length, 'collector zones');\n } catch (error) {\n console.error('[Database] ✗ Failed to save collector zones:', error);\n throw error;\n }\n}\n\n/**\n * Load all cached collector zones from the local table.\n * @returns {Promise} Array of zone objects, or null if empty\n */\nexport async function getLocalCollectorZones() {\n try {\n const rows = await sql`SELECT properties FROM collector_zones ORDER BY id`;\n if (rows.length === 0) return null;\n return rows.map(r => JSON.parse(r.properties));\n } catch (error) {\n console.error('[Database] ✗ Failed to read local collector zones:', error);\n return null;\n }\n}\n\n// ============================================================================\n// UPN Grid\n// ============================================================================\n\n/**\n * Save the UPN-grid for one district to the local table. Replaces any\n * previously cached grid (even if it was for a different district) — the\n * grid is static per district, so we only ever keep the current district's\n * cells locally.\n *\n * @param {Array} rows - Grid rows from the API\n * (each: { polygon, districtid, upn_prefix })\n * @param {number|string} districtId - The current district id\n */\nexport async function saveUpnGrid(rows, districtId) {\n try {\n await sql`BEGIN`;\n await sql`DELETE FROM upn_grid`;\n let saved = 0;\n for (const r of rows) {\n const wkt = r.polygon || r.geometry_wkt || r.geom || '';\n await sql`\n INSERT INTO upn_grid (districtid, upn_prefix, geometry_wkt, fetched_at)\n VALUES (${numOrNull(districtId)}, ${r.upn_prefix ?? null}, ${wkt}, CURRENT_TIMESTAMP)\n `;\n saved++;\n }\n await sql`COMMIT`;\n console.log('[Database] ✓ Saved', saved, 'UPN-grid cells (district', districtId, ')');\n } catch (error) {\n try { await sql`ROLLBACK`; } catch { /* no active txn */ }\n console.error('[Database] ✗ Failed to save UPN grid:', error);\n throw error;\n }\n}\n\n/**\n * Load the UPN-grid rows that belong to the given district. Returns null\n * if no cells are cached for that district — the caller should then fetch\n * from the API and call saveUpnGrid().\n *\n * @param {number|string} districtId\n * @returns {Promise}\n */\nexport async function getLocalUpnGrid(districtId) {\n try {\n const rows = await sql`\n SELECT id, districtid, upn_prefix, geometry_wkt\n FROM upn_grid\n WHERE districtid = ${numOrNull(districtId)}\n ORDER BY id\n `;\n if (rows.length === 0) return null;\n return rows;\n } catch (error) {\n console.error('[Database] ✗ Failed to read UPN grid:', error);\n return null;\n }\n}\n\n// ============================================================================\n// External imports (staging for shapefile / GeoJSON / KML uploads)\n// See LUPMIS2_Import_Upload_Design.docx §3 & §4.\n// ============================================================================\n\n/** Tiny RFC-4122-ish UUIDv4 (uses crypto.randomUUID when available). */\nfunction uuidv4() {\n if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {\n return crypto.randomUUID();\n }\n // Fallback for older browsers\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {\n const r = (Math.random() * 16) | 0;\n return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);\n });\n}\n\n/**\n * Create a new staging row for an imported dataset. Returns the import_id.\n *\n * @param {Object} opts\n * @param {string} opts.filename — original filename\n * @param {string} [opts.targetType] — initial target ('other' by default)\n * @param {number} [opts.featureCount] — number of features being staged\n * @returns {Promise<{ id: number, client_import_id: string }>}\n */\nexport async function createExternalImport(opts) {\n const { filename, targetType = 'other', featureCount = 0 } = opts;\n const clientImportId = uuidv4();\n try {\n await sql`\n INSERT INTO external_imports\n (filename, target_type, status, feature_count, client_import_id)\n VALUES\n (${filename}, ${targetType},\n ${targetType === 'other' ? 'other' : 'imported'},\n ${featureCount}, ${clientImportId})\n `;\n const idRow = await sql`SELECT last_insert_rowid() AS id`;\n const id = idRow[0]?.id;\n broadcastChange('external_imports', 'INSERT', id);\n return { id, client_import_id: clientImportId };\n } catch (error) {\n console.error('[Database] ✗ Failed to create external import:', error);\n throw error;\n }\n}\n\n/**\n * Bulk-insert staging features for an import. Wraps the inserts in a single\n * transaction (the upload payload is typically dozens to thousands of rows).\n *\n * @param {number} importId\n * @param {Array<{ geometry_wkt: string, properties: Object }>} features\n */\nexport async function addExternalImportFeatures(importId, features) {\n if (!Array.isArray(features) || features.length === 0) return 0;\n try {\n await sql`BEGIN`;\n let inserted = 0;\n for (const f of features) {\n const wkt = f.geometry_wkt || '';\n if (!wkt) continue;\n const propsJson = JSON.stringify(f.properties ?? {});\n const cuuid = f.client_uuid || uuidv4();\n await sql`\n INSERT INTO external_import_features\n (import_id, client_uuid, geometry_wkt, properties_json, upload_status)\n VALUES\n (${importId}, ${cuuid}, ${wkt}, ${propsJson}, 'pending')\n `;\n inserted++;\n }\n await sql`COMMIT`;\n broadcastChange('external_import_features', 'INSERT', importId);\n return inserted;\n } catch (error) {\n try { await sql`ROLLBACK`; } catch { /* no active txn */ }\n console.error('[Database] ✗ Failed to add import features:', error);\n throw error;\n }\n}\n\n/**\n * Update target type + mapping + status for a staged import. Pass any\n * subset of fields. Useful targets:\n * updateExternalImport(id, { targetType: 'parcels', mapping: {...},\n * status: 'mapped' })\n */\nexport async function updateExternalImport(importId, patch = {}) {\n try {\n const cur = await sql`SELECT * FROM external_imports WHERE id = ${importId}`;\n if (cur.length === 0) throw new Error(`Import ${importId} not found`);\n const row = cur[0];\n\n const targetType = patch.targetType ?? row.target_type;\n const mappingJson = patch.mapping !== undefined\n ? (patch.mapping ? JSON.stringify(patch.mapping) : null)\n : row.mapping_json;\n const status = patch.status ?? row.status;\n const errorCount = patch.errorCount ?? row.error_count;\n const lastUploadedAt = patch.lastUploadedAt ?? row.last_uploaded_at;\n\n await sql`\n UPDATE external_imports SET\n target_type = ${targetType},\n mapping_json = ${mappingJson},\n status = ${status},\n error_count = ${errorCount},\n last_uploaded_at = ${lastUploadedAt}\n WHERE id = ${importId}\n `;\n broadcastChange('external_imports', 'UPDATE', importId);\n } catch (error) {\n console.error('[Database] ✗ Failed to update external import:', error);\n throw error;\n }\n}\n\n/** Get an external_imports row by id (parsed mapping_json). */\nexport async function getExternalImport(importId) {\n try {\n const rows = await sql`SELECT * FROM external_imports WHERE id = ${importId}`;\n if (rows.length === 0) return null;\n const row = rows[0];\n return { ...row, mapping: row.mapping_json ? JSON.parse(row.mapping_json) : null };\n } catch (error) {\n console.error('[Database] ✗ Failed to read external import:', error);\n return null;\n }\n}\n\n/** List every external import, newest first. */\nexport async function listExternalImports() {\n try {\n return await sql`SELECT * FROM external_imports ORDER BY id DESC`;\n } catch (error) {\n console.error('[Database] ✗ Failed to list external imports:', error);\n return [];\n }\n}\n\n/** Get the staging features for an import (parsed properties_json). */\nexport async function getExternalImportFeatures(importId) {\n try {\n const rows = await sql`\n SELECT id, client_uuid, geometry_wkt, properties_json,\n upload_status, server_id, error_message\n FROM external_import_features\n WHERE import_id = ${importId}\n ORDER BY id\n `;\n return rows.map((r) => ({\n ...r,\n properties: r.properties_json ? JSON.parse(r.properties_json) : {},\n }));\n } catch (error) {\n console.error('[Database] ✗ Failed to read import features:', error);\n return [];\n }\n}\n\n/**\n * Bulk-rewrite the properties_json of every staged feature for an import.\n * Used after the user confirms a field-mapping: the caller passes a function\n * that receives each row's parsed properties and returns the remapped ones.\n * All updates run in a single transaction.\n *\n * @param {number} importId\n * @param {(props: Object) => Object} remap\n */\nexport async function remapImportedFeatureProperties(importId, remap) {\n try {\n const rows = await sql`\n SELECT id, properties_json\n FROM external_import_features\n WHERE import_id = ${importId}\n `;\n if (rows.length === 0) return 0;\n\n await sql`BEGIN`;\n let n = 0;\n for (const r of rows) {\n const before = r.properties_json ? JSON.parse(r.properties_json) : {};\n const after = remap(before) ?? {};\n await sql`\n UPDATE external_import_features\n SET properties_json = ${JSON.stringify(after)}\n WHERE id = ${r.id}\n `;\n n++;\n }\n await sql`COMMIT`;\n broadcastChange('external_import_features', 'UPDATE', importId);\n return n;\n } catch (error) {\n try { await sql`ROLLBACK`; } catch { /* */ }\n console.error('[Database] ✗ Failed to remap import features:', error);\n throw error;\n }\n}\n\n/** Delete a staged import (and its features via CASCADE). */\nexport async function deleteExternalImport(importId) {\n try {\n await sql`DELETE FROM external_imports WHERE id = ${importId}`;\n broadcastChange('external_imports', 'DELETE', importId);\n } catch (error) {\n console.error('[Database] ✗ Failed to delete external import:', error);\n throw error;\n }\n}\n\n// ============================================================================\n// Parcels\n// ============================================================================\n\n/** Coerce a value for an INTEGER column; '' / null / undefined / NaN → null. */\nfunction numOrNull(v) {\n if (v === '' || v === null || v === undefined) return null;\n const n = Number(v);\n return Number.isNaN(n) ? null : n;\n}\n\n/**\n * Save parcels to the local table (mirrors spatial.lu_parcels).\n * Replaces all server-cached rows. Each API field maps to its own column.\n * Geometry is taken from the server `geom` field (WKT, EPSG:4326).\n *\n * @param {Array} parcels - Array of parcel objects from the API\n */\nexport async function saveParcels(parcels) {\n try {\n // Wrap the bulk load in a single transaction — with ~25k parcels, per-row\n // auto-commits on OPFS would be prohibitively slow.\n await sql`BEGIN`;\n await sql`DELETE FROM parcels`;\n let saved = 0;\n for (const p of parcels) {\n const id = p.id ?? p.parcelid ?? p.parcel_id ?? null;\n if (id == null) continue; // skip rows without a usable ID\n // Geometry must be a WKT *string* for the geometry_wkt TEXT column.\n // The API sends WKT in `boundary` and a GeoJSON *object* in `geom`, so\n // prefer the string fields and only accept `geom` when it is a string.\n const wkt = p.boundary || p.geometry_wkt || p.polygon || p.wkt\n || (typeof p.geom === 'string' ? p.geom : '');\n await sql`\n INSERT OR REPLACE INTO parcels (\n id, upn, style, landuse, zone_code, zone_name, sector, block, parcel_no,\n prop_no, st_name, prop_add, fac_name, min_height, max_height, eff_date,\n lp_name, locality, mmda, last_update, remarks, geometry_wkt,\n created_at, updated_at, districtid, status, fetched_at\n ) VALUES (\n ${id}, ${p.upn ?? null}, ${numOrNull(p.style)}, ${p.landuse ?? null},\n ${p.zone_code ?? null}, ${p.zone_name ?? null}, ${p.sector ?? null},\n ${p.block ?? null}, ${p.parcel_no ?? null}, ${p.prop_no ?? null},\n ${p.st_name ?? null}, ${p.prop_add ?? null}, ${p.fac_name ?? null},\n ${numOrNull(p.min_height)}, ${numOrNull(p.max_height)}, ${p.eff_date ?? null},\n ${p.lp_name ?? null}, ${p.locality ?? null}, ${p.mmda ?? null},\n ${p.last_update ?? null}, ${p.remarks ?? null}, ${wkt},\n ${p.created_at ?? null}, ${p.updated_at ?? null}, ${numOrNull(p.districtid)},\n 'verified', CURRENT_TIMESTAMP\n )\n `;\n saved++;\n }\n await sql`COMMIT`;\n console.log('[Database] ✓ Saved', saved, 'parcels (from', parcels.length, 'rows,', parcels.length - saved, 'skipped/replaced)');\n } catch (error) {\n try { await sql`ROLLBACK`; } catch { /* no active txn */ }\n console.error('[Database] ✗ Failed to save parcels:', error);\n throw error;\n }\n}\n\n/**\n * Load all cached parcels from the local table.\n * Each row is a plain object keyed by column name (incl. geometry_wkt).\n * @returns {Promise} Array of parcel rows, or null if empty\n */\nexport async function getLocalParcels() {\n try {\n const rows = await sql`SELECT * FROM parcels ORDER BY id`;\n if (rows.length === 0) return null;\n return rows;\n } catch (error) {\n console.error('[Database] ✗ Failed to read local parcels:', error);\n return null;\n }\n}\n\n/**\n * Update a single parcel's attribute columns in the local table.\n * Geometry, id, created_at and status are left unchanged; updated_at is bumped.\n *\n * @param {number|string} parcelId - The parcel id\n * @param {Object} p - Updated attribute values (keys = lu_parcels columns)\n */\nexport async function updateParcel(parcelId, p) {\n try {\n await sql`\n UPDATE parcels SET\n upn = ${p.upn ?? null},\n style = ${numOrNull(p.style)},\n landuse = ${p.landuse ?? null},\n zone_code = ${p.zone_code ?? null},\n zone_name = ${p.zone_name ?? null},\n sector = ${p.sector ?? null},\n block = ${p.block ?? null},\n parcel_no = ${p.parcel_no ?? null},\n prop_no = ${p.prop_no ?? null},\n st_name = ${p.st_name ?? null},\n prop_add = ${p.prop_add ?? null},\n fac_name = ${p.fac_name ?? null},\n min_height = ${numOrNull(p.min_height)},\n max_height = ${numOrNull(p.max_height)},\n eff_date = ${p.eff_date ?? null},\n lp_name = ${p.lp_name ?? null},\n locality = ${p.locality ?? null},\n mmda = ${p.mmda ?? null},\n last_update = ${p.last_update ?? null},\n remarks = ${p.remarks ?? null},\n districtid = ${numOrNull(p.districtid)},\n updated_at = CURRENT_TIMESTAMP\n WHERE id = ${parcelId}\n `;\n console.log('[Database] ✓ Parcel updated:', parcelId);\n broadcastChange('parcels', 'UPDATE', parcelId);\n } catch (error) {\n console.error('[Database] ✗ Failed to update parcel:', parcelId, error);\n throw error;\n }\n}\n\n/**\n * Insert a newly drawn parcel into the local table.\n * The parcel is tagged with status='new' to indicate it needs verification.\n *\n * @param {string} geometryWkt - WKT geometry string (EPSG:4326)\n * @param {Object} p - Attribute values from the form (keys = lu_parcels columns)\n * @returns {Promise<{id: number}>} The new row id\n */\nexport async function insertNewParcel(geometryWkt, p = {}) {\n try {\n await sql`\n INSERT INTO parcels (\n id, upn, style, landuse, zone_code, zone_name, sector, block, parcel_no,\n prop_no, st_name, prop_add, fac_name, min_height, max_height, eff_date,\n lp_name, locality, mmda, last_update, remarks, geometry_wkt,\n created_at, updated_at, districtid, status, fetched_at\n ) VALUES (\n NULL, ${p.upn ?? null}, ${numOrNull(p.style)}, ${p.landuse ?? null},\n ${p.zone_code ?? null}, ${p.zone_name ?? null}, ${p.sector ?? null},\n ${p.block ?? null}, ${p.parcel_no ?? null}, ${p.prop_no ?? null},\n ${p.st_name ?? null}, ${p.prop_add ?? null}, ${p.fac_name ?? null},\n ${numOrNull(p.min_height)}, ${numOrNull(p.max_height)}, ${p.eff_date ?? null},\n ${p.lp_name ?? null}, ${p.locality ?? null}, ${p.mmda ?? null},\n ${p.last_update ?? null}, ${p.remarks ?? null}, ${geometryWkt},\n CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, ${numOrNull(p.districtid)},\n 'new', CURRENT_TIMESTAMP\n )\n `;\n const idResult = await sql`SELECT last_insert_rowid() as id`;\n const newId = idResult[0]?.id;\n console.log('[Database] ✓ New parcel inserted:', newId, '(status: new)');\n broadcastChange('parcels', 'INSERT', newId);\n return { id: newId };\n } catch (error) {\n console.error('[Database] ✗ Failed to insert new parcel:', error);\n throw error;\n }\n}\n\n// ============================================================================\n// Building Footprints\n// ============================================================================\n\n/**\n * Save building footprints to the local table.\n * Replaces all existing rows.\n *\n * @param {Array} footprints - Array of footprint objects from the API\n */\nexport async function saveBuildingFootprints(footprints) {\n try {\n // Log first entry's keys and value types to help debug field names\n if (footprints.length > 0) {\n const first = footprints[0];\n const types = {};\n for (const [k, v] of Object.entries(first)) {\n types[k] = v === null ? 'null' : typeof v;\n }\n console.log('[Database] First footprint field types:', types);\n }\n\n await sql`DELETE FROM building_footprints`;\n for (const f of footprints) {\n const props = JSON.stringify(f);\n\n // Geometry may arrive as a string (WKT) or an object (GeoJSON) —\n // coerce to a string so SQLocal can bind it.\n let rawWkt = f.polygon || f.boundary || f.geom || f.wkt || f.footprint || '';\n const wkt = typeof rawWkt === 'object' ? JSON.stringify(rawWkt) : String(rawWkt);\n\n // ID must be a primitive (number or null)\n let rawId = f.id || f.footprint_id || f.building_id || null;\n const id = (rawId !== null && typeof rawId === 'object') ? null : rawId;\n\n await sql`\n INSERT INTO building_footprints (id, geometry_wkt, properties, fetched_at)\n VALUES (${id}, ${wkt}, ${props}, CURRENT_TIMESTAMP)\n `;\n }\n console.log('[Database] ✓ Saved', footprints.length, 'building footprints');\n } catch (error) {\n console.error('[Database] ✗ Failed to save building footprints:', error);\n throw error;\n }\n}\n\n/**\n * Load all cached building footprints from the local table.\n * @returns {Promise} Array of footprint objects, or null if empty\n */\nexport async function getLocalBuildingFootprints() {\n try {\n const rows = await sql`SELECT properties FROM building_footprints ORDER BY id`;\n if (rows.length === 0) return null;\n return rows.map(r => JSON.parse(r.properties));\n } catch (error) {\n console.error('[Database] ✗ Failed to read local building footprints:', error);\n return null;\n }\n}\n\n/**\n * Save OSM roads to the local SQLite table.\n * Replaces all existing rows.\n *\n * @param {Array} roads - Array of road objects from the API\n */\nexport async function saveOSMRoads(roads) {\n try {\n if (roads.length > 0) {\n const first = roads[0];\n const types = {};\n for (const [k, v] of Object.entries(first)) {\n types[k] = v === null ? 'null' : typeof v;\n }\n console.log('[Database] First road field types:', types);\n }\n\n await sql`DELETE FROM osm_roads`;\n for (const r of roads) {\n const props = JSON.stringify(r);\n\n // Geometry — may arrive as WKT string or GeoJSON object\n let rawWkt = r.geom || r.geometry || r.wkt || r.road || r.line || '';\n const wkt = typeof rawWkt === 'object' ? JSON.stringify(rawWkt) : String(rawWkt);\n\n // osm_id must be a primitive — fall back to null if missing or malformed\n let rawId = r.osm_id ?? r.osmid ?? r.id ?? null;\n const osmId = (rawId !== null && typeof rawId === 'object') ? null : rawId;\n\n await sql`\n INSERT OR REPLACE INTO osm_roads (osm_id, geometry_wkt, properties, fetched_at)\n VALUES (${osmId}, ${wkt}, ${props}, CURRENT_TIMESTAMP)\n `;\n }\n console.log('[Database] ✓ Saved', roads.length, 'OSM roads');\n } catch (error) {\n console.error('[Database] ✗ Failed to save OSM roads:', error);\n throw error;\n }\n}\n\n/**\n * Load all cached OSM roads from the local table.\n * @returns {Promise} Array of road objects, or null if empty\n */\nexport async function getLocalOSMRoads() {\n try {\n const rows = await sql`SELECT properties FROM osm_roads ORDER BY osm_id`;\n if (rows.length === 0) return null;\n return rows.map(r => JSON.parse(r.properties));\n } catch (error) {\n console.error('[Database] ✗ Failed to read local OSM roads:', error);\n return null;\n }\n}\n\n// ============================================================================\n// Export / Import\n// ============================================================================\n\n/**\n * Export database for backup\n */\nexport async function exportDatabase() {\n return db.getDatabaseFile();\n}\n\n/**\n * Import database from backup\n */\nexport async function importDatabase(data) {\n await db.overwriteDatabaseFile(data);\n broadcastChange('*', 'IMPORT', null);\n}\n\n/**\n * Download database as file\n */\nexport async function downloadDatabase(filename = 'lupmis-backup.sqlite3') {\n const data = await exportDatabase();\n const blob = new Blob([data], { type: 'application/x-sqlite3' });\n const url = URL.createObjectURL(blob);\n\n const a = document.createElement('a');\n a.href = url;\n a.download = filename;\n a.click();\n\n URL.revokeObjectURL(url);\n}\n\n// Export to GeoJSON\nexport async function exportToGeoJSON() {\n const locations = await getLocations();\n\n return {\n type: 'FeatureCollection',\n features: locations.map((loc) => ({\n type: 'Feature',\n properties: {\n id: loc.id,\n name: loc.name,\n category: loc.category,\n notes: loc.notes,\n created_at: loc.created_at,\n },\n geometry: {\n type: 'Point',\n coordinates: [loc.lon, loc.lat],\n },\n })),\n };\n}\n\n// ============================================================================\n// Utility & Debug\n// ============================================================================\n\n/**\n * Get database status\n */\nexport async function getDatabaseStatus() {\n try {\n const tables = await sql`\n SELECT name FROM sqlite_master\n WHERE type='table' AND name NOT LIKE 'sqlite_%'\n ORDER BY name\n `;\n\n const locationCount = await getLocationCount();\n\n return {\n ready: isReady,\n databasePath: DATABASE_PATH,\n tables: tables.map(t => t.name),\n locationCount\n };\n } catch (error) {\n return {\n ready: false,\n error: error.message\n };\n}\n}\n\n// ============================================================================\n// Cached-Layer Management\n// ============================================================================\n\n/**\n * Tables that hold data fetched from the server.\n *\n * Clearing these is safe — the corresponding loaders (loadParcels,\n * loadBuildingFootprints, loadOSMRoads, loadCollectorZones, …) will re-fetch\n * the data from the API on the next app start.\n *\n * NOT included: user-created tables (`locations`, `pending_changes`) — those\n * hold local work that must not be auto-deleted.\n */\nexport const CACHED_LAYER_TABLES = Object.freeze([\n 'parcels',\n 'building_footprints',\n 'osm_roads',\n 'collector_zones',\n 'upn_grid',\n 'remote_data',\n]);\n\n/**\n * Check whether a table name is in the cleared-layer allow-list.\n * @param {string} tableName\n * @returns {boolean}\n */\nexport function isCachedLayerTable(tableName) {\n return CACHED_LAYER_TABLES.includes(tableName);\n}\n\n/**\n * Delete all rows from a single cached-layer table.\n * Rejects unknown table names so this can't be abused to drop user data.\n *\n * @param {string} tableName - One of CACHED_LAYER_TABLES\n * @returns {Promise} Number of rows that were in the table before deletion\n */\nexport async function clearTable(tableName) {\n if (!isCachedLayerTable(tableName)) {\n throw new Error(`Refusing to clear \"${tableName}\" — not a known cached-layer table`);\n }\n\n const before = await sql(`SELECT COUNT(*) AS n FROM \"${tableName}\"`);\n const count = before[0]?.n ?? 0;\n\n await sql(`DELETE FROM \"${tableName}\"`);\n console.log(`[Database] ✓ Cleared \"${tableName}\" (${count} rows)`);\n broadcastChange(tableName, 'CLEAR', null);\n return count;\n}\n\n/**\n * Clear every cached-layer table (whatever exists in this database).\n * Tables that don't exist yet are skipped silently.\n *\n * @returns {Promise<{ table: string, count: number }[]>} per-table report\n */\nexport async function clearAllCachedLayers() {\n const existing = await sql`\n SELECT name FROM sqlite_master\n WHERE type='table' AND name IN (\n 'parcels', 'building_footprints', 'osm_roads', 'collector_zones', 'upn_grid', 'remote_data'\n )\n `;\n const existingNames = new Set(existing.map((r) => r.name));\n\n const results = [];\n for (const tableName of CACHED_LAYER_TABLES) {\n if (!existingNames.has(tableName)) continue;\n try {\n const count = await clearTable(tableName);\n results.push({ table: tableName, count });\n } catch (err) {\n console.error(`[Database] Failed to clear ${tableName}:`, err);\n results.push({ table: tableName, count: 0, error: err.message });\n }\n }\n\n const total = results.reduce((s, r) => s + r.count, 0);\n console.log(`[Database] ✓ Cleared all cached layers: ${total} rows across ${results.length} tables`);\n return results;\n}\n\n/**\n * Get a list of all tables with their row counts.\n * @returns {Promise>}\n */\nexport async function getTableStats() {\n const tables = await sql`\n SELECT name FROM sqlite_master\n WHERE type='table' AND name NOT LIKE 'sqlite_%'\n ORDER BY name\n `;\n\n if (tables.length === 0) return [];\n\n // Build a UNION ALL query — table names come from sqlite_master so safe to embed.\n // sql() accepts a plain string as first argument (not only tagged template).\n const query = tables\n .map(t => `SELECT '${t.name}' AS name, COUNT(*) AS count FROM \"${t.name}\"`)\n .join(' UNION ALL ');\n\n return sql(query);\n}\n\n/**\n * Get all rows from a given table (max 200 rows for safety).\n * Table name is validated against sqlite_master before querying.\n * @param {string} tableName - Name of the table to read\n * @param {number} [limit=200] - Max rows to return\n * @returns {Promise<{columns: string[], rows: Object[]}>}\n */\nexport async function getTableContent(tableName, limit = 200) {\n // Validate that the table actually exists (prevent injection)\n const valid = await sql`\n SELECT name FROM sqlite_master\n WHERE type='table' AND name = ${tableName}\n `;\n if (valid.length === 0) {\n throw new Error(`Table \"${tableName}\" does not exist`);\n }\n\n const rows = await sql(`SELECT * FROM \"${tableName}\" LIMIT ${limit}`);\n\n // Extract column names from the first row (or return empty)\n const columns = rows.length > 0 ? Object.keys(rows[0]) : [];\n\n return { columns, rows };\n}\n\n// Debug function - call from console to test\nexport async function testDatabase() {\n console.log('=== DATABASE TEST ===');\n\n try {\n // 1. Check connection\n const version = await sql`SELECT sqlite_version() as v`;\n console.log('1. SQLite version:', version[0].v);\n\n // 2. Check tables\n const tables = await sql`SELECT name FROM sqlite_master WHERE type='table'`;\n console.log('2. Tables:', tables.map(t => t.name));\n\n // 3. Try to insert a test row\n console.log('3. Inserting test row...');\n await sql`INSERT INTO locations (name, longitude, latitude, category) VALUES ('TEST', -1.0, 7.0, 'test')`;\n\n // 4. Read it back\n const rows = await sql`SELECT * FROM locations WHERE name = 'TEST'`;\n console.log('4. Test row:', rows);\n\n // 5. Count all rows\n const count = await sql`SELECT COUNT(*) as c FROM locations`;\n console.log('5. Total rows:', count[0].c);\n\n // 6. Delete test row\n await sql`DELETE FROM locations WHERE name = 'TEST'`;\n console.log('6. Test row deleted');\n\n console.log('=== TEST PASSED ===');\n return true;\n } catch (error) {\n console.error('=== TEST FAILED ===', error);\n return false;\n}\n}\n\n// Expose to window for debugging\nif (typeof window !== 'undefined') {\n window.testDatabase = testDatabase;\n window.dbStatus = getDatabaseStatus;\n}\n\nexport async function closeDatabase() {\n channel.close();\n if (db.destroy) {\n await db.destroy();\n}\n}\n\n// ============================================================================\n// GPS Trails (storage adapter for the reusable GeoTracker module)\n// ============================================================================\n//\n// These functions implement the GeoTracker \"storage adapter\" contract using\n// SQLocal. They are intentionally generic (no map / UI coupling) so the same\n// schema + helpers can be lifted into another app alongside src/geotracker/.\n\n/**\n * Create a new trail row (status='recording') and return its local id.\n * @param {object} meta { uuid, name, startedAt, districtId }\n * @returns {Promise} local trail id\n */\nexport async function createGpsTrail(meta) {\n const { uuid, name = null, startedAt, districtId = null } = meta;\n await sql`\n INSERT INTO gps_trails (client_uuid, name, district_id, started_at, status)\n VALUES (${uuid}, ${name}, ${districtId}, ${startedAt}, 'recording')\n `;\n const idResult = await sql`SELECT last_insert_rowid() as id`;\n const id = idResult[0]?.id;\n broadcastChange('gps_trails', 'insert', id);\n return id;\n}\n\n/**\n * Append one recorded point to a trail.\n * @param {number} trailId\n * @param {object} point normalized fix + { seq }\n */\nexport async function addGpsTrailPoint(trailId, point) {\n const {\n seq, lon, lat,\n altitude = null, accuracy = null, altitudeAccuracy = null,\n heading = null, speed = null, satellites = null, timestamp,\n } = point;\n const recordedAt = typeof timestamp === 'number' ? new Date(timestamp).toISOString() : (timestamp || new Date().toISOString());\n await sql`\n INSERT INTO gps_trail_points\n (trail_id, seq, longitude, latitude, altitude, accuracy, altitude_accuracy, heading, speed, satellites, recorded_at)\n VALUES\n (${trailId}, ${seq}, ${lon}, ${lat}, ${altitude}, ${accuracy}, ${altitudeAccuracy}, ${heading}, ${speed}, ${satellites}, ${recordedAt})\n `;\n}\n\n/**\n * Finalise a trail: mark completed and store the summary.\n * @param {number} trailId\n * @param {object} summary { endedAt, pointCount, distanceM }\n */\nexport async function finishGpsTrail(trailId, summary) {\n const { endedAt, pointCount = 0, distanceM = 0 } = summary;\n await sql`\n UPDATE gps_trails\n SET ended_at = ${endedAt}, point_count = ${pointCount}, distance_m = ${distanceM}, status = 'completed'\n WHERE id = ${trailId}\n `;\n broadcastChange('gps_trails', 'update', trailId);\n}\n\n/**\n * Trails that are completed but not yet pushed to the server.\n * @returns {Promise}\n */\nexport async function getUnsyncedGpsTrails() {\n return sql`SELECT * FROM gps_trails WHERE synced = 0 AND status = 'completed' ORDER BY started_at ASC`;\n}\n\n/**\n * All points of a trail, in recorded order.\n * @param {number} trailId\n * @returns {Promise}\n */\nexport async function getGpsTrailPoints(trailId) {\n return sql`SELECT * FROM gps_trail_points WHERE trail_id = ${trailId} ORDER BY seq ASC`;\n}\n\n/**\n * Mark a trail as synced and record the server-assigned id.\n * @param {number} trailId\n * @param {string|number|null} remoteId\n */\nexport async function markGpsTrailSynced(trailId, remoteId = null) {\n await sql`UPDATE gps_trails SET synced = 1, remote_id = ${remoteId} WHERE id = ${trailId}`;\n broadcastChange('gps_trails', 'update', trailId);\n}\n\n/**\n * List trails (most recent first) for a history/list UI.\n * @returns {Promise}\n */\nexport async function getGpsTrails() {\n return sql`SELECT * FROM gps_trails ORDER BY started_at DESC`;\n}\n\n/**\n * Delete a trail and all its points.\n * @param {number} trailId\n */\nexport async function deleteGpsTrail(trailId) {\n await sql`DELETE FROM gps_trail_points WHERE trail_id = ${trailId}`;\n await sql`DELETE FROM gps_trails WHERE id = ${trailId}`;\n broadcastChange('gps_trails', 'delete', trailId);\n}\n\nexport default {\n sql,\n dbReady,\n initSchema,\n addLocation,\n getLocations,\n getLocation,\n updateLocation,\n deleteLocation,\n getLocationCount,\n getUnsyncedChanges,\n getUnsyncedLocations,\n markSynced,\n markLocationsSynced,\n saveRemoteData,\n getRemoteData,\n saveCollectorZones,\n getLocalCollectorZones,\n saveUpnGrid,\n getLocalUpnGrid,\n createExternalImport,\n addExternalImportFeatures,\n updateExternalImport,\n getExternalImport,\n listExternalImports,\n getExternalImportFeatures,\n remapImportedFeatureProperties,\n deleteExternalImport,\n saveParcels,\n getLocalParcels,\n updateParcel,\n insertNewParcel,\n saveBuildingFootprints,\n getLocalBuildingFootprints,\n saveOSMRoads,\n getLocalOSMRoads,\n createGpsTrail,\n addGpsTrailPoint,\n finishGpsTrail,\n getUnsyncedGpsTrails,\n getGpsTrailPoints,\n markGpsTrailSynced,\n getGpsTrails,\n deleteGpsTrail,\n CACHED_LAYER_TABLES,\n isCachedLayerTable,\n clearTable,\n clearAllCachedLayers,\n exportDatabase,\n exportToGeoJSON,\n importDatabase,\n downloadDatabase,\n getDatabaseStatus,\n getTableStats,\n getTableContent,\n testDatabase,\n onDatabaseChange,\n closeDatabase\n};\n","/**\n * Measurement unit formatting — Metric / Imperial.\n *\n * The active system is persisted in localStorage('measurement-system').\n * Every formatter reads the current setting so the UI updates immediately\n * after the user flips the toggle.\n *\n * All input values are in metres (length) or square metres (area).\n */\n\n// ── Conversion constants ────────────────────────────────────────────────────\nconst M_TO_FT = 3.28084;\nconst M_TO_MI = 0.000621371;\nconst SQM_TO_SQFT = 10.7639;\nconst SQM_TO_ACRE = 0.000247105;\nconst SQM_TO_SQMI = 3.861e-7;\n\n// ── System accessor ─────────────────────────────────────────────────────────\n\n/** @returns {'metric'|'imperial'} */\nexport function getSystem() {\n return localStorage.getItem('measurement-system') || 'metric';\n}\n\n// ── Length / distance ───────────────────────────────────────────────────────\n\n/**\n * Format a length value (in metres) for display.\n * Metric: m / km\n * Imperial: ft / mi\n */\nexport function formatLength(metres) {\n if (getSystem() === 'imperial') {\n const ft = metres * M_TO_FT;\n if (ft >= 5280) {\n return (Math.round(metres * M_TO_MI * 100) / 100) + ' mi';\n }\n return Math.round(ft) + ' ft';\n }\n // metric\n if (metres > 1000) {\n return (Math.round(metres / 1000 * 100) / 100) + ' km';\n }\n return (Math.round(metres * 100) / 100) + ' m';\n}\n\n/**\n * Format a length with both large and small units (for info popups).\n * Metric: \"1.23 km (1,230 m)\" or \"456 m\"\n * Imperial: \"1.23 mi (6,494 ft)\" or \"456 ft\"\n */\nexport function formatLengthFull(metres) {\n if (getSystem() === 'imperial') {\n const ft = metres * M_TO_FT;\n const mi = metres * M_TO_MI;\n if (ft >= 5280) {\n return `${mi.toFixed(2)} mi (${ft.toLocaleString('en', { maximumFractionDigits: 0 })} ft)`;\n }\n return `${ft.toLocaleString('en', { maximumFractionDigits: 1 })} ft`;\n }\n if (metres >= 1000) {\n return `${(metres / 1000).toFixed(2)} km (${metres.toLocaleString('en', { maximumFractionDigits: 0 })} m)`;\n }\n return `${metres.toLocaleString('en', { maximumFractionDigits: 1 })} m`;\n}\n\n// ── Area ────────────────────────────────────────────────────────────────────\n\n/**\n * Format an area value (in square metres) for display.\n * Metric: m² / km²\n * Imperial: ft² / acres / mi²\n */\nexport function formatArea(sqMetres) {\n if (getSystem() === 'imperial') {\n const acres = sqMetres * SQM_TO_ACRE;\n if (acres >= 640) {\n return (Math.round(sqMetres * SQM_TO_SQMI * 100) / 100) + ' mi²';\n }\n if (acres >= 1) {\n return (Math.round(acres * 100) / 100) + ' acres';\n }\n return Math.round(sqMetres * SQM_TO_SQFT).toLocaleString('en') + ' ft²';\n }\n // metric\n if (sqMetres > 1000000) {\n return (Math.round(sqMetres / 1000000 * 100) / 100) + ' km²';\n }\n return (Math.round(sqMetres * 100) / 100) + ' m²';\n}\n\n/**\n * Format an area with both large and small units (for info popups).\n * Metric: \"1.23 km² (1,230,000 m²)\" or \"456 m²\"\n * Imperial: \"1.23 mi² (787 acres)\" or \"2.5 acres\" or \"456 ft²\"\n */\nexport function formatAreaFull(sqMetres) {\n if (getSystem() === 'imperial') {\n const sqft = sqMetres * SQM_TO_SQFT;\n const acres = sqMetres * SQM_TO_ACRE;\n const sqmi = sqMetres * SQM_TO_SQMI;\n if (acres >= 640) {\n return `${sqmi.toFixed(2)} mi² (${acres.toLocaleString('en', { maximumFractionDigits: 0 })} acres)`;\n }\n if (acres >= 1) {\n return `${acres.toLocaleString('en', { maximumFractionDigits: 1 })} acres (${sqft.toLocaleString('en', { maximumFractionDigits: 0 })} ft²)`;\n }\n return `${sqft.toLocaleString('en', { maximumFractionDigits: 0 })} ft²`;\n }\n if (sqMetres > 1000000) {\n return `${(sqMetres / 1000000).toFixed(2)} km² (${sqMetres.toLocaleString('en', { maximumFractionDigits: 0 })} m²)`;\n }\n return `${sqMetres.toLocaleString('en', { maximumFractionDigits: 0 })} m²`;\n}\n\n// ── Circle helper ───────────────────────────────────────────────────────────\n\n/**\n * Format the area of a circle given its radius (in metres).\n */\nexport function formatCircleExtent(radiusMetres) {\n return formatArea(Math.PI * radiusMetres * radiusMetres);\n}\n","/**\n * Pure geometry functions for splitting a polygon by a line.\n *\n * No OpenLayers dependency — operates on raw coordinate arrays.\n */\n\n/**\n * Compute the intersection point of two 2D line segments.\n * Segment A: p1→p2, Segment B: p3→p4.\n *\n * @param {number[]} p1\n * @param {number[]} p2\n * @param {number[]} p3\n * @param {number[]} p4\n * @param {number} [eps=1e-10] tolerance for parallel check\n * @returns {{ point: number[], t: number, u: number } | null}\n * t = parametric position on segment A (0–1),\n * u = parametric position on segment B (0–1)\n */\nfunction segmentIntersection(p1, p2, p3, p4, eps = 1e-10) {\n const dx1 = p2[0] - p1[0];\n const dy1 = p2[1] - p1[1];\n const dx2 = p4[0] - p3[0];\n const dy2 = p4[1] - p3[1];\n\n const denom = dx1 * dy2 - dy1 * dx2;\n if (Math.abs(denom) < eps) return null; // parallel / collinear\n\n const dx3 = p3[0] - p1[0];\n const dy3 = p3[1] - p1[1];\n\n const t = (dx3 * dy2 - dy3 * dx2) / denom;\n const u = (dx3 * dy1 - dy3 * dx1) / denom;\n\n if (t < -eps || t > 1 + eps || u < -eps || u > 1 + eps) return null;\n\n return {\n point: [p1[0] + t * dx1, p1[1] + t * dy1],\n t: Math.max(0, Math.min(1, t)),\n u: Math.max(0, Math.min(1, u)),\n };\n}\n\n/**\n * Signed area of a ring (shoelace formula).\n * Positive = counter-clockwise, negative = clockwise.\n */\nfunction signedArea(ring) {\n let area = 0;\n for (let i = 0, n = ring.length; i < n - 1; i++) {\n area += (ring[i][0] * ring[i + 1][1]) - (ring[i + 1][0] * ring[i][1]);\n }\n return area / 2;\n}\n\n/**\n * Test whether a point is inside a ring (ray-casting algorithm).\n */\nfunction pointInRing(pt, ring) {\n let inside = false;\n for (let i = 0, j = ring.length - 2; i < ring.length - 1; j = i++) {\n const xi = ring[i][0], yi = ring[i][1];\n const xj = ring[j][0], yj = ring[j][1];\n if (((yi > pt[1]) !== (yj > pt[1])) &&\n (pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi)) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/**\n * Squared distance between two points.\n */\nfunction dist2(a, b) {\n return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n}\n\n/**\n * Find all intersection points between a cutting line and a polygon ring.\n *\n * @param {number[][]} ring Closed ring coordinates (first === last)\n * @param {number[][]} line LineString coordinates (2+ points)\n * @returns {Array<{ point: number[], ringSegIdx: number, ringT: number, lineSegIdx: number, lineT: number }>}\n */\nfunction findIntersections(ring, line) {\n const hits = [];\n const eps = 1e-10;\n\n for (let li = 0; li < line.length - 1; li++) {\n for (let ri = 0; ri < ring.length - 1; ri++) {\n const ix = segmentIntersection(ring[ri], ring[ri + 1], line[li], line[li + 1], eps);\n if (!ix) continue;\n\n // Skip if intersection is at the very start of the ring segment\n // but was already caught as the end of the previous segment\n const pt = ix.point;\n\n // Avoid duplicate hits at shared vertices\n let isDup = false;\n for (const h of hits) {\n if (dist2(h.point, pt) < 1e-6) {\n isDup = true;\n break;\n }\n }\n if (isDup) continue;\n\n hits.push({\n point: pt,\n ringSegIdx: ri,\n ringT: ix.t,\n lineSegIdx: li,\n lineT: ix.u,\n });\n }\n }\n\n // Sort by position along the cutting line\n hits.sort((a, b) => {\n if (a.lineSegIdx !== b.lineSegIdx) return a.lineSegIdx - b.lineSegIdx;\n return a.lineT - b.lineT;\n });\n\n return hits;\n}\n\n/**\n * Insert intersection points into a ring, returning the expanded ring\n * and the new indices of the inserted points.\n *\n * @param {number[][]} ring Closed ring (first === last)\n * @param {Array<{ point: number[], ringSegIdx: number, ringT: number }>} hits\n * Sorted by ringSegIdx then ringT.\n * @returns {{ ring: number[][], indices: number[] }}\n */\nfunction insertPointsIntoRing(ring, hits) {\n // Sort hits by ring position (segment index, then parametric t) so\n // we can insert from back to front without shifting earlier indices.\n const sorted = hits.map((h, i) => ({ ...h, origOrder: i }));\n sorted.sort((a, b) => {\n if (a.ringSegIdx !== b.ringSegIdx) return a.ringSegIdx - b.ringSegIdx;\n return a.ringT - b.ringT;\n });\n\n const expanded = ring.slice(); // copy\n const indices = new Array(sorted.length);\n\n // Insert from the end so that earlier insertions don't shift later indices.\n for (let k = sorted.length - 1; k >= 0; k--) {\n const h = sorted[k];\n const insertIdx = h.ringSegIdx + 1;\n\n // Check if this point is essentially identical to an existing vertex\n const snapDist = 1e-6;\n if (dist2(h.point, expanded[h.ringSegIdx]) < snapDist) {\n indices[h.origOrder] = h.ringSegIdx;\n continue;\n }\n if (dist2(h.point, expanded[h.ringSegIdx + 1]) < snapDist) {\n indices[h.origOrder] = h.ringSegIdx + 1;\n continue;\n }\n\n // Insert the new point\n expanded.splice(insertIdx, 0, h.point);\n indices[h.origOrder] = insertIdx;\n\n // Adjust indices for all previously recorded insertions\n // that reference a position >= insertIdx\n for (let j = k + 1; j < sorted.length; j++) {\n if (indices[sorted[j].origOrder] >= insertIdx) {\n indices[sorted[j].origOrder]++;\n }\n }\n }\n\n return { ring: expanded, indices };\n}\n\n/**\n * Extract a slice of a ring from index i0 to i1 (going forward, wrapping).\n * Both endpoints are included.\n *\n * @param {number[][]} ring Closed ring (first === last); length includes closing vertex\n * @param {number} i0 Start index (inclusive)\n * @param {number} i1 End index (inclusive)\n * @returns {number[][]}\n */\nfunction ringSlice(ring, i0, i1) {\n const n = ring.length - 1; // number of unique vertices (ring is closed)\n // Normalise indices into the [0, n-1] range\n const start = ((i0 % n) + n) % n;\n const end = ((i1 % n) + n) % n;\n const result = [];\n let idx = start;\n while (true) {\n result.push(ring[idx]);\n if (idx === end) break;\n idx = (idx + 1) % n;\n }\n return result;\n}\n\n/**\n * Extract the cutting line segment between two intersection points.\n *\n * @param {number[][]} line Full cutting line coordinates\n * @param {{ point: number[], lineSegIdx: number, lineT: number }} hit0\n * @param {{ point: number[], lineSegIdx: number, lineT: number }} hit1\n * @returns {number[][]} Coordinates from hit0.point to hit1.point along the line\n */\nfunction cuttingLineSlice(line, hit0, hit1) {\n const result = [hit0.point];\n\n // Include all intermediate line vertices between the two hit segments\n const startSeg = hit0.lineSegIdx;\n const endSeg = hit1.lineSegIdx;\n\n for (let i = startSeg + 1; i <= endSeg; i++) {\n result.push(line[i]);\n }\n\n // Add the end intersection point if it's not the same as the last vertex\n if (dist2(result[result.length - 1], hit1.point) > 1e-10) {\n result.push(hit1.point);\n }\n\n return result;\n}\n\n/**\n * Ensure a ring has the desired winding order.\n * @param {number[][]} ring Closed ring\n * @param {boolean} ccw true for counter-clockwise\n * @returns {number[][]}\n */\nfunction ensureWinding(ring, ccw) {\n const area = signedArea(ring);\n if ((ccw && area < 0) || (!ccw && area > 0)) {\n return ring.slice().reverse();\n }\n return ring;\n}\n\n/**\n * Close a ring (ensure first === last).\n */\nfunction closeRing(coords) {\n if (coords.length < 2) return coords;\n const first = coords[0];\n const last = coords[coords.length - 1];\n if (dist2(first, last) > 1e-10) {\n return [...coords, first.slice()];\n }\n return coords;\n}\n\n/**\n * Extend a cutting line so that both endpoints lie outside the polygon ring.\n * If an endpoint is inside, we extend the first/last segment outward past the\n * bounding box diagonal so it definitely exits.\n *\n * @param {number[][]} line Cutting line coordinates\n * @param {number[][]} ring Closed polygon ring\n * @returns {number[][]} Extended line (may be the original if already outside)\n */\nfunction extendLineOutsideRing(line, ring) {\n // Compute bounding-box diagonal for a generous extension distance\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const pt of ring) {\n if (pt[0] < minX) minX = pt[0];\n if (pt[1] < minY) minY = pt[1];\n if (pt[0] > maxX) maxX = pt[0];\n if (pt[1] > maxY) maxY = pt[1];\n }\n const diag = Math.sqrt((maxX - minX) ** 2 + (maxY - minY) ** 2) || 1;\n\n const result = line.slice();\n\n // Extend start if inside\n if (pointInRing(result[0], ring)) {\n const p0 = result[0];\n const p1 = result[1];\n const dx = p0[0] - p1[0];\n const dy = p0[1] - p1[1];\n const len = Math.sqrt(dx * dx + dy * dy) || 1;\n const scale = diag * 2 / len;\n result[0] = [p0[0] + dx * scale, p0[1] + dy * scale];\n }\n\n // Extend end if inside\n const last = result.length - 1;\n if (pointInRing(result[last], ring)) {\n const pN = result[last];\n const pN1 = result[last - 1];\n const dx = pN[0] - pN1[0];\n const dy = pN[1] - pN1[1];\n const len = Math.sqrt(dx * dx + dy * dy) || 1;\n const scale = diag * 2 / len;\n result[last] = [pN[0] + dx * scale, pN[1] + dy * scale];\n }\n\n return result;\n}\n\n/**\n * Split a polygon by a cutting line.\n *\n * The cutting line can start or end inside the polygon — the algorithm will\n * automatically extend it outward so it crosses the boundary at exactly 2\n * points. Multi-vertex cutting lines (with corners or approximated arcs)\n * are fully supported.\n *\n * @param {number[][][]} polygonCoords Polygon coordinates:\n * [exteriorRing, ...holeRings] where each ring is closed (first === last)\n * @param {number[][]} lineCoords Cutting line coordinates (2+ points)\n * @returns {number[][][][] | null} Two polygon coordinate arrays, or null if split failed\n */\nexport function splitPolygonByLine(polygonCoords, lineCoords) {\n const exteriorRing = polygonCoords[0];\n const holes = polygonCoords.slice(1);\n\n // Extend the cutting line if its endpoints are inside the polygon\n const extendedLine = extendLineOutsideRing(lineCoords, exteriorRing);\n\n // 1. Find intersections between cutting line and exterior ring\n const hits = findIntersections(exteriorRing, extendedLine);\n\n // We need exactly 2 intersection points for a simple split\n if (hits.length !== 2) {\n console.warn(`[polygonSplit] Expected 2 intersections, got ${hits.length}`);\n return null;\n }\n\n const [hit0, hit1] = hits;\n\n // 2. Insert intersection points into the ring\n const { ring: expandedRing, indices } = insertPointsIntoRing(exteriorRing, hits);\n const idx0 = indices[0];\n const idx1 = indices[1];\n\n // Ensure idx0 < idx1 for consistent traversal\n const [iA, iB] = idx0 < idx1 ? [idx0, idx1] : [idx1, idx0];\n const [hitA, hitB] = idx0 < idx1 ? [hit0, hit1] : [hit1, hit0];\n\n // 3. Get the cutting line segment between the two intersection points\n const cutForward = idx0 < idx1\n ? cuttingLineSlice(extendedLine, hit0, hit1)\n : cuttingLineSlice(extendedLine, hit1, hit0);\n const cutReverse = cutForward.slice().reverse();\n\n // 4. Build two polygon rings\n // Ring A: walk ring from iA to iB (forward), then cutting line reversed back to iA\n const sliceAB = ringSlice(expandedRing, iA, iB);\n const ringA = closeRing([...sliceAB, ...cutReverse.slice(1)]);\n\n // Ring B: walk ring from iB to iA (wrapping), then cutting line forward back to iB\n const sliceBA = ringSlice(expandedRing, iB, iA);\n const ringB = closeRing([...sliceBA, ...cutForward.slice(1)]);\n\n // 5. Match winding order to original\n const originalCCW = signedArea(exteriorRing) > 0;\n const finalA = ensureWinding(ringA, originalCCW);\n const finalB = ensureWinding(ringB, originalCCW);\n\n // 6. Build polygon coordinate arrays, assigning holes to the correct piece\n const polyA = [finalA];\n const polyB = [finalB];\n\n for (const hole of holes) {\n // Use the centroid of the hole to determine containment\n const centroid = holeCentroid(hole);\n if (pointInRing(centroid, finalA)) {\n polyA.push(hole);\n } else {\n polyB.push(hole);\n }\n }\n\n return [polyA, polyB];\n}\n\n/**\n * Compute the centroid of a closed ring.\n */\nfunction holeCentroid(ring) {\n let cx = 0, cy = 0;\n const n = ring.length - 1; // exclude closing vertex\n for (let i = 0; i < n; i++) {\n cx += ring[i][0];\n cy += ring[i][1];\n }\n return [cx / n, cy / n];\n}\n","/**\n * Lightweight toast notification system.\n *\n * Usage:\n * import { showToast } from '../toast.js';\n *\n * showToast('Something went wrong', 'error');\n * showToast('Merge successful!', 'success');\n * showToast('Select two adjacent polygons', 'info');\n */\n\n// ── Palette ──────────────────────────────────────────────────────────────────\n\nconst THEMES = {\n success: { bg: '#10b981', icon: '\\u2705' }, // green\n error: { bg: '#ef4444', icon: '\\u274c' }, // red\n warning: { bg: '#f59e0b', icon: '\\u26a0\\ufe0f' }, // amber\n info: { bg: '#0ea5e9', icon: '\\u2139\\ufe0f' }, // cyan\n};\n\n// ── Container (created once, appended to ) ────────────────────────────\n\nlet container = null;\n\nfunction ensureContainer() {\n if (container) return container;\n container = document.createElement('div');\n container.style.cssText = `\n position: fixed;\n top: 16px;\n left: 50%;\n transform: translateX(-50%);\n z-index: 10000;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n pointer-events: none;\n `;\n document.body.appendChild(container);\n return container;\n}\n\n// ── Public API ──────────────────────────────────────────────────────────────\n\n/**\n * Display a toast notification.\n *\n * @param {string} message Plain-text message to show.\n * @param {'success'|'error'|'warning'|'info'} [type='info']\n * @param {number} [duration=4000] Auto-dismiss time in ms.\n */\nexport function showToast(message, type = 'info', duration = 4000) {\n const parent = ensureContainer();\n const theme = THEMES[type] || THEMES.info;\n\n const el = document.createElement('div');\n el.style.cssText = `\n background: ${theme.bg};\n color: #fff;\n padding: 10px 18px;\n border-radius: 8px;\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n font-weight: 600;\n box-shadow: 0 4px 12px rgba(0,0,0,0.25);\n pointer-events: auto;\n cursor: pointer;\n opacity: 0;\n transition: opacity 0.25s ease, transform 0.25s ease;\n transform: translateY(-8px);\n max-width: 420px;\n text-align: center;\n line-height: 1.4;\n `;\n el.textContent = `${theme.icon} ${message}`;\n\n parent.appendChild(el);\n\n // Animate in\n requestAnimationFrame(() => {\n el.style.opacity = '1';\n el.style.transform = 'translateY(0)';\n });\n\n // Dismiss helper\n const dismiss = () => {\n el.style.opacity = '0';\n el.style.transform = 'translateY(-8px)';\n setTimeout(() => el.remove(), 300);\n };\n\n // Click to dismiss early\n el.addEventListener('click', dismiss);\n\n // Auto-dismiss\n setTimeout(dismiss, duration);\n}\n","/**\n * PolygonSplitInteraction\n *\n * A two-phase OpenLayers interaction for splitting polygons:\n * Phase 1 – SELECT: hover to highlight, click to select a polygon\n * Phase 2 – DRAW: draw a cutting line, double-click to finish\n *\n * After a successful split the original feature is removed and two new\n * coloured features are added. The interaction fires `beforesplit` and\n * `aftersplit` events compatible with ol-ext's UndoRedo.\n */\n\nimport ol_interaction_Interaction from 'ol/interaction/Interaction';\nimport ol_interaction_Draw from 'ol/interaction/Draw';\nimport VectorSource from 'ol/source/Vector';\nimport VectorLayer from 'ol/layer/Vector';\nimport Feature from 'ol/Feature';\nimport { Style, Stroke, Fill, Circle as CircleStyle } from 'ol/style';\nimport { LineString } from 'ol/geom';\nimport { Polygon as PolygonGeom } from 'ol/geom';\nimport { splitPolygonByLine } from '../geom/polygonSplit.js';\nimport { showToast } from '../toast.js';\n\n// Marker colours for the two split pieces\nconst SPLIT_COLORS = [\n { stroke: '#ef4444', fill: 'rgba(239,68,68,0.25)' }, // red\n { stroke: '#3b82f6', fill: 'rgba(59,130,246,0.25)' }, // blue\n];\n\n// Highlight style for the selected polygon (phase 1)\nconst HIGHLIGHT_STYLE = new Style({\n stroke: new Stroke({ color: '#0ea5e9', width: 3 }),\n fill: new Fill({ color: 'rgba(14,165,233,0.15)' }),\n});\n\n// Style for the cutting-line sketch (phase 2)\nconst SKETCH_STYLE = new Style({\n stroke: new Stroke({ color: '#f43f5e', width: 2, lineDash: [8, 6] }),\n image: new CircleStyle({\n radius: 5,\n fill: new Fill({ color: '#f43f5e' }),\n stroke: new Stroke({ color: '#fff', width: 1.5 }),\n }),\n});\n\nexport class PolygonSplitInteraction extends ol_interaction_Interaction {\n /**\n * @param {Object} options\n * @param {VectorSource|VectorSource[]} [options.sources] Sources containing\n * polygons to split. If omitted the interaction searches all visible\n * vector layers on the map.\n * @param {number} [options.snapDistance=25] Pixel distance for hover highlight.\n */\n constructor(options = {}) {\n super({\n handleEvent: (e) => this._handleEvent(e),\n });\n\n this.snapDistance_ = options.snapDistance || 25;\n this._sources = options.sources\n ? (Array.isArray(options.sources) ? options.sources : [options.sources])\n : null;\n\n // Phase: 'select' | 'draw' | 'pick'\n this._phase = 'select';\n this._selectedFeature = null;\n this._selectedSource = null;\n this._drawInteraction = null;\n this._splitFeatures = null; // the two pieces (for pick phase)\n\n // Overlay layer for highlighting the polygon under the cursor / selected\n this._overlaySource = new VectorSource({ useSpatialIndex: false });\n this._overlayLayer = new VectorLayer({\n source: this._overlaySource,\n displayInLayerSwitcher: false,\n style: HIGHLIGHT_STYLE,\n });\n }\n\n /* ------------------------------------------------------------------ */\n /* Map lifecycle */\n /* ------------------------------------------------------------------ */\n\n setMap(map) {\n if (this.getMap()) {\n this.getMap().removeLayer(this._overlayLayer);\n this._removeDrawInteraction();\n }\n super.setMap(map);\n if (map) {\n this._overlayLayer.setMap(map);\n }\n }\n\n setActive(active) {\n super.setActive(active);\n if (!active) {\n this._reset();\n }\n }\n\n /* ------------------------------------------------------------------ */\n /* Source helpers */\n /* ------------------------------------------------------------------ */\n\n _getSources() {\n if (this._sources) return this._sources;\n if (!this.getMap()) return [];\n const sources = [];\n const collect = (layers) => {\n layers.forEach((layer) => {\n if (layer.getVisible()) {\n if (layer.getSource && layer.getSource() instanceof VectorSource) {\n sources.push(layer.getSource());\n } else if (layer.getLayers) {\n collect(layer.getLayers());\n }\n }\n });\n };\n collect(this.getMap().getLayers());\n return sources;\n }\n\n /* ------------------------------------------------------------------ */\n /* Event router */\n /* ------------------------------------------------------------------ */\n\n _handleEvent(e) {\n if (!this.getActive()) return true;\n\n if (this._phase === 'select') {\n if (e.type === 'pointermove') return this._onSelectMove(e);\n if (e.type === 'singleclick') return this._onSelectClick(e);\n }\n // In 'draw' phase the Draw interaction handles events directly;\n // we only intercept Escape to cancel.\n if (this._phase === 'draw') {\n if (e.type === 'keydown' && e.originalEvent?.key === 'Escape') {\n this._cancelDraw();\n return false;\n }\n }\n\n // In 'pick' phase the user selects which split piece keeps the UPN\n if (this._phase === 'pick') {\n if (e.type === 'pointermove') return this._onPickMove(e);\n if (e.type === 'singleclick') return this._onPickClick(e);\n if (e.type === 'keydown' && e.originalEvent?.key === 'Escape') {\n this._reset();\n return false;\n }\n }\n\n return true;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 1: SELECT */\n /* ------------------------------------------------------------------ */\n\n _onSelectMove(e) {\n const map = this.getMap();\n if (!map) return true;\n\n this._overlaySource.clear();\n\n const hit = this._closestPolygon(e);\n if (hit) {\n // Show highlight copy\n const clone = hit.feature.clone();\n this._overlaySource.addFeature(clone);\n map.getTargetElement().style.cursor = 'pointer';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onSelectClick(e) {\n const hit = this._closestPolygon(e);\n if (!hit) return true;\n\n this._selectedFeature = hit.feature;\n this._selectedSource = hit.source;\n\n // Keep highlight visible during draw phase\n this._overlaySource.clear();\n const clone = hit.feature.clone();\n this._overlaySource.addFeature(clone);\n\n this._startDrawPhase();\n return false; // consume the click\n }\n\n /**\n * Find the closest polygon feature within snap distance.\n */\n _closestPolygon(e) {\n let best = null;\n let bestDist = this.snapDistance_ + 1;\n\n for (const source of this._getSources()) {\n const feat = source.getClosestFeatureToCoordinate(e.coordinate);\n if (!feat) continue;\n const geom = feat.getGeometry();\n if (!geom) continue;\n const type = geom.getType();\n if (type !== 'Polygon' && type !== 'MultiPolygon') continue;\n\n const closest = geom.getClosestPoint(e.coordinate);\n const line = new LineString([e.coordinate, closest]);\n const distPx = line.getLength() / e.frameState.viewState.resolution;\n\n if (distPx < bestDist) {\n bestDist = distPx;\n best = { feature: feat, source, coord: closest };\n }\n }\n return best;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 2: DRAW cutting line */\n /* ------------------------------------------------------------------ */\n\n _startDrawPhase() {\n this._phase = 'draw';\n const map = this.getMap();\n if (!map) return;\n\n map.getTargetElement().style.cursor = 'crosshair';\n\n this._drawInteraction = new ol_interaction_Draw({\n type: 'LineString',\n style: SKETCH_STYLE,\n });\n\n this._drawInteraction.on('drawend', (evt) => {\n const cuttingLine = evt.feature.getGeometry().getCoordinates();\n this._performSplit(cuttingLine);\n });\n\n map.addInteraction(this._drawInteraction);\n }\n\n _removeDrawInteraction() {\n if (this._drawInteraction && this.getMap()) {\n this.getMap().removeInteraction(this._drawInteraction);\n }\n this._drawInteraction = null;\n }\n\n _cancelDraw() {\n this._removeDrawInteraction();\n this._reset();\n }\n\n /* ------------------------------------------------------------------ */\n /* Split logic */\n /* ------------------------------------------------------------------ */\n\n _performSplit(cuttingLineCoords) {\n const feature = this._selectedFeature;\n const source = this._selectedSource;\n const geom = feature.getGeometry();\n\n let polygonCoords;\n if (geom.getType() === 'Polygon') {\n polygonCoords = geom.getCoordinates();\n } else if (geom.getType() === 'MultiPolygon') {\n // For MultiPolygon, try to split each sub-polygon and use the\n // first one that produces a valid result.\n // For now, use the first polygon ring.\n polygonCoords = geom.getCoordinates()[0];\n }\n\n const result = splitPolygonByLine(polygonCoords, cuttingLineCoords);\n\n if (!result) {\n console.warn('[PolygonSplit] Split failed — line must cross the polygon boundary at exactly 2 points.');\n // Stay in draw phase so user can retry\n this._removeDrawInteraction();\n this._startDrawPhase();\n return;\n }\n\n const [coordsA, coordsB] = result;\n\n // Create two new features from the split result\n const featureA = feature.clone();\n featureA.setGeometry(new PolygonGeom(coordsA));\n featureA.setStyle(new Style({\n stroke: new Stroke({ color: SPLIT_COLORS[0].stroke, width: 2.5 }),\n fill: new Fill({ color: SPLIT_COLORS[0].fill }),\n }));\n\n const featureB = feature.clone();\n featureB.setGeometry(new PolygonGeom(coordsB));\n featureB.setStyle(new Style({\n stroke: new Stroke({ color: SPLIT_COLORS[1].stroke, width: 2.5 }),\n fill: new Fill({ color: SPLIT_COLORS[1].fill }),\n }));\n\n // Dispatch beforesplit (compatible with ol-ext UndoRedo)\n const splitFeatures = [featureA, featureB];\n this.dispatchEvent({\n type: 'beforesplit',\n original: feature,\n features: splitFeatures,\n });\n source.dispatchEvent({\n type: 'beforesplit',\n original: feature,\n features: splitFeatures,\n });\n\n // Replace the original feature\n source.removeFeature(feature);\n source.addFeature(featureA);\n source.addFeature(featureB);\n\n // Dispatch aftersplit\n this.dispatchEvent({\n type: 'aftersplit',\n original: feature,\n features: splitFeatures,\n });\n source.dispatchEvent({\n type: 'aftersplit',\n original: feature,\n features: splitFeatures,\n });\n\n // Clean up draw interaction\n this._removeDrawInteraction();\n\n // If the original was a parcel, enter pick phase for UPN assignment\n const isParcel = feature.get('_layerType') === 'parcel';\n if (isParcel) {\n this._splitFeatures = splitFeatures;\n this._phase = 'pick';\n this._overlaySource.clear();\n const map = this.getMap();\n if (map) map.getTargetElement().style.cursor = '';\n showToast('Click the polygon that should keep the original identifier.', 'info', 5000);\n\n this.dispatchEvent({\n type: 'splitparcel',\n features: splitFeatures,\n originalProps: feature.getProperties(),\n source,\n });\n } else {\n this._reset();\n }\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 3: PICK — select which split piece keeps the UPN */\n /* ------------------------------------------------------------------ */\n\n _onPickMove(e) {\n const map = this.getMap();\n if (!map) return true;\n\n this._overlaySource.clear();\n\n const hit = this._closestSplitPiece(e);\n if (hit) {\n const clone = hit.clone();\n this._overlaySource.addFeature(clone);\n map.getTargetElement().style.cursor = 'pointer';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onPickClick(e) {\n const hit = this._closestSplitPiece(e);\n if (!hit) return true;\n\n this.dispatchEvent({\n type: 'splitpick',\n picked: hit,\n features: this._splitFeatures,\n });\n\n this._reset();\n return false;\n }\n\n /**\n * Find the closest split piece to the cursor.\n */\n _closestSplitPiece(e) {\n if (!this._splitFeatures) return null;\n let best = null;\n let bestDist = this.snapDistance_ + 1;\n\n for (const feat of this._splitFeatures) {\n const geom = feat.getGeometry();\n if (!geom) continue;\n const closest = geom.getClosestPoint(e.coordinate);\n const line = new LineString([e.coordinate, closest]);\n const distPx = line.getLength() / e.frameState.viewState.resolution;\n if (distPx < bestDist) {\n bestDist = distPx;\n best = feat;\n }\n }\n return best;\n }\n\n /* ------------------------------------------------------------------ */\n /* Reset */\n /* ------------------------------------------------------------------ */\n\n _reset() {\n this._phase = 'select';\n this._selectedFeature = null;\n this._selectedSource = null;\n this._splitFeatures = null;\n this._overlaySource.clear();\n this._removeDrawInteraction();\n\n const map = this.getMap();\n if (map) {\n map.getTargetElement().style.cursor = '';\n }\n }\n}\n","/**\n * Pure geometry functions for merging two adjacent polygons.\n *\n * No OpenLayers dependency — operates on raw coordinate arrays.\n */\n\n/**\n * Squared distance between two points.\n */\nfunction dist2(a, b) {\n return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n}\n\n/**\n * Signed area of a ring (shoelace formula).\n * Positive = counter-clockwise, negative = clockwise.\n */\nfunction signedArea(ring) {\n let area = 0;\n for (let i = 0, n = ring.length; i < n - 1; i++) {\n area += (ring[i][0] * ring[i + 1][1]) - (ring[i + 1][0] * ring[i][1]);\n }\n return area / 2;\n}\n\n/**\n * Test whether a point is inside a ring (ray-casting algorithm).\n */\nfunction pointInRing(pt, ring) {\n let inside = false;\n for (let i = 0, j = ring.length - 2; i < ring.length - 1; j = i++) {\n const xi = ring[i][0], yi = ring[i][1];\n const xj = ring[j][0], yj = ring[j][1];\n if (((yi > pt[1]) !== (yj > pt[1])) &&\n (pt[0] < (xj - xi) * (pt[1] - yi) / (yj - yi) + xi)) {\n inside = !inside;\n }\n }\n return inside;\n}\n\n/**\n * Ensure a ring has the desired winding order.\n */\nfunction ensureWinding(ring, ccw) {\n const area = signedArea(ring);\n if ((ccw && area < 0) || (!ccw && area > 0)) {\n return ring.slice().reverse();\n }\n return ring;\n}\n\n/**\n * Close a ring (ensure first === last).\n */\nfunction closeRing(coords) {\n if (coords.length < 2) return coords;\n if (dist2(coords[0], coords[coords.length - 1]) > 1e-10) {\n return [...coords, coords[0].slice()];\n }\n return coords;\n}\n\n/**\n * Perpendicular distance from a point to a segment.\n *\n * @param {number[]} pt\n * @param {number[]} segA Segment start\n * @param {number[]} segB Segment end\n * @returns {number} Squared distance\n */\nfunction distToSegmentSq(pt, segA, segB) {\n const dx = segB[0] - segA[0];\n const dy = segB[1] - segA[1];\n const lenSq = dx * dx + dy * dy;\n\n if (lenSq < 1e-20) return dist2(pt, segA); // degenerate segment\n\n // Parametric position of the projection\n let t = ((pt[0] - segA[0]) * dx + (pt[1] - segA[1]) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n\n const projX = segA[0] + t * dx;\n const projY = segA[1] + t * dy;\n return (pt[0] - projX) ** 2 + (pt[1] - projY) ** 2;\n}\n\n/**\n * Find the ring edge closest to a click coordinate.\n *\n * @param {number[][]} ring Closed ring\n * @param {number[]} clickCoord [x, y]\n * @returns {{ segIdx: number, distSq: number }}\n */\nfunction findClosestEdge(ring, clickCoord) {\n let bestIdx = 0;\n let bestDist = Infinity;\n const n = ring.length - 1; // unique vertices\n\n for (let i = 0; i < n; i++) {\n const d = distToSegmentSq(clickCoord, ring[i], ring[(i + 1) % n === 0 ? n : i + 1]);\n if (d < bestDist) {\n bestDist = d;\n bestIdx = i;\n }\n }\n return { segIdx: bestIdx, distSq: bestDist };\n}\n\n/**\n * Check if two coordinates are equal within tolerance.\n */\nfunction coordsEqual(a, b, tolSq) {\n return dist2(a, b) < tolSq;\n}\n\n/**\n * Test whether a point lies within tolerance of any edge of a ring.\n *\n * Unlike coordsEqual (vertex-to-vertex), this checks whether the point is\n * close to the ring's *boundary* — it projects onto segments, so it works\n * even when the two polygons have different vertex density along the shared\n * edge or when vertices are slightly offset from separate digitisation.\n *\n * @param {number[]} pt Point to test\n * @param {number[][]} ring Closed ring\n * @param {number} tolSq Squared distance tolerance\n * @returns {boolean}\n */\nfunction isVertexNearRing(pt, ring, tolSq) {\n const n = ring.length - 1;\n for (let i = 0; i < n; i++) {\n if (distToSegmentSq(pt, ring[i], ring[i + 1]) < tolSq) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Find the shared boundary between two polygon rings.\n *\n * Adjacent polygons share edges in reverse winding direction:\n * if A walks P→Q along the shared boundary, B walks Q→P.\n *\n * The algorithm has two stages:\n *\n * 1. **Seed validation** — uses `isVertexNearRing` (vertex-to-edge proximity)\n * to confirm the user-clicked edges actually lie on a common boundary.\n * This is the forgiving check that handles offset vertices from separate\n * digitisation.\n *\n * 2. **Lockstep extension** — walks both rings together (A forward, B in\n * the opposite direction) and extends the shared boundary one vertex at\n * a time. Three cases are tried at each step:\n * a) Both rings advance: vertex-to-vertex match (classic case).\n * b) Only A advances: A has an extra vertex that projects onto B's\n * frontier edge (different vertex density).\n * c) Only B advances: vice-versa.\n * Because extension is coupled to the *frontier edge* of the other ring\n * (not the entire ring), it cannot overshoot into non-shared territory,\n * even for small or closely-spaced polygons.\n *\n * @param {number[][]} ringA Closed ring\n * @param {number[][]} ringB Closed ring\n * @param {number} seedIdxA Seed edge index on ring A\n * @param {number} seedIdxB Seed edge index on ring B\n * @param {number} tolerance Distance tolerance (in map units)\n * @returns {{ startA: number, endA: number, startB: number, endB: number, reversed: boolean } | null}\n */\nfunction findSharedBoundary(ringA, ringB, seedIdxA, seedIdxB, tolerance) {\n const nA = ringA.length - 1; // unique vertices\n const nB = ringB.length - 1;\n const tolSq = tolerance * tolerance;\n\n // ── Validate seed edges ─────────────────────────────────────────────\n // Both vertices of the seed edge on A must be near ring B's boundary,\n // or both vertices of the seed edge on B must be near ring A's boundary.\n // This uses vertex-to-edge proximity so it handles offset digitisation.\n const a0 = ringA[seedIdxA];\n const a1 = ringA[(seedIdxA + 1) % nA];\n const b0 = ringB[seedIdxB];\n const b1 = ringB[(seedIdxB + 1) % nB];\n\n const a0NearB = isVertexNearRing(a0, ringB, tolSq);\n const a1NearB = isVertexNearRing(a1, ringB, tolSq);\n const b0NearA = isVertexNearRing(b0, ringA, tolSq);\n const b1NearA = isVertexNearRing(b1, ringA, tolSq);\n\n if (!(a0NearB && a1NearB) && !(b0NearA && b1NearA)) {\n console.warn('[polygonMerge] Seed edges are not on the shared boundary');\n return null;\n }\n\n // ── Determine winding direction ─────────────────────────────────────\n // Reversed (the normal case): A's a0 ≈ B's b1 and A's a1 ≈ B's b0.\n let reversed;\n if (coordsEqual(a0, b1, tolSq) && coordsEqual(a1, b0, tolSq)) {\n reversed = true;\n } else if (coordsEqual(a0, b0, tolSq) && coordsEqual(a1, b1, tolSq)) {\n reversed = false;\n } else {\n // Vertices don't match exactly — use proximity to decide direction\n reversed = dist2(a0, b1) < dist2(a0, b0);\n }\n\n // ── Initialise shared boundary ──────────────────────────────────────\n let startA = seedIdxA;\n let endA = (seedIdxA + 1) % nA;\n let startB, endB;\n\n if (reversed) {\n // A walks startA → endA, B walks startB ← endB (reversed ring order)\n startB = (seedIdxB + 1) % nB;\n endB = seedIdxB;\n } else {\n startB = seedIdxB;\n endB = (seedIdxB + 1) % nB;\n }\n\n // ── Extend forward (endA++, endB-- if reversed) ─────────────────────\n // Walk both rings in lockstep. At each step try three strategies:\n // 1. Both advance — vertices match (vertex-to-vertex).\n // 2. Only A advances — A's next vertex projects onto B's frontier edge.\n // 3. Only B advances — B's next vertex projects onto A's frontier edge.\n let safety = nA + nB;\n while (safety-- > 0) {\n const nextA = (endA + 1) % nA;\n const nextB = reversed ? (endB - 1 + nB) % nB : (endB + 1) % nB;\n if (nextA === startA || nextB === startB) break; // wrapped around\n\n // Case 1: vertex-to-vertex match\n if (coordsEqual(ringA[nextA], ringB[nextB], tolSq)) {\n endA = nextA;\n endB = nextB;\n continue;\n }\n\n // Case 2: A has extra vertex — project onto B's frontier edge\n if (distToSegmentSq(ringA[nextA], ringB[endB], ringB[nextB]) < tolSq) {\n endA = nextA;\n continue;\n }\n\n // Case 3: B has extra vertex — project onto A's frontier edge\n if (distToSegmentSq(ringB[nextB], ringA[endA], ringA[nextA]) < tolSq) {\n endB = nextB;\n continue;\n }\n\n break; // no match — end of shared boundary\n }\n\n // ── Extend backward (startA--, startB++ if reversed) ────────────────\n safety = nA + nB;\n while (safety-- > 0) {\n const prevA = (startA - 1 + nA) % nA;\n const prevB = reversed ? (startB + 1) % nB : (startB - 1 + nB) % nB;\n if (prevA === endA || prevB === endB) break;\n\n // Case 1: vertex-to-vertex match\n if (coordsEqual(ringA[prevA], ringB[prevB], tolSq)) {\n startA = prevA;\n startB = prevB;\n continue;\n }\n\n // Case 2: A has extra vertex — project onto B's frontier edge\n if (distToSegmentSq(ringA[prevA], ringB[startB], ringB[prevB]) < tolSq) {\n startA = prevA;\n continue;\n }\n\n // Case 3: B has extra vertex — project onto A's frontier edge\n if (distToSegmentSq(ringB[prevB], ringA[startA], ringA[prevA]) < tolSq) {\n startB = prevB;\n continue;\n }\n\n break;\n }\n\n return { startA, endA, startB, endB, reversed };\n}\n\n/**\n * Walk a ring from startIdx to endIdx (exclusive), going forward and wrapping.\n * Skips startIdx and stops before reaching endIdx.\n * Returns the vertices of the non-shared portion.\n *\n * @param {number[][]} ring Closed ring\n * @param {number} fromIdx Start walking from this index (inclusive)\n * @param {number} toIdx Stop at this index (inclusive)\n * @returns {number[][]}\n */\nfunction walkRing(ring, fromIdx, toIdx) {\n const n = ring.length - 1;\n const result = [];\n let idx = fromIdx;\n while (true) {\n result.push(ring[idx]);\n if (idx === toIdx) break;\n idx = (idx + 1) % n;\n // Safety: prevent infinite loops\n if (result.length > n + 1) break;\n }\n return result;\n}\n\n/**\n * Merge two adjacent polygons along their shared boundary.\n *\n * @param {number[][][]} polygonCoordsA Polygon A coordinates [exteriorRing, ...holes]\n * @param {number[][][]} polygonCoordsB Polygon B coordinates [exteriorRing, ...holes]\n * @param {number[]} clickCoordA Click coordinate on the shared edge of polygon A\n * @param {number[]} clickCoordB Click coordinate on the shared edge of polygon B\n * @param {number} [tolerance=5] Distance tolerance in map units (default 5 metres in EPSG:3857).\n * A larger tolerance handles polygons that were digitised separately and\n * whose shared vertices don't coincide exactly.\n * @returns {{ coords: number[][][], error?: undefined } | { coords: null, error: string }}\n * On success: `{ coords: [...] }`. On failure: `{ coords: null, error: 'reason' }`.\n */\nexport function mergePolygons(polygonCoordsA, polygonCoordsB, clickCoordA, clickCoordB, tolerance = 5) {\n const ringA = polygonCoordsA[0];\n const ringB = polygonCoordsB[0];\n const holesA = polygonCoordsA.slice(1);\n const holesB = polygonCoordsB.slice(1);\n\n // 1. Find seed edges (closest to user clicks)\n const seedA = findClosestEdge(ringA, clickCoordA);\n const seedB = findClosestEdge(ringB, clickCoordB);\n\n // 2. Find shared boundary\n const shared = findSharedBoundary(ringA, ringB, seedA.segIdx, seedB.segIdx, tolerance);\n if (!shared) {\n console.warn('[polygonMerge] Could not find shared boundary between polygons — seed edges are not near the other ring');\n return { coords: null, error: 'The selected edges are not on a shared boundary. Click edges that lie on the common border between the two polygons.' };\n }\n\n const { startA, endA, startB, endB, reversed } = shared;\n const nA = ringA.length - 1;\n const nB = ringB.length - 1;\n\n // 3. Stitch the non-shared portions together\n // A's shared goes from startA → endA. Non-shared: endA → startA (forward, wrapping).\n // B's shared (reversed case) goes from startB backward to endB.\n // Non-shared: startB → endB (forward).\n // B's shared (same-dir case) goes from startB → endB.\n // Non-shared: endB → startB (forward, wrapping).\n //\n // The last vertex of partA (startA) must coincide with the first vertex\n // of partB for a clean join.\n\n const partA = walkRing(ringA, endA, startA);\n\n let partB;\n if (reversed) {\n // B's non-shared goes from startB forward to endB.\n // startB vertex ≈ startA vertex (they meet at one end of the shared boundary).\n partB = walkRing(ringB, startB, endB);\n } else {\n // B's non-shared goes from endB forward to startB.\n partB = walkRing(ringB, endB, startB);\n }\n\n // partA ends at startA, partB starts at a vertex that should coincide.\n // Skip the first vertex of partB to avoid the duplicate junction point.\n const merged = [...partA, ...partB.slice(1)];\n\n // Snap the closing junction. With non-coincident vertices (separate\n // digitisation) the last vertex of partB may be a few metres from the\n // first vertex of partA (ringA[endA]). Replace it to avoid a tiny\n // sliver edge that closeRing would otherwise create.\n const tolSq = tolerance * tolerance;\n if (merged.length > 2 && dist2(merged[merged.length - 1], merged[0]) < tolSq) {\n merged[merged.length - 1] = merged[0].slice();\n }\n\n const mergedRing = closeRing(merged);\n\n // 4. Validate: the merged ring should have a reasonable area\n const areaA = Math.abs(signedArea(ringA));\n const areaB = Math.abs(signedArea(ringB));\n const areaMerged = Math.abs(signedArea(mergedRing));\n const expectedArea = areaA + areaB;\n\n // Allow 10% tolerance for area mismatch (shared edges can cause slight differences)\n if (areaMerged < expectedArea * 0.5 || areaMerged > expectedArea * 1.5) {\n console.warn(`[polygonMerge] Area mismatch: A=${areaA.toFixed(1)}, B=${areaB.toFixed(1)}, merged=${areaMerged.toFixed(1)}, expected≈${expectedArea.toFixed(1)}`);\n return { coords: null, error: 'Merge produced an invalid polygon (area mismatch). The polygons may not be truly adjacent — try clicking closer to the shared boundary.' };\n }\n\n // 5. Match winding order to original\n const originalCCW = signedArea(ringA) > 0;\n const finalRing = ensureWinding(mergedRing, originalCCW);\n\n // 6. Collect holes from both polygons\n const allHoles = [...holesA, ...holesB];\n // Filter: only include holes that actually fall inside the merged ring\n const validHoles = allHoles.filter(hole => {\n const cx = hole.reduce((s, p) => s + p[0], 0) / (hole.length - 1);\n const cy = hole.reduce((s, p) => s + p[1], 0) / (hole.length - 1);\n return pointInRing([cx, cy], finalRing);\n });\n\n return { coords: [finalRing, ...validHoles] };\n}\n","/**\n * PolygonMergeInteraction\n *\n * A four-phase OpenLayers interaction for merging two adjacent polygons:\n * Phase 1 – SELECT_A: hover to highlight, click to select polygon A\n * Phase 2 – SELECT_B: hover to highlight, click to select polygon B\n * Phase 3 – CLICK_EDGE_A: hover highlights edge, click to pick shared edge on A\n * Phase 4 – CLICK_EDGE_B: hover highlights edge, click to pick shared edge on B → merge\n *\n * After a successful merge the two original features are removed and one\n * merged feature (coloured green) is added. If both originals were parcels,\n * a `mergedparcel` event is fired so external code can present a UPN chooser.\n */\n\nimport ol_interaction_Interaction from 'ol/interaction/Interaction';\nimport VectorSource from 'ol/source/Vector';\nimport VectorLayer from 'ol/layer/Vector';\nimport Feature from 'ol/Feature';\nimport { Style, Stroke, Fill, Text } from 'ol/style';\nimport { LineString, Polygon as PolygonGeom } from 'ol/geom';\nimport { mergePolygons } from '../geom/polygonMerge.js';\nimport { showToast } from '../toast.js';\n\n// ── Styles ───────────────────────────────────────────────────────────────────\n\nconst HIGHLIGHT_A = new Style({\n stroke: new Stroke({ color: '#0ea5e9', width: 3 }),\n fill: new Fill({ color: 'rgba(14,165,233,0.15)' }),\n});\n\nconst HIGHLIGHT_B = new Style({\n stroke: new Stroke({ color: '#f59e0b', width: 3 }),\n fill: new Fill({ color: 'rgba(245,158,11,0.15)' }),\n});\n\n// Labelled versions for permanent highlights (shown after selection)\nconst LABEL_A = new Style({\n stroke: new Stroke({ color: '#0ea5e9', width: 3 }),\n fill: new Fill({ color: 'rgba(14,165,233,0.15)' }),\n text: new Text({\n text: 'A',\n font: 'bold 22px Exo, sans-serif',\n fill: new Fill({ color: '#0ea5e9' }),\n stroke: new Stroke({ color: '#fff', width: 4 }),\n overflow: true,\n }),\n});\n\nconst LABEL_B = new Style({\n stroke: new Stroke({ color: '#f59e0b', width: 3 }),\n fill: new Fill({ color: 'rgba(245,158,11,0.15)' }),\n text: new Text({\n text: 'B',\n font: 'bold 22px Exo, sans-serif',\n fill: new Fill({ color: '#f59e0b' }),\n stroke: new Stroke({ color: '#fff', width: 4 }),\n overflow: true,\n }),\n});\n\nconst EDGE_STYLE = new Style({\n stroke: new Stroke({ color: '#ec4899', width: 4, lineDash: [10, 6] }),\n});\n\nconst MERGE_STYLE = new Style({\n stroke: new Stroke({ color: '#10b981', width: 2.5 }),\n fill: new Fill({ color: 'rgba(16,185,129,0.3)' }),\n});\n\n// ── Interaction ──────────────────────────────────────────────────────────────\n\nexport class PolygonMergeInteraction extends ol_interaction_Interaction {\n /**\n * @param {Object} [options]\n * @param {number} [options.snapDistance=25] Pixel distance for hover detection.\n * @param {number} [options.tolerance=5] Map-unit tolerance for shared-edge matching.\n */\n constructor(options = {}) {\n super({\n handleEvent: (e) => this._handleEvent(e),\n });\n\n this.snapDistance_ = options.snapDistance || 25;\n this.tolerance_ = options.tolerance || 5;\n\n // Phase: 'select_a' | 'select_b' | 'click_edge_a' | 'click_edge_b'\n this._phase = 'select_a';\n\n // Selected features and their sources\n this._featureA = null;\n this._sourceA = null;\n this._featureB = null;\n this._sourceB = null;\n\n // Clicked edge coordinates (map coords)\n this._edgeClickA = null;\n this._edgeClickB = null;\n\n // Overlay for polygon highlights\n this._highlightSource = new VectorSource({ useSpatialIndex: false });\n this._highlightLayer = new VectorLayer({\n source: this._highlightSource,\n displayInLayerSwitcher: false,\n style: (f) => f.get('_highlightStyle') || HIGHLIGHT_A,\n });\n\n // Overlay for edge highlights\n this._edgeSource = new VectorSource({ useSpatialIndex: false });\n this._edgeLayer = new VectorLayer({\n source: this._edgeSource,\n displayInLayerSwitcher: false,\n style: EDGE_STYLE,\n });\n }\n\n /* ------------------------------------------------------------------ */\n /* Map lifecycle */\n /* ------------------------------------------------------------------ */\n\n setMap(map) {\n if (this.getMap()) {\n this.getMap().removeLayer(this._highlightLayer);\n this.getMap().removeLayer(this._edgeLayer);\n }\n super.setMap(map);\n if (map) {\n this._highlightLayer.setMap(map);\n this._edgeLayer.setMap(map);\n }\n }\n\n setActive(active) {\n super.setActive(active);\n if (!active) this._reset();\n }\n\n /* ------------------------------------------------------------------ */\n /* Source helpers */\n /* ------------------------------------------------------------------ */\n\n _getSources() {\n if (!this.getMap()) return [];\n const sources = [];\n const collect = (layers) => {\n layers.forEach((layer) => {\n if (layer.getVisible()) {\n if (layer.getSource && layer.getSource() instanceof VectorSource) {\n sources.push(layer.getSource());\n } else if (layer.getLayers) {\n collect(layer.getLayers());\n }\n }\n });\n };\n collect(this.getMap().getLayers());\n return sources;\n }\n\n /* ------------------------------------------------------------------ */\n /* Event router */\n /* ------------------------------------------------------------------ */\n\n _handleEvent(e) {\n if (!this.getActive()) return true;\n\n // Escape cancels at any phase\n if (e.type === 'keydown' && e.originalEvent?.key === 'Escape') {\n this._reset();\n return false;\n }\n\n switch (this._phase) {\n case 'select_a':\n if (e.type === 'pointermove') return this._onSelectMove(e, null);\n if (e.type === 'singleclick') return this._onSelectAClick(e);\n break;\n case 'select_b':\n if (e.type === 'pointermove') return this._onSelectMove(e, this._featureA);\n if (e.type === 'singleclick') return this._onSelectBClick(e);\n break;\n case 'click_edge_a':\n if (e.type === 'pointermove') return this._onEdgeMove(e, this._featureA);\n if (e.type === 'singleclick') return this._onEdgeAClick(e);\n break;\n case 'click_edge_b':\n if (e.type === 'pointermove') return this._onEdgeMove(e, this._featureB);\n if (e.type === 'singleclick') return this._onEdgeBClick(e);\n break;\n }\n return true;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 1 & 2: SELECT polygons */\n /* ------------------------------------------------------------------ */\n\n _onSelectMove(e, skipFeature) {\n const map = this.getMap();\n if (!map) return true;\n\n // Keep existing highlights for already-selected polygons\n this._highlightSource.clear();\n this._edgeSource.clear();\n this._rebuildHighlights();\n\n const hit = this._closestPolygon(e, skipFeature);\n if (hit) {\n const style = this._phase === 'select_a' ? HIGHLIGHT_A : HIGHLIGHT_B;\n const clone = hit.feature.clone();\n clone.set('_highlightStyle', style);\n this._highlightSource.addFeature(clone);\n map.getTargetElement().style.cursor = 'pointer';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onSelectAClick(e) {\n const hit = this._closestPolygon(e, null);\n if (!hit) return true;\n\n this._featureA = hit.feature;\n this._sourceA = hit.source;\n this._phase = 'select_b';\n\n this._rebuildHighlights();\n return false;\n }\n\n _onSelectBClick(e) {\n const hit = this._closestPolygon(e, this._featureA);\n if (!hit) return true;\n\n this._featureB = hit.feature;\n this._sourceB = hit.source;\n this._phase = 'click_edge_a';\n\n this._rebuildHighlights();\n this.getMap().getTargetElement().style.cursor = 'crosshair';\n return false;\n }\n\n /**\n * Find the closest polygon feature within snap distance.\n * Optionally skip a feature (used in phase 2 to avoid re-selecting A).\n */\n _closestPolygon(e, skipFeature) {\n let best = null;\n let bestDist = this.snapDistance_ + 1;\n\n for (const source of this._getSources()) {\n const feat = source.getClosestFeatureToCoordinate(e.coordinate);\n if (!feat) continue;\n if (skipFeature && feat === skipFeature) continue;\n const geom = feat.getGeometry();\n if (!geom) continue;\n const type = geom.getType();\n if (type !== 'Polygon' && type !== 'MultiPolygon') continue;\n\n const closest = geom.getClosestPoint(e.coordinate);\n const line = new LineString([e.coordinate, closest]);\n const distPx = line.getLength() / e.frameState.viewState.resolution;\n\n if (distPx < bestDist) {\n bestDist = distPx;\n best = { feature: feat, source, coord: closest };\n }\n }\n return best;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 3 & 4: CLICK edges */\n /* ------------------------------------------------------------------ */\n\n _onEdgeMove(e, feature) {\n const map = this.getMap();\n if (!map) return true;\n\n this._edgeSource.clear();\n\n const edge = this._closestEdgeSegment(feature, e);\n if (edge) {\n const edgeFeat = new Feature(new LineString([edge.segStart, edge.segEnd]));\n this._edgeSource.addFeature(edgeFeat);\n map.getTargetElement().style.cursor = 'crosshair';\n }\n return true;\n }\n\n _onEdgeAClick(e) {\n this._edgeClickA = e.coordinate;\n this._phase = 'click_edge_b';\n this._edgeSource.clear();\n return false;\n }\n\n _onEdgeBClick(e) {\n this._edgeClickB = e.coordinate;\n this._performMerge();\n return false;\n }\n\n /**\n * Find the closest edge segment of a polygon feature to the cursor.\n */\n _closestEdgeSegment(feature, e) {\n const geom = feature.getGeometry();\n let ring;\n if (geom.getType() === 'Polygon') {\n ring = geom.getCoordinates()[0];\n } else if (geom.getType() === 'MultiPolygon') {\n ring = geom.getCoordinates()[0][0];\n } else {\n return null;\n }\n\n const resolution = e.frameState.viewState.resolution;\n let bestDist = Infinity;\n let bestSeg = null;\n const n = ring.length - 1;\n\n for (let i = 0; i < n; i++) {\n const a = ring[i];\n const b = ring[i + 1];\n const dx = b[0] - a[0], dy = b[1] - a[1];\n const lenSq = dx * dx + dy * dy;\n if (lenSq < 1e-20) continue;\n\n let t = ((e.coordinate[0] - a[0]) * dx + (e.coordinate[1] - a[1]) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n const projX = a[0] + t * dx, projY = a[1] + t * dy;\n const distPx = Math.sqrt((e.coordinate[0] - projX) ** 2 + (e.coordinate[1] - projY) ** 2) / resolution;\n\n if (distPx < bestDist) {\n bestDist = distPx;\n bestSeg = { segStart: a, segEnd: b };\n }\n }\n return bestDist <= this.snapDistance_ ? bestSeg : null;\n }\n\n /* ------------------------------------------------------------------ */\n /* Merge logic */\n /* ------------------------------------------------------------------ */\n\n _performMerge() {\n const featureA = this._featureA;\n const featureB = this._featureB;\n const sourceA = this._sourceA;\n const sourceB = this._sourceB;\n\n // Extract polygon coordinates\n const geomA = featureA.getGeometry();\n const geomB = featureB.getGeometry();\n const coordsA = geomA.getType() === 'Polygon' ? geomA.getCoordinates() : geomA.getCoordinates()[0];\n const coordsB = geomB.getType() === 'Polygon' ? geomB.getCoordinates() : geomB.getCoordinates()[0];\n\n const result = mergePolygons(coordsA, coordsB, this._edgeClickA, this._edgeClickB, this.tolerance_);\n\n if (!result.coords) {\n showToast(result.error || 'Merge failed — try clicking on the shared boundary.', 'error', 5000);\n // Return to edge click phase for retry\n this._edgeClickA = null;\n this._edgeClickB = null;\n this._phase = 'click_edge_a';\n this._edgeSource.clear();\n return;\n }\n\n // Create merged feature (clone A for default properties)\n const mergedFeature = featureA.clone();\n mergedFeature.setGeometry(new PolygonGeom(result.coords));\n mergedFeature.setStyle(MERGE_STYLE);\n\n // Dispatch beforemerge events\n const evtData = {\n type: 'beforemerge',\n original: [featureA, featureB],\n merged: mergedFeature,\n };\n this.dispatchEvent(evtData);\n sourceA.dispatchEvent({ ...evtData });\n if (sourceB !== sourceA) {\n sourceB.dispatchEvent({ ...evtData });\n }\n\n // Replace originals with merged\n sourceA.removeFeature(featureA);\n sourceB.removeFeature(featureB);\n sourceA.addFeature(mergedFeature);\n\n // Dispatch aftermerge events\n const afterEvt = {\n type: 'aftermerge',\n original: [featureA, featureB],\n merged: mergedFeature,\n };\n this.dispatchEvent(afterEvt);\n sourceA.dispatchEvent({ ...afterEvt });\n if (sourceB !== sourceA) {\n sourceB.dispatchEvent({ ...afterEvt });\n }\n\n // If both features were parcels, fire mergedparcel so MapView can show the UPN chooser\n const isParcelA = featureA.get('_layerType') === 'parcel';\n const isParcelB = featureB.get('_layerType') === 'parcel';\n if (isParcelA && isParcelB) {\n this.dispatchEvent({\n type: 'mergedparcel',\n merged: mergedFeature,\n propsA: featureA.getProperties(),\n propsB: featureB.getProperties(),\n coordinate: this._edgeClickA,\n });\n showToast('Polygons merged — choose which identifier to keep.', 'success');\n } else {\n showToast('Polygons merged successfully.', 'success');\n }\n\n // Clean up\n this._reset();\n }\n\n /* ------------------------------------------------------------------ */\n /* Highlight management */\n /* ------------------------------------------------------------------ */\n\n /**\n * Rebuild the permanent highlights for already-selected polygons.\n */\n _rebuildHighlights() {\n // Remove previous non-hover highlights\n const toRemove = [];\n this._highlightSource.getFeatures().forEach((f) => {\n if (f.get('_permanent')) toRemove.push(f);\n });\n toRemove.forEach((f) => this._highlightSource.removeFeature(f));\n\n if (this._featureA) {\n const cloneA = this._featureA.clone();\n cloneA.set('_highlightStyle', LABEL_A);\n cloneA.set('_permanent', true);\n this._highlightSource.addFeature(cloneA);\n }\n if (this._featureB) {\n const cloneB = this._featureB.clone();\n cloneB.set('_highlightStyle', LABEL_B);\n cloneB.set('_permanent', true);\n this._highlightSource.addFeature(cloneB);\n }\n }\n\n /* ------------------------------------------------------------------ */\n /* Reset */\n /* ------------------------------------------------------------------ */\n\n _reset() {\n this._phase = 'select_a';\n this._featureA = null;\n this._sourceA = null;\n this._featureB = null;\n this._sourceB = null;\n this._edgeClickA = null;\n this._edgeClickB = null;\n this._highlightSource.clear();\n this._edgeSource.clear();\n\n const map = this.getMap();\n if (map) {\n map.getTargetElement().style.cursor = '';\n }\n }\n}\n","/**\n * Pure geometry functions for dividing a polygon into N equal-area pieces.\n *\n * No OpenLayers dependency — operates on raw coordinate arrays.\n *\n * The algorithm finds the polygon's longest edge, then places N-1 cutting\n * lines perpendicular to that edge. Each cutting-line position is found\n * via binary search so that the piece it cuts off has exactly 1/N of the\n * remaining area. The actual cut is delegated to `splitPolygonByLine()`.\n */\n\nimport { splitPolygonByLine } from './polygonSplit.js';\n\n// ── Utility helpers (self-contained) ─────────────────────────────────────────\n\nfunction dist2(a, b) {\n return (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n}\n\n/**\n * Signed area of a ring (shoelace formula).\n */\nfunction signedArea(ring) {\n let area = 0;\n for (let i = 0, n = ring.length; i < n - 1; i++) {\n area += ring[i][0] * ring[i + 1][1] - ring[i + 1][0] * ring[i][1];\n }\n return area / 2;\n}\n\n/**\n * Absolute polygon area, accounting for holes.\n */\nfunction polygonArea(coords) {\n let area = Math.abs(signedArea(coords[0]));\n for (let i = 1; i < coords.length; i++) {\n area -= Math.abs(signedArea(coords[i]));\n }\n return area;\n}\n\n/**\n * Find the longest edge of a ring and return direction vectors.\n *\n * @param {number[][]} ring Closed ring\n * @returns {{ p0: number[], p1: number[], along: number[], perp: number[] }}\n * `along` = unit vector along the longest edge,\n * `perp` = unit vector perpendicular to `along` (rotated 90° CCW)\n */\nfunction longestEdge(ring) {\n const n = ring.length - 1; // unique vertices\n let bestLen = -1;\n let bestI = 0;\n\n for (let i = 0; i < n; i++) {\n const d = dist2(ring[i], ring[i + 1]);\n if (d > bestLen) {\n bestLen = d;\n bestI = i;\n }\n }\n\n const p0 = ring[bestI];\n const p1 = ring[bestI + 1];\n const len = Math.sqrt(bestLen);\n const along = [(p1[0] - p0[0]) / len, (p1[1] - p0[1]) / len];\n // Perpendicular: rotate 90° CCW\n const perp = [-along[1], along[0]];\n\n return { p0, p1, along, perp };\n}\n\n/**\n * Build a cutting line perpendicular to `along` at parameter `t`.\n *\n * The line passes through `origin + t * along` and extends `extent` units\n * in both `perp` directions — long enough to fully cross the polygon.\n */\nfunction makeCuttingLine(origin, along, perp, t, extent) {\n const cx = origin[0] + t * along[0];\n const cy = origin[1] + t * along[1];\n return [\n [cx - extent * perp[0], cy - extent * perp[1]],\n [cx + extent * perp[0], cy + extent * perp[1]],\n ];\n}\n\n/**\n * Project the centroid of a polygon's exterior ring onto the `along` axis.\n * Returns the scalar parameter `t` relative to `origin`.\n */\nfunction centroidT(coords, origin, along) {\n const ring = coords[0];\n const n = ring.length - 1;\n let sx = 0, sy = 0;\n for (let i = 0; i < n; i++) {\n sx += ring[i][0];\n sy += ring[i][1];\n }\n const cx = sx / n - origin[0];\n const cy = sy / n - origin[1];\n return cx * along[0] + cy * along[1];\n}\n\n// ── Main export ──────────────────────────────────────────────────────────────\n\n/**\n * Divide a polygon into N equal-area pieces by parallel cuts perpendicular\n * to a user-selected edge.\n *\n * @param {number[][][]} polygonCoords Polygon coordinates [ring, ...holes]\n * @param {number} n Number of pieces (must be >= 1)\n * @param {number[][]} edgeCoords The selected edge `[p0, p1]` — cuts will be\n * perpendicular to this edge direction.\n * @returns {{ pieces: number[][][][], error?: undefined } | { pieces: null, error: string }}\n */\nexport function dividePolygon(polygonCoords, n, edgeCoords) {\n if (!Number.isInteger(n) || n < 1) {\n return { pieces: null, error: 'Number of divisions must be a positive integer.' };\n }\n if (n === 1) {\n return { pieces: [polygonCoords] };\n }\n\n const ring = polygonCoords[0];\n const totalArea = polygonArea(polygonCoords);\n\n if (totalArea < 1e-6) {\n return { pieces: null, error: 'Polygon has no measurable area.' };\n }\n\n // 1. Determine cutting direction from the selected edge\n let p0, along, perp;\n if (edgeCoords && edgeCoords.length === 2) {\n p0 = edgeCoords[0];\n const dx = edgeCoords[1][0] - edgeCoords[0][0];\n const dy = edgeCoords[1][1] - edgeCoords[0][1];\n const len = Math.sqrt(dx * dx + dy * dy);\n if (len < 1e-10) {\n return { pieces: null, error: 'Selected edge has zero length.' };\n }\n along = [dx / len, dy / len];\n perp = [-along[1], along[0]];\n } else {\n // Fallback: use longest edge\n const edge = longestEdge(ring);\n p0 = edge.p0;\n along = edge.along;\n perp = edge.perp;\n }\n const origin = p0;\n\n // 2. Project all vertices onto the `along` axis to find extent\n const nVerts = ring.length - 1;\n let tMin = Infinity, tMax = -Infinity;\n for (let i = 0; i < nVerts; i++) {\n const dx = ring[i][0] - origin[0];\n const dy = ring[i][1] - origin[1];\n const t = dx * along[0] + dy * along[1];\n if (t < tMin) tMin = t;\n if (t > tMax) tMax = t;\n }\n\n // Cutting line extent: enough to cross the polygon in the `perp` direction\n let perpMin = Infinity, perpMax = -Infinity;\n for (let i = 0; i < nVerts; i++) {\n const dx = ring[i][0] - origin[0];\n const dy = ring[i][1] - origin[1];\n const p = dx * perp[0] + dy * perp[1];\n if (p < perpMin) perpMin = p;\n if (p > perpMax) perpMax = p;\n }\n const extent = (perpMax - perpMin) * 1.5; // generous overshoot\n\n // 3. Iteratively cut pieces\n const pieces = [];\n let remaining = polygonCoords;\n let remainingCount = n;\n\n for (let i = 0; i < n - 1; i++) {\n const remainingArea = polygonArea(remaining);\n const targetArea = remainingArea / remainingCount;\n\n // Re-project the remaining polygon to get its current t-range\n const remRing = remaining[0];\n const remN = remRing.length - 1;\n let rMin = Infinity, rMax = -Infinity;\n for (let j = 0; j < remN; j++) {\n const dx = remRing[j][0] - origin[0];\n const dy = remRing[j][1] - origin[1];\n const t = dx * along[0] + dy * along[1];\n if (t < rMin) rMin = t;\n if (t > rMax) rMax = t;\n }\n\n // Binary search for the cutting position\n let lo = rMin;\n let hi = rMax;\n let bestT = (lo + hi) / 2;\n let bestPiece = null;\n let bestRemaining = null;\n let bestError = Infinity;\n\n for (let iter = 0; iter < 40; iter++) {\n const mid = (lo + hi) / 2;\n const line = makeCuttingLine(origin, along, perp, mid, extent);\n const result = splitPolygonByLine(remaining, line);\n\n if (!result) {\n // Cutting line didn't produce a valid split — nudge and retry\n // Try slightly shifted positions\n const nudge = (hi - lo) * 0.01;\n const lineA = makeCuttingLine(origin, along, perp, mid + nudge, extent);\n const resultA = splitPolygonByLine(remaining, lineA);\n if (resultA) {\n const [halfA, halfB] = resultA;\n const tA = centroidT(halfA, origin, along);\n const tB = centroidT(halfB, origin, along);\n const nearPiece = tA < tB ? halfA : halfB;\n const farPiece = tA < tB ? halfB : halfA;\n const nearArea = polygonArea(nearPiece);\n const err = Math.abs(nearArea - targetArea);\n if (err < bestError) {\n bestError = err;\n bestT = mid + nudge;\n bestPiece = nearPiece;\n bestRemaining = farPiece;\n }\n }\n // Try the other direction\n const lineB = makeCuttingLine(origin, along, perp, mid - nudge, extent);\n const resultB = splitPolygonByLine(remaining, lineB);\n if (resultB) {\n const [halfA, halfB] = resultB;\n const tA = centroidT(halfA, origin, along);\n const tB = centroidT(halfB, origin, along);\n const nearPiece = tA < tB ? halfA : halfB;\n const farPiece = tA < tB ? halfB : halfA;\n const nearArea = polygonArea(nearPiece);\n const err = Math.abs(nearArea - targetArea);\n if (err < bestError) {\n bestError = err;\n bestT = mid - nudge;\n bestPiece = nearPiece;\n bestRemaining = farPiece;\n }\n }\n // Bisect anyway to keep converging\n lo = mid;\n continue;\n }\n\n const [halfA, halfB] = result;\n const tA = centroidT(halfA, origin, along);\n const tB = centroidT(halfB, origin, along);\n const nearPiece = tA < tB ? halfA : halfB;\n const farPiece = tA < tB ? halfB : halfA;\n const nearArea = polygonArea(nearPiece);\n\n const err = Math.abs(nearArea - targetArea);\n if (err < bestError) {\n bestError = err;\n bestT = mid;\n bestPiece = nearPiece;\n bestRemaining = farPiece;\n }\n\n // Converged?\n if (err / remainingArea < 0.001) break;\n\n // Adjust search range\n if (nearArea < targetArea) {\n lo = mid; // need to cut farther out\n } else {\n hi = mid; // need to cut closer\n }\n }\n\n if (!bestPiece || !bestRemaining) {\n return {\n pieces: null,\n error: `Could not find a valid cut for piece ${i + 1} of ${n}. The polygon shape may be too irregular for equal division.`,\n };\n }\n\n pieces.push(bestPiece);\n remaining = bestRemaining;\n remainingCount--;\n }\n\n // The last remaining piece is the Nth piece\n pieces.push(remaining);\n\n return { pieces };\n}\n","/**\n * PolygonDivideInteraction\n *\n * A three-phase OpenLayers interaction for dividing a polygon into N\n * equal-area pieces:\n * Phase 1 – SELECT: hover to highlight, click to select a polygon\n * Phase 2 – EDGE: hover to highlight edges, click to pick the divide\n * direction (cuts will be perpendicular to this edge)\n * Phase 3 – FORM: wait for the popup form to call performDivide(n)\n *\n * After a successful divide the original feature is removed and N new\n * coloured features are added. The interaction fires `beforedivide` and\n * `afterdivide` events compatible with ol-ext's UndoRedo.\n */\n\nimport ol_interaction_Interaction from 'ol/interaction/Interaction';\nimport VectorSource from 'ol/source/Vector';\nimport VectorLayer from 'ol/layer/Vector';\nimport Feature from 'ol/Feature';\nimport { Style, Stroke, Fill } from 'ol/style';\nimport { LineString, Polygon as PolygonGeom } from 'ol/geom';\nimport { dividePolygon } from '../geom/polygonDivide.js';\nimport { showToast } from '../toast.js';\n\n// Highlight style for the selected polygon (phase 1)\nconst HIGHLIGHT_STYLE = new Style({\n stroke: new Stroke({ color: '#0ea5e9', width: 3 }),\n fill: new Fill({ color: 'rgba(14,165,233,0.15)' }),\n});\n\n// Style for the hovered edge (phase 2)\nconst EDGE_STYLE = new Style({\n stroke: new Stroke({ color: '#8b5cf6', width: 4, lineDash: [10, 6] }),\n});\n\n/**\n * Generate N visually distinct colours using evenly-spaced HSL hues.\n */\nfunction pieceColors(n) {\n const colors = [];\n for (let i = 0; i < n; i++) {\n const hue = Math.round((i * 360) / n);\n colors.push({\n stroke: `hsl(${hue}, 70%, 45%)`,\n fill: `hsla(${hue}, 70%, 55%, 0.25)`,\n });\n }\n return colors;\n}\n\nexport class PolygonDivideInteraction extends ol_interaction_Interaction {\n /**\n * @param {Object} options\n * @param {VectorSource|VectorSource[]} [options.sources] Specific sources\n * to search. If omitted the interaction searches all visible vector layers.\n * @param {number} [options.snapDistance=25] Pixel distance for hover.\n */\n constructor(options = {}) {\n super({\n handleEvent: (e) => this._handleEvent(e),\n });\n\n this.snapDistance_ = options.snapDistance || 25;\n this._sources = options.sources\n ? (Array.isArray(options.sources) ? options.sources : [options.sources])\n : null;\n\n // Phase: 'select' | 'edge' | 'form' | 'pick'\n this._phase = 'select';\n this._selectedFeature = null;\n this._selectedSource = null;\n this._selectedEdge = null; // [p0, p1] — the edge the user clicked\n this._dividedFeatures = null; // features created after divide (for pick phase)\n\n // Overlay layer for polygon highlight\n this._overlaySource = new VectorSource({ useSpatialIndex: false });\n this._overlayLayer = new VectorLayer({\n source: this._overlaySource,\n displayInLayerSwitcher: false,\n style: HIGHLIGHT_STYLE,\n });\n\n // Overlay layer for edge highlight\n this._edgeSource = new VectorSource({ useSpatialIndex: false });\n this._edgeLayer = new VectorLayer({\n source: this._edgeSource,\n displayInLayerSwitcher: false,\n style: EDGE_STYLE,\n });\n }\n\n /* ------------------------------------------------------------------ */\n /* Map lifecycle */\n /* ------------------------------------------------------------------ */\n\n setMap(map) {\n if (this.getMap()) {\n this.getMap().removeLayer(this._overlayLayer);\n this.getMap().removeLayer(this._edgeLayer);\n }\n super.setMap(map);\n if (map) {\n this._overlayLayer.setMap(map);\n this._edgeLayer.setMap(map);\n }\n }\n\n setActive(active) {\n super.setActive(active);\n if (!active) {\n this._reset();\n }\n }\n\n /* ------------------------------------------------------------------ */\n /* Source helpers */\n /* ------------------------------------------------------------------ */\n\n _getSources() {\n if (this._sources) return this._sources;\n if (!this.getMap()) return [];\n const sources = [];\n const collect = (layers) => {\n layers.forEach((layer) => {\n if (layer.getVisible()) {\n if (layer.getSource && layer.getSource() instanceof VectorSource) {\n sources.push(layer.getSource());\n } else if (layer.getLayers) {\n collect(layer.getLayers());\n }\n }\n });\n };\n collect(this.getMap().getLayers());\n return sources;\n }\n\n /* ------------------------------------------------------------------ */\n /* Event router */\n /* ------------------------------------------------------------------ */\n\n _handleEvent(e) {\n if (!this.getActive()) return true;\n\n // Escape cancels at any phase\n if (e.type === 'keydown' && e.originalEvent?.key === 'Escape') {\n if (this._phase === 'form') {\n this.cancelDivide();\n } else {\n this._reset();\n }\n return false;\n }\n\n if (this._phase === 'select') {\n if (e.type === 'pointermove') return this._onSelectMove(e);\n if (e.type === 'singleclick') return this._onSelectClick(e);\n }\n\n if (this._phase === 'edge') {\n if (e.type === 'pointermove') return this._onEdgeMove(e);\n if (e.type === 'singleclick') return this._onEdgeClick(e);\n }\n\n if (this._phase === 'pick') {\n if (e.type === 'pointermove') return this._onPickMove(e);\n if (e.type === 'singleclick') return this._onPickClick(e);\n }\n\n return true;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 1: SELECT polygon */\n /* ------------------------------------------------------------------ */\n\n _onSelectMove(e) {\n const map = this.getMap();\n if (!map) return true;\n\n this._overlaySource.clear();\n\n const hit = this._closestPolygon(e);\n if (hit) {\n const clone = hit.feature.clone();\n this._overlaySource.addFeature(clone);\n map.getTargetElement().style.cursor = 'pointer';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onSelectClick(e) {\n const hit = this._closestPolygon(e);\n if (!hit) return true;\n\n this._selectedFeature = hit.feature;\n this._selectedSource = hit.source;\n\n // Keep polygon highlight visible during edge phase\n this._overlaySource.clear();\n const clone = hit.feature.clone();\n clone.set('_permanent', true);\n this._overlaySource.addFeature(clone);\n\n this._phase = 'edge';\n showToast('Click the edge to divide along.', 'info', 3000);\n return false;\n }\n\n _closestPolygon(e) {\n let best = null;\n let bestDist = this.snapDistance_ + 1;\n\n for (const source of this._getSources()) {\n const feat = source.getClosestFeatureToCoordinate(e.coordinate);\n if (!feat) continue;\n const geom = feat.getGeometry();\n if (!geom) continue;\n const type = geom.getType();\n if (type !== 'Polygon' && type !== 'MultiPolygon') continue;\n\n const closest = geom.getClosestPoint(e.coordinate);\n const line = new LineString([e.coordinate, closest]);\n const distPx = line.getLength() / e.frameState.viewState.resolution;\n\n if (distPx < bestDist) {\n bestDist = distPx;\n best = { feature: feat, source };\n }\n }\n return best;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 2: EDGE selection */\n /* ------------------------------------------------------------------ */\n\n _onEdgeMove(e) {\n const map = this.getMap();\n if (!map) return true;\n\n this._edgeSource.clear();\n\n const edge = this._closestEdgeSegment(this._selectedFeature, e);\n if (edge) {\n const edgeFeat = new Feature(new LineString([edge.segStart, edge.segEnd]));\n this._edgeSource.addFeature(edgeFeat);\n map.getTargetElement().style.cursor = 'crosshair';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onEdgeClick(e) {\n const edge = this._closestEdgeSegment(this._selectedFeature, e);\n if (!edge) return true;\n\n this._selectedEdge = [edge.segStart, edge.segEnd];\n this._edgeSource.clear();\n\n this._phase = 'form';\n\n // Dispatch divideform so MapView can show the popup\n const geom = this._selectedFeature.getGeometry();\n const ext = geom.getExtent();\n const center = [(ext[0] + ext[2]) / 2, (ext[1] + ext[3]) / 2];\n\n this.dispatchEvent({\n type: 'divideform',\n feature: this._selectedFeature,\n source: this._selectedSource,\n coordinate: center,\n });\n\n return false;\n }\n\n /**\n * Find the closest edge segment of a polygon feature to the cursor.\n */\n _closestEdgeSegment(feature, e) {\n const geom = feature.getGeometry();\n let ring;\n if (geom.getType() === 'Polygon') {\n ring = geom.getCoordinates()[0];\n } else if (geom.getType() === 'MultiPolygon') {\n ring = geom.getCoordinates()[0][0];\n } else {\n return null;\n }\n\n const resolution = e.frameState.viewState.resolution;\n let bestDist = Infinity;\n let bestSeg = null;\n const n = ring.length - 1;\n\n for (let i = 0; i < n; i++) {\n const a = ring[i];\n const b = ring[i + 1];\n const dx = b[0] - a[0], dy = b[1] - a[1];\n const lenSq = dx * dx + dy * dy;\n if (lenSq < 1e-20) continue;\n\n let t = ((e.coordinate[0] - a[0]) * dx + (e.coordinate[1] - a[1]) * dy) / lenSq;\n t = Math.max(0, Math.min(1, t));\n const projX = a[0] + t * dx, projY = a[1] + t * dy;\n const distPx = Math.sqrt((e.coordinate[0] - projX) ** 2 + (e.coordinate[1] - projY) ** 2) / resolution;\n\n if (distPx < bestDist) {\n bestDist = distPx;\n bestSeg = { segStart: a, segEnd: b };\n }\n }\n return bestDist <= this.snapDistance_ ? bestSeg : null;\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 3: FORM — called externally by the popup */\n /* ------------------------------------------------------------------ */\n\n /**\n * Divide the selected polygon into `n` equal-area pieces.\n * Called by the MapView popup's Confirm handler.\n *\n * @param {number} n Number of pieces (>= 2)\n */\n performDivide(n) {\n if (this._phase !== 'form' || !this._selectedFeature) return;\n\n const feature = this._selectedFeature;\n const source = this._selectedSource;\n const geom = feature.getGeometry();\n\n let polygonCoords;\n if (geom.getType() === 'Polygon') {\n polygonCoords = geom.getCoordinates();\n } else if (geom.getType() === 'MultiPolygon') {\n polygonCoords = geom.getCoordinates()[0];\n }\n\n const result = dividePolygon(polygonCoords, n, this._selectedEdge);\n\n if (!result.pieces) {\n showToast(result.error || 'Division failed.', 'error', 5000);\n this._reset();\n return;\n }\n\n // Create N new coloured features\n const colors = pieceColors(n);\n const newFeatures = result.pieces.map((coords, i) => {\n const f = feature.clone();\n f.setGeometry(new PolygonGeom(coords));\n f.setStyle(new Style({\n stroke: new Stroke({ color: colors[i].stroke, width: 2.5 }),\n fill: new Fill({ color: colors[i].fill }),\n }));\n return f;\n });\n\n // Dispatch beforedivide (UndoRedo compatible)\n const evtData = {\n type: 'beforedivide',\n original: feature,\n features: newFeatures,\n };\n this.dispatchEvent(evtData);\n source.dispatchEvent({ ...evtData });\n\n // Replace original with pieces\n source.removeFeature(feature);\n for (const f of newFeatures) {\n source.addFeature(f);\n }\n\n // Dispatch afterdivide\n const afterEvt = {\n type: 'afterdivide',\n original: feature,\n features: newFeatures,\n };\n this.dispatchEvent(afterEvt);\n source.dispatchEvent({ ...afterEvt });\n\n // If original was a parcel, enter pick phase for UPN assignment\n const isParcel = feature.get('_layerType') === 'parcel';\n if (isParcel) {\n this._dividedFeatures = newFeatures;\n this._phase = 'pick';\n showToast('Click the polygon that should keep the original identifier.', 'info', 5000);\n\n this.dispatchEvent({\n type: 'dividedparcel',\n features: newFeatures,\n originalProps: feature.getProperties(),\n source,\n });\n } else {\n showToast(`Polygon divided into ${n} equal pieces.`, 'success');\n this._reset();\n }\n }\n\n /* ------------------------------------------------------------------ */\n /* Phase 4: PICK — select which piece keeps the UPN */\n /* ------------------------------------------------------------------ */\n\n _onPickMove(e) {\n const map = this.getMap();\n if (!map) return true;\n\n this._overlaySource.clear();\n\n // Highlight whichever divided piece is under the cursor\n const hit = this._closestDividedPiece(e);\n if (hit) {\n const clone = hit.clone();\n this._overlaySource.addFeature(clone);\n map.getTargetElement().style.cursor = 'pointer';\n } else {\n map.getTargetElement().style.cursor = '';\n }\n return true;\n }\n\n _onPickClick(e) {\n const hit = this._closestDividedPiece(e);\n if (!hit) return true;\n\n this.dispatchEvent({\n type: 'dividepick',\n picked: hit,\n features: this._dividedFeatures,\n });\n\n this._reset();\n return false;\n }\n\n /**\n * Find the closest divided piece to the cursor.\n */\n _closestDividedPiece(e) {\n if (!this._dividedFeatures) return null;\n let best = null;\n let bestDist = this.snapDistance_ + 1;\n\n for (const feat of this._dividedFeatures) {\n const geom = feat.getGeometry();\n if (!geom) continue;\n const closest = geom.getClosestPoint(e.coordinate);\n const line = new LineString([e.coordinate, closest]);\n const distPx = line.getLength() / e.frameState.viewState.resolution;\n if (distPx < bestDist) {\n bestDist = distPx;\n best = feat;\n }\n }\n return best;\n }\n\n /**\n * Cancel the divide operation and return to select phase.\n * Called by the MapView popup's Cancel handler.\n */\n cancelDivide() {\n this.dispatchEvent({ type: 'dividecancel' });\n this._reset();\n }\n\n /* ------------------------------------------------------------------ */\n /* Reset */\n /* ------------------------------------------------------------------ */\n\n _reset() {\n this._phase = 'select';\n this._selectedFeature = null;\n this._selectedSource = null;\n this._selectedEdge = null;\n this._dividedFeatures = null;\n this._overlaySource.clear();\n this._edgeSource.clear();\n\n const map = this.getMap();\n if (map) {\n map.getTargetElement().style.cursor = '';\n }\n }\n}\n","/**\n * MapView Component\n *\n * OpenLayers map with ol-ext LayerSwitcher for base map selection.\n *\n * Usage:\n * import { MapView } from './components/MapView.js';\n *\n * const map = new MapView('map', {\n * center: [-1.5, 7.5], // Ghana\n * zoom: 7,\n * basemap: 'osm'\n * });\n *\n * map.onClick((lon, lat) => console.log('Clicked:', lon, lat));\n * map.addMarker(lon, lat, { name: 'Point A' });\n */\n\nimport Map from 'ol/Map';\nimport View from 'ol/View';\nimport Overlay from 'ol/Overlay';\nimport TileLayer from 'ol/layer/Tile';\nimport ImageLayer from 'ol/layer/Image';\nimport LayerGroup from 'ol/layer/Group';\nimport VectorLayer from 'ol/layer/Vector';\nimport VectorImageLayer from 'ol/layer/VectorImage';\nimport VectorSource from 'ol/source/Vector';\nimport ImageWMS from 'ol/source/ImageWMS';\nimport TileWMS from 'ol/source/TileWMS';\nimport OSM from 'ol/source/OSM';\nimport XYZ from 'ol/source/XYZ';\nimport { fromLonLat, toLonLat } from 'ol/proj';\nimport { Point, LineString, Polygon as PolygonGeom } from 'ol/geom';\nimport Feature from 'ol/Feature';\nimport { Style, Circle, Fill, Stroke, Text } from 'ol/style';\nimport GeoJSON from 'ol/format/GeoJSON';\nimport { getArea, getLength } from 'ol/sphere';\nimport { fromCircle } from 'ol/geom/Polygon';\nimport ScaleLine from 'ol/control/ScaleLine';\nimport { formatLength, formatLengthFull, formatArea, formatAreaFull } from '../units.js';\n\n// ol-ext LayerSwitcher\nimport LayerSwitcher from 'ol-ext/control/LayerSwitcher';\n\n// ol-ext SearchNominatim\nimport SearchNominatim from 'ol-ext/control/SearchNominatim';\n\n// ol-ext EditBar for drawing/editing features\nimport EditBar from 'ol-ext/control/EditBar';\nimport Bar from 'ol-ext/control/Bar';\nimport Button from 'ol-ext/control/Button';\n\n// ol-ext TouchCursor for touch-enabled devices\nimport TouchCursor from 'ol-ext/interaction/TouchCursor';\n\n// ol-ext ModifyFeature for cross-layer modification\nimport ModifyFeature from 'ol-ext/interaction/ModifyFeature';\n\n// ol-ext UndoRedo interaction\nimport UndoRedo from 'ol-ext/interaction/UndoRedo';\n\n// ol-ext SnapGuides — snaps drawing vertices to alignment guides\nimport SnapGuides from 'ol-ext/interaction/SnapGuides';\n\n// ol Select interaction (for custom multi-layer Select)\nimport Select from 'ol/interaction/Select';\nimport { click as clickCondition } from 'ol/events/condition';\n\n// ol-ext Split interaction (for line splitting) and Toggle control\nimport Split from 'ol-ext/interaction/Split';\nimport Toggle from 'ol-ext/control/Toggle';\nimport TextButton from 'ol-ext/control/TextButton';\n\n// Custom polygon split interaction\nimport { PolygonSplitInteraction } from '../interactions/PolygonSplitInteraction.js';\n\n// Custom polygon merge interaction\nimport { PolygonMergeInteraction } from '../interactions/PolygonMergeInteraction.js';\n\n// Custom polygon divide interaction\nimport { PolygonDivideInteraction } from '../interactions/PolygonDivideInteraction.js';\n\n// Toast notifications\nimport { showToast } from '../toast.js';\n\n// CSS imports\nimport 'ol/ol.css';\nimport 'ol-ext/dist/ol-ext.css';\nimport '../styles/layerswitcher.css';\n\nexport class MapView {\n constructor(targetId, options = {}) {\n this.options = options;\n this.markerSource = new VectorSource();\n this.clickCallbacks = [];\n\n // Category emoji and label mapping\n // Add new categories here - they will automatically appear in the dropdown\n this.categoryEmojis = {\n 'default': { emoji: '📍', label: 'Default' },\n 'water': { emoji: '💧', label: 'Water Point' },\n 'school': { emoji: '🏫', label: 'School' },\n 'health': { emoji: '🏥', label: 'Health Facility' },\n 'market': { emoji: '🏪', label: 'Market' },\n 'other': { emoji: '📌', label: 'Other' }\n };\n\n // Helper to get emoji for a category\n this.getEmoji = (category) => {\n const cat = this.categoryEmojis[category];\n return cat ? cat.emoji : '📍';\n };\n\n // Helper to generate category options HTML for select dropdowns\n this.getCategoryOptionsHtml = () => {\n return Object.entries(this.categoryEmojis)\n .map(([key, { emoji, label }]) =>\n ``\n )\n .join('\\n ');\n };\n\n // Create emoji style helper\n this.createEmojiStyle = (emoji, fontSize = 24) => {\n return new Style({\n text: new Text({\n text: emoji,\n font: `${fontSize}px sans-serif`,\n textBaseline: 'bottom',\n textAlign: 'center',\n offsetY: -5,\n }),\n });\n };\n\n // Default marker style (pin emoji)\n this.defaultStyle = this.createEmojiStyle('📍', 32);\n\n // Selected marker style (larger)\n this.selectedStyle = this.createEmojiStyle('📍', 42);\n\n // Initialize category styles with emojis\n this.categoryStyles = {};\n for (const [category, { emoji }] of Object.entries(this.categoryEmojis)) {\n this.categoryStyles[category] = this.createEmojiStyle(emoji, 32);\n }\n\n // Create base layers group\n const baseLayers = this.createBaseLayers(options.basemap || 'topo');\n\n // Markers layer — hidden at startup; the user enables it from the\n // LayerSwitcher when they want to see location markers / category pins.\n this.markersLayer = new VectorLayer({\n title: 'Markers',\n source: this.markerSource,\n style: (feature) => this.getFeatureStyle(feature),\n visible: false,\n });\n\n // Overlay layers group (for remote data like boundaries)\n this.overlayGroup = new LayerGroup({\n title: 'Overlays',\n });\n\n // Create map\n // Layer order (bottom → top): Base Maps, Markers, Overlays\n // MapTools will insert Measurements and Drawings between Markers and Overlays.\n // initEditBar() will insert its Drawings group above those.\n // Final LayerSwitcher order (top → bottom):\n // Overlays, Drawings, Measurements, Markers, Base Maps\n this.map = new Map({\n target: targetId,\n layers: [\n baseLayers,\n this.markersLayer,\n this.overlayGroup,\n ],\n view: new View({\n center: fromLonLat(options.center || [0, 0]),\n zoom: options.zoom || 2,\n minZoom: options.minZoom || 2,\n maxZoom: options.maxZoom || 19,\n })\n });\n\n // Add LayerSwitcher control\n const layerSwitcher = new LayerSwitcher({\n collapsed: true,\n mouseover: true,\n extent: true,\n trash: false,\n oninfo: null,\n });\n this.map.addControl(layerSwitcher);\n\n // Apply the LUSPA branded icon to the LayerSwitcher's collapse button.\n // Done in JS so the URL respects Vite's BASE_URL — survives deployment\n // under any sub-path.\n // NOTE: folder name is `app-icons`, NOT `icons` — Apache aliases `/icons/`\n // by default to its own directory-listing thumbnails, which would\n // intercept this request server-side.\n queueMicrotask(() => {\n const btn = layerSwitcher.element?.querySelector(':scope > button');\n if (btn) {\n const baseUrl = (import.meta.env?.BASE_URL || '/').replace(/\\/?$/, '/');\n btn.style.backgroundImage = `url('${baseUrl}app-icons/luspa-72x72.png')`;\n }\n });\n\n // ------------------------------------------------------------------\n // Decorate each layer's
  • as it's rendered:\n // • inject a type-tag chip (WMS / XYZ / VEC / …) next to the label\n // • add a green \"+\" button to the \"External Source\" group header\n // After each draw cycle, refresh the panel chrome (active count badge\n // + footer reset button). Schedule once per cycle via a microtask.\n // ------------------------------------------------------------------\n let _lsChromeScheduled = false;\n layerSwitcher.on('drawlist', (evt) => {\n this._decorateLayerListItem(evt.layer, evt.li);\n\n if (!_lsChromeScheduled) {\n _lsChromeScheduled = true;\n queueMicrotask(() => {\n _lsChromeScheduled = false;\n this._refreshLayerSwitcherChrome(layerSwitcher);\n });\n }\n });\n\n // Re-render the chrome whenever any layer's visibility changes (so the\n // active-count badge updates even when the user toggles via the panel).\n this.map.getLayers().on('change', () => {\n this._refreshLayerSwitcherChrome(layerSwitcher);\n });\n // Hook visibility events on every layer (recursive into groups).\n this._wireLayerSwitcherVisibilityHooks(layerSwitcher);\n\n // Create the add-layer dialog (hidden by default)\n this._createAddLayerDialog();\n\n // Create the legend panel (shows legends for visible layers that have one)\n this._createLegendPanel();\n\n // Add ScaleBar control\n this.scaleBar = new ScaleLine({\n bar: true,\n steps: 4,\n text: true,\n minWidth: 140,\n });\n this.map.addControl(this.scaleBar);\n\n // GPS rendering layers (current position + recorded trail) and the\n // expandable \"My Location\" control (Locate Me + Record Trail sub-buttons).\n this._initGpsRendering();\n this._createLocationControl();\n\n // Dedicated base-map picker — sits above the My Location button\n this._createBaseMapPicker();\n\n // Add SearchNominatim control\n const searchNominatim = new SearchNominatim({\n placeholder: 'Search location...',\n typing: 300, // Delay before search (ms)\n minLength: 3, // Minimum characters to start search\n maxItems: 10, // Maximum results to show\n collapsed: true, // Start collapsed\n // Limit search to improve relevance (can be adjusted)\n // countrycodes: 'gh', // Uncomment to limit to Ghana\n });\n this.map.addControl(searchNominatim);\n\n // Handle search result selection\n searchNominatim.on('select', (event) => {\n const searchResult = event.search;\n if (searchResult) {\n // SearchNominatim returns a plain object with lon/lat properties (as strings)\n const lon = parseFloat(searchResult.lon);\n const lat = parseFloat(searchResult.lat);\n const lonLat = [lon, lat];\n const coordinate = fromLonLat(lonLat);\n\n // Navigate to the selected location\n this.navigateTo(lon, lat, 14);\n\n // Trigger search select callbacks\n const result = {\n coordinate: coordinate,\n lonLat: lonLat,\n name: searchResult.display_name || searchResult.name || 'Unknown',\n searchResult: searchResult,\n };\n this.searchSelectCallbacks.forEach(cb => cb(result));\n }\n });\n\n // Store reference for external access\n this.searchNominatim = searchNominatim;\n this.searchSelectCallbacks = [];\n\n // Track selected feature\n this.selectedFeature = null;\n\n // Create popup overlay for hover\n this.createPopup();\n\n // Create info popup for double-click feature details\n this.createInfoPopup();\n\n // Create Add Location popup form\n this.createAddLocationPopup();\n\n // Create editable parcel form popup\n this.createParcelEditPopup();\n\n // Create drawn polygon attribute popup\n this.createDrawnPolygonPopup();\n\n // Create merge identifier (UPN) chooser popup\n this.createMergePopup();\n\n // Create divide polygon popup (number input)\n this.createDividePopup();\n\n // Double-click callbacks\n this.dblClickCallbacks = [];\n\n // EditBar is set up lazily via initEditBar() once the Drawings\n // layer/group is available (called from main.js after loadLayers).\n this.editBar = null;\n this.drawingsSource = null;\n this.drawingsLayer = null;\n this.touchCursor = null;\n this._editBarActive = false;\n }\n\n // ============================================================================\n // EditBar + Drawings Layer + TouchCursor\n // ============================================================================\n\n /**\n * Initialise the EditBar with a dedicated \"Drawings\" LayerGroup.\n *\n * A \"Drawings\" LayerGroup is created at the top of the overlay stack\n * containing a \"sketches\" VectorLayer for storing drawn features.\n * The EditBar, Select and Modify interactions are only active while\n * edit mode is on; in all other cases normal click / double-click\n * behaviour is preserved.\n *\n * Call this once from main.js after the layer groups have been created.\n */\n initEditBar() {\n // 1. Create a \"Drawings\" LayerGroup with a \"sketches\" VectorLayer inside\n this.drawingsSource = new VectorSource();\n this.drawingsLayer = new VectorLayer({\n title: 'sketches',\n source: this.drawingsSource,\n style: new Style({\n stroke: new Stroke({ color: '#f59e0b', width: 2.5 }),\n fill: new Fill({ color: 'rgba(245,158,11,0.15)' }),\n image: new Circle({\n radius: 6,\n fill: new Fill({ color: '#f59e0b' }),\n stroke: new Stroke({ color: '#fff', width: 1.5 }),\n }),\n }),\n });\n\n this._drawingsGroup = new LayerGroup({\n title: 'Drawings',\n layers: [this.drawingsLayer],\n });\n // Insert as a top-level map layer just before the Overlays group so the\n // LayerSwitcher order is: Overlays > Drawings > Measurements > Markers > Base Maps.\n // Find Overlays by reference rather than assuming it is the last layer —\n // other layers (e.g. the GPS trail/position layers added by\n // _initGpsRendering) may sit on top of it.\n const mapLayers = this.map.getLayers();\n const overlayIdx = mapLayers.getArray().indexOf(this.overlayGroup);\n mapLayers.insertAt(overlayIdx >= 0 ? overlayIdx : mapLayers.getLength(), this._drawingsGroup);\n\n // 2. Create a Select interaction that works on ALL vector layers.\n // It starts INACTIVE so it doesn't steal clicks from normal handlers.\n this._selectInteraction = new Select({\n condition: clickCondition,\n filter: (feature, layer) => !!layer,\n layers: (layer) => layer instanceof VectorLayer,\n });\n this._selectInteraction.setActive(false);\n this.map.addInteraction(this._selectInteraction);\n\n // 3. Create a ModifyFeature interaction bound to the selection.\n // Also starts inactive.\n this._modifyInteraction = new ModifyFeature({\n features: this._selectInteraction.getFeatures(),\n });\n this._modifyInteraction.setActive(false);\n\n // 4. UndoRedo interaction — watches the drawings source\n this._undoRedo = new UndoRedo();\n this.map.addInteraction(this._undoRedo);\n\n // 5. Build the EditBar — all interactions enabled.\n this.editBar = new EditBar({\n source: this.drawingsSource,\n interactions: {\n Select: this._selectInteraction,\n ModifySelect: this._modifyInteraction,\n DrawPoint: true,\n DrawLine: true,\n DrawPolygon: true,\n DrawRegular: true,\n DrawHole: true,\n Delete: true,\n Info: true,\n Transform: true,\n Split: false,\n },\n });\n this.map.addControl(this.editBar);\n\n // 5b. Persistent vertex overlay — when edit mode is active and the user\n // selects a polygon (or line) for modification, render a small dot\n // at every vertex so the user can see all editable nodes at a glance.\n // ol-ext's ModifyFeature only renders the closest vertex on hover; this\n // overlay complements that without subclassing the interaction.\n this._setupVertexOverlay();\n\n // 6. Add extra buttons (Undo, Redo, Save) as a sub-bar\n // inside the EditBar so they appear inline.\n const extraBar = new Bar({\n group: true,\n // Stable class so CSS can move this group (undo/redo/save/snap) to a\n // second row on small screens — see `.ol-editbar-actions` media query.\n className: 'ol-editbar-actions',\n controls: [\n new Button({\n html: '',\n className: 'ol-undo',\n title: 'Undo',\n handleClick: () => {\n if (this._undoRedo.hasUndo()) this._undoRedo.undo();\n },\n }),\n new Button({\n html: '',\n className: 'ol-redo',\n title: 'Redo',\n handleClick: () => {\n if (this._undoRedo.hasRedo()) this._undoRedo.redo();\n },\n }),\n new Button({\n html: '',\n className: 'ol-save',\n title: 'Save drawings',\n handleClick: () => {\n this.dispatchEditEvent('save');\n },\n }),\n ],\n });\n this.editBar.addControl(extraBar);\n\n // 6a-split. Custom Split tool with Lines / Polygons sub-categories.\n // The default ol-ext Split only handles LineString. We add a parent\n // Toggle with a sub-bar containing two sub-toggles: \"Lines\" (ol-ext\n // Split) and \"Polygons\" (our PolygonSplitInteraction).\n // No explicit sources → both interactions search ALL visible vector layers,\n // so they work on drawn features, parcels, zones, and any other polygon layer.\n this._lineSplitInteraction = new Split();\n this._polygonSplitInteraction = new PolygonSplitInteraction();\n this.map.addInteraction(this._lineSplitInteraction);\n this.map.addInteraction(this._polygonSplitInteraction);\n this._lineSplitInteraction.setActive(false);\n this._polygonSplitInteraction.setActive(false);\n\n // When a parcel is split, the user picks which piece keeps the UPN.\n this._polygonSplitInteraction.on('splitpick', (evt) => {\n const idFields = ['UPN', 'upn', 'id', 'parcelid', 'parcel_id', 'PARCELID', 'PARCEL_ID', 'ID'];\n for (const feat of evt.features) {\n if (feat === evt.picked) continue;\n for (const field of idFields) {\n if (feat.get(field) !== undefined) {\n feat.set(field, '');\n }\n }\n }\n });\n\n // Polygon Divide interaction (parameter-driven equal-area division)\n this._polygonDivideInteraction = new PolygonDivideInteraction();\n this.map.addInteraction(this._polygonDivideInteraction);\n this._polygonDivideInteraction.setActive(false);\n\n const splitLineToggle = new Toggle({\n html: '',\n className: 'ol-split-line',\n title: 'Split Lines',\n name: 'SplitLine',\n interaction: this._lineSplitInteraction,\n autoActivate: true,\n });\n const splitPolyToggle = new Toggle({\n html: '',\n className: 'ol-split-polygon',\n title: 'Split Polygons',\n name: 'SplitPolygon',\n interaction: this._polygonSplitInteraction,\n });\n const splitDivideToggle = new Toggle({\n html: '',\n className: 'ol-split-divide',\n title: 'Divide Polygon',\n name: 'DividePolygon',\n interaction: this._polygonDivideInteraction,\n });\n\n const splitSubBar = new Bar({\n toggleOne: true,\n autoDeactivate: true,\n controls: [splitLineToggle, splitPolyToggle, splitDivideToggle],\n });\n\n const splitParentToggle = new Toggle({\n className: 'ol-split',\n title: 'Split',\n name: 'Split',\n bar: splitSubBar,\n onToggle: (active) => {\n if (!active) {\n this._lineSplitInteraction.setActive(false);\n this._polygonSplitInteraction.setActive(false);\n this._polygonDivideInteraction.setActive(false);\n }\n },\n });\n this.editBar.addControl(splitParentToggle);\n\n // Listen for divide form request → show divide popup\n this._polygonDivideInteraction.on('divideform', (evt) => {\n this.showDividePopup(evt.feature, evt.source, evt.coordinate);\n });\n this._polygonDivideInteraction.on('dividecancel', () => {\n this.hideDividePopup();\n });\n\n // When a parcel is divided, the user picks which piece keeps the UPN.\n // The picked piece gets the original properties; all others get UPN cleared.\n this._polygonDivideInteraction.on('dividepick', (evt) => {\n const idFields = ['UPN', 'upn', 'id', 'parcelid', 'parcel_id', 'PARCELID', 'PARCEL_ID', 'ID'];\n for (const feat of evt.features) {\n if (feat === evt.picked) continue;\n // Clear identifier fields on the non-picked pieces\n for (const field of idFields) {\n if (feat.get(field) !== undefined) {\n feat.set(field, '');\n }\n }\n }\n });\n\n // 6a-merge. Polygon Merge tool — select two adjacent polygons, click shared\n // edges, and merge them into one. For parcels, a UPN chooser popup appears.\n this._polygonMergeInteraction = new PolygonMergeInteraction();\n this.map.addInteraction(this._polygonMergeInteraction);\n this._polygonMergeInteraction.setActive(false);\n\n const mergeToggle = new Toggle({\n html: '',\n className: 'ol-merge',\n title: 'Merge Polygons',\n name: 'Merge',\n interaction: this._polygonMergeInteraction,\n });\n this.editBar.addControl(mergeToggle);\n\n // Listen for merged-parcel event → show UPN chooser\n this._polygonMergeInteraction.on('mergedparcel', (evt) => {\n this.showMergeIdentifierPopup(evt.merged, evt.propsA, evt.propsB, evt.coordinate);\n });\n\n // Small-screen layout: insert a zero-height, full-width flex line-break\n // immediately BEFORE the action group. On phones (see the .ol-editbar\n // media query) this forces the wrap to happen here, so the action group\n // (undo/redo/save/snap) together with the Split and Merge toggles all land\n // on a single second row instead of Split/Merge spilling onto a third row.\n // The break is display:none on wider screens, so desktop layout is unchanged.\n const editbarEl = this.editBar.element;\n if (editbarEl && extraBar.element && extraBar.element.parentNode === editbarEl) {\n const breakEl = document.createElement('div');\n breakEl.className = 'ol-editbar-break';\n editbarEl.insertBefore(breakEl, extraBar.element);\n }\n\n // 6b. SnapGuides — shows alignment guides while drawing.\n // Uses VectorImageLayer for GPU-friendly canvas rendering instead of\n // re-creating individual SVG elements on every guide update.\n this._snapGuidesEnabled = localStorage.getItem('snap-guides-enabled') === '1';\n this._snapGuides = new SnapGuides({\n pixelTolerance: 10,\n vectorClass: VectorImageLayer,\n });\n this.map.addInteraction(this._snapGuides);\n\n // Connect SnapGuides to whichever draw interaction becomes active.\n // setDrawInteraction() only tracks one at a time, so we re-bind\n // whenever a draw tool is activated.\n const drawToolNames = ['DrawPoint', 'DrawLine', 'DrawPolygon', 'DrawHole', 'DrawRegular'];\n for (const name of drawToolNames) {\n const interaction = this.editBar.getInteraction(name);\n if (interaction) {\n interaction.on('change:active', () => {\n if (interaction.getActive()) {\n this._snapGuides.setDrawInteraction(interaction);\n }\n });\n }\n }\n\n // Also connect SnapGuides to the Modify interaction for vertex editing\n if (this._modifyInteraction) {\n this._snapGuides.setModifyInteraction(this._modifyInteraction);\n }\n\n // 6c. Snap-guides toggle button (magnet icon) — persisted in localStorage\n const snapToggleBtn = new Button({\n html: '',\n className: 'ol-snap-toggle' + (this._snapGuidesEnabled ? ' ol-active' : ''),\n title: 'Toggle Snap Guides',\n handleClick: () => {\n this._snapGuidesEnabled = !this._snapGuidesEnabled;\n localStorage.setItem('snap-guides-enabled', this._snapGuidesEnabled ? '1' : '0');\n // Update visual state\n snapToggleBtn.element.classList.toggle('ol-active', this._snapGuidesEnabled);\n // Activate or deactivate the interaction\n if (this._snapGuides) {\n this._snapGuides.setActive(this._snapGuidesEnabled && this._editBarActive);\n }\n console.log('[MapView] Snap guides:', this._snapGuidesEnabled ? 'ON' : 'OFF');\n },\n });\n this._snapToggleBtn = snapToggleBtn;\n extraBar.addControl(snapToggleBtn);\n\n // Start hidden — use the full setEditMode(false) so the Select +\n // Modify interactions are deactivated (the EditBar constructor may\n // have re-activated them).\n this.setEditMode(false);\n\n // 7. Link EditBar visibility to the Drawings group's visibility.\n this._drawingsGroup.on('change:visible', () => {\n const visible = this._drawingsGroup.getVisible();\n this.setEditMode(visible);\n });\n\n // 8. Touch-device detection & TouchCursor setup\n const isTouchDevice = ('ontouchstart' in window) ||\n (navigator.maxTouchPoints > 0) ||\n (navigator.msMaxTouchPoints > 0);\n\n if (isTouchDevice) {\n this.touchCursor = new TouchCursor({\n className: 'ol-editbar-cursor',\n });\n this.map.addInteraction(this.touchCursor);\n this.touchCursor.setActive(false);\n console.log('[MapView] Touch device detected — TouchCursor added');\n }\n\n // 9. Listen for polygon features drawn via EditBar's DrawPolygon tool.\n // When a Polygon is added to the drawings source, show the attribute popup.\n this.drawingsSource.on('addfeature', (evt) => {\n const feature = evt.feature;\n const geom = feature.getGeometry();\n if (!geom || geom.getType() !== 'Polygon') return;\n\n const coordinate = geom.getInteriorPoint().getCoordinates();\n this.showDrawnPolygonPopup(feature, coordinate);\n });\n\n console.log('[MapView] EditBar initialised with Drawings group, UndoRedo and SnapGuides (default:', this._snapGuidesEnabled ? 'ON' : 'OFF', ')');\n }\n\n /**\n * Dispatch a custom edit event (e.g. 'save').\n * External code can listen via mapView.onEditEvent('save', callback).\n * @param {string} type\n */\n dispatchEditEvent(type) {\n if (!this._editEventListeners) return;\n const listeners = this._editEventListeners[type];\n if (listeners) {\n listeners.forEach((fn) => fn());\n }\n }\n\n /**\n * Listen for custom edit events (e.g. 'save').\n * @param {string} type - Event name\n * @param {Function} callback\n */\n onEditEvent(type, callback) {\n if (!this._editEventListeners) this._editEventListeners = {};\n if (!this._editEventListeners[type]) this._editEventListeners[type] = [];\n this._editEventListeners[type].push(callback);\n }\n\n /**\n * Toggle edit mode on or off.\n *\n * When ON: EditBar is visible, Select + Modify interactions are active.\n * When OFF: EditBar is hidden, Select + Modify are deactivated, any\n * current selection is cleared so normal click / double-click\n * events work without interference.\n *\n * @param {boolean} active\n */\n setEditMode(active) {\n this._editBarActive = !!active;\n\n if (this.editBar) {\n this.editBar.setVisible(this._editBarActive);\n\n if (!this._editBarActive) {\n // Deactivate all EditBar controls (DrawPoint, DrawLine, etc.)\n // so no draw interaction stays active in the background.\n this.editBar.deactivateControls();\n }\n }\n\n // Activate / deactivate Select + Modify\n if (this._selectInteraction) {\n if (!this._editBarActive) {\n // Clear any current selection first\n this._selectInteraction.getFeatures().clear();\n }\n this._selectInteraction.setActive(this._editBarActive);\n }\n if (this._modifyInteraction) {\n this._modifyInteraction.setActive(this._editBarActive);\n }\n\n // Toggle SnapGuides — only active when both edit mode AND the user toggle are on\n if (this._snapGuides) {\n this._snapGuides.setActive(this._snapGuidesEnabled && this._editBarActive);\n }\n\n // Toggle TouchCursor\n if (this.touchCursor) {\n this.touchCursor.setActive(this._editBarActive);\n }\n\n // Clear persistent vertex highlights when leaving edit mode\n if (!this._editBarActive && this._vertexOverlaySource) {\n this._vertexOverlaySource.clear();\n }\n\n console.log('[MapView] Edit mode:', this._editBarActive ? 'ON' : 'OFF');\n }\n\n /**\n * Check whether edit mode (select / modify) is currently active.\n * @returns {boolean}\n */\n isEditMode() {\n return this._editBarActive;\n }\n\n // ============================================================================\n // Persistent Vertex Highlight Overlay\n // ============================================================================\n\n /**\n * Create a vector layer that renders a small dot at every vertex of any\n * currently-selected feature (polygon, multipolygon, line, multiline).\n * Only active while edit mode is on.\n *\n * Hooks:\n * - `select` event from the Select interaction → rebuild dots for the new selection\n * - `change` event on the selected feature → reposition dots when a vertex is dragged\n */\n _setupVertexOverlay() {\n this._vertexOverlaySource = new VectorSource();\n this._vertexOverlayLayer = new VectorLayer({\n title: '__vertex_highlight__',\n source: this._vertexOverlaySource,\n // Render above all other overlays but below ModifyFeature's hover indicator\n zIndex: 990,\n style: new Style({\n image: new Circle({\n radius: 4,\n fill: new Fill({ color: 'rgba(14,165,233,0.85)' }), // brand blue\n stroke: new Stroke({ color: '#fff', width: 1.2 }),\n }),\n }),\n });\n // Hide from LayerSwitcher — purely visual, not user-toggleable\n this._vertexOverlayLayer.set('displayInLayerSwitcher', false);\n this.map.addLayer(this._vertexOverlayLayer);\n\n // Bound handler so we can attach/detach by reference\n this._onSelectedFeatureGeomChange = () => this._refreshVertexOverlay();\n\n // Track which feature(s) we're listening on, so we can unhook cleanly\n this._vertexTrackedFeatures = new Set();\n\n // When the selection changes, swap which features we listen to and rebuild dots\n this._selectInteraction.on('select', () => this._refreshVertexOverlay());\n }\n\n /**\n * Rebuild the vertex overlay from the current Select interaction's features.\n * No-ops when not in edit mode.\n */\n _refreshVertexOverlay() {\n if (!this._vertexOverlaySource) return;\n this._vertexOverlaySource.clear();\n\n // Detach change listeners from previously-tracked features\n if (this._vertexTrackedFeatures) {\n for (const f of this._vertexTrackedFeatures) {\n f.un('change', this._onSelectedFeatureGeomChange);\n }\n this._vertexTrackedFeatures.clear();\n }\n\n if (!this._editBarActive || !this._selectInteraction) return;\n\n const selected = this._selectInteraction.getFeatures().getArray();\n for (const feat of selected) {\n const geom = feat.getGeometry();\n if (!geom) continue;\n const type = geom.getType();\n if (!['Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'].includes(type)) {\n continue;\n }\n const coords = this._collectAllVertices(geom);\n for (const c of coords) {\n this._vertexOverlaySource.addFeature(new Feature(new Point(c)));\n }\n // Listen for vertex moves on this feature\n feat.on('change', this._onSelectedFeatureGeomChange);\n this._vertexTrackedFeatures.add(feat);\n }\n }\n\n /**\n * Walk a (Multi)Polygon or (Multi)LineString geometry and return the flat\n * list of vertex coordinates. Polygon rings have a duplicate closing vertex\n * (last == first) which is dropped here so we don't render two dots on top\n * of each other.\n *\n * @param {Geometry} geom\n * @returns {Array>}\n */\n _collectAllVertices(geom) {\n const out = [];\n const isCoord = (v) => Array.isArray(v) && typeof v[0] === 'number';\n\n const visitRing = (ring, isPolygonRing) => {\n const len = isPolygonRing && ring.length > 1 ? ring.length - 1 : ring.length;\n for (let i = 0; i < len; i++) out.push(ring[i]);\n };\n\n const type = geom.getType();\n const coords = geom.getCoordinates();\n\n switch (type) {\n case 'Polygon':\n // coords = [outerRing, hole1, hole2, …]\n for (const ring of coords) visitRing(ring, true);\n break;\n case 'MultiPolygon':\n // coords = [poly1, poly2, …]; each poly = [outerRing, hole1, …]\n for (const poly of coords) for (const ring of poly) visitRing(ring, true);\n break;\n case 'LineString':\n visitRing(coords, false);\n break;\n case 'MultiLineString':\n for (const line of coords) visitRing(line, false);\n break;\n default:\n // Fallback: deep walk to find arrays of [x, y]\n const walk = (v) => {\n if (isCoord(v)) out.push(v);\n else if (Array.isArray(v)) for (const sub of v) walk(sub);\n };\n walk(coords);\n }\n return out;\n }\n\n /**\n * Get the Drawings layer for external access.\n * @returns {VectorLayer}\n */\n getDrawingsLayer() {\n return this.drawingsLayer;\n }\n\n /**\n * Get the Drawings source for external access.\n * @returns {VectorSource}\n */\n getDrawingsSource() {\n return this.drawingsSource;\n }\n\n /**\n * Get the EditBar control for external access.\n * @returns {EditBar}\n */\n getEditBar() {\n return this.editBar;\n }\n\n /**\n * Update the ScaleBar units ('metric' or 'imperial').\n * @param {'metric'|'imperial'} system\n */\n setScaleBarUnits(system) {\n if (this.scaleBar) {\n this.scaleBar.setUnits(system === 'imperial' ? 'imperial' : 'metric');\n }\n }\n\n /**\n * Create the popup overlay element and add to map\n */\n createPopup() {\n // Create popup container element\n this.popupElement = document.createElement('div');\n this.popupElement.className = 'map-popup';\n this.popupElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n color: var(--card-foreground, #1e1a4b);\n border-radius: 8px;\n padding: 10px 14px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.25);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 150px;\n max-width: 280px;\n pointer-events: none;\n z-index: 1000;\n border: 1px solid var(--border, #1e1a4b1f);\n `;\n\n // Create the overlay\n this.popup = new Overlay({\n element: this.popupElement,\n positioning: 'bottom-center',\n offset: [0, -15],\n stopEvent: false,\n });\n\n this.map.addOverlay(this.popup);\n\n // Set up hover handler\n this.setupHoverPopup();\n }\n\n /**\n * Set up the hover popup behavior\n */\n setupHoverPopup() {\n let currentFeature = null;\n\n this.map.on('pointermove', (evt) => {\n if (evt.dragging) {\n this.hidePopup();\n return;\n }\n\n // Only find features that are location markers (have 'name' property)\n const feature = this.map.forEachFeatureAtPixel(evt.pixel, (f) => {\n // Only return features that have a 'name' property (location markers)\n if (f.get('name')) {\n return f;\n }\n return null;\n });\n\n if (feature && feature !== currentFeature) {\n currentFeature = feature;\n this.showPopup(feature, evt.coordinate);\n } else if (!feature && currentFeature) {\n currentFeature = null;\n this.hidePopup();\n }\n\n // Update cursor - only show pointer for location markers\n this.map.getTargetElement().style.cursor = feature ? 'pointer' : '';\n });\n\n // Hide popup when mouse leaves the map\n this.map.getTargetElement().addEventListener('mouseleave', () => {\n this.hidePopup();\n currentFeature = null;\n });\n }\n\n /**\n * Show popup with feature attributes\n */\n showPopup(feature, coordinate) {\n const name = feature.get('name') || 'Unnamed';\n const category = feature.get('category') || 'default';\n const description = feature.get('description');\n const lon = feature.get('lon');\n const lat = feature.get('lat');\n const emoji = this.getEmoji(category);\n\n // Build popup content\n let html = `\n
    \n ${emoji} ${this.escapeHtml(name)}\n
    \n `;\n\n // Category badge\n const categoryColors = {\n 'water': '#3b82f6',\n 'school': '#f59e0b',\n 'health': '#ef4444',\n 'market': '#8b5cf6',\n 'default': '#2d5016',\n 'other': '#6b7280'\n };\n const catColor = categoryColors[category] || '#6b7280';\n html += `\n
    \n ${category}\n
    \n `;\n\n // Description if available\n if (description) {\n html += `\n
    \n ${this.escapeHtml(description)}\n
    \n `;\n }\n\n // Coordinates\n if (lon !== undefined && lat !== undefined) {\n html += `\n
    \n ${Number(lon).toFixed(5)}, ${Number(lat).toFixed(5)}\n
    \n `;\n }\n\n this.popupElement.innerHTML = html;\n this.popup.setPosition(coordinate);\n }\n\n /**\n * Hide the popup\n */\n hidePopup() {\n this.popup.setPosition(undefined);\n }\n\n /**\n * Create the info popup overlay for double-click feature details\n */\n createInfoPopup() {\n this.infoPopupElement = document.createElement('div');\n this.infoPopupElement.className = 'map-info-popup';\n this.infoPopupElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n color: var(--card-foreground, #1e1a4b);\n border-radius: 10px;\n padding: 0;\n box-shadow: 0 4px 16px rgba(0,0,0,0.3);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 220px;\n max-width: 320px;\n max-height: 70vh;\n display: flex;\n flex-direction: column;\n z-index: 1001;\n border: 1px solid var(--border, #1e1a4b1f);\n overflow: hidden;\n `;\n\n this.infoPopup = new Overlay({\n element: this.infoPopupElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true,\n autoPan: true,\n autoPanAnimation: { duration: 250 },\n });\n\n this.map.addOverlay(this.infoPopup);\n }\n\n /**\n * Show the info popup with feature attributes and area\n * @param {Feature} feature - OpenLayers feature\n * @param {Array} coordinate - Map coordinate [x, y]\n * @param {Object} [options] - Display options\n * @param {string} [options.title='Feature Info'] - Popup header title\n * @param {string} [options.color='#e11d48'] - Header background colour\n */\n showInfoPopup(feature, coordinate, options = {}) {\n const { title = 'Feature Info', color = '#e11d48' } = options;\n const properties = feature.getProperties();\n const geometry = feature.getGeometry();\n const geomType = geometry.getType();\n\n // Build attributes table rows (skip geometry and internal keys)\n const skipKeys = ['geometry', '_layerType'];\n let rows = '';\n for (const [key, value] of Object.entries(properties)) {\n if (skipKeys.includes(key) || value === undefined || value === null) continue;\n rows += `\n \n ${this.escapeHtml(key)}\n ${this.escapeHtml(String(value))}\n \n `;\n }\n\n // Add measurement row based on geometry type\n if (geomType === 'Polygon' || geomType === 'MultiPolygon') {\n // Area for polygons\n const areaSqm = getArea(geometry, { projection: 'EPSG:3857' });\n const areaFormatted = formatAreaFull(areaSqm);\n rows += `\n \n area\n ${areaFormatted}\n \n `;\n } else if (geomType === 'LineString' || geomType === 'MultiLineString') {\n // Length for lines\n const lengthM = getLength(geometry, { projection: 'EPSG:3857' });\n const lengthFormatted = formatLengthFull(lengthM);\n rows += `\n \n length\n ${lengthFormatted}\n \n `;\n } else if (geomType === 'Point') {\n // Coordinates for points\n const coords = toLonLat(geometry.getCoordinates());\n const lon = coords[0].toFixed(6);\n const lat = coords[1].toFixed(6);\n rows += `\n \n longitude\n ${lon}\n \n \n latitude\n ${lat}\n \n `;\n }\n\n const html = `\n
    \n ${this.escapeHtml(title)}\n \n
    \n
    \n \n ${rows}\n
    \n
    \n `;\n\n this.infoPopupElement.innerHTML = html;\n this.infoPopup.setPosition(coordinate);\n\n // Close button handler\n this.infoPopupElement.querySelector('#info-popup-close').addEventListener('click', () => {\n this.hideInfoPopup();\n });\n }\n\n /**\n * Hide the info popup\n */\n hideInfoPopup() {\n this.infoPopup.setPosition(undefined);\n }\n\n // ============================================================================\n // Circle Intersection Analysis\n // ============================================================================\n\n /**\n * Analyse which features from overlay layers intersect a measurement circle\n * and show the results in the info popup.\n *\n * @param {Feature} circleFeature - The measurement circle feature (Circle geometry)\n * @param {Array} coordinate - Map coordinate for popup placement [x, y]\n */\n /**\n * Collect intersection results (parcels, zones, other) into a\n * structured { label, value } array for both HTML and PDF rendering.\n */\n _collectIntersectionRows(parcelFeatures, zoneFeatures, otherByLayer) {\n const dataRows = [];\n\n if (parcelFeatures.length > 0) {\n dataRows.push({ label: 'Parcels', value: String(parcelFeatures.length), color: '#0ea5e9' });\n }\n\n if (zoneFeatures.length > 0) {\n const names = zoneFeatures.map(f =>\n f.get('colzonename') || f.get('zone_name') || f.get('name') || 'unnamed'\n );\n dataRows.push({ label: 'Zones', value: String(zoneFeatures.length), color: '#7c3aed' });\n dataRows.push({ label: 'Zone Names', value: names.map(n => this.escapeHtml(n)).join(', '), color: '#7c3aed' });\n }\n\n for (const [title, features] of Object.entries(otherByLayer)) {\n dataRows.push({ label: this.escapeHtml(title), value: `${features.length} feature(s)` });\n }\n\n if (dataRows.length === 0) {\n dataRows.push({ label: '', value: 'No intersecting features found', empty: true });\n }\n\n return dataRows;\n }\n\n /**\n * Build the full popup HTML for an analysis popup (circle or area).\n *\n * @param {string} emoji - Header emoji\n * @param {string} title - e.g. \"Circle Analysis\"\n * @param {Array<{label:string, value:string, color?:string, empty?:boolean}>} dataRows\n * @returns {string} HTML\n */\n _buildAnalysisPopupHtml(emoji, title, dataRows) {\n let tableRows = '';\n for (const row of dataRows) {\n if (row.empty) {\n tableRows += `\n \n ${row.value}\n `;\n continue;\n }\n const labelColor = row.color || 'var(--muted-foreground, #7a7a7a)';\n const border = row._first ? '' : 'border-top:1px solid var(--border, #1e1a4b1f);';\n tableRows += `\n \n ${row.label}\n ${row.value}\n `;\n }\n\n return `\n
    \n ${emoji} ${title}\n \n
    \n
    \n \n ${tableRows}\n
    \n
    \n
    \n \n \n
    `;\n }\n\n /**\n * Show the analysis popup, attach close + PDF / GIS export handlers.\n *\n * @param {string} emoji\n * @param {string} title - e.g. \"Area Analysis\" / \"Circle Analysis\"\n * @param {Array} dataRows - summary rows (PDF uses these)\n * @param {number[]} coordinate - popup anchor\n * @param {Object} [exportContext] - features + clip geometry for GIS export.\n * When omitted, the Export GIS button is\n * disabled (no features to export).\n * { kind: 'area' | 'circle',\n * clipGeometry,\n * parcelFeatures, zoneFeatures, otherByLayer }\n */\n _showAnalysisPopup(emoji, title, dataRows, coordinate, exportContext = null) {\n this.infoPopupElement.innerHTML = this._buildAnalysisPopupHtml(emoji, title, dataRows);\n this.infoPopup.setPosition(coordinate);\n\n this.infoPopupElement.querySelector('#info-popup-close').addEventListener('click', () => {\n this.hideInfoPopup();\n });\n\n // PDF export — dynamic import so jspdf is only loaded on demand\n this.infoPopupElement.querySelector('#info-popup-export-pdf')?.addEventListener('click', () => {\n // Strip HTML from values and remove the color/empty keys for the PDF\n const pdfRows = dataRows\n .filter(r => !r.empty)\n .map(r => ({ label: r.label, value: r.value.replace(/<[^>]*>/g, '') }));\n\n import('../pdf-export.js').then(({ exportAnalysisPDF }) => {\n exportAnalysisPDF({ title, rows: pdfRows });\n }).catch(err => {\n console.error('[MapView] PDF export failed:', err);\n });\n });\n\n // GIS export — dispatches a window-level CustomEvent so main.js can open\n // the format/field-rename modal without MapView pulling in the writers.\n const gisBtn = this.infoPopupElement.querySelector('#info-popup-export-gis');\n if (gisBtn) {\n const total = exportContext\n ? exportContext.parcelFeatures.length\n + exportContext.zoneFeatures.length\n + Object.values(exportContext.otherByLayer).reduce((s, arr) => s + arr.length, 0)\n : 0;\n if (!exportContext || total === 0) {\n gisBtn.disabled = true;\n gisBtn.style.opacity = '0.5';\n gisBtn.style.cursor = 'not-allowed';\n gisBtn.title = 'No intersecting features to export';\n } else {\n gisBtn.addEventListener('click', () => {\n window.dispatchEvent(new CustomEvent('lupmis:export-gis', {\n detail: { title, ...exportContext },\n }));\n });\n }\n }\n }\n\n showCircleIntersectionPopup(circleFeature, coordinate) {\n const circleGeom = circleFeature.getGeometry();\n if (!circleGeom || typeof circleGeom.getCenter !== 'function') return;\n\n // Convert the OL Circle to a polygon (64 sides) for intersection testing\n const circlePoly = fromCircle(circleGeom, 64);\n const circleExtent = circlePoly.getExtent();\n\n const radius = circleFeature.get('_radius') || circleGeom.getRadius();\n\n // Collect intersecting features grouped by layer type\n const parcelFeatures = [];\n const zoneFeatures = [];\n const otherByLayer = {};\n\n const intersectsCircle = (feature) => {\n const geom = feature.getGeometry();\n if (!geom) return false;\n const fExtent = geom.getExtent();\n if (\n fExtent[2] < circleExtent[0] ||\n fExtent[0] > circleExtent[2] ||\n fExtent[3] < circleExtent[1] ||\n fExtent[1] > circleExtent[3]\n ) {\n return false;\n }\n return circlePoly.intersectsExtent(fExtent) && this._geometriesIntersect(circlePoly, geom);\n };\n\n const scanGroup = (group, groupTitle) => {\n group.getLayers().forEach((layer) => {\n if (layer instanceof LayerGroup) {\n scanGroup(layer, layer.get('title') || groupTitle);\n } else if (layer instanceof VectorLayer && layer.getVisible()) {\n const layerTitle = layer.get('title') || groupTitle || 'Unknown';\n const source = layer.getSource();\n if (!source) return;\n\n const candidates = source.getFeaturesInExtent(circleExtent);\n for (const f of candidates) {\n const fType = f.get('_layerType');\n if (fType === 'measure_circle' || fType === 'measure_circle_radius') continue;\n\n if (!intersectsCircle(f)) continue;\n\n if (fType === 'parcel') {\n parcelFeatures.push(f);\n } else if (fType === 'collector_zone') {\n zoneFeatures.push(f);\n } else {\n if (!otherByLayer[layerTitle]) otherByLayer[layerTitle] = [];\n otherByLayer[layerTitle].push(f);\n }\n }\n }\n });\n };\n\n scanGroup(this.overlayGroup, 'Overlays');\n\n // Build structured data rows\n const radiusFormatted = formatLength(radius);\n const areaSqm = Math.PI * radius * radius;\n const areaFormatted = formatArea(areaSqm);\n\n const dataRows = [\n { label: 'Radius', value: radiusFormatted, _first: true },\n { label: 'Area', value: areaFormatted },\n ...this._collectIntersectionRows(parcelFeatures, zoneFeatures, otherByLayer),\n ];\n\n this._showAnalysisPopup('⭕', 'Circle Analysis', dataRows, coordinate, {\n kind: 'circle',\n clipGeometry: circlePoly,\n parcelFeatures,\n zoneFeatures,\n otherByLayer,\n });\n }\n\n /**\n * Show an intersection-analysis popup for a measured area polygon.\n * Same logic as showCircleIntersectionPopup but works with an\n * arbitrary Polygon geometry instead of a circle.\n *\n * @param {Feature} polygonFeature - The measure_area feature\n * @param {number[]} coordinate - Map coordinate for the popup anchor\n */\n showAreaIntersectionPopup(polygonFeature, coordinate) {\n const polyGeom = polygonFeature.getGeometry();\n if (!polyGeom) return;\n\n const polyExtent = polyGeom.getExtent();\n\n // Compute area via ol/sphere for geodesic accuracy\n const areaSqm = getArea(polyGeom, { projection: 'EPSG:3857' });\n const areaFormatted = formatArea(areaSqm);\n\n // Compute perimeter\n const perimeterM = getLength(polyGeom, { projection: 'EPSG:3857' });\n const perimeterFormatted = formatLength(perimeterM);\n\n // Collect intersecting features grouped by layer type\n const parcelFeatures = [];\n const zoneFeatures = [];\n const otherByLayer = {};\n\n const intersectsPoly = (feature) => {\n const geom = feature.getGeometry();\n if (!geom) return false;\n const fExtent = geom.getExtent();\n if (\n fExtent[2] < polyExtent[0] ||\n fExtent[0] > polyExtent[2] ||\n fExtent[3] < polyExtent[1] ||\n fExtent[1] > polyExtent[3]\n ) {\n return false;\n }\n return polyGeom.intersectsExtent(fExtent) && this._geometriesIntersect(polyGeom, geom);\n };\n\n const scanGroup = (group, groupTitle) => {\n group.getLayers().forEach((layer) => {\n if (layer instanceof LayerGroup) {\n scanGroup(layer, layer.get('title') || groupTitle);\n } else if (layer instanceof VectorLayer && layer.getVisible()) {\n const layerTitle = layer.get('title') || groupTitle || 'Unknown';\n const source = layer.getSource();\n if (!source) return;\n\n const candidates = source.getFeaturesInExtent(polyExtent);\n for (const f of candidates) {\n const fType = f.get('_layerType');\n if (fType === 'measure_area' || fType === 'measure_circle' || fType === 'measure_circle_radius') continue;\n\n if (!intersectsPoly(f)) continue;\n\n if (fType === 'parcel') {\n parcelFeatures.push(f);\n } else if (fType === 'collector_zone') {\n zoneFeatures.push(f);\n } else {\n if (!otherByLayer[layerTitle]) otherByLayer[layerTitle] = [];\n otherByLayer[layerTitle].push(f);\n }\n }\n }\n });\n };\n\n scanGroup(this.overlayGroup, 'Overlays');\n\n // Build structured data rows\n const dataRows = [\n { label: 'Area', value: areaFormatted, _first: true },\n { label: 'Perimeter', value: perimeterFormatted },\n ...this._collectIntersectionRows(parcelFeatures, zoneFeatures, otherByLayer),\n ];\n\n this._showAnalysisPopup('📐', 'Area Analysis', dataRows, coordinate, {\n kind: 'area',\n clipGeometry: polyGeom,\n parcelFeatures,\n zoneFeatures,\n otherByLayer,\n });\n }\n\n /**\n * Test whether two geometries truly intersect (beyond just extent overlap).\n * Works for Polygon/MultiPolygon against any geometry type.\n *\n * @param {Geometry} geomA - First geometry (usually the circle polygon)\n * @param {Geometry} geomB - Second geometry\n * @returns {boolean}\n * @private\n */\n _geometriesIntersect(geomA, geomB) {\n const typeB = geomB.getType();\n\n // For polygons / multi-polygons: check if any coordinate of B is inside A,\n // or if any coordinate of A is inside B (covers overlap & containment).\n if (typeB === 'Polygon' || typeB === 'MultiPolygon') {\n // Check if any vertex of B lies inside A (use flatCoordinates for efficiency)\n const flatB = geomB.getFlatCoordinates();\n const stride = geomB.getStride();\n for (let i = 0; i < flatB.length; i += stride) {\n if (geomA.intersectsCoordinate([flatB[i], flatB[i + 1]])) return true;\n }\n // Check if any vertex of A lies inside B\n const flatA = geomA.getFlatCoordinates();\n const strideA = geomA.getStride();\n for (let i = 0; i < flatA.length; i += strideA) {\n if (geomB.intersectsCoordinate([flatA[i], flatA[i + 1]])) return true;\n }\n return false;\n }\n\n if (typeB === 'Point') {\n return geomA.intersectsCoordinate(geomB.getCoordinates());\n }\n\n if (typeB === 'LineString' || typeB === 'MultiLineString') {\n const flatB = geomB.getFlatCoordinates();\n const stride = geomB.getStride();\n for (let i = 0; i < flatB.length; i += stride) {\n if (geomA.intersectsCoordinate([flatB[i], flatB[i + 1]])) return true;\n }\n return false;\n }\n\n // Fallback: extent overlap is good enough\n return true;\n }\n\n // ============================================================================\n // Parcel Edit Popup (single-click editable form)\n // ============================================================================\n\n /**\n * Create the parcel edit popup overlay with a dynamic form.\n */\n createParcelEditPopup() {\n this.parcelEditElement = document.createElement('div');\n this.parcelEditElement.className = 'map-parcel-edit-popup';\n this.parcelEditElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n color: var(--card-foreground, #1e1a4b);\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 280px;\n max-width: 360px;\n max-height: 420px;\n z-index: 1002;\n border: 2px solid var(--primary, #005eb8);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n `;\n\n this.parcelEditPopup = new Overlay({\n element: this.parcelEditElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true,\n autoPan: true,\n autoPanAnimation: { duration: 250 },\n });\n\n this.map.addOverlay(this.parcelEditPopup);\n\n // Callbacks for save events\n this._parcelEditCallbacks = [];\n // Track the current feature being edited\n this._parcelEditFeature = null;\n }\n\n /**\n * Show the parcel edit popup with an editable form for all feature attributes.\n * Internal keys (_layerType, geometry) are excluded from the form.\n *\n * @param {Feature} feature - The OL feature to edit\n * @param {Array} coordinate - Map coordinate [x, y]\n */\n showParcelEditPopup(feature, coordinate) {\n this._parcelEditFeature = feature;\n const properties = feature.getProperties();\n\n // Keys to skip in the form\n const skipKeys = ['geometry', '_layerType'];\n\n // Build form fields from feature properties\n let fieldsHtml = '';\n for (const [key, value] of Object.entries(properties)) {\n if (skipKeys.includes(key)) continue;\n const displayVal = (value === null || value === undefined) ? '' : String(value);\n const escapedKey = this.escapeHtml(key);\n const escapedVal = this.escapeHtml(displayVal);\n fieldsHtml += `\n
    \n \n \n
    \n `;\n }\n\n const html = `\n
    \n ✏️ Edit Parcel\n \n
    \n
    \n ${fieldsHtml}\n
    \n \n \n
    \n
    \n `;\n\n this.parcelEditElement.innerHTML = html;\n this.parcelEditPopup.setPosition(coordinate);\n\n // Close / Cancel handlers\n this.parcelEditElement.querySelector('.parcel-edit-close').addEventListener('click', () => {\n this.hideParcelEditPopup();\n });\n this.parcelEditElement.querySelector('.parcel-edit-cancel').addEventListener('click', () => {\n this.hideParcelEditPopup();\n });\n\n // Form submit handler\n const form = this.parcelEditElement.querySelector('.parcel-edit-form');\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n\n // Collect all edited values\n const formData = new FormData(form);\n const updatedProps = {};\n for (const [key, value] of formData.entries()) {\n updatedProps[key] = value;\n }\n\n // Restore internal properties that were excluded from the form\n updatedProps._layerType = 'parcel';\n\n // Update the feature's properties in-place\n for (const [key, value] of Object.entries(updatedProps)) {\n this._parcelEditFeature.set(key, value);\n }\n\n // Notify external listeners\n for (const cb of this._parcelEditCallbacks) {\n cb(this._parcelEditFeature, updatedProps);\n }\n\n this.hideParcelEditPopup();\n });\n }\n\n /**\n * Hide the parcel edit popup.\n */\n hideParcelEditPopup() {\n this.parcelEditPopup.setPosition(undefined);\n this._parcelEditFeature = null;\n }\n\n /**\n * Register a callback for when a parcel edit is saved.\n * Callback receives (feature, updatedProperties).\n *\n * @param {Function} callback\n */\n onParcelEdit(callback) {\n this._parcelEditCallbacks.push(callback);\n }\n\n // ============================================================================\n // Merge Identifier (UPN) Chooser Popup\n // ============================================================================\n\n /**\n * Create the merge identifier popup overlay.\n * Shown after two parcels are merged so the user can choose which UPN to keep.\n */\n createMergePopup() {\n this.mergePopupElement = document.createElement('div');\n this.mergePopupElement.className = 'map-merge-popup';\n this.mergePopupElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n color: var(--card-foreground, #1e1a4b);\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 280px;\n max-width: 360px;\n z-index: 1002;\n border: 2px solid #10b981;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n `;\n\n this.mergePopup = new Overlay({\n element: this.mergePopupElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true,\n autoPan: true,\n autoPanAnimation: { duration: 250 },\n });\n\n this.map.addOverlay(this.mergePopup);\n }\n\n /**\n * Show the merge identifier popup so the user can pick which parcel's\n * attributes (including UPN) the merged polygon should inherit.\n *\n * @param {Feature} mergedFeature The newly created merged feature\n * @param {Object} propsA Properties from original parcel A\n * @param {Object} propsB Properties from original parcel B\n * @param {Array} coordinate Map coordinate [x, y] for popup placement\n */\n showMergeIdentifierPopup(mergedFeature, propsA, propsB, coordinate) {\n // Extract identifiers — try common parcel ID field names\n const idFields = ['UPN', 'upn', 'id', 'parcelid', 'parcel_id', 'PARCELID', 'PARCEL_ID', 'ID'];\n const getLabel = (props) => {\n for (const field of idFields) {\n if (props[field] !== undefined && props[field] !== null && String(props[field]).trim()) {\n return { field, value: String(props[field]) };\n }\n }\n return { field: 'id', value: 'Unknown' };\n };\n\n const labelA = getLabel(propsA);\n const labelB = getLabel(propsB);\n\n const html = `\n
    \n 🔗 Merged Parcel — Choose Identifier\n \n
    \n
    \n

    \n Select which parcel's attributes the merged polygon should keep:\n

    \n \n \n
    \n \n \n
    \n
    \n `;\n\n this.mergePopupElement.innerHTML = html;\n this.mergePopup.setPosition(coordinate);\n\n // Close / Cancel — keep parcel A properties (the default from clone)\n const close = () => {\n this.mergePopup.setPosition(undefined);\n };\n this.mergePopupElement.querySelector('.merge-popup-close').addEventListener('click', close);\n this.mergePopupElement.querySelector('.merge-popup-cancel').addEventListener('click', close);\n\n // Confirm — apply chosen parcel's properties\n this.mergePopupElement.querySelector('.merge-popup-confirm').addEventListener('click', () => {\n const choice = this.mergePopupElement.querySelector('input[name=\"merge-choice\"]:checked').value;\n const chosenProps = choice === 'A' ? propsA : propsB;\n\n // Copy all properties (except geometry) onto the merged feature\n const skipKeys = ['geometry'];\n for (const [key, value] of Object.entries(chosenProps)) {\n if (skipKeys.includes(key)) continue;\n mergedFeature.set(key, value);\n }\n // Ensure _layerType is preserved\n mergedFeature.set('_layerType', 'parcel');\n\n // Notify parcel edit callbacks\n for (const cb of this._parcelEditCallbacks) {\n cb(mergedFeature, chosenProps);\n }\n\n close();\n });\n\n // Highlight radio labels on selection\n const labels = this.mergePopupElement.querySelectorAll('label');\n const radios = this.mergePopupElement.querySelectorAll('input[name=\"merge-choice\"]');\n const updateHighlight = () => {\n labels.forEach((lbl) => {\n const radio = lbl.querySelector('input');\n lbl.style.borderColor = radio.checked ? (radio.value === 'A' ? '#0ea5e9' : '#f59e0b') : 'var(--border, #1e1a4b1f)';\n });\n };\n radios.forEach((r) => r.addEventListener('change', updateHighlight));\n updateHighlight();\n }\n\n // ============================================================================\n // Divide Polygon Popup (number input)\n // ============================================================================\n\n /**\n * Create the divide polygon popup overlay.\n * Shown after the user selects a polygon with the Divide tool, so they\n * can enter the number of equal pieces.\n */\n createDividePopup() {\n this.dividePopupElement = document.createElement('div');\n this.dividePopupElement.className = 'map-divide-popup';\n this.dividePopupElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n color: var(--card-foreground, #1e1a4b);\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.3);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 260px;\n max-width: 320px;\n z-index: 1002;\n border: 2px solid #8b5cf6;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n `;\n\n this.dividePopup = new Overlay({\n element: this.dividePopupElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true,\n autoPan: true,\n autoPanAnimation: { duration: 250 },\n });\n\n this.map.addOverlay(this.dividePopup);\n }\n\n /**\n * Show the divide popup so the user can enter the number of divisions.\n *\n * @param {Feature} feature The selected polygon feature\n * @param {VectorSource} source The source containing the feature\n * @param {Array} coordinate Map coordinate [x, y] for popup placement\n */\n showDividePopup(feature, source, coordinate) {\n const html = `\n
    \n Divide Polygon\n \n
    \n
    \n

    \n Enter the number of equal pieces:\n

    \n \n
    \n \n \n
    \n
    \n `;\n\n this.dividePopupElement.innerHTML = html;\n this.dividePopup.setPosition(coordinate);\n\n const input = this.dividePopupElement.querySelector('.divide-input');\n input.focus();\n input.select();\n\n // Close / Cancel\n const cancel = () => {\n this.hideDividePopup();\n this._polygonDivideInteraction.cancelDivide();\n };\n this.dividePopupElement.querySelector('.divide-popup-close').addEventListener('click', cancel);\n this.dividePopupElement.querySelector('.divide-popup-cancel').addEventListener('click', cancel);\n\n // Confirm\n this.dividePopupElement.querySelector('.divide-popup-confirm').addEventListener('click', () => {\n const n = parseInt(input.value, 10);\n if (!n || n < 2) {\n input.style.borderColor = '#ef4444';\n return;\n }\n this.hideDividePopup();\n this._polygonDivideInteraction.performDivide(n);\n });\n\n // Allow Enter key to confirm\n input.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n this.dividePopupElement.querySelector('.divide-popup-confirm').click();\n }\n });\n }\n\n /**\n * Hide the divide popup.\n */\n hideDividePopup() {\n this.dividePopup.setPosition(undefined);\n }\n\n // ============================================================================\n // Drawn Polygon Attribute Popup\n // ============================================================================\n\n /**\n * Create the drawn polygon attribute popup overlay.\n * Shown after the area measurement polygon is completed so the user can\n * attach parcel-like attributes to the drawn polygon.\n */\n createDrawnPolygonPopup() {\n this.drawnPolygonElement = document.createElement('div');\n this.drawnPolygonElement.className = 'map-drawn-polygon-popup';\n this.drawnPolygonElement.style.cssText = `\n position: absolute;\n background: var(--card, #fff);\n border-radius: var(--radius-xl, 0.75rem);\n box-shadow: 0 4px 20px rgba(0,0,0,0.2);\n font-family: var(--font-body, 'Exo', sans-serif);\n font-size: 13px;\n min-width: 280px;\n max-width: 360px;\n max-height: 420px;\n z-index: 1002;\n border: 2px solid var(--success, #006b3f);\n overflow: hidden;\n display: flex;\n flex-direction: column;\n `;\n\n this.drawnPolygonPopup = new Overlay({\n element: this.drawnPolygonElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true,\n autoPan: true,\n autoPanAnimation: { duration: 250 },\n });\n\n this.map.addOverlay(this.drawnPolygonPopup);\n this._drawnPolygonCallbacks = [];\n this._drawnPolygonFeature = null;\n }\n\n /**\n * Get attribute keys from existing parcel features on the map.\n * Scans the overlay group for the first feature with _layerType='parcel'\n * and returns its property key names (excluding internal keys).\n *\n * @returns {string[]} Array of attribute key names\n */\n getParcelAttributeKeys() {\n const skipKeys = ['geometry', '_layerType'];\n const keys = [];\n\n const scanGroup = (group) => {\n if (keys.length > 0) return;\n group.getLayers().forEach((layer) => {\n if (keys.length > 0) return;\n if (layer instanceof LayerGroup) {\n scanGroup(layer);\n } else if (layer instanceof VectorLayer) {\n const source = layer.getSource();\n if (!source) return;\n for (const f of source.getFeatures()) {\n if (f.get('_layerType') !== 'parcel') continue;\n const props = f.getProperties();\n for (const key of Object.keys(props)) {\n if (!skipKeys.includes(key)) keys.push(key);\n }\n return; // one parcel is enough for the schema\n }\n }\n });\n };\n\n scanGroup(this.overlayGroup);\n return keys;\n }\n\n /**\n * Show the drawn polygon attribute popup.\n * Discovers attribute keys from existing parcel features and creates\n * a blank form with those fields.\n *\n * @param {Feature} feature - The drawn polygon feature\n * @param {Array} coordinate - Map coordinate [x, y] for popup placement\n */\n showDrawnPolygonPopup(feature, coordinate) {\n this._drawnPolygonFeature = feature;\n\n // Discover attribute keys from existing parcels\n const attributeKeys = this.getParcelAttributeKeys();\n\n if (attributeKeys.length === 0) {\n console.warn('[MapView] No parcel attributes found — cannot build form');\n return;\n }\n\n // Build form fields (all blank)\n let fieldsHtml = '';\n for (const key of attributeKeys) {\n const escapedKey = this.escapeHtml(key);\n fieldsHtml += `\n
    \n \n \n
    \n `;\n }\n\n // Area display\n const geom = feature.getGeometry();\n const areaSqm = getArea(geom, { projection: 'EPSG:3857' });\n const areaFormatted = formatArea(areaSqm);\n\n const html = `\n
    \n 📐 Polygon Attributes\n \n
    \n
    \n Area: ${areaFormatted}\n
    \n
    \n ${fieldsHtml}\n
    \n \n \n
    \n
    \n `;\n\n this.drawnPolygonElement.innerHTML = html;\n this.drawnPolygonPopup.setPosition(coordinate);\n\n // Close / Cancel handlers\n this.drawnPolygonElement.querySelector('.drawn-polygon-close').addEventListener('click', () => {\n this.hideDrawnPolygonPopup();\n });\n this.drawnPolygonElement.querySelector('.drawn-polygon-cancel').addEventListener('click', () => {\n this.hideDrawnPolygonPopup();\n });\n\n // Form submit handler\n const form = this.drawnPolygonElement.querySelector('.drawn-polygon-form');\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n\n const formData = new FormData(form);\n const props = {};\n for (const [key, value] of formData.entries()) {\n props[key] = value;\n }\n\n // Set properties on the feature\n for (const [key, value] of Object.entries(props)) {\n this._drawnPolygonFeature.set(key, value);\n }\n\n // Tag as parcel so it integrates with existing parcel tools\n this._drawnPolygonFeature.set('_layerType', 'parcel');\n\n // Notify listeners\n for (const cb of this._drawnPolygonCallbacks) {\n cb(this._drawnPolygonFeature, props);\n }\n\n this.hideDrawnPolygonPopup();\n });\n }\n\n /**\n * Hide the drawn polygon attribute popup.\n */\n hideDrawnPolygonPopup() {\n this.drawnPolygonPopup.setPosition(undefined);\n this._drawnPolygonFeature = null;\n }\n\n /**\n * Register a callback for when drawn polygon attributes are saved.\n * Callback receives (feature, properties).\n *\n * @param {Function} callback\n */\n onDrawnPolygonSave(callback) {\n this._drawnPolygonCallbacks.push(callback);\n }\n\n /**\n * Register a double-click callback.\n * Callback receives (lon, lat, feature, event).\n * Feature is the first feature found at the click pixel across all overlay layers,\n * or null if no feature was hit.\n * When a feature is hit, the default double-click-zoom is suppressed.\n */\n onDblClick(callback) {\n this.dblClickCallbacks.push(callback);\n\n // Set up the listener once\n if (this.dblClickCallbacks.length === 1) {\n this.map.on('dblclick', (evt) => {\n const [lon, lat] = toLonLat(evt.coordinate);\n\n // Find any feature at the clicked pixel (overlay layers, not just markers)\n let clickedFeature = null;\n this.map.forEachFeatureAtPixel(evt.pixel, (feature) => {\n clickedFeature = feature;\n return true; // stop at first hit\n });\n\n // If a feature was hit, prevent the default double-click zoom\n if (clickedFeature) {\n evt.preventDefault();\n evt.stopPropagation();\n }\n\n // Call all registered callbacks\n for (const cb of this.dblClickCallbacks) {\n cb(lon, lat, clickedFeature, evt);\n }\n\n // Return false to suppress DoubleClickZoom interaction when on a feature\n if (clickedFeature) return false;\n });\n }\n\n return () => {\n const idx = this.dblClickCallbacks.indexOf(callback);\n if (idx > -1) this.dblClickCallbacks.splice(idx, 1);\n };\n }\n\n /**\n * Escape HTML to prevent XSS\n */\n escapeHtml(text) {\n if (!text) return '';\n const div = document.createElement('div');\n div.textContent = text;\n return div.innerHTML;\n }\n\n /**\n * Create the Add Location popup form overlay\n */\n createAddLocationPopup() {\n // Create popup container element\n this.addLocationPopupElement = document.createElement('div');\n this.addLocationPopupElement.className = 'map-add-location-popup';\n this.addLocationPopupElement.innerHTML = `\n
    \n ➕ Add Location\n \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n 📍 \n
    \n \n
    \n `;\n\n // Create the overlay\n this.addLocationPopup = new Overlay({\n element: this.addLocationPopupElement,\n positioning: 'bottom-center',\n offset: [0, -10],\n stopEvent: true, // Prevent click from propagating\n autoPan: true,\n autoPanAnimation: {\n duration: 250,\n },\n });\n\n this.map.addOverlay(this.addLocationPopup);\n\n // Store clicked coordinates\n this.addLocationCoords = null;\n\n // Set up close button handler\n const closeBtn = this.addLocationPopupElement.querySelector('.add-location-popup-close');\n closeBtn.addEventListener('click', () => {\n this.hideAddLocationPopup();\n });\n\n // Store form submit callbacks\n this.addLocationCallbacks = [];\n }\n\n /**\n * Show the Add Location popup at the specified coordinate\n */\n showAddLocationPopup(coordinate) {\n const [lon, lat] = toLonLat(coordinate);\n this.addLocationCoords = { lon, lat };\n\n // Update coordinates display\n const coordsEl = this.addLocationPopupElement.querySelector('#map-location-coords');\n coordsEl.textContent = `${lon.toFixed(6)}, ${lat.toFixed(6)}`;\n\n // Reset form\n const form = this.addLocationPopupElement.querySelector('#map-add-location-form');\n form.reset();\n\n // Position and show popup\n this.addLocationPopup.setPosition(coordinate);\n }\n\n /**\n * Hide the Add Location popup\n */\n hideAddLocationPopup() {\n this.addLocationPopup.setPosition(undefined);\n this.addLocationCoords = null;\n }\n\n /**\n * Register a callback for when a location is submitted via the map popup\n * Callback receives: { name, category, description, lon, lat }\n */\n onAddLocation(callback) {\n this.addLocationCallbacks.push(callback);\n\n // Set up form submit handler (only once)\n if (this.addLocationCallbacks.length === 1) {\n const form = this.addLocationPopupElement.querySelector('#map-add-location-form');\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n\n if (!this.addLocationCoords) return;\n\n const formData = new FormData(form);\n const data = {\n name: formData.get('name'),\n category: formData.get('category'),\n description: formData.get('description'),\n lon: this.addLocationCoords.lon,\n lat: this.addLocationCoords.lat,\n };\n\n // Call all registered callbacks\n this.addLocationCallbacks.forEach(cb => cb(data));\n\n // Hide popup after submission\n this.hideAddLocationPopup();\n });\n }\n }\n\n /**\n * Create base layers group for LayerSwitcher\n */\n createBaseLayers(defaultBasemap) {\n\n\n const topoLayer = new TileLayer({\n title: 'Topographic',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'topo',\n source: new XYZ({\n url: 'https://{a-c}.tile.opentopomap.org/{z}/{x}/{y}.png',\n attributions: 'Map data: © OpenTopoMap',\n maxZoom: 17,\n crossOrigin: 'anonymous',\n }),\n });\n topoLayer.set('basemapKey', 'topo');\n\n const cartoLightLayer = new TileLayer({\n title: 'Carto Light',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'carto-light',\n source: new XYZ({\n url: 'https://{a-c}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png',\n attributions: '© CARTO',\n maxZoom: 19,\n crossOrigin: 'anonymous',\n }),\n });\n cartoLightLayer.set('basemapKey', 'carto-light');\n\n const cartoDarkLayer = new TileLayer({\n title: 'Carto Dark',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'carto-dark',\n source: new XYZ({\n url: 'https://{a-c}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}.png',\n attributions: '© CARTO',\n maxZoom: 19,\n crossOrigin: 'anonymous',\n }),\n });\n cartoDarkLayer.set('basemapKey', 'carto-dark');\n\n const osmCycleLayer = new TileLayer({\n title: 'OSM Cycle map',\n type: 'base',\n zIndex: -100,\n visible: false, //defaultBasemap === 'osm',\n source: new OSM({\n \t\t\t\t\t\"url\" : \"https://tile.thunderforest.com/cycle/{z}/{x}/{y}.png?apikey=ae1339c46dd3446b9c491e7336d38760\"\n\t\t\t\t\t\t}),\n });\n\n osmCycleLayer.set('basemapKey', 'cycle');\n\n const satelliteLayer = new TileLayer({\n title: 'Satellite',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'satellite',\n source: new XYZ({\n url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n attributions: 'Tiles © Esri',\n maxZoom: 19,\n crossOrigin: 'anonymous',\n }),\n });\n satelliteLayer.set('basemapKey', 'satellite');\n const googleLayer = new TileLayer({\n title: 'Google Sat',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'googlesat',\n source: new XYZ({\n// url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}',\n url: 'http://mt0.google.com/vt/lyrs=y&hl=en&x={x}&y={y}&z={z}&s=Ga',\n attributions: 'Tiles © Google',\n maxZoom: 19,\n crossOrigin: 'anonymous',\n }),\n });\n googleLayer.set('basemapKey', 'googlesat');\n\n const osmLayer = new TileLayer({\n title: 'OpenStreetMap',\n type: 'base',\n zIndex: -100,\n visible: defaultBasemap === 'osm',\n source: new OSM(),\n });\n osmLayer.set('basemapKey', 'osm');\n\n // Remember the base-map layers so setBaseMap() can toggle visibility later\n this._baseMapLayers = [\n cartoLightLayer, cartoDarkLayer, osmCycleLayer,\n satelliteLayer, googleLayer, osmLayer, topoLayer,\n ];\n\n\n // Return LayerGroup. Hidden from the main LayerSwitcher — base maps are\n // managed by the dedicated base-map picker (see _createBaseMapPicker)\n // accessed via the layers-stack icon above the My Location button.\n const baseGroup = new LayerGroup({\n title: 'Base Maps',\n layers: [\n cartoLightLayer,\n cartoDarkLayer,\n satelliteLayer,\n osmCycleLayer,\n googleLayer,\n osmLayer,\n topoLayer,\n ],\n });\n baseGroup.set('displayInLayerSwitcher', false);\n return baseGroup;\n }\n\n /**\n * Switch the active base map by key.\n * Sets exactly one base layer visible; hides all others.\n *\n * @param {string} key Basemap key: 'none' | 'topo' | 'osm' | 'satellite' | 'googlesat' | 'carto-light' | 'carto-dark' | 'cycle'\n * @returns {boolean} true if the key matched a known base layer (or 'none')\n */\n setBaseMap(key) {\n if (!this._baseMapLayers) return false;\n // 'none' switches the base map off entirely — hide every base layer so the\n // map renders on a blank background (useful over imagery overlays / when a\n // full-coverage overlay should stand alone).\n if (key === 'none') {\n for (const layer of this._baseMapLayers) layer.setVisible(false);\n console.log('[MapView] Base map switched off (none)');\n this.map.dispatchEvent({ type: 'basemapchange', key: 'none' });\n return true;\n }\n let matched = false;\n for (const layer of this._baseMapLayers) {\n const on = layer.get('basemapKey') === key;\n layer.setVisible(on);\n if (on) matched = true;\n }\n if (matched) {\n console.log('[MapView] Base map switched to:', key);\n // Notify external UIs (Settings dropdown, base-map picker, …) so they\n // can keep their visible state in sync.\n this.map.dispatchEvent({ type: 'basemapchange', key });\n }\n return matched;\n }\n\n /**\n * Build the floating \"Base Map\" picker — a small icon button stacked\n * directly above the My Location control, plus a slide-out card with\n * thumbnail chips for every selectable base map.\n *\n * Hidden in tandem with the main LayerSwitcher: clicking outside the\n * picker (or making a selection) closes it.\n *\n * Two-way sync with the existing Settings dropdown is via the\n * `basemapchange` event fired from setBaseMap().\n */\n _createBaseMapPicker() {\n // Configuration — must match the basemapKey set in createBaseLayers.\n // The colour gradients hint at each base map's character so the chip is\n // recognisable without rendering an actual tile preview.\n const OPTIONS = [\n { key: 'topo', label: 'Topographic', grad: 'linear-gradient(135deg,#e8d5b7,#a67c52)' },\n { key: 'osm', label: 'OpenStreetMap',grad: 'linear-gradient(135deg,#d4e6f1,#85c1e9)' },\n { key: 'satellite', label: 'Satellite', grad: 'linear-gradient(135deg,#1b4332,#40916c)' },\n { key: 'googlesat', label: 'Google Sat', grad: 'linear-gradient(135deg,#2a5d3d,#4a8c5a)' },\n { key: 'carto-light', label: 'Carto Light', grad: 'linear-gradient(135deg,#f5f5f5,#d4d4d4)' },\n { key: 'carto-dark', label: 'Carto Dark', grad: 'linear-gradient(135deg,#1a1a2e,#0f3460)' },\n // \"None\" turns the base map off — checkerboard hints at a blank/transparent background.\n { key: 'none', label: 'None', grad: 'repeating-conic-gradient(#e5e7eb 0 25%, #fff 0 50%) 50% / 12px 12px' },\n ];\n\n const target = this.map.getTargetElement();\n if (!target) return;\n\n // ---------- Toggle button ----------\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'ls-basemap-toggle';\n btn.title = 'Switch base map';\n btn.setAttribute('aria-label', 'Switch base map');\n btn.innerHTML =\n '' +\n '' +\n '' +\n '' +\n '';\n target.appendChild(btn);\n\n // ---------- Picker panel ----------\n const panel = document.createElement('div');\n panel.className = 'ls-basemap-panel';\n panel.innerHTML =\n '
    Base Map
    ' +\n '
    ' +\n OPTIONS.map((opt) => `\n \n `).join('') +\n '
    ';\n target.appendChild(panel);\n\n this._basemapPanel = panel;\n this._basemapToggle = btn;\n\n /** Mark the radio matching the currently-visible base layer. */\n const syncSelection = (key) => {\n const k = key || this._baseMapLayers?.find((l) => l.getVisible())?.get('basemapKey');\n panel.querySelectorAll('input[name=\"lupmis-basemap\"]').forEach((r) => {\n r.checked = (r.value === k);\n });\n };\n syncSelection();\n\n // ---------- Events ----------\n\n // Toggle button → open / close the panel\n btn.addEventListener('click', (e) => {\n e.stopPropagation();\n const open = !panel.classList.contains('open');\n panel.classList.toggle('open', open);\n btn.classList.toggle('active', open);\n if (open) syncSelection();\n });\n\n // Click outside → close\n document.addEventListener('click', (e) => {\n if (!panel.classList.contains('open')) return;\n if (panel.contains(e.target) || btn.contains(e.target)) return;\n panel.classList.remove('open');\n btn.classList.remove('active');\n });\n\n // Selection → apply, persist, close\n panel.addEventListener('change', (e) => {\n const radio = e.target.closest('input[type=radio][name=\"lupmis-basemap\"]');\n if (!radio) return;\n const key = radio.value;\n this.setBaseMap(key);\n try { localStorage.setItem('default-basemap', key); } catch {}\n panel.classList.remove('open');\n btn.classList.remove('active');\n });\n\n // Keep the radio state synced when other UIs (Settings dropdown) change it\n this.map.on('basemapchange', (evt) => syncSelection(evt.key));\n }\n\n // ============================================================================\n // GPS: current-position + trail rendering, and the expandable Location control\n //\n // NOTE: MapView deliberately knows nothing about the GeoTracker engine,\n // SQLocal, or sync. It only (a) renders what it's told and (b) emits UI\n // intents via callbacks. main.js wires those intents to the GeoTracker so the\n // map stays reusable/decoupled.\n // ============================================================================\n\n /** Create the vector layers used to draw the live position and the trail. */\n _initGpsRendering() {\n this._gpsPositionSource = new VectorSource();\n this._gpsTrailSource = new VectorSource();\n this._gpsTrailCoords = []; // [ [x,y], ... ] in map projection\n\n // Trail line (drawn under the position marker)\n this._gpsTrailLayer = new VectorLayer({\n source: this._gpsTrailSource,\n zIndex: 940,\n style: new Style({\n stroke: new Stroke({ color: '#ff6d00', width: 4, lineCap: 'round', lineJoin: 'round' }),\n }),\n properties: { title: 'GPS Trail', displayInLayerSwitcher: false },\n });\n\n // Current position: accuracy halo + solid dot\n this._gpsPositionLayer = new VectorLayer({\n source: this._gpsPositionSource,\n zIndex: 950,\n style: (feature) => {\n if (feature.get('_kind') === 'accuracy') {\n return new Style({\n fill: new Fill({ color: 'rgba(0,94,184,0.12)' }),\n stroke: new Stroke({ color: 'rgba(0,94,184,0.35)', width: 1 }),\n });\n }\n return new Style({\n image: new Circle({\n radius: 7,\n fill: new Fill({ color: '#005eb8' }),\n stroke: new Stroke({ color: '#ffffff', width: 2.5 }),\n }),\n });\n },\n properties: { title: 'GPS Position', displayInLayerSwitcher: false },\n });\n\n this.map.addLayer(this._gpsTrailLayer);\n this.map.addLayer(this._gpsPositionLayer);\n\n this._gpsCallbacks = { locate: [], record: [] };\n this._gpsRecording = false;\n }\n\n /** Register a callback fired when the user taps \"Locate Me\". */\n onLocateMe(cb) { this._gpsCallbacks.locate.push(cb); }\n /** Register a callback fired when the user toggles trail recording. Receives the desired state (true=start). */\n onToggleRecording(cb) { this._gpsCallbacks.record.push(cb); }\n\n /**\n * Draw / move the current-position marker and accuracy halo.\n * @param {number} lon\n * @param {number} lat\n * @param {number|null} [accuracy] horizontal accuracy in metres\n */\n showCurrentPosition(lon, lat, accuracy = null) {\n if (lon == null || lat == null) return;\n const center = fromLonLat([lon, lat]);\n this._gpsPositionSource.clear();\n\n if (accuracy && accuracy > 0) {\n // Approximate the accuracy circle in projected units. Good enough for a\n // visual halo at typical zoom levels.\n const resAtLat = accuracy / Math.cos((lat * Math.PI) / 180);\n const halo = new Feature({ geometry: new PolygonGeom([this._circleRing(center, resAtLat)]) });\n halo.set('_kind', 'accuracy');\n this._gpsPositionSource.addFeature(halo);\n }\n const dot = new Feature({ geometry: new Point(center) });\n dot.set('_kind', 'dot');\n this._gpsPositionSource.addFeature(dot);\n }\n\n /** @private build a ring of coordinates approximating a circle (metres → projected). */\n _circleRing(center, radiusMeters, segments = 48) {\n // Convert metres to projected units (Web Mercator) roughly via the\n // resolution at the centre latitude.\n const ring = [];\n const metersPerUnit = 1; // EPSG:3857 units are metres (approx near equator/locally)\n const r = radiusMeters / metersPerUnit;\n for (let i = 0; i <= segments; i++) {\n const a = (i / segments) * 2 * Math.PI;\n ring.push([center[0] + r * Math.cos(a), center[1] + r * Math.sin(a)]);\n }\n return ring;\n }\n\n /** Smoothly center the view on a coordinate. */\n centerOn(lon, lat, zoom = 16) {\n const view = this.map.getView();\n view.animate({ center: fromLonLat([lon, lat]), zoom, duration: 500 });\n }\n\n /** Reset the trail line (call when a new recording starts). */\n startTrailRender() {\n this._gpsTrailCoords = [];\n this._gpsTrailSource.clear();\n }\n\n /** Append a coordinate to the growing trail line. */\n appendTrailPoint(lon, lat) {\n if (lon == null || lat == null) return;\n this._gpsTrailCoords.push(fromLonLat([lon, lat]));\n this._gpsTrailSource.clear();\n if (this._gpsTrailCoords.length >= 2) {\n this._gpsTrailSource.addFeature(new Feature({ geometry: new LineString(this._gpsTrailCoords) }));\n }\n }\n\n /** Remove the rendered trail (does not affect stored data). */\n clearTrailRender() {\n this._gpsTrailCoords = [];\n this._gpsTrailSource.clear();\n }\n\n /** Reflect recording state on the control button. */\n setRecordingState(active) {\n this._gpsRecording = !!active;\n if (this._recordBtn) {\n this._recordBtn.classList.toggle('recording', this._gpsRecording);\n this._recordBtn.title = this._gpsRecording ? 'Stop trail recording' : 'Record GPS trail';\n this._recordBtn.innerHTML = this._gpsRecording\n ? ''\n : '';\n }\n if (this._locateToggle) this._locateToggle.classList.toggle('recording', this._gpsRecording);\n }\n\n /**\n * Build the expandable \"My Location\" control: a main button that reveals two\n * sub-buttons (Locate Me, Record Trail). Anchored at the same spot the old\n * ol-ext GeolocationButton occupied (bottom-right), so the base-map picker\n * still lines up above it.\n */\n _createLocationControl() {\n const target = this.map.getTargetElement();\n if (!target) return;\n\n // Main toggle\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.className = 'ls-locate-toggle';\n toggle.title = 'My Location';\n toggle.setAttribute('aria-label', 'My Location');\n toggle.innerHTML = '';\n target.appendChild(toggle);\n\n // Sub-button cluster (hidden until the main button is tapped)\n const actions = document.createElement('div');\n actions.className = 'ls-locate-actions';\n actions.innerHTML =\n '' +\n '';\n target.appendChild(actions);\n\n this._locateToggle = toggle;\n this._locateActions = actions;\n this._locateMeBtn = actions.querySelector('.ls-locate-me');\n this._recordBtn = actions.querySelector('.ls-locate-record');\n\n const close = () => { actions.classList.remove('open'); toggle.classList.remove('active'); };\n const open = () => { actions.classList.add('open'); toggle.classList.add('active'); };\n\n toggle.addEventListener('click', (e) => {\n e.stopPropagation();\n actions.classList.contains('open') ? close() : open();\n });\n\n // Tap outside closes the cluster (but never while recording, so the stop\n // button stays reachable).\n document.addEventListener('click', (e) => {\n if (!actions.classList.contains('open')) return;\n if (actions.contains(e.target) || toggle.contains(e.target)) return;\n if (this._gpsRecording) return;\n close();\n });\n\n this._locateMeBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n for (const cb of this._gpsCallbacks.locate) { try { cb(); } catch (err) { console.error(err); } }\n if (!this._gpsRecording) close();\n });\n\n this._recordBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n const next = !this._gpsRecording;\n for (const cb of this._gpsCallbacks.record) { try { cb(next); } catch (err) { console.error(err); } }\n });\n }\n\n /**\n * Get style for a feature (handles selection state)\n */\n getFeatureStyle(feature) {\n const category = feature.get('category') || 'default';\n const emoji = this.getEmoji(category);\n\n if (feature === this.selectedFeature) {\n // Return selected style with the correct emoji and highlight\n return [\n // Background highlight circle\n new Style({\n image: new Circle({\n radius: 22,\n fill: new Fill({ color: 'rgba(220, 38, 38, 0.25)' }),\n stroke: new Stroke({ color: '#dc2626', width: 3 }),\n }),\n }),\n // Emoji on top, larger\n new Style({\n text: new Text({\n text: emoji,\n font: '40px sans-serif',\n textBaseline: 'bottom',\n textAlign: 'center',\n offsetY: -5,\n }),\n }),\n ];\n }\n\n // Check for custom style\n const customStyle = feature.get('style');\n if (customStyle) {\n return customStyle;\n }\n\n // Return category-based emoji style\n if (this.categoryStyles[category]) {\n return this.categoryStyles[category];\n }\n\n return this.defaultStyle;\n }\n\n /**\n * Set category-based styles with emojis\n * @param {Object} styles - Map of category to config { emoji, label, fontSize }\n */\n setCategoryStyles(styles) {\n for (const [category, config] of Object.entries(styles)) {\n // Update category mapping if provided\n if (config.emoji) {\n if (!this.categoryEmojis[category]) {\n this.categoryEmojis[category] = { emoji: config.emoji, label: config.label || category };\n } else {\n this.categoryEmojis[category].emoji = config.emoji;\n if (config.label) {\n this.categoryEmojis[category].label = config.label;\n }\n }\n }\n\n // Create/update style\n const emoji = this.getEmoji(category);\n const fontSize = config.fontSize || 28;\n\n this.categoryStyles[category] = this.createEmojiStyle(emoji, fontSize);\n }\n\n // Refresh markers\n this.markerSource.changed();\n }\n\n /**\n * Add a single marker\n */\n addMarker(lon, lat, properties = {}) {\n console.log('[MapView] Adding marker at', lon, lat, 'with properties:', properties);\n\n const feature = new Feature({\n geometry: new Point(fromLonLat([lon, lat])),\n ...properties,\n });\n\n // Store original coordinates for easy access\n feature.set('lon', lon);\n feature.set('lat', lat);\n\n this.markerSource.addFeature(feature);\n console.log('[MapView] Marker added, total features:', this.markerSource.getFeatures().length);\n return feature;\n }\n\n /**\n * Add multiple markers from an array of location objects\n */\n addMarkers(locations) {\n console.log('[MapView] Adding', locations.length, 'markers');\n\n const features = locations.map((loc) => {\n const feature = new Feature({\n geometry: new Point(fromLonLat([loc.longitude, loc.latitude])),\n id: loc.id,\n name: loc.name,\n description: loc.description,\n category: loc.category,\n lon: loc.longitude,\n lat: loc.latitude,\n });\n return feature;\n });\n\n this.markerSource.addFeatures(features);\n console.log('[MapView] Markers added, total features:', this.markerSource.getFeatures().length);\n return features;\n }\n\n /**\n * Clear all markers\n */\n clearMarkers() {\n this.markerSource.clear();\n this.selectedFeature = null;\n }\n\n /**\n * Remove a specific marker by feature or ID\n */\n removeMarker(featureOrId) {\n if (typeof featureOrId === 'object') {\n this.markerSource.removeFeature(featureOrId);\n } else {\n const feature = this.markerSource.getFeatures().find(\n f => f.get('id') === featureOrId\n );\n if (feature) {\n this.markerSource.removeFeature(feature);\n }\n }\n }\n\n /**\n * Get all markers\n */\n getMarkers() {\n return this.markerSource.getFeatures();\n }\n\n /**\n * Find marker by ID\n */\n findMarker(id) {\n return this.markerSource.getFeatures().find(f => f.get('id') === id);\n }\n\n /**\n * Select a marker (highlights it)\n */\n selectMarker(featureOrId) {\n if (typeof featureOrId === 'object') {\n this.selectedFeature = featureOrId;\n } else {\n this.selectedFeature = this.findMarker(featureOrId);\n }\n this.markerSource.changed();\n return this.selectedFeature;\n }\n\n /**\n * Clear selection\n */\n clearSelection() {\n this.selectedFeature = null;\n this.markerSource.changed();\n }\n\n /**\n * Zoom to a specific location\n */\n zoomTo(lon, lat, zoom = 15) {\n this.map.getView().animate({\n center: fromLonLat([lon, lat]),\n zoom: zoom,\n duration: 500,\n });\n }\n\n /**\n * Fit view to show all markers\n */\n fitToMarkers(padding = 50) {\n const extent = this.markerSource.getExtent();\n if (extent && extent[0] !== Infinity) {\n this.map.getView().fit(extent, {\n padding: [padding, padding, padding, padding],\n duration: 500,\n maxZoom: 16,\n });\n }\n }\n\n /**\n * Get current map center in lon/lat\n */\n getCenter() {\n const center = this.map.getView().getCenter();\n return toLonLat(center);\n }\n\n /**\n * Get current zoom level\n */\n getZoom() {\n return this.map.getView().getZoom();\n }\n\n /**\n * Set map center\n */\n setCenter(lon, lat) {\n this.map.getView().setCenter(fromLonLat([lon, lat]));\n }\n\n /**\n * Set zoom level\n */\n setZoom(zoom) {\n this.map.getView().setZoom(zoom);\n }\n\n /**\n * Register click callback\n * Callback receives (lon, lat, feature, event)\n *\n * Single-click is delayed by 300 ms so that a double-click can cancel it.\n * If the click lands on an overlay feature (e.g. district boundary) the\n * single-click is suppressed entirely — only double-click will fire.\n */\n onClick(callback) {\n this.clickCallbacks.push(callback);\n\n // Set up click handler if this is the first callback\n if (this.clickCallbacks.length === 1) {\n this._clickTimer = null;\n\n // Double-click cancels any pending single-click\n this.map.on('dblclick', () => {\n if (this._clickTimer) {\n clearTimeout(this._clickTimer);\n this._clickTimer = null;\n }\n });\n\n this.map.on('click', (evt) => {\n // Cancel any previous pending click\n if (this._clickTimer) {\n clearTimeout(this._clickTimer);\n this._clickTimer = null;\n }\n\n // When NOT in edit / draw mode, immediately clear any feature\n // the Select interaction may have grabbed on this click so the\n // user never sees a selection flash.\n if (!this._editBarActive && this._selectInteraction) {\n this._selectInteraction.getFeatures().clear();\n }\n\n // Check what features sit under the click pixel\n let hasOverlayFeature = false;\n let hasParcelFeature = false;\n let markerFeature = null;\n this.map.forEachFeatureAtPixel(evt.pixel, (feature) => {\n if (feature.get('_layerType') === 'parcel') {\n hasParcelFeature = true;\n }\n if (feature.get('name')) {\n markerFeature = feature;\n }\n hasOverlayFeature = true;\n });\n\n // If an overlay feature was hit, suppress single-click\n // UNLESS it's a parcel or a location marker\n if (hasOverlayFeature && !hasParcelFeature && !markerFeature) {\n return;\n }\n\n // Delay the single-click to allow double-click to cancel it\n const [lon, lat] = toLonLat(evt.coordinate);\n this._clickTimer = setTimeout(() => {\n this._clickTimer = null;\n\n // Find location marker at pixel\n let clickedFeature = null;\n this.map.forEachFeatureAtPixel(evt.pixel, (feature) => {\n if (feature.get('name')) {\n clickedFeature = feature;\n return true;\n }\n });\n\n for (const cb of this.clickCallbacks) {\n cb(lon, lat, clickedFeature, evt);\n }\n }, 300);\n });\n }\n\n // Return unsubscribe function\n return () => {\n const index = this.clickCallbacks.indexOf(callback);\n if (index > -1) {\n this.clickCallbacks.splice(index, 1);\n }\n };\n }\n\n /**\n * Register pointer move callback (for hover effects)\n */\n onPointerMove(callback) {\n this.map.on('pointermove', (evt) => {\n if (evt.dragging) return;\n\n const [lon, lat] = toLonLat(evt.coordinate);\n\n // Only find location markers (features with 'name' property)\n let hoveredFeature = null;\n this.map.forEachFeatureAtPixel(evt.pixel, (feature) => {\n if (feature.get('name')) {\n hoveredFeature = feature;\n return true;\n }\n });\n\n // Change cursor\n this.map.getTargetElement().style.cursor = hoveredFeature ? 'pointer' : '';\n\n callback(lon, lat, hoveredFeature, evt);\n });\n }\n\n /**\n * Enable cursor change on marker hover\n * Note: This is now handled automatically by the popup system\n */\n enableHoverCursor() {\n // Cursor changes are now handled by setupHoverPopup()\n // This method is kept for backwards compatibility\n }\n\n /**\n * Add a GeoJSON layer (visible in LayerSwitcher).\n * By default the layer is added to the root overlay group.\n * Pass a targetGroup (LayerGroup) to nest it inside a specific group.\n *\n * @param {Object} geojson - GeoJSON FeatureCollection or Feature\n * @param {string} title - Layer title for the LayerSwitcher\n * @param {Object} [styleOptions] - Optional style configuration\n * @param {string} [styleOptions.strokeColor='#3b82f6'] - Stroke color\n * @param {number} [styleOptions.strokeWidth=2] - Stroke width\n * @param {string} [styleOptions.fillColor='rgba(59,130,246,0.1)'] - Fill color\n * @param {number[]} [styleOptions.strokeDash] - Dash pattern for the stroke\n * (passed straight to ol/style/Stroke#lineDash, e.g. [4,4]). Useful for\n * contextual overlays (grids, draft outlines) so they read differently\n * from solid property boundaries.\n * @param {LayerGroup} [targetGroup] - Optional group to add the layer to\n * @returns {VectorLayer} The created layer\n */\n addGeoJSONLayer(geojson, title, styleOptions = {}, targetGroup = null) {\n const {\n strokeColor = '#3b82f6',\n strokeWidth = 2,\n strokeDash = null,\n fillColor = 'rgba(59,130,246,0.1)',\n // Optional line \"casing\": a thicker darker stroke drawn UNDERNEATH the\n // main stroke. Used for road-like layers to make light-colored lines\n // visible on any base map. Set lineCasingColor to enable; the casing\n // width defaults to strokeWidth + 2.\n lineCasingColor = null,\n lineCasingWidth = null,\n pointRadius = 5,\n pointFillColor = null, // defaults to strokeColor\n pointStrokeColor = '#ffffff',\n pointStrokeWidth = 1.5,\n } = styleOptions;\n\n const source = new VectorSource({\n features: new GeoJSON().readFeatures(geojson, {\n featureProjection: 'EPSG:3857',\n }),\n });\n\n // Build per-geometry styles. OpenLayers picks `image` for Point /\n // MultiPoint, `stroke`+`fill` for Polygon / MultiPolygon, and `stroke`\n // alone for LineString / MultiLineString. Putting all three on a single\n // Style is enough — but a Style with only stroke+fill leaves Points\n // invisible, which is what was happening on shapefile import.\n const fillStyle = new Fill({ color: fillColor });\n const pointStyle = new Circle({\n radius: pointRadius,\n fill: new Fill({ color: pointFillColor || strokeColor }),\n stroke: new Stroke({ color: pointStrokeColor, width: pointStrokeWidth }),\n });\n\n // If a line casing is requested, return an array of two Styles per\n // feature: the casing renders first (underneath), then the inner stroke.\n // For polygons the casing also outlines them; for points the casing has\n // no effect (Point geometries only render `image`).\n const mainStroke = new Stroke({\n color: strokeColor,\n width: strokeWidth,\n ...(strokeDash ? { lineDash: strokeDash } : {}),\n });\n\n let layerStyle;\n if (lineCasingColor) {\n const casingW = lineCasingWidth != null ? lineCasingWidth : strokeWidth + 2;\n layerStyle = [\n new Style({\n stroke: new Stroke({ color: lineCasingColor, width: casingW }),\n }),\n new Style({\n stroke: mainStroke,\n fill: fillStyle,\n image: pointStyle,\n }),\n ];\n } else {\n layerStyle = new Style({\n stroke: mainStroke,\n fill: fillStyle,\n image: pointStyle,\n });\n }\n\n const layer = new VectorLayer({\n title: title,\n source: source,\n style: layerStyle,\n });\n layer.set('typeTag', styleOptions.typeTag || 'VEC');\n\n // Derive a friendly \"Vector / Polygon\" / \"Vector / Line\" / \"Vector / Point\"\n // subtitle from the first feature's geometry type, unless the caller\n // already supplied one in styleOptions.\n //\n // Layers created EMPTY (parcels, OSM_roads, …, populated later from the\n // API) leave the subtitle absent until the first feature arrives —\n // see the `addfeature` listener below.\n const describeFromGeom = (geomType) => {\n if (!geomType) return null;\n if (geomType.includes('Polygon')) return 'Vector / Polygon';\n if (geomType.includes('LineString')) return 'Vector / Line';\n if (geomType.includes('Point')) return 'Vector / Point';\n return 'Vector';\n };\n\n if (styleOptions.typeDescription) {\n layer.set('typeDescription', styleOptions.typeDescription);\n } else {\n const feats = source.getFeatures();\n const initial = describeFromGeom(feats[0]?.getGeometry?.()?.getType?.());\n if (initial) {\n layer.set('typeDescription', initial);\n } else {\n // Source is empty — wait for the first feature and set then.\n const once = (ev) => {\n const desc = describeFromGeom(ev.feature.getGeometry?.()?.getType?.());\n if (desc) layer.set('typeDescription', desc);\n source.un('addfeature', once);\n };\n source.on('addfeature', once);\n }\n }\n\n const group = targetGroup || this.overlayGroup;\n group.getLayers().push(layer);\n\n console.log('[MapView] GeoJSON layer added:', title, '→', source.getFeatures().length, 'features',\n targetGroup ? `(in group \"${targetGroup.get('title')}\")` : '');\n return layer;\n }\n\n /**\n * Add a LayerGroup to the overlay group.\n * Used to create layer categories from the remote catalogue;\n * individual vector layers will be added into these groups later.\n *\n * @param {number|string} id - Unique layer group id (from the API)\n * @param {string} title - Group title for the LayerSwitcher\n * @param {string} [description=''] - Group description (stored as property)\n * @returns {LayerGroup} The created (empty) layer group\n */\n addLayerGroup(id, title, description = '') {\n const group = new LayerGroup({\n title: title.trim(),\n });\n\n // Store metadata for later use\n group.set('layerId', id);\n group.set('description', description);\n\n this.overlayGroup.getLayers().push(group);\n\n console.log('[MapView] Layer group added:', title.trim(), '(id:', id + ')');\n return group;\n }\n\n /**\n * Add a WMS layer to a layer group.\n *\n * @param {string} groupTitle Title of the target LayerGroup (e.g. 'Biophysical Environment')\n * @param {string} title Display title for the layer\n * @param {string} url WMS server URL\n * @param {string} layers WMS LAYERS parameter\n * @param {Object} [options] Extra options\n * @param {string} [options.serverType='geoserver'] Server type hint ('geoserver'|'mapserver'|'qgis'|null)\n * @param {string} [options.style] WMS STYLES parameter (e.g. 'colours' for DEAfrica DEM)\n * @param {boolean} [options.visible=true] Initial visibility\n * @param {string} [options.attributions] Attribution HTML\n * @param {number} [options.opacity=1] Layer opacity (0–1). Use ~0.5 for background-style layers.\n * @param {number} [options.zIndex] Render z-index. Use negative values (e.g. -10) to force the\n * layer behind all default-z-index layers regardless of group order.\n * @param {string} [options.legendUrl] URL of a legend image to display while the layer is visible.\n * @param {boolean} [options.onlineOnly=false] If true, show a toast when the user toggles the layer on\n * while offline, explaining that the layer requires connectivity.\n * @returns {TileLayer|null} The created layer, or null if group not found\n */\n addWMSLayer(groupTitle, title, url, layers, options = {}) {\n const group = this.getLayerGroupByTitle(groupTitle);\n if (!group) {\n console.warn(`[MapView] Layer group \"${groupTitle}\" not found — cannot add WMS layer \"${title}\"`);\n return null;\n }\n\n const params = { LAYERS: layers, TILED: true, WIDTH: 256, HEIGHT: 256 };\n if (options.style !== undefined) params.STYLES = options.style;\n\n const wmsSource = new TileWMS({\n url,\n params,\n serverType: options.serverType !== undefined ? options.serverType : 'geoserver',\n crossOrigin: 'anonymous',\n hidpi: false,\n attributions: options.attributions,\n });\n\n const wmsLayer = new TileLayer({\n title,\n visible: options.visible !== undefined ? options.visible : true,\n source: wmsSource,\n opacity: options.opacity !== undefined ? options.opacity : 1,\n zIndex: options.zIndex,\n });\n wmsLayer.set('typeTag', 'WMS');\n wmsLayer.set('typeDescription', 'WMS / Raster');\n\n // Show toast on tile load errors (e.g. server rejects request)\n wmsSource.on('tileloaderror', () => {\n showToast(`WMS layer \"${title}\" — tile load error. Check the URL and layer name.`, 'warning', 5000);\n });\n\n group.getLayers().push(wmsLayer);\n\n // Register legend AFTER push so that a failure here doesn't block the LayerSwitcher\n if (options.legendUrl) {\n try {\n this._registerLegend(wmsLayer, title, options.legendUrl);\n } catch (err) {\n console.warn(`[MapView] Could not register legend for \"${title}\":`, err);\n }\n }\n\n // Online-only warning: when the user toggles the layer on while offline,\n // surface a toast explaining why nothing will render.\n if (options.onlineOnly) {\n this._attachOnlineOnlyHandler(wmsLayer, title);\n }\n\n console.log(`[MapView] WMS layer added: \"${title}\" → group \"${groupTitle}\"`);\n return wmsLayer;\n }\n\n /**\n * Add an XYZ tile layer to a layer group.\n *\n * @param {string} groupTitle Title of the target LayerGroup\n * @param {string} title Display title for the layer\n * @param {string} url XYZ tile URL template (with {z}/{x}/{y} placeholders)\n * @param {Object} [options] Extra options\n * @param {boolean} [options.visible=true] Initial visibility\n * @param {string} [options.attributions] Attribution HTML\n * @param {number} [options.maxZoom=19] Maximum zoom level\n * @param {number} [options.opacity=1] Layer opacity (0–1). Use ~0.5 for background-style layers.\n * @param {number} [options.zIndex] Render z-index. Use negative values to force behind other layers.\n * @param {string} [options.legendUrl] URL of a legend image to display while the layer is visible.\n * @param {boolean} [options.onlineOnly=false] If true, show a toast when the user toggles the layer on\n * while offline, explaining that the layer requires connectivity.\n * @returns {TileLayer|null} The created layer, or null if group not found\n */\n addXYZLayer(groupTitle, title, url, options = {}) {\n const group = this.getLayerGroupByTitle(groupTitle);\n if (!group) {\n console.warn(`[MapView] Layer group \"${groupTitle}\" not found — cannot add XYZ layer \"${title}\"`);\n return null;\n }\n\n const xyzSource = new XYZ({\n url,\n crossOrigin: 'anonymous',\n maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,\n attributions: options.attributions,\n });\n\n const xyzLayer = new TileLayer({\n title,\n visible: options.visible !== undefined ? options.visible : true,\n source: xyzSource,\n opacity: options.opacity !== undefined ? options.opacity : 1,\n zIndex: options.zIndex,\n });\n xyzLayer.set('typeTag', 'XYZ');\n xyzLayer.set('typeDescription', 'XYZ / Tile');\n\n // Show toast on tile load errors\n xyzSource.on('tileloaderror', () => {\n showToast(`XYZ layer \"${title}\" — tile load error. Check the URL.`, 'warning', 5000);\n });\n\n group.getLayers().push(xyzLayer);\n\n // Register legend AFTER push so that a failure here doesn't block the LayerSwitcher\n if (options.legendUrl) {\n try {\n this._registerLegend(xyzLayer, title, options.legendUrl);\n } catch (err) {\n console.warn(`[MapView] Could not register legend for \"${title}\":`, err);\n }\n }\n\n // Online-only warning: when the user toggles the layer on while offline,\n // surface a toast explaining why nothing will render.\n if (options.onlineOnly) {\n this._attachOnlineOnlyHandler(xyzLayer, title);\n }\n\n console.log(`[MapView] XYZ layer added: \"${title}\" → group \"${groupTitle}\"`);\n return xyzLayer;\n }\n\n // ============================================================================\n // Add External Layer Dialog\n // ============================================================================\n\n /**\n * Create the add-layer dialog overlay (hidden by default).\n * Appended to the map target element so it stays within the map viewport.\n */\n _createAddLayerDialog() {\n this._addLayerDialog = document.createElement('div');\n this._addLayerDialog.className = 'map-add-layer-dialog';\n this._addLayerDialog.style.cssText = `\n display:none;position:absolute;top:0;left:0;right:0;bottom:0;\n z-index:1100;background:rgba(0,0,0,0.4);\n align-items:center;justify-content:center;\n `;\n\n const card = document.createElement('div');\n card.style.cssText = `\n background:var(--card, #fff);color:var(--card-foreground, #1e1a4b);\n border-radius:12px;box-shadow:0 8px 30px rgba(0,0,0,0.35);\n font-family:var(--font-body, 'Exo', sans-serif);font-size:13px;\n width:340px;max-width:90vw;border:2px solid #10b981;overflow:hidden;\n `;\n\n card.innerHTML = `\n
    \n Add External Layer\n \n
    \n
    \n
    \n \n
    \n \n \n \n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n WMS LAYERS parameter (e.g. workspace:layer)\n
    \n
    \n
    \n \n \n
    \n
    \n \n \n
    \n
    \n `;\n\n this._addLayerDialog.appendChild(card);\n this.map.getTargetElement().appendChild(this._addLayerDialog);\n\n // Type radio change — toggle layer name row visibility\n const nameRow = card.querySelector('.add-layer-name-row');\n const nameHint = card.querySelector('.add-layer-name-hint');\n const urlInput = card.querySelector('.add-layer-url');\n card.querySelectorAll('input[name=\"add-layer-type\"]').forEach((radio) => {\n radio.addEventListener('change', () => {\n const type = radio.value;\n if (type === 'xyz') {\n nameRow.style.display = 'none';\n urlInput.placeholder = 'https://example.com/tiles/{z}/{x}/{y}.png';\n } else {\n nameRow.style.display = '';\n urlInput.placeholder = type === 'wms'\n ? 'https://example.com/wms'\n : 'https://example.com/wfs';\n nameHint.textContent = type === 'wms'\n ? 'WMS LAYERS parameter (e.g. workspace:layer)'\n : 'WFS typename (e.g. workspace:layer)';\n }\n });\n });\n\n // Close / Cancel\n const close = () => this._hideAddLayerDialog();\n card.querySelector('.add-layer-close').addEventListener('click', close);\n card.querySelector('.add-layer-cancel').addEventListener('click', close);\n this._addLayerDialog.addEventListener('click', (e) => {\n if (e.target === this._addLayerDialog) close();\n });\n\n // Confirm\n card.querySelector('.add-layer-confirm').addEventListener('click', () => {\n const type = card.querySelector('input[name=\"add-layer-type\"]:checked').value;\n const url = card.querySelector('.add-layer-url').value.trim();\n const layerName = card.querySelector('.add-layer-name').value.trim();\n const title = card.querySelector('.add-layer-title').value.trim();\n\n if (!url) {\n card.querySelector('.add-layer-url').style.borderColor = '#ef4444';\n return;\n }\n if ((type === 'wms' || type === 'wfs') && !layerName) {\n card.querySelector('.add-layer-name').style.borderColor = '#ef4444';\n return;\n }\n if (!title) {\n card.querySelector('.add-layer-title').style.borderColor = '#ef4444';\n return;\n }\n\n this._addExternalLayer(type, url, layerName, title);\n this._hideAddLayerDialog();\n });\n\n // Enter key to confirm\n card.addEventListener('keydown', (e) => {\n if (e.key === 'Enter') {\n e.preventDefault();\n card.querySelector('.add-layer-confirm').click();\n }\n if (e.key === 'Escape') {\n e.preventDefault();\n close();\n }\n });\n }\n\n /**\n * Show the add-layer dialog.\n */\n showAddLayerDialog() {\n const dlg = this._addLayerDialog;\n // Reset form\n dlg.querySelector('.add-layer-url').value = '';\n dlg.querySelector('.add-layer-name').value = '';\n dlg.querySelector('.add-layer-title').value = '';\n dlg.querySelectorAll('input[name=\"add-layer-type\"]')[0].checked = true;\n dlg.querySelector('.add-layer-name-row').style.display = '';\n dlg.querySelector('.add-layer-url').placeholder = 'https://example.com/wms';\n dlg.querySelector('.add-layer-name-hint').textContent = 'WMS LAYERS parameter (e.g. workspace:layer)';\n\n // Reset border colours\n dlg.querySelectorAll('input[type=\"text\"]').forEach((inp) => {\n inp.style.borderColor = 'var(--border, #1e1a4b1f)';\n });\n\n dlg.style.display = 'flex';\n dlg.querySelector('.add-layer-url').focus();\n }\n\n /**\n * Hide the add-layer dialog.\n */\n _hideAddLayerDialog() {\n this._addLayerDialog.style.display = 'none';\n }\n\n /**\n * Add an external layer to the \"External Source\" group.\n *\n * @param {string} type 'wms' | 'wfs' | 'xyz'\n * @param {string} url Server URL\n * @param {string} layerName WMS LAYERS / WFS typename (ignored for XYZ)\n * @param {string} title Display title in layer switcher\n */\n _addExternalLayer(type, url, layerName, title) {\n const group = this._externalSourceGroup;\n if (!group) {\n showToast('Layer group \"External Source\" not found.', 'error', 4000);\n return;\n }\n\n let layer;\n\n switch (type) {\n case 'wms': {\n const wmsSrc = new TileWMS({\n url,\n params: { LAYERS: layerName, TILED: true, WIDTH: 256, HEIGHT: 256 },\n serverType: 'geoserver',\n crossOrigin: 'anonymous',\n hidpi: false,\n });\n layer = new TileLayer({\n title,\n visible: true,\n source: wmsSrc,\n });\n wmsSrc.on('tileloaderror', () => {\n showToast(`WMS \"${title}\" — tile load error. Check URL and layer name.`, 'warning', 5000);\n });\n break;\n }\n\n case 'wfs': {\n const wfsUrl = `${url}${url.includes('?') ? '&' : '?'}` +\n `service=WFS&version=1.1.0&request=GetFeature` +\n `&typename=${encodeURIComponent(layerName)}` +\n `&outputFormat=application/json&srsname=EPSG:3857`;\n\n const wfsSource = new VectorSource({\n url: wfsUrl,\n format: new GeoJSON(),\n });\n wfsSource.on('featuresloaderror', () => {\n showToast(`WFS \"${title}\" — load error. Check URL and layer name.`, 'warning', 5000);\n });\n\n layer = new VectorLayer({\n title,\n visible: true,\n source: wfsSource,\n style: new Style({\n stroke: new Stroke({ color: '#e11d48', width: 2 }),\n fill: new Fill({ color: 'rgba(225,29,72,0.15)' }),\n }),\n });\n break;\n }\n\n case 'xyz':\n layer = new TileLayer({\n title,\n visible: true,\n source: new XYZ({\n url,\n crossOrigin: 'anonymous',\n }),\n });\n layer.getSource().on('tileloaderror', () => {\n showToast(`XYZ \"${title}\" — tile load error. Check the URL template.`, 'warning', 5000);\n });\n break;\n\n default:\n showToast(`Unknown layer type: ${type}`, 'error', 4000);\n return;\n }\n\n // Tag for the LayerSwitcher chip\n layer.set('typeTag', type.toUpperCase()); // 'WMS' | 'WFS' | 'XYZ'\n layer.set('typeDescription', {\n wms: 'WMS / Raster',\n wfs: 'WFS / Vector',\n xyz: 'XYZ / Tile',\n }[type] || type.toUpperCase());\n\n // User-added external layers ARE removable — they're not part of the\n // app's built-in data model.\n layer.set('removable', true);\n\n group.getLayers().push(layer);\n showToast(`Layer \"${title}\" added to External Source.`, 'success', 3000);\n console.log(`[MapView] External ${type.toUpperCase()} layer added: \"${title}\"`);\n }\n\n // ============================================================================\n // LayerSwitcher decoration (Option A — visual refresh)\n // ============================================================================\n\n /**\n * Decorate a layer's
  • after ol-ext renders it:\n * • inject a type-tag chip next to the layer label\n * • inject the green \"+\" button on the External Source group header\n *\n * Idempotent — safe to call repeatedly; each injected element checks\n * whether it already exists in the row.\n */\n _decorateLayerListItem(layer, li) {\n // 1. Type-tag chip (e.g. WMS / XYZ / VEC) next to the layer name.\n // Inserted INSIDE the label's so it doesn't collide with the\n // label's left padding (where ol-ext draws the checkbox via ::before).\n const tag = layer.get('typeTag'); // 'WMS' | 'WFS' | 'XYZ' | 'VEC' | 'GEO' | 'BASE'\n if (tag) {\n const labelSpan = li.querySelector(':scope > .li-content > label > span');\n if (labelSpan && !labelSpan.querySelector(':scope > .ls-type-tag')) {\n const chip = document.createElement('span');\n chip.className = `ls-type-tag ls-type-tag-${String(tag).toLowerCase()}`;\n chip.textContent = String(tag);\n chip.title = `${tag} layer`;\n labelSpan.appendChild(chip);\n }\n }\n\n // 2. Replace ol-ext's bar-drawn +/- chevron with the GeoView chevron SVG.\n // The SVG uses stroke=\"currentColor\", so CSS `color` (set in\n // layerswitcher.css) tints it. Rotation handles the open/closed state.\n const btnBar = li.querySelector(':scope > .ol-layerswitcher-buttons');\n if (btnBar) {\n const chevronEl = btnBar.querySelector(':scope > .expend-layers, :scope > .collapse-layers');\n if (chevronEl && !chevronEl.querySelector(':scope > svg.ls-chevron-svg')) {\n chevronEl.innerHTML =\n '' +\n '' +\n '';\n }\n }\n\n // 3. Layer-type subtitle (\"Vector / Polygon\", \"WMS / Raster\", …) below\n // the layer name. Only rendered when layer.get('typeDescription') is\n // set. For layers that start empty and gain features later (the API\n // loaders), we listen for `change:typeDescription` and update or\n // insert the subtitle then.\n const content = li.querySelector(':scope > .li-content');\n const ensureSubtitle = () => {\n if (!content) return;\n const text = layer.get('typeDescription');\n let sub = content.querySelector(':scope > .ls-layer-subtitle');\n if (!text) {\n if (sub) sub.remove();\n return;\n }\n if (!sub) {\n sub = document.createElement('div');\n sub.className = 'ls-layer-subtitle';\n const label = content.querySelector(':scope > label');\n if (label && label.nextSibling) {\n content.insertBefore(sub, label.nextSibling);\n } else {\n content.appendChild(sub);\n }\n }\n sub.textContent = text;\n };\n ensureSubtitle();\n if (!layer._lsSubtitleHooked) {\n layer._lsSubtitleHooked = true;\n layer.on('change:typeDescription', () => {\n // The
  • may not exist any more (panel re-rendered between events)\n // — guard with a fresh lookup via the LayerSwitcher next time it draws.\n // For now we just call ensureSubtitle bound to the original li.\n ensureSubtitle();\n });\n }\n\n // 4. Per-layer Remove button — only for layers explicitly marked\n // `removable: true` (external sources, imported files, …). Built-in\n // layers (Parcels, OSM_roads, district boundary, …) are NOT removable\n // so the user can't accidentally delete them.\n if (layer.get('removable') === true && btnBar && !btnBar.querySelector(':scope > .ls-remove-btn')) {\n const removeBtn = document.createElement('button');\n removeBtn.type = 'button';\n removeBtn.className = 'ls-remove-btn';\n removeBtn.title = 'Remove this layer';\n removeBtn.setAttribute('aria-label', 'Remove layer');\n removeBtn.innerHTML =\n '' +\n '' +\n '';\n removeBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this._removeLayer(layer);\n });\n btnBar.appendChild(removeBtn);\n }\n\n // 5b. Import-state chip on layers staged via the external-dataset import\n // flow (LUPMIS2_Import_Upload_Design.docx §3.2). The chip's text and\n // behaviour depend on `_externalImportStatus`:\n // 'mapped' → \"Upload N\" (click → upload)\n // 'uploading' → spinner (disabled)\n // 'submitted' → \"✓ submitted\" (in upload_tmp, awaiting review)\n // 'migrated' → \"✓ live\" (supervisor promoted to lu_parcels)\n // 'failed' → \"N errors — fix?\"\n // 'other'/null→ no chip\n // Clicks dispatch a window-level CustomEvent so main.js can react\n // without MapView knowing anything about staging.\n const importId = layer.get('_externalImportId');\n if (importId != null) {\n const labelSpan = li.querySelector(':scope > .li-content > label > span');\n let chip = labelSpan ? labelSpan.querySelector(':scope > .ls-import-chip') : null;\n const status = layer.get('_externalImportStatus') || 'mapped';\n const featureCount = layer.getSource()?.getFeatures().length ?? 0;\n const errorCount = layer.get('_externalImportErrorCount') ?? 0;\n\n // Decide chip appearance.\n const chipSpec = (() => {\n switch (status) {\n case 'mapped':\n return { text: `Upload ${featureCount}`, cls: 'ls-import-chip-mapped',\n title: 'Upload this dataset to the database', clickable: true };\n case 'uploading':\n return { text: '…', cls: 'ls-import-chip-uploading',\n title: 'Uploading…', clickable: false };\n case 'submitted':\n return { text: '✓ submitted', cls: 'ls-import-chip-submitted',\n title: 'Uploaded — awaiting supervisor review', clickable: false };\n case 'migrated':\n return { text: '✓ live', cls: 'ls-import-chip-migrated',\n title: 'Approved by supervisor and live on the server', clickable: false };\n case 'failed':\n return { text: `${errorCount} errors — fix?`, cls: 'ls-import-chip-failed',\n title: 'Some rows failed; click to review', clickable: true };\n case 'other':\n case null:\n case undefined:\n default:\n return null;\n }\n })();\n\n if (!chipSpec) {\n if (chip) chip.remove();\n } else if (labelSpan) {\n if (!chip) {\n chip = document.createElement('span');\n chip.className = 'ls-import-chip';\n labelSpan.appendChild(chip);\n }\n chip.className = `ls-import-chip ${chipSpec.cls}`;\n chip.textContent = chipSpec.text;\n chip.title = chipSpec.title;\n chip.style.cursor = chipSpec.clickable ? 'pointer' : 'default';\n chip.style.opacity = chipSpec.clickable ? '1' : '0.85';\n\n // Replace any prior listener by cloning the node.\n const fresh = chip.cloneNode(true);\n chip.replaceWith(fresh);\n chip = fresh;\n\n if (chipSpec.clickable) {\n chip.addEventListener('click', (e) => {\n e.preventDefault();\n e.stopPropagation();\n window.dispatchEvent(new CustomEvent('lupmis:import-chip-click', {\n detail: { importId, status, layer },\n }));\n });\n }\n }\n }\n\n // 5. \"+\" button on the External Source group\n const groupTitle = (layer.get('title') || '').toLowerCase();\n if (groupTitle.includes('external')) {\n this._externalSourceGroup = layer;\n // btnBar already resolved above (same .ol-layerswitcher-buttons element)\n if (btnBar && !btnBar.querySelector('.ol-add-layer')) {\n const addBtn = document.createElement('span');\n addBtn.className = 'ol-add-layer';\n addBtn.title = 'Add external layer';\n addBtn.textContent = '+';\n addBtn.style.cssText = `\n display:inline-flex !important;align-items:center;justify-content:center;\n width:22px !important;height:22px !important;border-radius:50%;\n background:#41b6a6 !important;color:#fff !important;\n font-size:15px !important;font-weight:700;\n cursor:pointer;line-height:1 !important;\n margin:0 4px 0 0;vertical-align:middle;\n transition:background 0.2s;box-sizing:border-box;border:none;\n `;\n addBtn.addEventListener('mouseenter', () => { addBtn.style.background = '#329686'; });\n addBtn.addEventListener('mouseleave', () => { addBtn.style.background = '#41b6a6'; });\n addBtn.addEventListener('click', (e) => {\n e.stopPropagation();\n this.showAddLayerDialog();\n });\n btnBar.prepend(addBtn);\n }\n }\n }\n\n /**\n * Remove a layer from its parent group, after confirmation. Only called\n * from the per-layer × button injected by `_decorateLayerListItem` — and\n * that button is only injected for layers marked `removable: true`, so\n * built-in layers (Parcels, OSM_roads, …) can never reach this path.\n *\n * @param {Layer} layer\n */\n _removeLayer(layer) {\n const title = layer.get('title') || 'this layer';\n if (!confirm(`Remove \"${title}\" from the map?\\n\\nThis only affects the current session — built-in layers cannot be removed.`)) {\n return;\n }\n\n // Find the parent group that owns this layer and call .remove() on its\n // collection. Walk recursively from the overlay group.\n const visit = (group) => {\n const layers = group.getLayers();\n if (layers.getArray().includes(layer)) {\n layers.remove(layer);\n return true;\n }\n let removed = false;\n layers.forEach((child) => {\n if (!removed && child.getLayers) {\n removed = visit(child);\n }\n });\n return removed;\n };\n\n const ok = visit(this.overlayGroup);\n if (ok) {\n console.log(`[MapView] Removed layer \"${title}\"`);\n showToast(`Removed \"${title}\" from the map.`, 'info', 3000);\n } else {\n console.warn(`[MapView] Could not find layer \"${title}\" in any group`);\n }\n }\n\n /**\n * Inject (or refresh) the panel chrome — an \"active count\" badge at the top\n * and a footer row with \"Reset overlays\" button at the bottom.\n *\n * The chrome lives in `.panel-container` (the wrapping
    ), not inside\n * the `
      ` — that way the badge and footer are siblings of\n * the layer list rather than malformed children of a `
        `.\n *\n * Called from drawlist via queueMicrotask, so it runs once per redraw cycle\n * regardless of how many layers are in the panel.\n */\n _refreshLayerSwitcherChrome(layerSwitcher) {\n const panelContainer = layerSwitcher.element?.querySelector('.panel-container');\n const ul = layerSwitcher.element?.querySelector('ul.panel');\n if (!panelContainer || !ul) return;\n\n // --- Active-count badge (top of panel-container, before the
          ) ---\n let badge = panelContainer.querySelector(':scope > .ls-active-badge');\n if (!badge) {\n badge = document.createElement('div');\n badge.className = 'ls-active-badge';\n badge.innerHTML = `\n Layers\n 0 active\n `;\n panelContainer.insertBefore(badge, ul);\n }\n\n // --- Footer row (bottom of panel-container, after the
            ) ---\n let footer = panelContainer.querySelector(':scope > .ls-footer-row');\n if (!footer) {\n footer = document.createElement('div');\n footer.className = 'ls-footer-row';\n footer.innerHTML = `\n — layers total\n \n `;\n panelContainer.appendChild(footer);\n\n footer.querySelector('.ls-footer-btn').addEventListener('click', (e) => {\n e.stopPropagation();\n this._resetAllOverlays();\n });\n }\n\n // --- Update counters ---\n const counts = this._countLayers();\n badge.querySelector('.ls-active-badge-count').textContent =\n `${counts.activeOverlays} active`;\n footer.querySelector('.ls-footer-note').textContent =\n `${counts.totalOverlays} overlay${counts.totalOverlays === 1 ? '' : 's'}`;\n }\n\n /**\n * Walk the overlay group recursively, returning the number of *leaf* layers\n * (i.e. not groups) and how many of them are currently visible.\n * Excludes base maps and internal layers (Markers, Drawings, vertex overlay).\n */\n _countLayers() {\n let totalOverlays = 0;\n let activeOverlays = 0;\n\n const HIDDEN_INTERNAL = new Set(['__vertex_highlight__']);\n\n const visit = (group) => {\n group.getLayers().forEach((layer) => {\n if (layer.get('displayInLayerSwitcher') === false) return;\n if (HIDDEN_INTERNAL.has(layer.get('title'))) return;\n\n if (layer.getLayers) {\n visit(layer);\n } else {\n totalOverlays++;\n if (layer.getVisible()) activeOverlays++;\n }\n });\n };\n if (this.overlayGroup) visit(this.overlayGroup);\n return { totalOverlays, activeOverlays };\n }\n\n /**\n * Hide every overlay layer (base maps stay on). Wired to the footer\n * \"Reset overlays\" button.\n */\n _resetAllOverlays() {\n const HIDDEN_INTERNAL = new Set(['__vertex_highlight__']);\n const visit = (group) => {\n group.getLayers().forEach((layer) => {\n if (layer.get('displayInLayerSwitcher') === false) return;\n if (HIDDEN_INTERNAL.has(layer.get('title'))) return;\n\n if (layer.getLayers) {\n visit(layer);\n } else {\n layer.setVisible(false);\n }\n });\n };\n if (this.overlayGroup) visit(this.overlayGroup);\n console.log('[MapView] Reset overlays — all hidden');\n }\n\n /**\n * Hook `change:visible` on every overlay leaf so the active-count badge\n * stays in sync even when ol-ext doesn't re-fire drawlist (e.g. ticking\n * a checkbox just toggles visibility without rebuilding the list).\n * Also re-hooks when a new layer is added.\n */\n _wireLayerSwitcherVisibilityHooks(layerSwitcher) {\n const refresh = () => this._refreshLayerSwitcherChrome(layerSwitcher);\n\n const hookLayer = (layer) => {\n if (layer._lsVisHooked) return;\n layer._lsVisHooked = true;\n layer.on('change:visible', refresh);\n };\n\n const visit = (group) => {\n group.getLayers().forEach((layer) => {\n if (layer.getLayers) {\n visit(layer);\n // Listen for layers added later to this group\n if (!group._lsAddHooked) {\n group._lsAddHooked = true;\n group.getLayers().on('add', (ev) => {\n const added = ev.element;\n if (added.getLayers) visit(added); else hookLayer(added);\n refresh();\n });\n }\n } else {\n hookLayer(layer);\n }\n });\n };\n\n if (this.overlayGroup) visit(this.overlayGroup);\n }\n\n // ============================================================================\n // Online-Only Layer Helper\n // ============================================================================\n\n /**\n * Attach a `change:visible` listener that shows an info toast when the user\n * toggles a layer ON while the device is offline. Used for layers that fetch\n * tiles or features from a remote service and therefore have no useful\n * cached state.\n *\n * The check uses navigator.onLine, which is the same signal as the rest of\n * the app's online detection.\n *\n * @param {Layer} layer\n * @param {string} title Display title used in the toast message\n */\n _attachOnlineOnlyHandler(layer, title) {\n layer.set('onlineOnly', true);\n layer.on('change:visible', () => {\n if (layer.getVisible() && !navigator.onLine) {\n showToast(\n `\"${title}\" requires an internet connection. Connect to view this layer.`,\n 'info',\n 5000,\n );\n }\n });\n }\n\n // ============================================================================\n // Legend Panel — shows legend images for visible layers that have one\n // ============================================================================\n\n /**\n * Create the legend panel, positioned bottom-right inside the map target.\n * Hidden when no visible layers have a registered legend.\n */\n _createLegendPanel() {\n this._legendPanel = document.createElement('div');\n this._legendPanel.className = 'map-legend-panel';\n this._legendPanel.style.cssText = `\n position:absolute;right:10px;bottom:40px;z-index:900;\n display:none;flex-direction:column;gap:6px;\n background:var(--card, #fff);color:var(--card-foreground, #1e1a4b);\n border:1px solid var(--border, #1e1a4b1f);border-radius:8px;\n box-shadow:0 4px 12px rgba(0,0,0,0.15);\n font-family:var(--font-body, 'Exo', sans-serif);font-size:11px;\n max-width:220px;max-height:60%;overflow-y:auto;\n padding:8px 10px;\n `;\n this.map.getTargetElement().appendChild(this._legendPanel);\n\n // Map of layer → { wrapper, title, imgUrl }\n this._legendEntries = new Map();\n }\n\n /**\n * Register a layer's legend image and wire up visibility tracking.\n * Called from addWMSLayer / addXYZLayer when a legendUrl is supplied.\n *\n * @param {Layer} layer The OpenLayers layer\n * @param {string} title Display title for the legend header\n * @param {string} legendUrl URL of the legend image\n */\n _registerLegend(layer, title, legendUrl) {\n if (!this._legendPanel) return;\n\n // Build the legend entry — a div with header + image\n const wrapper = document.createElement('div');\n wrapper.className = 'map-legend-entry';\n wrapper.style.cssText = 'border-bottom:1px solid var(--border, #1e1a4b1f);padding-bottom:6px;';\n wrapper.innerHTML = `\n
            \n ${this._escapeHtml(title)}\n
            \n \"${this._escapeHtml(title)}\n `;\n\n this._legendEntries.set(layer, wrapper);\n\n // Listen for visibility changes. Wrap in try/catch so a DOM error here\n // cannot break the LayerSwitcher's click handler (which fires change:visible\n // synchronously and relies on a subsequent setTimeout to update the checkbox).\n const update = () => {\n try { this._updateLegendPanel(); }\n catch (err) { console.warn('[MapView] legend panel update failed:', err); }\n };\n layer.on('change:visible', update);\n\n // Trigger initial state\n update();\n }\n\n /**\n * Refresh the legend panel contents: include entries for each visible\n * registered layer, and show/hide the panel based on whether any are visible.\n */\n _updateLegendPanel() {\n if (!this._legendPanel) return;\n\n // Rebuild children from scratch in a stable order (Map iteration order = insertion order)\n const children = [];\n for (const [layer, wrapper] of this._legendEntries) {\n if (layer.getVisible()) children.push(wrapper);\n }\n\n // Remove trailing bottom-border on the last entry for a clean look\n this._legendEntries.forEach((w) => {\n w.style.borderBottom = '1px solid var(--border, #1e1a4b1f)';\n w.style.paddingBottom = '6px';\n });\n if (children.length > 0) {\n children[children.length - 1].style.borderBottom = 'none';\n children[children.length - 1].style.paddingBottom = '0';\n }\n\n // Swap the DOM children\n this._legendPanel.replaceChildren(...children);\n this._legendPanel.style.display = children.length > 0 ? 'flex' : 'none';\n }\n\n /**\n * Escape HTML special characters for safe text insertion.\n */\n _escapeHtml(str) {\n return String(str)\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''');\n }\n\n /**\n * Find a LayerGroup inside the overlay group by its layerId.\n *\n * @param {number|string} id - The layerId to search for\n * @returns {LayerGroup|null} The matching group, or null\n */\n getLayerGroup(id) {\n let found = null;\n this.overlayGroup.getLayers().forEach((layer) => {\n if (layer.get('layerId') === id) {\n found = layer;\n }\n });\n return found;\n }\n\n /**\n * Find a LayerGroup inside the overlay group by its title.\n *\n * @param {string} title - The group title to search for\n * @returns {LayerGroup|null} The matching group, or null\n */\n getLayerGroupByTitle(title) {\n let found = null;\n this.overlayGroup.getLayers().forEach((layer) => {\n if (layer.get('title') === title) {\n found = layer;\n }\n });\n return found;\n }\n\n /**\n * Get the overlay LayerGroup for advanced usage\n */\n getOverlayGroup() {\n return this.overlayGroup;\n }\n\n /**\n * Get the OpenLayers map instance for advanced usage\n */\n getMap() {\n return this.map;\n }\n\n // ============================================================================\n // Extent Helpers (used by offline-tile downloader)\n // ============================================================================\n\n /**\n * Get the current map view's visible extent in EPSG:3857 (Web Mercator).\n * @returns {Array} [minX, minY, maxX, maxY]\n */\n getCurrentViewExtent() {\n const view = this.map.getView();\n const size = this.map.getSize();\n if (!size) return null;\n return view.calculateExtent(size);\n }\n\n /**\n * Get the bounding extent of the District Boundary layer (if present).\n * Searches the overlay group for a vector layer titled \"District Boundary\"\n * and returns the extent of its source.\n *\n * @returns {{ extent: Array, title: string } | null}\n */\n getDistrictBoundaryExtent() {\n let found = null;\n const visit = (group) => {\n group.getLayers().forEach((layer) => {\n if (layer.getLayers) {\n visit(layer); // sub-group\n } else if (layer.get('title') === 'District Boundary') {\n const src = layer.getSource && layer.getSource();\n if (src && typeof src.getExtent === 'function') {\n const ex = src.getExtent();\n if (ex && Number.isFinite(ex[0])) {\n found = { extent: ex, title: layer.get('title') };\n }\n }\n }\n });\n };\n visit(this.overlayGroup);\n return found;\n }\n\n /**\n * Get the marker source for advanced usage\n */\n getMarkerSource() {\n return this.markerSource;\n }\n\n /**\n * Get the markers layer for advanced usage\n */\n getMarkersLayer() {\n return this.markersLayer;\n }\n\n /**\n * Update map size (call after container resize)\n */\n updateSize() {\n this.map.updateSize();\n }\n\n /**\n * Register a callback for when a search result is selected\n * Callback receives: { coordinate, lonLat: [lon, lat], name, searchResult }\n * Navigation to the location happens automatically\n */\n onSearchSelect(callback) {\n this.searchSelectCallbacks.push(callback);\n }\n\n /**\n * Navigate/fly to a specific location\n * @param {number} lon - Longitude\n * @param {number} lat - Latitude\n * @param {number} zoom - Zoom level (default: 14)\n * @param {number} duration - Animation duration in ms (default: 500)\n */\n navigateTo(lon, lat, zoom = 14, duration = 500) {\n const coordinate = fromLonLat([lon, lat]);\n this.map.getView().animate({\n center: coordinate,\n zoom: zoom,\n duration: duration,\n });\n }\n}\n\n// Export OpenLayers utilities for convenience\nexport { fromLonLat, toLonLat };\n\nexport default MapView;\n","/**\n * MapTools - Drawing and Measurement Tools\n * \n * Provides:\n * - Circle measurement tool with radius/area tooltip\n * - Control bar with drawing tools\n * - Line and polygon measurement\n * \n * Refactored from olmapstuffgis.js for LUPMIS PWA\n */\n\nimport { Draw } from 'ol/interaction';\nimport { Circle as CircleStyle, Fill, Stroke, Style } from 'ol/style';\nimport { Vector as VectorLayer } from 'ol/layer';\nimport { Vector as VectorSource } from 'ol/source';\nimport Overlay from 'ol/Overlay';\nimport { LineString, Circle, Polygon } from 'ol/geom';\nimport { getLength, getArea } from 'ol/sphere';\nimport Feature from 'ol/Feature';\nimport { unByKey } from 'ol/Observable';\nimport { formatLength, formatArea, formatCircleExtent } from '../units.js';\n\n// ol-ext imports\nimport EditBar from 'ol-ext/control/EditBar';\nimport Toggle from 'ol-ext/control/Toggle';\nimport Button from 'ol-ext/control/Button';\n\nexport class MapTools {\n constructor(map, options = {}) {\n this.map = map;\n this.options = options;\n \n // Create measurement layer\n this.measureSource = new VectorSource();\n this.measureLayer = new VectorLayer({\n source: this.measureSource,\n style: this.getMeasureStyle(),\n title: 'Measurements',\n zIndex: 100,\n });\n\n // Create drawing layer (utility layer for temporary draw interactions;\n // hidden from LayerSwitcher since the EditBar has its own \"Drawings\" group)\n this.drawSource = new VectorSource();\n this.drawLayer = new VectorLayer({\n source: this.drawSource,\n style: this.getDrawStyle(),\n title: 'Draw sketches',\n displayInLayerSwitcher: false,\n zIndex: 99,\n });\n\n // Insert both layers just before the Overlays group so the LayerSwitcher\n // order becomes: Overlays > Measurements > Markers > Base Maps. Locate the\n // Overlays group by title rather than assuming it is the last layer —\n // other layers (e.g. the GPS trail/position layers) may sit on top of it.\n const layers = this.map.getLayers();\n let overlayIdx = layers.getArray().findIndex((l) => l.get('title') === 'Overlays');\n if (overlayIdx < 0) overlayIdx = layers.getLength();\n layers.insertAt(overlayIdx, this.drawLayer);\n layers.insertAt(overlayIdx, this.measureLayer);\n \n // Active interaction\n this.activeInteraction = null;\n this.measureTooltip = null;\n this.measureTooltipElement = null;\n \n // Callbacks\n this.onMeasureCompleteCallbacks = [];\n this.onDrawCompleteCallbacks = [];\n }\n \n /**\n * Get style for measurement features\n */\n getMeasureStyle() {\n return new Style({\n fill: new Fill({\n color: 'rgba(255, 233, 106, 0.2)'\n }),\n stroke: new Stroke({\n color: '#8B008B',\n lineDash: [10, 10],\n width: 2\n }),\n image: new CircleStyle({\n radius: 5,\n stroke: new Stroke({\n color: '#8B008B'\n }),\n fill: new Fill({\n color: 'rgba(255, 233, 106, 0.5)'\n })\n })\n });\n }\n \n /**\n * Get style for drawing features\n */\n getDrawStyle() {\n return new Style({\n fill: new Fill({\n color: 'rgba(255, 233, 106, 0.3)'\n }),\n stroke: new Stroke({\n color: '#8B008B',\n width: 2\n }),\n image: new CircleStyle({\n radius: 6,\n stroke: new Stroke({\n color: '#8B008B',\n width: 2\n }),\n fill: new Fill({\n color: '#FFE96A'\n })\n })\n });\n }\n \n /**\n * Create measurement tooltip overlay\n */\n createMeasureTooltip() {\n if (this.measureTooltipElement) {\n this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);\n }\n this.measureTooltipElement = document.createElement('div');\n this.measureTooltipElement.className = 'measure-tooltip';\n this.measureTooltip = new Overlay({\n element: this.measureTooltipElement,\n offset: [15, 0],\n positioning: 'center-left',\n stopEvent: false,\n });\n this.map.addOverlay(this.measureTooltip);\n }\n \n /**\n * Remove any active interaction\n */\n deactivate() {\n if (this.activeInteraction) {\n this.map.removeInteraction(this.activeInteraction);\n this.activeInteraction = null;\n }\n if (this.measureTooltip) {\n this.map.removeOverlay(this.measureTooltip);\n this.measureTooltip = null;\n }\n if (this.measureTooltipElement && this.measureTooltipElement.parentNode) {\n this.measureTooltipElement.parentNode.removeChild(this.measureTooltipElement);\n this.measureTooltipElement = null;\n }\n }\n \n /**\n * Start circle measurement tool\n * Draws a circle and shows radius + area in tooltip\n */\n startCircleMeasure() {\n this.deactivate();\n this.createMeasureTooltip();\n \n const drawCircle = new Draw({\n source: this.measureSource,\n type: 'Circle',\n style: new Style({\n fill: new Fill({\n color: 'rgba(255, 233, 106, 0.2)'\n }),\n stroke: new Stroke({\n color: 'rgba(139, 0, 139, 0.7)',\n lineDash: [10, 10],\n width: 2\n }),\n image: new CircleStyle({\n radius: 5,\n stroke: new Stroke({\n color: 'rgba(139, 0, 139, 0.7)'\n }),\n fill: new Fill({\n color: 'rgba(255, 233, 106, 0.5)'\n })\n })\n })\n });\n \n this.activeInteraction = drawCircle;\n this.map.addInteraction(drawCircle);\n \n let listener;\n \n drawCircle.on('drawstart', (evt) => {\n const sketch = evt.feature;\n \n listener = sketch.getGeometry().on('change', (e) => {\n const geom = e.target;\n \n if (geom instanceof Circle) {\n const radius = geom.getRadius();\n const area = formatCircleExtent(radius);\n const radiusFormatted = formatLength(radius);\n \n const output = `${radiusFormatted}
            ${area}`;\n \n this.measureTooltipElement.innerHTML = output;\n this.measureTooltip.setPosition(geom.getLastCoordinate());\n }\n });\n });\n \n drawCircle.on('drawend', (evt) => {\n const feature = evt.feature;\n const geom = feature.getGeometry();\n const center = geom.getCenter();\n const radius = geom.getRadius();\n\n // Tag the circle feature so the dblclick handler can identify it\n feature.set('_layerType', 'measure_circle');\n feature.set('_radius', radius);\n feature.set('_center', center);\n\n // Create radius line for visualization\n const radiusLine = new Feature({\n geometry: new LineString([\n center,\n [center[0] + radius, center[1]]\n ])\n });\n radiusLine.set('_layerType', 'measure_circle_radius');\n this.measureSource.addFeature(radiusLine);\n \n // Make tooltip static\n this.measureTooltipElement.className = 'measure-tooltip measure-tooltip-static';\n this.measureTooltip.setOffset([0, -7]);\n \n // Create new tooltip for next measurement\n this.measureTooltipElement = null;\n this.createMeasureTooltip();\n \n unByKey(listener);\n \n // Trigger callbacks\n const result = {\n type: 'circle',\n center: center,\n radius: radius,\n area: Math.PI * radius * radius,\n feature: feature,\n };\n this.onMeasureCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawCircle;\n }\n \n /**\n * Start line measurement tool\n */\n startLineMeasure() {\n this.deactivate();\n this.createMeasureTooltip();\n \n const drawLine = new Draw({\n source: this.measureSource,\n type: 'LineString',\n style: this.getMeasureStyle(),\n });\n \n this.activeInteraction = drawLine;\n this.map.addInteraction(drawLine);\n \n let listener;\n \n drawLine.on('drawstart', (evt) => {\n const sketch = evt.feature;\n \n listener = sketch.getGeometry().on('change', (e) => {\n const geom = e.target;\n const length = getLength(geom);\n const output = formatLength(length);\n \n this.measureTooltipElement.innerHTML = output;\n this.measureTooltip.setPosition(geom.getLastCoordinate());\n });\n });\n \n drawLine.on('drawend', (evt) => {\n const feature = evt.feature;\n const geom = feature.getGeometry();\n const length = getLength(geom);\n \n this.measureTooltipElement.className = 'measure-tooltip measure-tooltip-static';\n this.measureTooltipElement = null;\n this.createMeasureTooltip();\n \n unByKey(listener);\n \n const result = {\n type: 'line',\n length: length,\n feature: feature,\n };\n this.onMeasureCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawLine;\n }\n \n /**\n * Start polygon/area measurement tool\n */\n startAreaMeasure() {\n this.deactivate();\n this.createMeasureTooltip();\n \n const drawPolygon = new Draw({\n source: this.measureSource,\n type: 'Polygon',\n style: this.getMeasureStyle(),\n });\n \n this.activeInteraction = drawPolygon;\n this.map.addInteraction(drawPolygon);\n \n let listener;\n \n drawPolygon.on('drawstart', (evt) => {\n const sketch = evt.feature;\n \n listener = sketch.getGeometry().on('change', (e) => {\n const geom = e.target;\n const area = getArea(geom);\n const output = formatArea(area);\n \n this.measureTooltipElement.innerHTML = output;\n this.measureTooltip.setPosition(geom.getInteriorPoint().getCoordinates());\n });\n });\n \n drawPolygon.on('drawend', (evt) => {\n const feature = evt.feature;\n const geom = feature.getGeometry();\n const area = getArea(geom);\n\n // Tag so the double-click handler can identify it\n feature.set('_layerType', 'measure_area');\n feature.set('_area', area);\n\n this.measureTooltipElement.className = 'measure-tooltip measure-tooltip-static';\n this.measureTooltipElement = null;\n this.createMeasureTooltip();\n\n unByKey(listener);\n\n const result = {\n type: 'polygon',\n area: area,\n feature: feature,\n coordinate: geom.getInteriorPoint().getCoordinates(),\n };\n this.onMeasureCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawPolygon;\n }\n \n /**\n * Start point drawing tool\n */\n startDrawPoint() {\n this.deactivate();\n \n const drawPoint = new Draw({\n source: this.drawSource,\n type: 'Point',\n style: this.getDrawStyle(),\n });\n \n this.activeInteraction = drawPoint;\n this.map.addInteraction(drawPoint);\n \n drawPoint.on('drawend', (evt) => {\n const result = {\n type: 'point',\n feature: evt.feature,\n };\n this.onDrawCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawPoint;\n }\n \n /**\n * Start line drawing tool\n */\n startDrawLine() {\n this.deactivate();\n \n const drawLine = new Draw({\n source: this.drawSource,\n type: 'LineString',\n style: this.getDrawStyle(),\n });\n \n this.activeInteraction = drawLine;\n this.map.addInteraction(drawLine);\n \n drawLine.on('drawend', (evt) => {\n const result = {\n type: 'line',\n feature: evt.feature,\n };\n this.onDrawCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawLine;\n }\n \n /**\n * Start polygon drawing tool\n */\n startDrawPolygon() {\n this.deactivate();\n \n const drawPolygon = new Draw({\n source: this.drawSource,\n type: 'Polygon',\n style: this.getDrawStyle(),\n });\n \n this.activeInteraction = drawPolygon;\n this.map.addInteraction(drawPolygon);\n \n drawPolygon.on('drawend', (evt) => {\n const result = {\n type: 'polygon',\n feature: evt.feature,\n };\n this.onDrawCompleteCallbacks.forEach(cb => cb(result));\n });\n \n return drawPolygon;\n }\n \n /**\n * Clear all measurements\n */\n clearMeasurements() {\n this.measureSource.clear();\n // Remove static tooltips\n const tooltips = document.querySelectorAll('.measure-tooltip-static');\n tooltips.forEach(el => el.parentNode.removeChild(el));\n }\n \n /**\n * Clear all drawings\n */\n clearDrawings() {\n this.drawSource.clear();\n }\n \n /**\n * Clear all (measurements + drawings)\n */\n clearAll() {\n this.clearMeasurements();\n this.clearDrawings();\n }\n \n /**\n * Register callback for measurement completion\n */\n onMeasureComplete(callback) {\n this.onMeasureCompleteCallbacks.push(callback);\n }\n \n /**\n * Register callback for drawing completion\n */\n onDrawComplete(callback) {\n this.onDrawCompleteCallbacks.push(callback);\n }\n \n /**\n * Create a control bar with measurement and drawing tools\n * Returns the ol-ext Bar control\n */\n createControlBar(options = {}) {\n const position = options.position || 'top-left';\n \n // Main control bar\n const mainBar = new EditBar({\n group: true,\n className: 'map-tools-bar',\n });\n \n // Measurement toggle group\n const measureBar = new EditBar({\n toggleOne: true,\n group: true,\n });\n \n // Circle measure button\n const circleBtn = new Toggle({\n html: '',\n title: 'Measure Circle (radius & area)',\n className: 'measure-circle-btn',\n onToggle: (active) => {\n if (active) {\n this.startCircleMeasure();\n } else {\n this.deactivate();\n }\n }\n });\n measureBar.addControl(circleBtn);\n \n // Line measure button\n const lineBtn = new Toggle({\n html: '📏',\n title: 'Measure Distance',\n className: 'measure-line-btn',\n onToggle: (active) => {\n if (active) {\n this.startLineMeasure();\n } else {\n this.deactivate();\n }\n }\n });\n measureBar.addControl(lineBtn);\n \n // Area measure button\n const areaBtn = new Toggle({\n html: '',\n title: 'Measure Area',\n className: 'measure-area-btn',\n onToggle: (active) => {\n if (active) {\n this.startAreaMeasure();\n } else {\n this.deactivate();\n }\n }\n });\n measureBar.addControl(areaBtn);\n \n // Clear measurements button\n const clearBtn = new Button({\n html: '🗑️',\n title: 'Clear Measurements',\n className: 'clear-measure-btn',\n handleClick: () => {\n this.clearMeasurements();\n // Deactivate any active toggle\n circleBtn.setActive(false);\n lineBtn.setActive(false);\n areaBtn.setActive(false);\n }\n });\n measureBar.addControl(clearBtn);\n \n mainBar.addControl(measureBar);\n \n return mainBar;\n }\n \n /**\n * Get the measure layer\n */\n getMeasureLayer() {\n return this.measureLayer;\n }\n \n /**\n * Get the draw layer\n */\n getDrawLayer() {\n return this.drawLayer;\n }\n \n /**\n * Get the measure source\n */\n getMeasureSource() {\n return this.measureSource;\n }\n \n /**\n * Get the draw source\n */\n getDrawSource() {\n return this.drawSource;\n }\n \n /**\n * Check if any tool is currently active\n */\n isActive() {\n return this.activeInteraction !== null;\n }\n}\n\nexport default MapTools;\n","/**\n * PWA Module\n * \n * Handles Progressive Web App functionality:\n * - Service Worker registration\n * - Install prompt handling\n * - Offline detection\n * - Update notifications\n * \n * Note: The Service Worker (sw.js) handles caching.\n * The SharedWorker (shared-db-worker.js) handles database.\n * They are separate workers with different purposes.\n */\n\n// ============================================================================\n// Service Worker Registration\n// ============================================================================\n\nlet swRegistration = null;\n\nexport async function registerServiceWorker() {\n if (!('serviceWorker' in navigator)) {\n console.warn('[PWA] Service Workers not supported');\n return null;\n }\n \n try {\n swRegistration = await navigator.serviceWorker.register('/sw.js', {\n scope: '/'\n });\n \n console.log('[PWA] Service Worker registered:', swRegistration.scope);\n \n // Handle updates\n swRegistration.addEventListener('updatefound', () => {\n const newWorker = swRegistration.installing;\n \n newWorker.addEventListener('statechange', () => {\n if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {\n // New version available\n console.log('[PWA] New version available');\n showUpdateNotification();\n }\n });\n });\n \n return swRegistration;\n \n } catch (error) {\n console.error('[PWA] Service Worker registration failed:', error);\n return null;\n }\n}\n\n// ============================================================================\n// Install Prompt\n// ============================================================================\n\nlet deferredPrompt = null;\nlet installButton = null;\n\n/**\n * Initialize install prompt handling\n * @param {string|HTMLElement} buttonSelector - Button element or selector\n */\nexport function initInstallPrompt(buttonSelector = '#install-btn') {\n installButton = typeof buttonSelector === 'string' \n ? document.querySelector(buttonSelector)\n : buttonSelector;\n \n if (!installButton) {\n console.warn('[PWA] Install button not found:', buttonSelector);\n return;\n }\n \n // Initially hide the button\n installButton.style.display = 'none';\n \n // Listen for the beforeinstallprompt event\n window.addEventListener('beforeinstallprompt', (e) => {\n e.preventDefault();\n deferredPrompt = e;\n \n // Show the install button\n installButton.style.display = 'block';\n console.log('[PWA] Install prompt ready');\n });\n \n // Handle install button click\n installButton.addEventListener('click', async () => {\n if (!deferredPrompt) {\n // Show manual instructions for Safari\n showManualInstallInstructions();\n return;\n }\n \n deferredPrompt.prompt();\n const { outcome } = await deferredPrompt.userChoice;\n \n console.log('[PWA] Install prompt outcome:', outcome);\n \n deferredPrompt = null;\n installButton.style.display = 'none';\n });\n \n // Hide button if app is already installed\n window.addEventListener('appinstalled', () => {\n console.log('[PWA] App installed');\n deferredPrompt = null;\n installButton.style.display = 'none';\n });\n \n // Check if running as installed PWA\n if (window.matchMedia('(display-mode: standalone)').matches) {\n installButton.style.display = 'none';\n }\n}\n\nfunction showManualInstallInstructions() {\n const isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent);\n const isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);\n \n let message = 'To install this app:\\n\\n';\n \n if (isIOS) {\n message += '1. Tap the Share button (square with arrow)\\n';\n message += '2. Scroll down and tap \"Add to Home Screen\"';\n } else if (isSafari) {\n message += '1. Click File menu\\n';\n message += '2. Click \"Add to Dock\"';\n } else {\n message += '1. Click the menu button (three dots)\\n';\n message += '2. Click \"Install\" or \"Add to Home Screen\"';\n }\n \n alert(message);\n}\n\n// ============================================================================\n// Offline Detection\n// ============================================================================\n\nlet offlineIndicator = null;\nconst offlineListeners = new Set();\n\n/**\n * Initialize offline detection\n * @param {string|HTMLElement} indicatorSelector - Element to show when offline\n */\nexport function initOfflineDetection(indicatorSelector = '#offline-indicator') {\n offlineIndicator = typeof indicatorSelector === 'string'\n ? document.querySelector(indicatorSelector)\n : indicatorSelector;\n \n // Set initial state\n updateOfflineUI(!navigator.onLine);\n \n // Listen for online/offline events\n window.addEventListener('online', () => {\n console.log('[PWA] Back online');\n updateOfflineUI(false);\n notifyOfflineListeners(false);\n });\n \n window.addEventListener('offline', () => {\n console.log('[PWA] Gone offline');\n updateOfflineUI(true);\n notifyOfflineListeners(true);\n });\n}\n\nfunction updateOfflineUI(isOffline) {\n if (offlineIndicator) {\n offlineIndicator.style.display = isOffline ? 'block' : 'none';\n }\n \n // Also toggle a class on body for CSS styling\n document.body.classList.toggle('is-offline', isOffline);\n}\n\n/**\n * Subscribe to offline state changes\n * @param {Function} listener - Callback(isOffline: boolean)\n * @returns {Function} Unsubscribe function\n */\nexport function onOfflineChange(listener) {\n offlineListeners.add(listener);\n // Immediately call with current state\n listener(!navigator.onLine);\n return () => offlineListeners.delete(listener);\n}\n\nfunction notifyOfflineListeners(isOffline) {\n for (const listener of offlineListeners) {\n try {\n listener(isOffline);\n } catch (e) {\n console.error('[PWA] Offline listener error:', e);\n }\n }\n}\n\n/**\n * Check if currently online\n */\nexport function isOnline() {\n return navigator.onLine;\n}\n\n// ============================================================================\n// Update Handling\n// ============================================================================\n\nlet updateCallback = null;\n\n/**\n * Set callback for when updates are available\n * @param {Function} callback - Called when new version is ready\n */\nexport function onUpdateAvailable(callback) {\n updateCallback = callback;\n}\n\nfunction showUpdateNotification() {\n if (updateCallback) {\n updateCallback();\n return;\n }\n \n // Default behavior\n if (confirm('A new version is available. Reload now?')) {\n applyUpdate();\n }\n}\n\n/**\n * Apply pending update (reload with new version)\n */\nexport function applyUpdate() {\n if (swRegistration?.waiting) {\n swRegistration.waiting.postMessage({ type: 'SKIP_WAITING' });\n }\n window.location.reload();\n}\n\n// ============================================================================\n// Communication with Service Worker\n// ============================================================================\n\n/**\n * Send a message to the service worker\n * @param {Object} message - Message to send\n */\nexport function postToServiceWorker(message) {\n navigator.serviceWorker.controller?.postMessage(message);\n}\n\n/**\n * Request the service worker to cache specific modules\n * @param {string[]} moduleNames - Array of module names to cache\n */\nexport function cacheModules(moduleNames) {\n postToServiceWorker({\n type: 'CACHE_MODULES',\n payload: { modules: moduleNames }\n });\n}\n\n/**\n * Request the service worker to clear user-specific caches\n * (Call this on logout)\n */\nexport function clearUserCaches() {\n postToServiceWorker({\n type: 'CLEAR_USER_CACHE'\n });\n}\n\n/**\n * Get the Service Worker we can postMessage to. Resolves with:\n * • `navigator.serviceWorker.controller` if it's already in control of the\n * page (fastest path), or\n * • `registration.active` once `navigator.serviceWorker.ready` resolves\n * (covers the first-load case before the SW has claimed the page).\n *\n * Rejects after `timeoutMs` if no SW becomes available — which would only\n * happen in a private/incognito context, an unsupported browser, or when\n * registration genuinely failed.\n *\n * @param {{ timeoutMs?: number }} [opts]\n * @returns {Promise}\n */\nexport async function getActiveServiceWorker({ timeoutMs = 10000 } = {}) {\n if (!('serviceWorker' in navigator)) {\n throw new Error('Service Workers not supported in this browser');\n }\n\n // Fastest path — page is already SW-controlled\n if (navigator.serviceWorker.controller) {\n return navigator.serviceWorker.controller;\n }\n\n // Otherwise wait for the registration to become ready (active SW exists\n // for this scope, even if it hasn't claimed THIS page yet)\n const ready = navigator.serviceWorker.ready;\n const timeout = new Promise((_, reject) =>\n setTimeout(() => reject(new Error('Service-worker readiness timeout')), timeoutMs)\n );\n\n const registration = await Promise.race([ready, timeout]);\n\n // The controller may have appeared while we were waiting; otherwise use\n // the registration's active worker (we can still postMessage to it — caches\n // are shared across the origin)\n const sw = navigator.serviceWorker.controller || registration.active;\n if (!sw) {\n throw new Error('No active service worker available');\n }\n return sw;\n}\n\n/**\n * Subscribe to controller-change events. The callback fires whenever a new\n * Service Worker takes control of the page (e.g. after an SW update or first\n * activation on initial load). Useful for re-querying SW-backed state once\n * the SW has actually taken over.\n *\n * @param {() => void} callback\n * @returns {() => void} unsubscribe function\n */\nexport function onServiceWorkerControllerChange(callback) {\n if (!('serviceWorker' in navigator)) return () => {};\n const handler = () => {\n try { callback(); } catch (e) { console.error('[PWA] controllerchange handler error:', e); }\n };\n navigator.serviceWorker.addEventListener('controllerchange', handler);\n return () => navigator.serviceWorker.removeEventListener('controllerchange', handler);\n}\n\n/**\n * Send a message to the service worker and wait for a single reply with the\n * given response type. Waits for the SW to become available if it isn't yet.\n * Resolves with the reply payload, or rejects after a timeout.\n *\n * @template T\n * @param {string} requestType - Message type to send (e.g. 'GET_TILE_STATS')\n * @param {string} responseType - Message type expected back (e.g. 'TILE_STATS')\n * @param {Object} [extra={}] - Extra fields merged into the outgoing message\n * @param {number} [timeoutMs=5000] Reply timeout (after the SW is available)\n * @param {number} [readyTimeoutMs=10000] Timeout for the SW to be available\n * @returns {Promise}\n */\nasync function requestFromServiceWorker(requestType, responseType, extra = {}, timeoutMs = 5000, readyTimeoutMs = 10000) {\n const sw = await getActiveServiceWorker({ timeoutMs: readyTimeoutMs });\n\n return new Promise((resolve, reject) => {\n const channel = new MessageChannel();\n const timer = setTimeout(() => {\n channel.port1.close();\n reject(new Error(`Service-worker reply \"${responseType}\" timed out`));\n }, timeoutMs);\n\n channel.port1.onmessage = (event) => {\n if (event.data?.type === responseType) {\n clearTimeout(timer);\n channel.port1.close();\n const { type, ...rest } = event.data;\n resolve(rest);\n }\n };\n\n sw.postMessage({ type: requestType, ...extra }, [channel.port2]);\n });\n}\n\n/**\n * Get statistics about tiles cached locally on this device, broken down by\n * provider. Waits up to `readyTimeoutMs` for the service worker to become\n * available. Returns null only if the SW genuinely cannot be reached\n * (private mode, registration failure, or timeout).\n *\n * @returns {Promise<{\n * totals: { count: number, estBytes: number },\n * byProvider: Array<{ key: string, label: string, count: number, limit: number, estBytes: number }>\n * } | null>}\n */\nexport async function getTileCacheStats() {\n try {\n const reply = await requestFromServiceWorker('GET_TILE_STATS', 'TILE_STATS');\n return reply.stats;\n } catch (err) {\n console.warn('[PWA] getTileCacheStats failed:', err);\n return null;\n }\n}\n\n/**\n * Delete every cached tile from this device. Doesn't touch the app shell,\n * modules, or API caches — only the per-provider tile buckets.\n * Waits for the SW to be available before sending the request.\n *\n * @returns {Promise} true if the request was acknowledged\n */\nexport async function clearTileCaches() {\n try {\n await requestFromServiceWorker('CLEAR_TILE_CACHES', 'TILE_CACHES_CLEARED');\n return true;\n } catch (err) {\n console.warn('[PWA] clearTileCaches failed:', err);\n return false;\n }\n}\n\n/**\n * Delete cached tiles for a single provider. `cacheName` must match one of\n * the per-provider caches reported by `getTileCacheStats()` (e.g.\n * `tiles-osm-v4`, `tiles-topo-v4`). Unknown names are rejected by the SW.\n *\n * @param {string} cacheName\n * @returns {Promise} true if the cache was actually deleted\n */\nexport async function clearTileCacheForProvider(cacheName) {\n if (!cacheName) return false;\n try {\n const reply = await requestFromServiceWorker(\n 'CLEAR_TILE_CACHE', 'TILE_CACHE_CLEARED',\n { cacheName },\n );\n return !!reply.deleted;\n } catch (err) {\n console.warn(`[PWA] clearTileCacheForProvider(${cacheName}) failed:`, err);\n return false;\n }\n}\n\n/**\n * Get total disk used by this origin (Cache API + IndexedDB + OPFS).\n * Returns null if the Storage API is not available.\n *\n * @returns {Promise<{ usage: number, quota: number } | null>}\n */\nexport async function getStorageEstimate() {\n if (!navigator.storage?.estimate) return null;\n try {\n const { usage, quota } = await navigator.storage.estimate();\n return { usage: usage || 0, quota: quota || 0 };\n } catch (err) {\n console.warn('[PWA] getStorageEstimate failed:', err);\n return null;\n }\n}\n\n// ============================================================================\n// Auto-initialization\n// ============================================================================\n\n/**\n * Initialize all PWA features\n * @param {Object} options\n */\nexport async function initPWA(options = {}) {\n const {\n installButton = '#install-btn',\n offlineIndicator = '#offline-indicator',\n autoRegisterSW = true\n } = options;\n \n if (autoRegisterSW) {\n await registerServiceWorker();\n }\n \n initInstallPrompt(installButton);\n initOfflineDetection(offlineIndicator);\n \n console.log('[PWA] Initialized');\n}\n\n// Export for direct use\nexport default {\n registerServiceWorker,\n initInstallPrompt,\n initOfflineDetection,\n initPWA,\n isOnline,\n onOfflineChange,\n onUpdateAvailable,\n applyUpdate,\n postToServiceWorker,\n cacheModules,\n clearUserCaches,\n getTileCacheStats,\n clearTileCaches,\n clearTileCacheForProvider,\n getStorageEstimate,\n getActiveServiceWorker,\n onServiceWorkerControllerChange,\n};\n","/**\n * Offline Tile Downloader\n *\n * Pre-fetches map tiles for a given extent and zoom range so they are stored\n * in the Service Worker's per-host tile cache for offline use.\n *\n * The downloader simply issues `fetch()` calls; the existing SW intercepts\n * them and routes to the right cache bucket. No direct Cache API access is\n * needed here — the SW is the single source of truth for storage.\n *\n * Throttling defaults are conservative to respect tile-server usage policies:\n * • 2 concurrent requests\n * • 50 ms inter-batch delay\n * • Standard browser User-Agent / Referer headers\n *\n * Usage:\n * const downloader = new OfflineTileDownloader({\n * baseMap: 'topo',\n * extent3857: [minX, minY, maxX, maxY], // EPSG:3857\n * minZoom: 10,\n * maxZoom: 15,\n * onProgress: (s) => console.log(s),\n * });\n * await downloader.start();\n * downloader.cancel(); // any time\n */\n\n// ============================================================================\n// Base-map URL templates\n// ============================================================================\n\n/**\n * Tile URL templates for base maps that may be downloaded for offline use.\n *\n * The SW recognises these hosts in `getTileCacheName()` and routes them to\n * the matching `tiles-*-vN` cache. If you add a new entry here, also add\n * the host to the SW's classifier or the tiles will not be cached.\n */\nexport const BASEMAP_TEMPLATES = {\n topo: {\n url: 'https://a.tile.opentopomap.org/{z}/{x}/{y}.png',\n label: 'Topographic',\n maxZoom: 17,\n cacheKey: 'tiles-topo',\n },\n osm: {\n url: 'https://a.tile.openstreetmap.org/{z}/{x}/{y}.png',\n label: 'OpenStreetMap',\n maxZoom: 19,\n cacheKey: 'tiles-osm',\n },\n};\n\n// Approximate bytes per raster tile — used for storage estimates.\nexport const AVG_TILE_BYTES = 30 * 1024;\n\n// ============================================================================\n// Tile coordinate math (Web Mercator XYZ scheme)\n// ============================================================================\n\nconst ORIGIN_SHIFT = 2 * Math.PI * 6378137 / 2; // 20037508.342789244\n\n/** Convert Web Mercator metres → (lon, lat) in degrees. */\nfunction metersToLonLat(x, y) {\n const lon = (x / ORIGIN_SHIFT) * 180;\n let lat = (y / ORIGIN_SHIFT) * 180;\n lat = 180 / Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);\n return [lon, lat];\n}\n\n/** Tile (x, y) in XYZ scheme for a given lon/lat at zoom z. */\nfunction lonLatToTile(lon, lat, z) {\n const n = Math.pow(2, z);\n const x = Math.floor((lon + 180) / 360 * n);\n const latRad = lat * Math.PI / 180;\n const y = Math.floor(\n (1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * n\n );\n return { x, y };\n}\n\n/** Tile range covering an EPSG:3857 extent at a given zoom level. */\nexport function tileRangeForExtent(extent3857, z) {\n const [minX, minY, maxX, maxY] = extent3857;\n const [minLon, minLat] = metersToLonLat(minX, minY);\n const [maxLon, maxLat] = metersToLonLat(maxX, maxY);\n\n const tl = lonLatToTile(minLon, maxLat, z); // top-left in XYZ (NW)\n const br = lonLatToTile(maxLon, minLat, z); // bottom-right (SE)\n\n const n = Math.pow(2, z);\n const minTileX = Math.max(0, Math.min(tl.x, br.x));\n const maxTileX = Math.min(n - 1, Math.max(tl.x, br.x));\n const minTileY = Math.max(0, Math.min(tl.y, br.y));\n const maxTileY = Math.min(n - 1, Math.max(tl.y, br.y));\n\n return {\n z,\n minX: minTileX, maxX: maxTileX,\n minY: minTileY, maxY: maxTileY,\n count: (maxTileX - minTileX + 1) * (maxTileY - minTileY + 1),\n };\n}\n\n/** Total tile count for an extent across a zoom range (inclusive). */\nexport function countTiles(extent3857, minZ, maxZ) {\n let total = 0;\n for (let z = minZ; z <= maxZ; z++) {\n total += tileRangeForExtent(extent3857, z).count;\n }\n return total;\n}\n\n/**\n * Enumerate every tile in an extent across a zoom range.\n * Returns an array of { z, x, y } objects. For very large ranges this can be\n * large — the caller is expected to validate the count first.\n */\nexport function enumerateTiles(extent3857, minZ, maxZ) {\n const out = [];\n for (let z = minZ; z <= maxZ; z++) {\n const r = tileRangeForExtent(extent3857, z);\n for (let x = r.minX; x <= r.maxX; x++) {\n for (let y = r.minY; y <= r.maxY; y++) {\n out.push({ z, x, y });\n }\n }\n }\n return out;\n}\n\n/**\n * Format a tile URL for a given coordinate using a {z}/{x}/{y} template.\n */\nexport function formatTileUrl(template, { z, x, y }) {\n return template\n .replace('{z}', z)\n .replace('{x}', x)\n .replace('{y}', y);\n}\n\n// ============================================================================\n// OfflineTileDownloader\n// ============================================================================\n\n/**\n * Concurrent, throttled tile downloader. Issues `fetch()` per tile; the\n * service worker handles caching transparently.\n *\n * Events via `onProgress` callback:\n * { phase: 'running' | 'done' | 'cancelled' | 'error',\n * done, total, ok, failed, cached,\n * elapsedMs, etaMs }\n */\nexport class OfflineTileDownloader {\n constructor({\n baseMap, // 'topo' | 'osm'\n extent3857, // [minX, minY, maxX, maxY]\n minZoom,\n maxZoom,\n concurrency = 2, // OSM ToS-friendly default\n interBatchDelayMs = 50,\n onProgress = () => {},\n }) {\n const tpl = BASEMAP_TEMPLATES[baseMap];\n if (!tpl) throw new Error(`Unknown base map: ${baseMap}`);\n if (maxZoom > tpl.maxZoom) {\n console.warn(`[OfflineTiles] ${baseMap}: maxZoom ${maxZoom} > supported ${tpl.maxZoom}; clamping`);\n maxZoom = tpl.maxZoom;\n }\n\n this.baseMap = baseMap;\n this.template = tpl.url;\n this.extent = extent3857;\n this.minZoom = minZoom;\n this.maxZoom = maxZoom;\n this.concurrency = Math.max(1, Math.min(concurrency, 6));\n this.interBatchDelayMs = interBatchDelayMs;\n this.onProgress = onProgress;\n\n this._abortCtrl = null;\n this._cancelled = false;\n }\n\n /**\n * Begin downloading. Returns a Promise that resolves with the final stats\n * when complete, or when cancelled.\n */\n async start() {\n if (this._abortCtrl) throw new Error('Downloader already started');\n this._abortCtrl = new AbortController();\n this._cancelled = false;\n\n const tiles = enumerateTiles(this.extent, this.minZoom, this.maxZoom);\n const total = tiles.length;\n const startedAt = Date.now();\n\n let done = 0, ok = 0, failed = 0, cached = 0;\n\n const emit = (phase) => {\n const elapsedMs = Date.now() - startedAt;\n const etaMs = done > 0 ? Math.round((elapsedMs / done) * (total - done)) : null;\n this.onProgress({ phase, done, total, ok, failed, cached, elapsedMs, etaMs });\n };\n\n emit('running');\n\n // Process in chunks of `concurrency`\n for (let i = 0; i < tiles.length; i += this.concurrency) {\n if (this._cancelled) break;\n\n const batch = tiles.slice(i, i + this.concurrency);\n await Promise.all(batch.map(async (t) => {\n if (this._cancelled) return;\n const url = formatTileUrl(this.template, t);\n\n try {\n const res = await fetch(url, {\n signal: this._abortCtrl.signal,\n // Hint the SW that this is a passive prefetch\n cache: 'default',\n });\n\n if (res.ok) {\n ok++;\n // Detect \"served from SW cache\" via headers — not reliable across\n // implementations, so we just count all 200s as ok. Reading the body\n // (or cancelling it) lets the browser GC the response promptly.\n if (res.body) res.body.cancel().catch(() => {});\n } else if (res.status === 408) {\n // Our SW returns 408 when offline AND nothing cached. Treat as failed.\n failed++;\n } else {\n failed++;\n }\n } catch (err) {\n if (err.name === 'AbortError') {\n // Cancellation — don't count\n } else {\n failed++;\n }\n }\n done++;\n }));\n\n emit('running');\n\n if (this.interBatchDelayMs > 0 && i + this.concurrency < tiles.length) {\n await new Promise((r) => setTimeout(r, this.interBatchDelayMs));\n }\n }\n\n emit(this._cancelled ? 'cancelled' : 'done');\n\n return {\n phase: this._cancelled ? 'cancelled' : 'done',\n done, total, ok, failed, cached,\n elapsedMs: Date.now() - startedAt,\n };\n }\n\n /**\n * Cancel an in-flight download. Resolves on the next batch boundary.\n */\n cancel() {\n this._cancelled = true;\n if (this._abortCtrl) this._abortCtrl.abort();\n }\n}\n\n// ============================================================================\n// Predefined extents\n// ============================================================================\n\n/**\n * Whole-of-Ghana bounding box in EPSG:3857.\n * Approximate: -3.3°W → 1.2°E, 4.5°N → 11.2°N.\n */\nexport const GHANA_EXTENT_3857 = (() => {\n const lonLatToMeters = (lon, lat) => {\n const x = lon * ORIGIN_SHIFT / 180;\n const y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);\n return [x, y * ORIGIN_SHIFT / 180];\n };\n const sw = lonLatToMeters(-3.3, 4.5);\n const ne = lonLatToMeters(1.2, 11.2);\n return [sw[0], sw[1], ne[0], ne[1]];\n})();\n\n// Useful for size estimates\nexport function estimatedSizeBytes(tileCount) {\n return tileCount * AVG_TILE_BYTES;\n}\n","/**\n * Remote Database Module\n *\n * Handles all API communication with the PostgreSQL backend server.\n * Provides GET and POST methods for fetching and pushing data.\n *\n * Usage:\n * import { remoteGet, remotePost, getDistrictBoundary } from './remotedb.js';\n *\n * const boundary = await getDistrictBoundary();\n */\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst API_BASE = 'https://api.lupmis4luspa.org/api/spatial_planning';\n\n/**\n * Per-request credentials sent with every API call.\n *\n * `district_id` is resolved dynamically — when the PWA is loaded via the PHP\n * entry point (public/index.php), the SSO session is injected into the page\n * as `window.LUPMIS_SESSION` and we read the authenticated user's district\n * from there. In local development (Vite serves index.html directly without\n * PHP), the global is undefined and we fall back to the hard-coded test\n * district below.\n *\n * `api_token` is currently a single global app token — not per-user.\n */\nconst FALLBACK_DISTRICT_ID = '1';\nconst API_TOKEN = '1c46538c712e9b5b';\n\n/**\n * Returns the authenticated user's district_id.\n *\n * - No SSO session at all (window.LUPMIS_SESSION undefined): we're in local\n * development → fall back to the hard-coded test district.\n * - Session present but no district_id: the user is authenticated but not\n * assigned to any district → return null. The bootstrap in main.js detects\n * this case BEFORE any API call and shows a blocking message; this null\n * is defence-in-depth so we never silently send district_id=1 for an\n * authenticated user.\n *\n * The getter runs on each spread of API_CREDENTIALS, so a session change at\n * runtime takes effect immediately.\n */\nfunction resolveDistrictId() {\n try {\n if (typeof window === 'undefined') return FALLBACK_DISTRICT_ID;\n const session = window.LUPMIS_SESSION;\n if (!session || typeof session !== 'object') return FALLBACK_DISTRICT_ID;\n const id = session.district_id;\n if (id === null || id === undefined || String(id).length === 0) return null;\n return String(id);\n } catch { /* no-op */ }\n return FALLBACK_DISTRICT_ID;\n}\n\nconst API_CREDENTIALS = {\n get district_id() { return resolveDistrictId(); },\n api_token: API_TOKEN,\n};\n\n/**\n * Get the full session payload (or null if not authenticated).\n * Exposed for UI code that wants to display the user's name, email, etc.\n *\n * Dev-mode helper: setting `localStorage['dev-session']` to a JSON object\n * (e.g. via `lupmisDevSession({...})` in the console) overrides the real\n * session — useful when running against `localhost:5173` to test the\n * authenticated UI without standing up a PHP server.\n */\nexport function getSession() {\n // 1. Real session injected by index.php (production)\n if (typeof window !== 'undefined' && window.LUPMIS_SESSION && window.LUPMIS_SESSION.user_id) {\n return window.LUPMIS_SESSION;\n }\n // 2. Dev-mode override (developer's own localStorage tweak)\n try {\n const raw = localStorage.getItem('dev-session');\n if (raw) {\n const parsed = JSON.parse(raw);\n if (parsed && parsed.user_id) return parsed;\n }\n } catch { /* ignore */ }\n return null;\n}\n\n// Console helper — set a fake session for dev work. Reload to apply.\n// lupmisDevSession({ user_id: 42, district_id: '1', full_name: 'Test User', ... })\n// Clear it via lupmisDevSession(null) or localStorage.removeItem('dev-session').\nif (typeof window !== 'undefined') {\n window.lupmisDevSession = (payload) => {\n if (payload == null) {\n localStorage.removeItem('dev-session');\n console.log('[Dev] Session override cleared. Reload to apply.');\n } else {\n localStorage.setItem('dev-session', JSON.stringify(payload));\n console.log('[Dev] Session override saved. Reload to apply:', payload);\n }\n };\n}\n\n// ============================================================================\n// Server Reachability\n// ============================================================================\n\n/** Default timeout for API requests (ms) */\nconst REQUEST_TIMEOUT = 30_000;\n\n/** Timeout for the fast reachability probe (ms) */\nconst PING_TIMEOUT = 5_000;\n\n/** Cached result of the last reachability check */\nlet _serverReachable = null;\n\n/**\n * Quick probe to determine if the API server is responding.\n * Sends a small POST to a lightweight endpoint with a short timeout.\n * The result is cached so subsequent calls within the same page load\n * return immediately.\n *\n * @param {boolean} [force=false] - Re-check even if a cached result exists\n * @returns {Promise} true if the server responded in time\n */\nexport async function checkServerReachable(force = false) {\n if (_serverReachable !== null && !force) return _serverReachable;\n\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), PING_TIMEOUT);\n\n try {\n const response = await fetch(`${API_BASE}/get_layers.php`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Accept': 'application/json' },\n body: JSON.stringify(API_CREDENTIALS),\n signal: controller.signal,\n });\n _serverReachable = response.ok;\n } catch {\n _serverReachable = false;\n } finally {\n clearTimeout(timer);\n }\n\n console.log('[RemoteDB] Server reachable:', _serverReachable);\n return _serverReachable;\n}\n\n/**\n * Returns the cached server-reachability flag (synchronous).\n * Returns null if checkServerReachable() has not been called yet.\n * @returns {boolean|null}\n */\nexport function isServerReachable() {\n return _serverReachable;\n}\n\n// ============================================================================\n// Core Request Helpers\n// ============================================================================\n\n/**\n * Create an AbortController that auto-aborts after `ms` milliseconds.\n * If the caller already supplied a signal in `options`, it is combined\n * so that either the caller's abort or the timeout will cancel the request.\n */\nfunction withTimeout(options, ms = REQUEST_TIMEOUT) {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), ms);\n\n // If the caller provided their own signal, chain it\n if (options.signal) {\n options.signal.addEventListener('abort', () => controller.abort());\n }\n\n return {\n signal: controller.signal,\n clear: () => clearTimeout(timer),\n };\n}\n\n/**\n * Perform a GET request to the remote API.\n * Credentials are sent as URL query parameters.\n * Automatically times out after REQUEST_TIMEOUT ms.\n *\n * @param {string} endpoint - API endpoint filename (e.g. 'get_district_boundary.php')\n * @param {Object} [params={}] - Additional query parameters\n * @param {Object} [options={}] - Extra fetch options\n * @returns {Promise} Parsed JSON response\n */\nexport async function remoteGet(endpoint, params = {}, options = {}) {\n const url = new URL(`${API_BASE}/${endpoint}`);\n\n // Attach credentials and any extra params as query string\n const allParams = { ...API_CREDENTIALS, ...params };\n for (const [key, value] of Object.entries(allParams)) {\n url.searchParams.set(key, value);\n }\n\n console.log('[RemoteDB] GET', url.toString());\n\n const timeout = withTimeout(options);\n try {\n const response = await fetch(url.toString(), {\n method: 'GET',\n headers: {\n 'Accept': 'application/json'\n },\n ...options,\n signal: timeout.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = await response.json();\n console.log('[RemoteDB] GET response:', endpoint, '→', typeof data === 'object' ? `${Array.isArray(data) ? data.length + ' items' : 'object'}` : data);\n return data;\n\n } catch (error) {\n if (error.name === 'AbortError') {\n console.error('[RemoteDB] GET timed out:', endpoint);\n throw new Error(`Request timed out: ${endpoint}`);\n }\n console.error('[RemoteDB] GET failed:', endpoint, error);\n throw error;\n } finally {\n timeout.clear();\n }\n}\n\n/**\n * Perform a POST request to the remote API.\n * Credentials are included in the JSON body.\n * Automatically times out after REQUEST_TIMEOUT ms.\n *\n * @param {string} endpoint - API endpoint filename (e.g. 'some_endpoint.php')\n * @param {Object} [body={}] - Request payload (credentials are merged in)\n * @param {Object} [options={}] - Extra fetch options\n * @returns {Promise} Parsed JSON response\n */\nexport async function remotePost(endpoint, body = {}, options = {}) {\n const url = `${API_BASE}/${endpoint}`;\n\n const payload = { ...API_CREDENTIALS, ...body };\n\n console.log('[RemoteDB] POST', url);\n\n const timeout = withTimeout(options);\n try {\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Accept': 'application/json'\n },\n body: JSON.stringify(payload),\n ...options,\n signal: timeout.signal,\n });\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n\n const data = await response.json();\n console.log('[RemoteDB] POST response:', endpoint, '→', typeof data === 'object' ? `${Array.isArray(data) ? data.length + ' items' : 'object'}` : data);\n return data;\n\n } catch (error) {\n if (error.name === 'AbortError') {\n console.error('[RemoteDB] POST timed out:', endpoint);\n throw new Error(`Request timed out: ${endpoint}`);\n }\n console.error('[RemoteDB] POST failed:', endpoint, error);\n throw error;\n } finally {\n timeout.clear();\n }\n}\n\n// ============================================================================\n// Spatial Planning Endpoints\n// ============================================================================\n\n/**\n * Fetch district boundary geometry from the server.\n *\n * @returns {Promise} District boundary GeoJSON or API response\n */\nexport async function getDistrictBoundary() {\n return remotePost('get_district_boundary.php');\n}\n\n/**\n * Fetch the list of available map layer categories from the server.\n *\n * Response format:\n * { success: true, data: [{ id, name, description, createdt, editdt }, ...] }\n *\n * @returns {Promise} Layer categories list\n */\nexport async function getLayers() {\n return remotePost('get_layers.php');\n}\n\n/**\n * Fetch all collector zones for the current district.\n *\n * Expected response:\n * { success: true, data: [{ id, zone_name, boundary: \"MULTIPOLYGON(...)\", ... }, ...] }\n *\n * @returns {Promise} Collector zones list\n */\nexport async function getCollectorZones() {\n return remotePost('get_all_collector_zone_per_district.php');\n}\n\n/**\n * Fetch all parcels for the current district.\n *\n * Expected response:\n * { success: true, data: [{ id, ..., polygon: \"POLYGON(...)\" | \"MULTIPOLYGON(...)\", ... }, ...] }\n *\n * @returns {Promise} Parcels list\n */\nexport async function getDistrictParcels() {\n return remotePost('get_parcels_per_district.php');\n}\n\n/**\n * Fetch all building footprints for the current district.\n *\n * Expected response:\n * { success: true, data: [{ id, ..., polygon: \"POLYGON(...)\" | \"MULTIPOLYGON(...)\", ... }, ...] }\n *\n * @returns {Promise} Building footprints list\n */\nexport async function getBuildingFootprints() {\n return remotePost('get_all_footprint_per_district.php');\n}\n\n/**\n * Fetch the Contours hillshade elevation layer from the server.\n *\n * Source: table `be_contour_hillside` in the local PostgreSQL `public` schema\n * (imported from OpenTopography's viz.hh_hillshade).\n *\n * The current district_id is passed automatically via API_CREDENTIALS.\n *\n * Expected response:\n * { success: true, data: [{ id, elevation, geom: \"LINESTRING(...)\" | \"MULTILINESTRING(...)\" | \"POLYGON(...)\", ... }, ...] }\n *\n * @returns {Promise} Contours hillshade list\n */\nexport async function getContoursHillshade() {\n return remotePost('get_contours_hillshade.php');\n}\n\n/**\n * Fetch the OSM roads layer from the server.\n *\n * Source: table `pi_osm_roads` in the local PostgreSQL `public` schema\n * (imported from OpenStreetMap road network for the district).\n *\n * Expected response:\n * { success: true, data: [{ id, ..., geom: \"LINESTRING(...)\" | \"MULTILINESTRING(...)\", ... }, ...] }\n *\n * @returns {Promise} OSM roads list\n */\nexport async function getOSMRoads() {\n return remotePost('get_osm_roads.php');\n}\n\n/**\n * Fetch the UPN-grid (district sub-division) for the current district.\n *\n * The grid is static per district, so callers cache it locally and only\n * re-fetch when the user becomes associated with a different district\n * (see saveUpnGrid / getLocalUpnGrid in database.js and loadUpnGrid in\n * main.js).\n *\n * Source: spatial.upn_grid; endpoint runs ST_AsText(geom_4326) AS polygon.\n *\n * Expected response:\n * { success: true,\n * data: [{ polygon: \"POLYGON((...))\" | \"MULTIPOLYGON(((...)))\",\n * districtid: 122,\n * upn_prefix: \"AB\" }, ...] }\n *\n * @returns {Promise}\n */\nexport async function getUpnGrid() {\n return remotePost('get_upn_grid_per_district.php');\n}\n\n/**\n * Push a recorded GPS trail (with all its points) to the server.\n *\n * Implements the GeoTracker \"sync adapter\" contract: store-and-forward — the\n * whole trail is uploaded once recording stops (and retried when back online).\n * `district_id` and `api_token` are attached automatically by remotePost().\n *\n * ── SERVER SIDE (NOT YET CREATED) ───────────────────────────────────────\n * Proposed endpoint: `save_gps_trail.php`\n * Proposed PostgreSQL/PostGIS tables (SRID 4326):\n *\n * CREATE TABLE be_gps_trail (\n * id SERIAL PRIMARY KEY,\n * client_uuid TEXT UNIQUE, -- de-dupe re-syncs\n * district_id INTEGER,\n * name TEXT,\n * started_at TIMESTAMPTZ,\n * ended_at TIMESTAMPTZ,\n * point_count INTEGER,\n * distance_m DOUBLE PRECISION,\n * track GEOMETRY(LineStringZ, 4326), -- optional aggregate line\n * createdt TIMESTAMPTZ DEFAULT now()\n * );\n * CREATE TABLE be_gps_trail_point (\n * id SERIAL PRIMARY KEY,\n * trail_id INTEGER REFERENCES be_gps_trail(id) ON DELETE CASCADE,\n * seq INTEGER,\n * geom GEOMETRY(PointZ, 4326),\n * accuracy DOUBLE PRECISION,\n * altitude DOUBLE PRECISION,\n * heading DOUBLE PRECISION,\n * speed DOUBLE PRECISION,\n * satellites INTEGER, -- nullable (web has no sat count)\n * recorded_at TIMESTAMPTZ\n * );\n *\n * Request body (JSON, plus injected credentials):\n * { client_uuid, name, started_at, ended_at, point_count, distance_m,\n * points: [ { seq, longitude, latitude, altitude, accuracy,\n * altitude_accuracy, heading, speed, satellites, recorded_at } ] }\n *\n * Expected response: { success: true, id: }\n * Should be idempotent on client_uuid (INSERT ... ON CONFLICT DO UPDATE).\n * ─────────────────────────────────────────────────────────────────────────\n *\n * @param {Object} trail local trail row (client_uuid, name, started_at, …)\n * @param {Array} points local point rows (seq, longitude, latitude, …)\n * @returns {Promise<{ remoteId: (string|number|null) }>}\n */\nexport async function pushGpsTrail(trail, points) {\n const payload = {\n client_uuid: trail.client_uuid,\n name: trail.name ?? null,\n started_at: trail.started_at,\n ended_at: trail.ended_at,\n point_count: trail.point_count ?? points.length,\n distance_m: trail.distance_m ?? 0,\n points: (points || []).map((p) => ({\n seq: p.seq,\n longitude: p.longitude,\n latitude: p.latitude,\n altitude: p.altitude ?? null,\n accuracy: p.accuracy ?? null,\n altitude_accuracy: p.altitude_accuracy ?? null,\n heading: p.heading ?? null,\n speed: p.speed ?? null,\n satellites: p.satellites ?? null,\n recorded_at: p.recorded_at,\n })),\n };\n const res = await remotePost('save_gps_trail.php', payload);\n return { remoteId: res?.id ?? res?.remote_id ?? null };\n}\n\n// ============================================================================\n// Exports\n// ============================================================================\n\nexport default {\n getSession,\n checkServerReachable,\n isServerReachable,\n remoteGet,\n remotePost,\n getDistrictBoundary,\n getLayers,\n getDistrictParcels,\n getCollectorZones,\n getBuildingFootprints,\n getContoursHillshade,\n getOSMRoads,\n getUpnGrid,\n pushGpsTrail,\n};\n","/**\n * geo-utils.js — pure, dependency-free geospatial helpers for the GeoTracker\n * module. No browser APIs, no framework imports — safe to reuse anywhere\n * (including Node, web workers, or other projects).\n *\n * @module geotracker/geo-utils\n */\n\nconst EARTH_RADIUS_M = 6371008.8; // mean Earth radius (metres)\nconst DEG2RAD = Math.PI / 180;\n\n/**\n * Great-circle distance between two lon/lat points using the haversine\n * formula.\n *\n * @param {number} lon1\n * @param {number} lat1\n * @param {number} lon2\n * @param {number} lat2\n * @returns {number} distance in metres\n */\nexport function haversineMeters(lon1, lat1, lon2, lat2) {\n const dLat = (lat2 - lat1) * DEG2RAD;\n const dLon = (lon2 - lon1) * DEG2RAD;\n const a =\n Math.sin(dLat / 2) ** 2 +\n Math.cos(lat1 * DEG2RAD) * Math.cos(lat2 * DEG2RAD) * Math.sin(dLon / 2) ** 2;\n return 2 * EARTH_RADIUS_M * Math.asin(Math.min(1, Math.sqrt(a)));\n}\n\n/**\n * Total length of a polyline expressed as an array of points.\n * @param {Array<{lon:number, lat:number}>} points\n * @returns {number} metres\n */\nexport function pathLengthMeters(points) {\n let total = 0;\n for (let i = 1; i < points.length; i++) {\n total += haversineMeters(points[i - 1].lon, points[i - 1].lat, points[i].lon, points[i].lat);\n }\n return total;\n}\n\n/**\n * Format a latitude or longitude for compact display.\n * @param {number} value\n * @param {number} [decimals=5] ~1.1 m precision at 5 dp\n * @returns {string}\n */\nexport function formatCoord(value, decimals = 5) {\n if (value == null || Number.isNaN(value)) return '—';\n return value.toFixed(decimals);\n}\n\n/**\n * Format a distance in metres into a friendly string (m below 1 km, km above).\n * @param {number} meters\n * @returns {string}\n */\nexport function formatDistance(meters) {\n if (meters == null || Number.isNaN(meters)) return '—';\n if (meters < 1000) return `${Math.round(meters)} m`;\n return `${(meters / 1000).toFixed(2)} km`;\n}\n\n/**\n * Format a horizontal accuracy (metres) into a friendly ± string.\n * @param {number|null} meters\n * @returns {string}\n */\nexport function formatAccuracy(meters) {\n if (meters == null || Number.isNaN(meters)) return '—';\n return `±${Math.round(meters)} m`;\n}\n\n/**\n * Classify a horizontal accuracy into a qualitative fix-quality bucket. Useful\n * for colour-coding the UI without needing satellite count.\n * @param {number|null} meters\n * @returns {'good'|'fair'|'poor'|'none'}\n */\nexport function accuracyQuality(meters) {\n if (meters == null || Number.isNaN(meters)) return 'none';\n if (meters <= 10) return 'good';\n if (meters <= 30) return 'fair';\n return 'poor';\n}\n","/**\n * GeoTracker.js — a framework-agnostic GPS live-position + trail-recording\n * engine. It has **no** dependency on OpenLayers, Bootstrap, SQLocal, or any\n * LUPMIS code, so it can be dropped into any web project. Persistence and\n * server sync are provided by the host through small adapter objects.\n *\n * ─────────────────────────────────────────────────────────────────────────\n * STORAGE ADAPTER (required for recording) — all methods may be async:\n * createTrail(meta) -> trailId // meta: {uuid,name,startedAt,...}\n * addPoint(trailId, point) -> void // point: normalized fix (see below)\n * finishTrail(trailId, summary)-> void // summary: {endedAt,pointCount,distanceM}\n * getUnsyncedTrails() -> Array // trails with synced=0 and completed\n * getTrailPoints(trailId) -> Array\n * markTrailSynced(trailId, remoteId) -> void\n *\n * SYNC ADAPTER (optional) — store-and-forward:\n * pushTrail(trail, points) -> { remoteId } | throws\n * isOnline?() -> boolean // optional connectivity probe\n *\n * NORMALIZED FIX shape emitted on 'position' and stored via addPoint:\n * { lon, lat, accuracy, altitude, altitudeAccuracy, heading, speed,\n * satellites:null, timestamp }\n * (satellites is always null on the web Geolocation API — kept for parity\n * with native builds that can populate it.)\n * ─────────────────────────────────────────────────────────────────────────\n *\n * @module geotracker/GeoTracker\n */\n\nimport { haversineMeters } from './geo-utils.js';\n\n/** @typedef {'idle'|'watching'|'recording'} GeoTrackerState */\n\nconst DEFAULTS = {\n /** Minimum metres between two recorded trail points. */\n minDistanceM: 5,\n /** Ignore fixes arriving faster than this (throttle, ms). */\n minIntervalMs: 1000,\n /** Record a point at least this often even when stationary (heartbeat, ms). */\n heartbeatMs: 20000,\n /** Drop fixes worse than this horizontal accuracy (metres). 0 = accept all. */\n maxAccuracyM: 50,\n /** navigator.geolocation options. */\n enableHighAccuracy: true,\n timeoutMs: 15000,\n maximumAgeMs: 0,\n};\n\nexport class GeoTracker {\n /**\n * @param {object} [options]\n * @param {object} [options.storage] storage adapter (see module docs)\n * @param {object} [options.sync] sync adapter (see module docs)\n * @param {Geolocation} [options.geolocation] inject navigator.geolocation (for tests)\n * @param {number} [options.minDistanceM]\n * @param {number} [options.minIntervalMs]\n * @param {number} [options.heartbeatMs]\n * @param {number} [options.maxAccuracyM]\n * @param {boolean} [options.enableHighAccuracy]\n */\n constructor(options = {}) {\n this.opts = { ...DEFAULTS, ...options };\n this.storage = options.storage || null;\n this.sync = options.sync || null;\n this._geo = options.geolocation ||\n (typeof navigator !== 'undefined' ? navigator.geolocation : null);\n\n /** @type {GeoTrackerState} */\n this._state = 'idle';\n this._watchId = null;\n this._live = false; // live readout requested\n this._recording = false; // recording in progress\n\n this._activeTrailId = null;\n this._activeTrailUuid = null;\n this._lastRecorded = null; // last point actually written {lon,lat,timestamp}\n this._lastRecordedAt = 0;\n this._distanceM = 0;\n this._pointCount = 0;\n this._lastFix = null; // most recent normalized fix (any quality)\n\n /** @type {Record>} */\n this._listeners = Object.create(null);\n }\n\n // ── Events ────────────────────────────────────────────────────────────\n\n /**\n * Subscribe to an event. Returns an unsubscribe function.\n * Events: 'position' | 'point' | 'statechange' | 'trailstart' |\n * 'trailstop' | 'error' | 'syncstatus'\n * @param {string} event\n * @param {Function} cb\n * @returns {() => void}\n */\n on(event, cb) {\n (this._listeners[event] || (this._listeners[event] = new Set())).add(cb);\n return () => this._listeners[event]?.delete(cb);\n }\n\n _emit(event, payload) {\n const set = this._listeners[event];\n if (!set) return;\n for (const cb of set) {\n try { cb(payload); } catch (err) { console.error(`[GeoTracker] listener for \"${event}\" threw`, err); }\n }\n }\n\n // ── Public state ──────────────────────────────────────────────────────\n\n /** @returns {GeoTrackerState} */\n get state() { return this._state; }\n get isRecording() { return this._recording; }\n get lastFix() { return this._lastFix; }\n get isSupported() { return !!this._geo; }\n\n _setState(s) {\n if (this._state === s) return;\n this._state = s;\n this._emit('statechange', s);\n }\n\n // ── Live readout (watch without recording) ──────────────────────────────\n\n /**\n * Begin a position watch purely for the live readout (no trail is recorded).\n * Safe to call repeatedly.\n */\n startLive() {\n if (!this._geo) { this._emit('error', new Error('Geolocation not supported')); return; }\n this._live = true;\n this._ensureWatch();\n }\n\n /** Stop the live readout. Has no effect while a recording is in progress. */\n stopLive() {\n this._live = false;\n if (!this._recording) this._teardownWatch();\n }\n\n /**\n * One-shot position request (e.g. for a \"Locate me\" button). Resolves with a\n * normalized fix. Does not start/stop the watch.\n * @returns {Promise}\n */\n getCurrentPosition() {\n return new Promise((resolve, reject) => {\n if (!this._geo) { reject(new Error('Geolocation not supported')); return; }\n this._geo.getCurrentPosition(\n (pos) => {\n const fix = GeoTracker.normalize(pos);\n this._lastFix = fix;\n this._emit('position', fix);\n resolve(fix);\n },\n (err) => { this._emit('error', err); reject(err); },\n {\n enableHighAccuracy: this.opts.enableHighAccuracy,\n timeout: this.opts.timeoutMs,\n maximumAge: this.opts.maximumAgeMs,\n }\n );\n });\n }\n\n // ── Recording ───────────────────────────────────────────────────────────\n\n /**\n * Start recording a new trail. Creates the trail in storage, then records\n * filtered points as the device moves.\n * @param {object} [meta] e.g. { name, districtId }\n * @returns {Promise<{trailId:*, uuid:string}>}\n */\n async startRecording(meta = {}) {\n if (!this._geo) throw new Error('Geolocation not supported');\n if (!this.storage) throw new Error('GeoTracker: no storage adapter configured');\n if (this._recording) return { trailId: this._activeTrailId, uuid: this._activeTrailUuid };\n\n const uuid = GeoTracker.uuid();\n const startedAt = new Date().toISOString();\n const trailMeta = { uuid, name: meta.name || null, startedAt, ...meta };\n const trailId = await this.storage.createTrail(trailMeta);\n\n this._activeTrailId = trailId;\n this._activeTrailUuid = uuid;\n this._lastRecorded = null;\n this._lastRecordedAt = 0;\n this._distanceM = 0;\n this._pointCount = 0;\n this._recording = true;\n\n this._ensureWatch();\n this._setState('recording');\n this._emit('trailstart', { trailId, uuid, startedAt });\n return { trailId, uuid };\n }\n\n /**\n * Stop the active recording, finalise the trail summary, and (if a sync\n * adapter is present) attempt to push it immediately.\n * @returns {Promise<{trailId:*, pointCount:number, distanceM:number, synced:boolean}>}\n */\n async stopRecording() {\n if (!this._recording) return null;\n const trailId = this._activeTrailId;\n const endedAt = new Date().toISOString();\n const summary = { endedAt, pointCount: this._pointCount, distanceM: this._distanceM };\n\n this._recording = false;\n if (!this._live) this._teardownWatch();\n this._setState(this._live ? 'watching' : 'idle');\n\n try {\n await this.storage.finishTrail(trailId, summary);\n } catch (err) {\n this._emit('error', err);\n }\n this._emit('trailstop', { trailId, ...summary });\n\n let synced = false;\n if (this.sync) {\n try { synced = await this._syncTrail(trailId); }\n catch (err) { this._emit('error', err); }\n }\n\n this._activeTrailId = null;\n this._activeTrailUuid = null;\n return { trailId, pointCount: summary.pointCount, distanceM: summary.distanceM, synced };\n }\n\n // ── Sync (store-and-forward) ────────────────────────────────────────────\n\n /**\n * Push all completed-but-unsynced trails to the server via the sync adapter.\n * Call on app start and whenever connectivity returns.\n * @returns {Promise<{pushed:number, failed:number}>}\n */\n async syncPending() {\n if (!this.sync || !this.storage) return { pushed: 0, failed: 0 };\n if (this.sync.isOnline && !this.sync.isOnline()) return { pushed: 0, failed: 0 };\n\n let pushed = 0, failed = 0;\n const trails = await this.storage.getUnsyncedTrails();\n for (const trail of trails) {\n try {\n const ok = await this._syncTrail(trail.id ?? trail.trailId, trail);\n ok ? pushed++ : failed++;\n } catch (err) {\n failed++;\n this._emit('error', err);\n }\n }\n this._emit('syncstatus', { pushed, failed });\n return { pushed, failed };\n }\n\n /** @private push a single trail by id. */\n async _syncTrail(trailId, trailRow) {\n const points = await this.storage.getTrailPoints(trailId);\n const trail = trailRow || { id: trailId };\n const result = await this.sync.pushTrail(trail, points);\n const remoteId = result && (result.remoteId ?? result.id ?? null);\n await this.storage.markTrailSynced(trailId, remoteId);\n return true;\n }\n\n // ── Internal watch handling ──────────────────────────────────────────────\n\n /** @private start the geolocation watch if not already running. */\n _ensureWatch() {\n if (this._watchId != null || !this._geo) {\n if (this._state === 'idle' && this._live) this._setState('watching');\n return;\n }\n this._watchId = this._geo.watchPosition(\n (pos) => this._onFix(pos),\n (err) => this._emit('error', err),\n {\n enableHighAccuracy: this.opts.enableHighAccuracy,\n timeout: this.opts.timeoutMs,\n maximumAge: this.opts.maximumAgeMs,\n }\n );\n if (!this._recording) this._setState('watching');\n }\n\n /** @private stop the geolocation watch. */\n _teardownWatch() {\n if (this._watchId != null && this._geo) {\n this._geo.clearWatch(this._watchId);\n }\n this._watchId = null;\n }\n\n /** @private handle a raw Geolocation fix. */\n async _onFix(pos) {\n const fix = GeoTracker.normalize(pos);\n this._lastFix = fix;\n this._emit('position', fix); // always emit for the live readout\n\n if (!this._recording) return;\n\n const { minIntervalMs, minDistanceM, heartbeatMs, maxAccuracyM } = this.opts;\n const now = fix.timestamp;\n\n // Throttle very frequent fixes.\n if (this._lastRecordedAt && (now - this._lastRecordedAt) < minIntervalMs) return;\n // Drop low-quality fixes (unless this is the very first point).\n if (maxAccuracyM > 0 && fix.accuracy != null && fix.accuracy > maxAccuracyM && this._lastRecorded) return;\n\n let keep = false;\n let stepM = 0;\n if (!this._lastRecorded) {\n keep = true; // always record the first point\n } else {\n stepM = haversineMeters(this._lastRecorded.lon, this._lastRecorded.lat, fix.lon, fix.lat);\n const elapsed = now - this._lastRecordedAt;\n if (stepM >= minDistanceM || elapsed >= heartbeatMs) keep = true;\n }\n if (!keep) return;\n\n if (this._lastRecorded) this._distanceM += stepM;\n this._pointCount += 1;\n this._lastRecorded = { lon: fix.lon, lat: fix.lat, timestamp: now };\n this._lastRecordedAt = now;\n\n try {\n await this.storage.addPoint(this._activeTrailId, { ...fix, seq: this._pointCount });\n this._emit('point', {\n trailId: this._activeTrailId,\n seq: this._pointCount,\n point: fix,\n distanceM: this._distanceM,\n pointCount: this._pointCount,\n });\n } catch (err) {\n this._emit('error', err);\n }\n }\n\n // ── Static helpers ────────────────────────────────────────────────────────\n\n /** Normalize a browser GeolocationPosition into the module's fix shape. */\n static normalize(pos) {\n const c = pos.coords || {};\n const num = (v) => (v != null && !Number.isNaN(v) ? v : null);\n return {\n lon: c.longitude,\n lat: c.latitude,\n accuracy: num(c.accuracy),\n altitude: num(c.altitude),\n altitudeAccuracy: num(c.altitudeAccuracy),\n heading: num(c.heading),\n speed: num(c.speed),\n satellites: null, // not exposed by the web Geolocation API\n timestamp: pos.timestamp || Date.now(),\n };\n }\n\n /** RFC4122-ish UUID, using crypto when available. */\n static uuid() {\n if (typeof crypto !== 'undefined' && crypto.randomUUID) return crypto.randomUUID();\n return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (ch) => {\n const r = (Math.random() * 16) | 0;\n const v = ch === 'x' ? r : (r & 0x3) | 0x8;\n return v.toString(16);\n });\n }\n}\n\nexport default GeoTracker;\n","/**\n * geotracker-lupmis.js — LUPMIS2 integration layer for the reusable GeoTracker.\n *\n * This is the ONLY place that couples the generic src/geotracker/ engine to\n * LUPMIS specifics (SQLocal storage, the PHP sync endpoint, district id,\n * online checks). To reuse GeoTracker in another app, copy src/geotracker/ and\n * write a file like this one with that app's storage + sync adapters.\n *\n * @module geotracker-lupmis\n */\n\nimport { GeoTracker } from './geotracker/GeoTracker.js';\nimport {\n createGpsTrail,\n addGpsTrailPoint,\n finishGpsTrail,\n getUnsyncedGpsTrails,\n getGpsTrailPoints,\n markGpsTrailSynced,\n} from './database.js';\nimport { pushGpsTrail } from './remotedb.js';\nimport { isOnline } from './pwa.js';\nimport { getSession } from './remotedb.js';\n\n/**\n * Storage adapter — maps the GeoTracker contract onto the SQLocal helpers in\n * database.js. The district id is stamped onto each trail at creation time.\n */\nconst sqlocalStorage = {\n async createTrail(meta) {\n const districtId = meta.districtId\n ?? getSession()?.district_id\n ?? null;\n return createGpsTrail({ ...meta, districtId: districtId != null ? String(districtId) : null });\n },\n addPoint: (trailId, point) => addGpsTrailPoint(trailId, point),\n finishTrail: (trailId, summary) => finishGpsTrail(trailId, summary),\n getUnsyncedTrails: () => getUnsyncedGpsTrails(),\n getTrailPoints: (trailId) => getGpsTrailPoints(trailId),\n markTrailSynced: (trailId, remote) => markGpsTrailSynced(trailId, remote),\n};\n\n/**\n * Sync adapter — store-and-forward upload via the PHP endpoint. `isOnline()`\n * lets the tracker skip pushes while offline (it retries later).\n */\nconst remoteSync = {\n pushTrail: (trail, points) => pushGpsTrail(trail, points),\n isOnline: () => isOnline(),\n};\n\n/**\n * The configured, app-wide tracker instance. Tunables chosen for field\n * walking/driving: a point every ~5 m, throttled to ≥1 s, with a 20 s\n * heartbeat so stationary pauses still leave a breadcrumb, dropping fixes\n * worse than 50 m accuracy.\n */\nexport const geoTracker = new GeoTracker({\n storage: sqlocalStorage,\n sync: remoteSync,\n minDistanceM: 5,\n minIntervalMs: 1000,\n heartbeatMs: 20000,\n maxAccuracyM: 50,\n enableHighAccuracy: true,\n});\n\nexport default geoTracker;\n","/**\n * LUPMIS2 — iframe embed bridge\n *\n * Implements the postMessage contract defined in\n * LUPMIS2_Permit_Map_Integration.docx §2\n * which itself follows the iframe channel from\n * LUPMIS2_Reusable_Mapping_Concept.docx §3.2 / §4.\n *\n * Outbound (embed → host):\n * { type: 'ready' }\n * { type: 'parcel:select', upn, parcel_id, lon, lat,\n * zone_code, zone_name, landuse,\n * min_height, max_height }\n * { type: 'parcel:cleared' }\n * { type: 'error', code, message }\n *\n * Inbound (host → embed):\n * { type: 'set:view', lon, lat, zoom }\n * { type: 'set:selected', upn }\n * { type: 'clear:selected' }\n * { type: 'set:basemap', key }\n *\n * The bridge is framework-agnostic apart from the OpenLayers imports — it\n * lives one level above the proposed `map-core` library so once that library\n * is extracted (concept §3.1) this file can be lifted into it unchanged.\n *\n * Note on security: outbound messages are sent with target origin `*` because\n * the embed cannot know its parent's origin in advance and the payload is\n * non-sensitive (selection metadata only). The HOST is expected to verify\n * `event.origin === ''` before trusting any message, as\n * documented in §2.2 of the integration doc. Inbound commands are\n * type-checked against a strict whitelist before being acted on.\n */\n\nimport { fromLonLat, toLonLat } from 'ol/proj.js';\nimport { getCenter } from 'ol/extent.js';\nimport VectorLayer from 'ol/layer/Vector.js';\nimport VectorSource from 'ol/source/Vector.js';\nimport { Style, Stroke, Fill } from 'ol/style.js';\n\nconst KNOWN_COMMANDS = new Set([\n 'set:view',\n 'set:selected',\n 'clear:selected',\n 'set:basemap',\n]);\n\n/**\n * Create and install the embed bridge.\n *\n * @param {Object} opts\n * @param {Object} opts.mapView — the MapView instance (uses onClick,\n * getMap, setBaseMap).\n * @param {Object} opts.embedConfig — window.LUPMIS_EMBED contents.\n * @returns {{ attachParcelsLayer: (layer) => void, emitError: (code, msg) => void }}\n */\nexport function createEmbedBridge({ mapView, embedConfig }) {\n const map = mapView.getMap();\n const parent = (window.parent && window.parent !== window) ? window.parent : null;\n\n // -------------------------------------------------------------------------\n // Highlight layer — visual cue for the currently-selected parcel.\n // -------------------------------------------------------------------------\n const highlightSource = new VectorSource();\n const highlightLayer = new VectorLayer({\n source: highlightSource,\n zIndex: 9999,\n style: new Style({\n stroke: new Stroke({ color: '#f97316', width: 3 }),\n fill: new Fill({ color: 'rgba(249,115,22,0.18)' }),\n }),\n properties: {\n title: 'Permit selection',\n displayInLayerSwitcher: false,\n },\n });\n map.addLayer(highlightLayer);\n\n let parcelsLayer = null;\n let pendingSelectUpn = embedConfig?.upn ? String(embedConfig.upn) : null;\n let readyEmitted = false;\n\n // -------------------------------------------------------------------------\n // Outbound\n // -------------------------------------------------------------------------\n function send(message) {\n if (!parent) {\n console.warn('[embed-bridge] No parent window — would have sent:', message);\n return;\n }\n try {\n parent.postMessage(message, '*');\n } catch (e) {\n console.warn('[embed-bridge] postMessage failed:', e);\n }\n }\n\n function emitError(code, message) {\n send({ type: 'error', code, message });\n }\n\n function emitReady() {\n if (readyEmitted) return;\n readyEmitted = true;\n send({ type: 'ready' });\n }\n\n /** Build a `parcel:select` payload from a feature and (optionally) the click point. */\n function parcelPayload(feature, lon, lat) {\n const p = feature.getProperties();\n let outLon = lon, outLat = lat;\n if (outLon == null || outLat == null) {\n const ext = feature.getGeometry()?.getExtent();\n if (ext) {\n const [cx, cy] = toLonLat(getCenter(ext));\n outLon = cx; outLat = cy;\n }\n }\n return {\n type: 'parcel:select',\n upn: p.upn ?? null,\n parcel_id: p.id ?? null,\n lon: outLon ?? null,\n lat: outLat ?? null,\n zone_code: p.zone_code ?? null,\n zone_name: p.zone_name ?? null,\n landuse: p.landuse ?? null,\n min_height: p.min_height ?? null,\n max_height: p.max_height ?? null,\n };\n }\n\n function highlightFeature(feature) {\n highlightSource.clear();\n if (feature) {\n const clone = feature.clone();\n highlightSource.addFeature(clone);\n }\n }\n\n // -------------------------------------------------------------------------\n // Click → parcel:select / parcel:cleared\n // -------------------------------------------------------------------------\n mapView.onClick((lon, lat, _markerFeature, evt) => {\n let parcelFeature = null;\n map.forEachFeatureAtPixel(evt.pixel, (f) => {\n if (f.get('_layerType') === 'parcel') {\n parcelFeature = f;\n return true;\n }\n });\n if (parcelFeature) {\n highlightFeature(parcelFeature);\n send(parcelPayload(parcelFeature, lon, lat));\n } else {\n highlightFeature(null);\n send({ type: 'parcel:cleared' });\n }\n });\n\n // -------------------------------------------------------------------------\n // Inbound commands\n // -------------------------------------------------------------------------\n window.addEventListener('message', (event) => {\n const msg = event.data;\n if (!msg || typeof msg !== 'object' || !KNOWN_COMMANDS.has(msg.type)) return;\n try {\n switch (msg.type) {\n case 'set:view': {\n if (typeof msg.lon === 'number' && typeof msg.lat === 'number') {\n const view = map.getView();\n view.setCenter(fromLonLat([msg.lon, msg.lat]));\n if (typeof msg.zoom === 'number') view.setZoom(msg.zoom);\n }\n break;\n }\n case 'set:selected':\n if (msg.upn) selectByUpn(String(msg.upn));\n break;\n case 'clear:selected':\n highlightFeature(null);\n pendingSelectUpn = null;\n break;\n case 'set:basemap':\n if (msg.key && typeof mapView.setBaseMap === 'function') {\n mapView.setBaseMap(msg.key);\n }\n break;\n }\n } catch (e) {\n emitError('COMMAND_FAILED', `Failed to handle ${msg.type}: ${e.message}`);\n }\n });\n\n /**\n * Find the parcel with the given UPN, highlight it, fit the view to it,\n * and emit a synthesized parcel:select so the host receives the metadata.\n * If the parcels haven't finished loading yet, the UPN is queued and the\n * lookup is retried as features stream in.\n */\n function selectByUpn(upn) {\n if (!parcelsLayer) { pendingSelectUpn = upn; return; }\n const features = parcelsLayer.getSource().getFeatures();\n const feature = features.find((f) => String(f.get('upn') ?? '') === upn);\n if (!feature) { pendingSelectUpn = upn; return; }\n\n pendingSelectUpn = null;\n highlightFeature(feature);\n const ext = feature.getGeometry()?.getExtent();\n if (ext) {\n map.getView().fit(ext, { padding: [50, 50, 50, 50], duration: 400, maxZoom: 17 });\n }\n send(parcelPayload(feature, null, null));\n }\n\n // -------------------------------------------------------------------------\n // Parcels attached → emit `ready`, drain any pending set:selected\n // -------------------------------------------------------------------------\n function attachParcelsLayer(layer) {\n parcelsLayer = layer;\n const source = layer.getSource();\n\n const drain = () => {\n // Microtask hop so a batch addFeatures() finishes before we react.\n queueMicrotask(() => {\n if (pendingSelectUpn) selectByUpn(pendingSelectUpn);\n emitReady();\n });\n };\n\n if (source.getFeatures().length > 0) {\n drain();\n } else {\n // Stay subscribed: parcels may arrive in waves (cache then API refresh),\n // and a pending UPN may only resolve after the second wave.\n let scheduled = false;\n source.on('addfeature', () => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n if (pendingSelectUpn) selectByUpn(pendingSelectUpn);\n emitReady();\n });\n });\n }\n }\n\n // -------------------------------------------------------------------------\n // Apply initial config: basemap + view (UPN is handled after parcels load)\n // -------------------------------------------------------------------------\n if (embedConfig?.basemap && typeof mapView.setBaseMap === 'function') {\n mapView.setBaseMap(embedConfig.basemap);\n }\n if (typeof embedConfig?.lon === 'number' && typeof embedConfig?.lat === 'number') {\n const view = map.getView();\n view.setCenter(fromLonLat([embedConfig.lon, embedConfig.lat]));\n view.setZoom(typeof embedConfig?.zoom === 'number' ? embedConfig.zoom : 15);\n }\n\n return { attachParcelsLayer, emitError };\n}\n","/**\n * Target-type auto-detect + field auto-mapping for imported FeatureCollections.\n *\n * Pure helpers — no DOM, no map, no DB. The mapping modal calls these once\n * after the file has been parsed to seed its initial state, and re-uses them\n * whenever the user changes target type so the field map updates accordingly.\n *\n * Contract per LUPMIS2_Import_Upload_Design.docx §3.\n *\n * detectTargetType(fc) → 'parcels'|'collector_zones'|'osm_roads'\n * |'building_footprints'|'other'\n * autoMapFields(fc, targetType) → { [lupmisColumn]: sourceField | null }\n * TARGET_TYPES → metadata used by the modal dropdown\n * TARGET_FIELDS[targetType] → ordered list of LUPMIS2 columns the\n * upload payload must populate\n */\n\n// ---------------------------------------------------------------------------\n// Target-type registry\n// ---------------------------------------------------------------------------\n\nexport const TARGET_TYPES = [\n { key: 'parcels', label: 'Parcels', geometryFamily: 'polygon' },\n { key: 'collector_zones', label: 'Collector Zones', geometryFamily: 'polygon' },\n { key: 'building_footprints', label: 'Building Footprints', geometryFamily: 'polygon' },\n { key: 'osm_roads', label: 'OSM Roads', geometryFamily: 'line' },\n { key: 'other', label: 'Other (view only)', geometryFamily: 'any' },\n];\n\n// LUPMIS2 column lists per target type, in the order the mapping modal\n// should display them. Subset of the typed-table schemas the user actually\n// edits — system columns (id, created_at, updated_at, fetched_at, status)\n// are NOT user-mapped.\nexport const TARGET_FIELDS = {\n parcels: [\n 'upn', 'landuse', 'zone_code', 'zone_name', 'sector', 'block',\n 'parcel_no', 'prop_no', 'st_name', 'prop_add', 'fac_name',\n 'min_height', 'max_height', 'eff_date', 'lp_name', 'locality',\n 'mmda', 'last_update', 'remarks',\n ],\n collector_zones: [\n 'zone_name',\n ],\n building_footprints: [\n // The remote table is a thin schema today; we leave room for the\n // database team to add columns later (the modal will accept more).\n ],\n osm_roads: [\n 'osm_id', 'name', 'highway',\n ],\n other: [],\n};\n\n// ---------------------------------------------------------------------------\n// Type-detect signals\n// ---------------------------------------------------------------------------\n\n/**\n * Inspect every feature's geometry type. We return the dominant family\n * because shapefiles can sometimes mix (rare but possible).\n *\n * @returns {'polygon'|'line'|'point'|'mixed'|'none'}\n */\nfunction dominantGeometryFamily(fc) {\n if (!fc?.features?.length) return 'none';\n let polys = 0, lines = 0, points = 0;\n for (const f of fc.features) {\n const t = f?.geometry?.type;\n if (!t) continue;\n if (t === 'Polygon' || t === 'MultiPolygon') polys++;\n else if (t === 'LineString' || t === 'MultiLineString') lines++;\n else if (t === 'Point' || t === 'MultiPoint') points++;\n }\n const total = polys + lines + points;\n if (total === 0) return 'none';\n const max = Math.max(polys, lines, points);\n if (max < total * 0.85) return 'mixed';\n if (polys === max) return 'polygon';\n if (lines === max) return 'line';\n return 'point';\n}\n\n/**\n * Build a normalised attribute-name set across the first N features (so\n * inconsistent rows don't skew detection).\n */\nfunction attributeFingerprint(fc, sampleSize = 50) {\n const set = new Set();\n const n = Math.min(sampleSize, fc.features.length);\n for (let i = 0; i < n; i++) {\n const props = fc.features[i]?.properties;\n if (!props || typeof props !== 'object') continue;\n for (const key of Object.keys(props)) {\n set.add(String(key).toLowerCase());\n }\n }\n return set;\n}\n\n/** Does the fingerprint contain at least one of the given candidates? */\nfunction has(fp, ...candidates) {\n for (const c of candidates) if (fp.has(c)) return true;\n return false;\n}\n\n/**\n * Suggest a target type based on geometry family + attribute fingerprint.\n * Conservative: returns 'other' whenever the signal isn't strong enough,\n * leaving the user to choose explicitly.\n */\nexport function detectTargetType(fc) {\n const family = dominantGeometryFamily(fc);\n if (family === 'none' || family === 'mixed') return 'other';\n const fp = attributeFingerprint(fc);\n\n if (family === 'line') {\n if (has(fp, 'osm_id', 'highway')) return 'osm_roads';\n return 'other';\n }\n\n if (family === 'polygon') {\n // Parcels are the most attribute-rich polygon: UPN is the strongest tell.\n if (has(fp, 'upn', 'parcel_no', 'landuse', 'lu_code', 'zone_code') &&\n // a single \"zone_name\" without UPN is more likely a zone overlay\n has(fp, 'upn', 'parcel_no', 'landuse', 'lu_code')) {\n return 'parcels';\n }\n if (has(fp, 'zone_name', 'colzonename', 'colzonenr')) return 'collector_zones';\n if (has(fp, 'building', 'building:levels', 'building_levels', 'height',\n 'min_height', 'max_height') &&\n !has(fp, 'upn', 'parcel_no')) {\n return 'building_footprints';\n }\n return 'other';\n }\n\n // Points have no upload target in the current design.\n return 'other';\n}\n\n// ---------------------------------------------------------------------------\n// Field auto-mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Per-LUPMIS2-column candidate source field names. Lower-case, ordered by\n * preference. Matching is case-insensitive and ignores spaces / underscores\n * / hyphens.\n */\nconst FIELD_CANDIDATES = {\n // Parcels (lu_parcels)\n upn: ['upn', 'unique_parcel_no', 'parcel_id', 'pid'],\n landuse: ['landuse', 'land_use', 'lu', 'lu_code'],\n zone_code: ['zone_code', 'zonecode', 'zone'],\n zone_name: ['zone_name', 'zonename', 'colzonename'],\n sector: ['sector', 'sec'],\n block: ['block', 'blk'],\n parcel_no: ['parcel_no', 'parcelno', 'plot_no', 'plotno'],\n prop_no: ['prop_no', 'propertyno', 'property_no'],\n st_name: ['st_name', 'street', 'street_name', 'road'],\n prop_add: ['prop_add', 'address', 'addr'],\n fac_name: ['fac_name', 'facility', 'facilityname'],\n min_height: ['min_height', 'minheight', 'h_min'],\n max_height: ['max_height', 'maxheight', 'h_max', 'height'],\n eff_date: ['eff_date', 'effectivedate', 'effdate'],\n lp_name: ['lp_name', 'lpname', 'localplan'],\n locality: ['locality', 'town', 'settlement'],\n mmda: ['mmda', 'district', 'assembly'],\n last_update:['last_update', 'lastupdate', 'updated'],\n remarks: ['remarks', 'notes', 'comments'],\n\n // OSM roads\n osm_id: ['osm_id', 'osmid', 'id'],\n name: ['name', 'street_name', 'st_name'],\n highway: ['highway', 'road_class', 'class'],\n};\n\n/** Normalise a field name for matching (lowercase, strip _ - and spaces). */\nfunction normaliseKey(s) {\n return String(s).toLowerCase().replace(/[\\s_\\-]+/g, '');\n}\n\n/**\n * Suggest a source-field → LUPMIS2-column mapping for the given target type.\n * Unmapped columns get null so the modal can show \"(none)\" and let the user\n * pick from a dropdown of available source fields.\n *\n * @param {Object} fc — parsed FeatureCollection\n * @param {string} targetType — one of TARGET_TYPES keys\n * @returns {Object} { [lupmisColumn]: sourceField|null }\n */\nexport function autoMapFields(fc, targetType) {\n const columns = TARGET_FIELDS[targetType] || [];\n if (columns.length === 0) return {};\n\n const fp = attributeFingerprint(fc, 50);\n // Build normalised → original lookup for available source fields\n const sourceByNorm = new Map();\n for (const key of fp) {\n sourceByNorm.set(normaliseKey(key), key);\n }\n\n const mapping = {};\n for (const col of columns) {\n const candidates = FIELD_CANDIDATES[col] || [col];\n let matched = null;\n for (const cand of candidates) {\n const n = normaliseKey(cand);\n if (sourceByNorm.has(n)) {\n matched = sourceByNorm.get(n);\n break;\n }\n }\n mapping[col] = matched;\n }\n return mapping;\n}\n\n/**\n * Apply a mapping to one source-feature properties object and return the\n * LUPMIS2-shaped properties (column-name keys). Source fields not in the\n * mapping are dropped. Used during the staging-row insert.\n */\nexport function applyFieldMapping(sourceProps, mapping) {\n const out = {};\n for (const [targetCol, sourceKey] of Object.entries(mapping || {})) {\n if (sourceKey == null) continue;\n if (sourceProps && Object.prototype.hasOwnProperty.call(sourceProps, sourceKey)) {\n out[targetCol] = sourceProps[sourceKey];\n }\n }\n return out;\n}\n\n/**\n * Return the list of distinct source-property names (the union across all\n * features), preserving discovery order — used to populate the per-column\n * dropdown in the mapping modal.\n */\nexport function listSourceFields(fc) {\n const seen = new Map();\n for (const f of fc.features || []) {\n const props = f?.properties;\n if (!props || typeof props !== 'object') continue;\n for (const k of Object.keys(props)) {\n if (!seen.has(k)) seen.set(k, true);\n }\n }\n return Array.from(seen.keys());\n}\n","/**\n * Import-mapping modal controller.\n *\n * openImportMappingModal({ importId, filename, fc, onResult })\n *\n * Populates the modal from the parsed FeatureCollection, lets the user pick\n * a target type and adjust the field map, then calls onResult with one of:\n *\n * { action: 'cancel' } — keep as Other / view only\n * { action: 'save', targetType, mapping }\n * { action: 'upload', targetType, mapping }\n *\n * The caller is responsible for updating external_imports + the staged\n * features (this module knows nothing about the DB or the map).\n *\n * See LUPMIS2_Import_Upload_Design.docx §3.1.\n */\n\nimport { Modal } from 'bootstrap';\nimport {\n TARGET_TYPES,\n TARGET_FIELDS,\n detectTargetType,\n autoMapFields,\n listSourceFields,\n} from './import-detect.js';\n\nconst els = {}; // cached DOM lookups\nlet modal = null;\nlet state = null; // { importId, filename, fc, sourceFields, mapping, targetType, onResult }\n\nfunction cacheEls() {\n if (els.root) return;\n els.root = document.getElementById('importMappingModal');\n els.filename = document.getElementById('import-modal-filename');\n els.summary = document.getElementById('import-modal-summary');\n els.target = document.getElementById('import-modal-target');\n els.targetHint = document.getElementById('import-modal-target-hint');\n els.fieldsWrap = document.getElementById('import-modal-fields-wrap');\n els.tbody = document.getElementById('import-modal-fields-tbody');\n els.btnSave = document.getElementById('import-modal-save');\n els.btnSaveUpload = document.getElementById('import-modal-save-upload');\n els.btnCancel = document.getElementById('import-modal-cancel');\n\n // Populate the target-type dropdown once.\n if (els.target && !els.target.dataset.populated) {\n els.target.innerHTML = TARGET_TYPES\n .map((t) => ``)\n .join('');\n els.target.dataset.populated = '1';\n }\n\n // Event wiring (idempotent).\n if (els.target && !els.target.dataset.wired) {\n els.target.dataset.wired = '1';\n els.target.addEventListener('change', onTargetChange);\n }\n if (els.btnSave && !els.btnSave.dataset.wired) {\n els.btnSave.dataset.wired = '1';\n els.btnSave.addEventListener('click', () => finish('save'));\n }\n if (els.btnSaveUpload && !els.btnSaveUpload.dataset.wired) {\n els.btnSaveUpload.dataset.wired = '1';\n els.btnSaveUpload.addEventListener('click', () => finish('upload'));\n }\n // Cancel uses Bootstrap's data-bs-dismiss; we hook the hidden event so\n // closing via × / ESC / Cancel all behave the same: a 'cancel' result.\n if (els.root && !els.root.dataset.wired) {\n els.root.dataset.wired = '1';\n els.root.addEventListener('hidden.bs.modal', () => {\n if (state?.onResult && !state._resolved) {\n state._resolved = true;\n state.onResult({ action: 'cancel' });\n }\n state = null;\n });\n }\n}\n\n/** Render the field-mapping table for the current targetType. */\nfunction renderFieldsTable() {\n const targetType = state.targetType;\n const columns = TARGET_FIELDS[targetType] || [];\n\n // \"Other (view only)\" → no fields to map.\n if (targetType === 'other' || columns.length === 0) {\n els.fieldsWrap.style.display = 'none';\n return;\n }\n els.fieldsWrap.style.display = '';\n\n const optionsHtml = ['']\n .concat(state.sourceFields.map((s) =>\n ``))\n .join('');\n\n els.tbody.innerHTML = columns.map((col) => {\n const current = state.mapping[col] || '';\n const select = optionsHtml.replace(\n `