tempest-react-sdk 0.14.0 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -17,7 +17,7 @@
17
17
 
18
18
  > 💡 `pip install -r docs/requirements.txt && mkdocs serve` é só para preview local — em produção use as URLs do GitHub Pages acima. / For local preview only — in production use the GitHub Pages URLs above.
19
19
 
20
- Shared React/TypeScript building blocks used across Tempest frontends: UI components, hooks, HTTP client, auth store, query keys, forms (zod), real-time transports (SSE / WebSocket / Web Push / Service Worker), theme, i18n, telemetry, feature flags, offline storage, error boundary, and a curated set of utilities (`cn`, `formatCurrency`, `formatCPF`, etc.).
20
+ Shared React/TypeScript building blocks used across Tempest frontends: UI components, hooks, HTTP client, auth store, query keys, forms (zod), real-time transports (SSE / WebSocket / Web Push / Service Worker), self-hosted geolocation (tile-free maps, trajectory tracking, distance/estimate math), theme, i18n, telemetry, feature flags, offline storage, error boundary, and a curated set of utilities (`cn`, `formatCurrency`, `formatCPF`, etc.).
21
21
 
22
22
  The goal is to start every new React frontend with the same opinionated foundation already in place — no copy-pasting `Button`/`Input` styles, no rewriting the same auth Zustand store, no re-inventing the SSE reconnect loop. The patterns here are a distillation of what was consolidated in **alofans-frontend** and **transport-admin-system** — apps that consume the SDK gain consistency without paying for boilerplate.
23
23
 
@@ -207,6 +207,7 @@ Every module is re-exported from the package root — `import { Button, useDebou
207
207
  | `forms` _(peer: `zod`, `react-hook-form`)_ | `validateForm`, `zodResolver`, `useZodForm`, `validateCPF`, `validateCNPJ`, `formatCEP`, `formatCNPJ`, `unmask`, `CPFInput`, `CNPJInput`, `PhoneInput`, `CEPInput`, `MoneyInput`, `useViaCEP` |
208
208
  | `sse` | `createEventStream`, `useEventStream` |
209
209
  | `ws` | `createWebSocket`, `useWebSocket` |
210
+ | `geo` _(opt. peer `leaflet`)_ | `haversineKm`, `pathLengthKm`, `bearingDeg`, `estimateTravel`, `createOSRMBackend`, `boundingBox`, `projectMercator`, `fitProjection`, `createPositionTracker`, `usePositionTracker`, `TrajectoryMap` — tile-free SVG map + trajectory tracking (no external/paid API; Leaflet is an opt-in, lazy-loaded tile layer for self-hosted tiles), types: `Coordinate`, `TrackPoint`, `TravelEstimate`, `TravelMode`, `GeoBounds`, `RoutingBackend` |
210
211
  | `push` | `WebPushClient`, `WebPushUnsupportedError`, `WebPushPermissionDeniedError`, `usePushSubscription`, `urlBase64ToUint8Array`, `isPushSupported` |
211
212
  | `sw` _(also subpath `tempest-react-sdk/sw`)_ | `registerServiceWorker`, `skipWaiting`, `unregisterAllServiceWorkers`, `installPushHandler`, `installNotificationClickHandler`, `installSkipWaitingListener`, `installPrecache` (app-shell offline), `installRuntimeCache` (per-route caching, incl. `rangeRequests`), `createPartialResponse` (206 range slicing), `installBackgroundSync` (offline mutation queue) — the React-free `tempest-react-sdk/sw` subpath is ideal for bundling into your own `sw.ts` |
212
213
  | `charts` _(subpath `tempest-react-sdk/charts`, opt. peer `recharts`)_ | `AreaChart`, `BarChart`, `LineChart`, `PieChart`, `RadarChart`, `DEFAULT_CHART_COLORS` — themed recharts wrappers (recharts externalized; install it only if you use charts) |
@@ -235,6 +236,7 @@ Every module is re-exported from the package root — `import { Button, useDebou
235
236
  | `forms` _(peer: `zod`, `react-hook-form`)_ | `validateForm`, `zodResolver`, `useZodForm`, `validateCPF`, `validateCNPJ`, `formatCEP`, `formatCNPJ`, `unmask`, `CPFInput`, `CNPJInput`, `PhoneInput`, `CEPInput`, `MoneyInput`, `useViaCEP` |
236
237
  | `sse` | `createEventStream`, `useEventStream` |
237
238
  | `ws` | `createWebSocket`, `useWebSocket` |
239
+ | `geo` _(opt. peer `leaflet`)_ | `haversineKm`, `pathLengthKm`, `bearingDeg`, `estimateTravel`, `createOSRMBackend`, `boundingBox`, `projectMercator`, `fitProjection`, `createPositionTracker`, `usePositionTracker`, `TrajectoryMap` — tile-free SVG map + trajectory tracking (no external/paid API; Leaflet is an opt-in, lazy-loaded tile layer for self-hosted tiles), types: `Coordinate`, `TrackPoint`, `TravelEstimate`, `TravelMode`, `GeoBounds`, `RoutingBackend` |
238
240
  | `push` | `WebPushClient`, `WebPushUnsupportedError`, `WebPushPermissionDeniedError`, `usePushSubscription`, `urlBase64ToUint8Array`, `isPushSupported` |
239
241
  | `sw` _(also subpath `tempest-react-sdk/sw`)_ | `registerServiceWorker`, `skipWaiting`, `unregisterAllServiceWorkers`, `installPushHandler`, `installNotificationClickHandler`, `installSkipWaitingListener`, `installPrecache` (app-shell offline), `installRuntimeCache` (per-route caching, incl. `rangeRequests`), `createPartialResponse` (206 range slicing), `installBackgroundSync` (offline mutation queue) — the React-free `tempest-react-sdk/sw` subpath is ideal for bundling into your own `sw.ts` |
240
242
  | `editor` _(subpath `tempest-react-sdk/editor`, opt. peers `@tiptap/react`+`@tiptap/starter-kit`)_ | `RichTextEditor` — themed tiptap v3 rich-text editor with toolbar (tiptap externalized; install it only if you use the editor) |
@@ -0,0 +1,51 @@
1
+ import { jsx as p } from "react/jsx-runtime";
2
+ import { useRef as L, useState as x, useEffect as b } from "react";
3
+ import { boundingBox as v } from "./tempest-react-sdk.js";
4
+ function j({
5
+ points: t,
6
+ current: o,
7
+ tileUrl: f,
8
+ tileAttribution: c,
9
+ strokeColor: i
10
+ }) {
11
+ const l = L(null), [s, h] = x(null);
12
+ return b(() => {
13
+ let e = null, n = !1;
14
+ return import("leaflet").then((m) => {
15
+ if (n || !l.current) return;
16
+ const r = m.default ?? m;
17
+ e = r.map(l.current, { attributionControl: !0 }), r.tileLayer(f, {
18
+ attribution: c ?? "",
19
+ maxZoom: 19
20
+ }).addTo(e);
21
+ const d = t.map((g) => [g.latitude, g.longitude]);
22
+ d.length > 0 && (r.polyline(d, {
23
+ color: i ?? "#2563eb",
24
+ weight: 4
25
+ }).addTo(e), r.circleMarker(d[0], { radius: 6, color: "#16a34a" }).addTo(e));
26
+ const u = o ?? t[t.length - 1];
27
+ u && r.circleMarker([u.latitude, u.longitude], {
28
+ radius: 6,
29
+ color: i ?? "#2563eb"
30
+ }).addTo(e);
31
+ const a = v(o ? [...t, o] : [...t]);
32
+ a ? e.fitBounds(
33
+ [
34
+ [a.minLatitude, a.minLongitude],
35
+ [a.maxLatitude, a.maxLongitude]
36
+ ],
37
+ { padding: [24, 24] }
38
+ ) : e.setView([0, 0], 2);
39
+ }).catch(() => {
40
+ n || h(
41
+ "Leaflet não encontrado. Instale `leaflet` para usar tiles, ou remova `tileUrl` para o plot SVG."
42
+ );
43
+ }), () => {
44
+ n = !0, e?.remove();
45
+ };
46
+ }, [t, o, f, c, i]), s ? /* @__PURE__ */ p("div", { style: { padding: 16, fontSize: 13, color: "var(--tempest-danger-fg)" }, children: s }) : /* @__PURE__ */ p("div", { ref: l, style: { width: "100%", height: "100%" } });
47
+ }
48
+ export {
49
+ j as LeafletTrajectory
50
+ };
51
+ //# sourceMappingURL=leaflet-map-BHBcL_7k.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaflet-map-BHBcL_7k.js","sources":["../src/geo/leaflet-map.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { boundingBox } from \"./bounds\";\nimport type { Coordinate } from \"./types\";\n\n/**\n * Minimal structural typing for the slice of the Leaflet API this layer uses.\n * Declared locally so the SDK type-checks and builds even when `leaflet` (an\n * optional peer) is not installed — the real module is loaded at runtime.\n */\ninterface LeafletMapInstance {\n setView: (center: [number, number], zoom: number) => LeafletMapInstance;\n fitBounds: (bounds: [[number, number], [number, number]], options?: unknown) => void;\n remove: () => void;\n}\ninterface LeafletLayer {\n addTo: (map: LeafletMapInstance) => LeafletLayer;\n}\ninterface LeafletModule {\n map: (el: HTMLElement, options?: unknown) => LeafletMapInstance;\n tileLayer: (url: string, options?: unknown) => LeafletLayer;\n polyline: (latlngs: [number, number][], options?: unknown) => LeafletLayer;\n circleMarker: (latlng: [number, number], options?: unknown) => LeafletLayer;\n}\n\nexport interface LeafletTrajectoryProps {\n points: readonly Coordinate[];\n current?: Coordinate | null;\n tileUrl: string;\n tileAttribution?: string;\n strokeColor?: string;\n}\n\n/**\n * Leaflet-backed tile layer for {@link TrajectoryMap}. Loaded lazily and only\n * when a `tileUrl` is provided. Requires `leaflet` to be installed by the app\n * (optional peer dependency) plus its stylesheet imported once:\n * `import \"leaflet/dist/leaflet.css\"`.\n */\nexport function LeafletTrajectory({\n points,\n current,\n tileUrl,\n tileAttribution,\n strokeColor,\n}: LeafletTrajectoryProps) {\n const nodeRef = useRef<HTMLDivElement>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let map: LeafletMapInstance | null = null;\n let cancelled = false;\n\n const specifier = \"leaflet\";\n import(/* @vite-ignore */ specifier)\n .then((mod: { default?: LeafletModule } & LeafletModule) => {\n if (cancelled || !nodeRef.current) return;\n const L: LeafletModule = mod.default ?? mod;\n\n map = L.map(nodeRef.current, { attributionControl: true });\n L.tileLayer(tileUrl, {\n attribution: tileAttribution ?? \"\",\n maxZoom: 19,\n }).addTo(map);\n\n const latlngs = points.map((p): [number, number] => [p.latitude, p.longitude]);\n if (latlngs.length > 0) {\n L.polyline(latlngs, {\n color: strokeColor ?? \"#2563eb\",\n weight: 4,\n }).addTo(map);\n L.circleMarker(latlngs[0], { radius: 6, color: \"#16a34a\" }).addTo(map);\n }\n\n const marker = current ?? points[points.length - 1];\n if (marker) {\n L.circleMarker([marker.latitude, marker.longitude], {\n radius: 6,\n color: strokeColor ?? \"#2563eb\",\n }).addTo(map);\n }\n\n const box = boundingBox(current ? [...points, current] : [...points]);\n if (box) {\n map.fitBounds(\n [\n [box.minLatitude, box.minLongitude],\n [box.maxLatitude, box.maxLongitude],\n ],\n { padding: [24, 24] },\n );\n } else {\n map.setView([0, 0], 2);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setError(\n \"Leaflet não encontrado. Instale `leaflet` para usar tiles, ou remova `tileUrl` para o plot SVG.\",\n );\n }\n });\n\n return () => {\n cancelled = true;\n map?.remove();\n };\n }, [points, current, tileUrl, tileAttribution, strokeColor]);\n\n if (error) {\n return (\n <div style={{ padding: 16, fontSize: 13, color: \"var(--tempest-danger-fg)\" }}>\n {error}\n </div>\n );\n }\n\n return <div ref={nodeRef} style={{ width: \"100%\", height: \"100%\" }} />;\n}\n"],"names":["LeafletTrajectory","points","current","tileUrl","tileAttribution","strokeColor","nodeRef","useRef","error","setError","useState","useEffect","map","cancelled","mod","L","latlngs","p","marker","box","boundingBox","jsx"],"mappings":";;;AAsCO,SAASA,EAAkB;AAAA,EAC9B,QAAAC;AAAA,EACA,SAAAC;AAAA,EACA,SAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,aAAAC;AACJ,GAA2B;AACvB,QAAMC,IAAUC,EAAuB,IAAI,GACrC,CAACC,GAAOC,CAAQ,IAAIC,EAAwB,IAAI;AA8DtD,SA5DAC,EAAU,MAAM;AACZ,QAAIC,IAAiC,MACjCC,IAAY;AAGhB,kBADkB,WAEb,KAAK,CAACC,MAAqD;AACxD,UAAID,KAAa,CAACP,EAAQ,QAAS;AACnC,YAAMS,IAAmBD,EAAI,WAAWA;AAExC,MAAAF,IAAMG,EAAE,IAAIT,EAAQ,SAAS,EAAE,oBAAoB,IAAM,GACzDS,EAAE,UAAUZ,GAAS;AAAA,QACjB,aAAaC,KAAmB;AAAA,QAChC,SAAS;AAAA,MAAA,CACZ,EAAE,MAAMQ,CAAG;AAEZ,YAAMI,IAAUf,EAAO,IAAI,CAACgB,MAAwB,CAACA,EAAE,UAAUA,EAAE,SAAS,CAAC;AAC7E,MAAID,EAAQ,SAAS,MACjBD,EAAE,SAASC,GAAS;AAAA,QAChB,OAAOX,KAAe;AAAA,QACtB,QAAQ;AAAA,MAAA,CACX,EAAE,MAAMO,CAAG,GACZG,EAAE,aAAaC,EAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,UAAA,CAAW,EAAE,MAAMJ,CAAG;AAGzE,YAAMM,IAAShB,KAAWD,EAAOA,EAAO,SAAS,CAAC;AAClD,MAAIiB,KACAH,EAAE,aAAa,CAACG,EAAO,UAAUA,EAAO,SAAS,GAAG;AAAA,QAChD,QAAQ;AAAA,QACR,OAAOb,KAAe;AAAA,MAAA,CACzB,EAAE,MAAMO,CAAG;AAGhB,YAAMO,IAAMC,EAAYlB,IAAU,CAAC,GAAGD,GAAQC,CAAO,IAAI,CAAC,GAAGD,CAAM,CAAC;AACpE,MAAIkB,IACAP,EAAI;AAAA,QACA;AAAA,UACI,CAACO,EAAI,aAAaA,EAAI,YAAY;AAAA,UAClC,CAACA,EAAI,aAAaA,EAAI,YAAY;AAAA,QAAA;AAAA,QAEtC,EAAE,SAAS,CAAC,IAAI,EAAE,EAAA;AAAA,MAAE,IAGxBP,EAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;AAAA,IAE7B,CAAC,EACA,MAAM,MAAM;AACT,MAAKC,KACDJ;AAAA,QACI;AAAA,MAAA;AAAA,IAGZ,CAAC,GAEE,MAAM;AACT,MAAAI,IAAY,IACZD,GAAK,OAAA;AAAA,IACT;AAAA,EACJ,GAAG,CAACX,GAAQC,GAASC,GAASC,GAAiBC,CAAW,CAAC,GAEvDG,IAEI,gBAAAa,EAAC,OAAA,EAAI,OAAO,EAAE,SAAS,IAAI,UAAU,IAAI,OAAO,2BAAA,GAC3C,UAAAb,EAAA,CACL,IAID,gBAAAa,EAAC,OAAA,EAAI,KAAKf,GAAS,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAA,EAAO,CAAG;AACxE;"}
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const p=require("react/jsx-runtime"),c=require("react"),x=require("./tempest-react-sdk.cjs");function y({points:t,current:i,tileUrl:s,tileAttribution:f,strokeColor:l}){const o=c.useRef(null),[g,L]=c.useState(null);return c.useEffect(()=>{let e=null,n=!1;return import("leaflet").then(m=>{if(n||!o.current)return;const r=m.default??m;e=r.map(o.current,{attributionControl:!0}),r.tileLayer(s,{attribution:f??"",maxZoom:19}).addTo(e);const d=t.map(h=>[h.latitude,h.longitude]);d.length>0&&(r.polyline(d,{color:l??"#2563eb",weight:4}).addTo(e),r.circleMarker(d[0],{radius:6,color:"#16a34a"}).addTo(e));const u=i??t[t.length-1];u&&r.circleMarker([u.latitude,u.longitude],{radius:6,color:l??"#2563eb"}).addTo(e);const a=x.boundingBox(i?[...t,i]:[...t]);a?e.fitBounds([[a.minLatitude,a.minLongitude],[a.maxLatitude,a.maxLongitude]],{padding:[24,24]}):e.setView([0,0],2)}).catch(()=>{n||L("Leaflet não encontrado. Instale `leaflet` para usar tiles, ou remova `tileUrl` para o plot SVG.")}),()=>{n=!0,e?.remove()}},[t,i,s,f,l]),g?p.jsx("div",{style:{padding:16,fontSize:13,color:"var(--tempest-danger-fg)"},children:g}):p.jsx("div",{ref:o,style:{width:"100%",height:"100%"}})}exports.LeafletTrajectory=y;
2
+ //# sourceMappingURL=leaflet-map-BzYV9czG.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaflet-map-BzYV9czG.cjs","sources":["../src/geo/leaflet-map.tsx"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { boundingBox } from \"./bounds\";\nimport type { Coordinate } from \"./types\";\n\n/**\n * Minimal structural typing for the slice of the Leaflet API this layer uses.\n * Declared locally so the SDK type-checks and builds even when `leaflet` (an\n * optional peer) is not installed — the real module is loaded at runtime.\n */\ninterface LeafletMapInstance {\n setView: (center: [number, number], zoom: number) => LeafletMapInstance;\n fitBounds: (bounds: [[number, number], [number, number]], options?: unknown) => void;\n remove: () => void;\n}\ninterface LeafletLayer {\n addTo: (map: LeafletMapInstance) => LeafletLayer;\n}\ninterface LeafletModule {\n map: (el: HTMLElement, options?: unknown) => LeafletMapInstance;\n tileLayer: (url: string, options?: unknown) => LeafletLayer;\n polyline: (latlngs: [number, number][], options?: unknown) => LeafletLayer;\n circleMarker: (latlng: [number, number], options?: unknown) => LeafletLayer;\n}\n\nexport interface LeafletTrajectoryProps {\n points: readonly Coordinate[];\n current?: Coordinate | null;\n tileUrl: string;\n tileAttribution?: string;\n strokeColor?: string;\n}\n\n/**\n * Leaflet-backed tile layer for {@link TrajectoryMap}. Loaded lazily and only\n * when a `tileUrl` is provided. Requires `leaflet` to be installed by the app\n * (optional peer dependency) plus its stylesheet imported once:\n * `import \"leaflet/dist/leaflet.css\"`.\n */\nexport function LeafletTrajectory({\n points,\n current,\n tileUrl,\n tileAttribution,\n strokeColor,\n}: LeafletTrajectoryProps) {\n const nodeRef = useRef<HTMLDivElement>(null);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let map: LeafletMapInstance | null = null;\n let cancelled = false;\n\n const specifier = \"leaflet\";\n import(/* @vite-ignore */ specifier)\n .then((mod: { default?: LeafletModule } & LeafletModule) => {\n if (cancelled || !nodeRef.current) return;\n const L: LeafletModule = mod.default ?? mod;\n\n map = L.map(nodeRef.current, { attributionControl: true });\n L.tileLayer(tileUrl, {\n attribution: tileAttribution ?? \"\",\n maxZoom: 19,\n }).addTo(map);\n\n const latlngs = points.map((p): [number, number] => [p.latitude, p.longitude]);\n if (latlngs.length > 0) {\n L.polyline(latlngs, {\n color: strokeColor ?? \"#2563eb\",\n weight: 4,\n }).addTo(map);\n L.circleMarker(latlngs[0], { radius: 6, color: \"#16a34a\" }).addTo(map);\n }\n\n const marker = current ?? points[points.length - 1];\n if (marker) {\n L.circleMarker([marker.latitude, marker.longitude], {\n radius: 6,\n color: strokeColor ?? \"#2563eb\",\n }).addTo(map);\n }\n\n const box = boundingBox(current ? [...points, current] : [...points]);\n if (box) {\n map.fitBounds(\n [\n [box.minLatitude, box.minLongitude],\n [box.maxLatitude, box.maxLongitude],\n ],\n { padding: [24, 24] },\n );\n } else {\n map.setView([0, 0], 2);\n }\n })\n .catch(() => {\n if (!cancelled) {\n setError(\n \"Leaflet não encontrado. Instale `leaflet` para usar tiles, ou remova `tileUrl` para o plot SVG.\",\n );\n }\n });\n\n return () => {\n cancelled = true;\n map?.remove();\n };\n }, [points, current, tileUrl, tileAttribution, strokeColor]);\n\n if (error) {\n return (\n <div style={{ padding: 16, fontSize: 13, color: \"var(--tempest-danger-fg)\" }}>\n {error}\n </div>\n );\n }\n\n return <div ref={nodeRef} style={{ width: \"100%\", height: \"100%\" }} />;\n}\n"],"names":["LeafletTrajectory","points","current","tileUrl","tileAttribution","strokeColor","nodeRef","useRef","error","setError","useState","useEffect","map","cancelled","mod","L","latlngs","p","marker","box","boundingBox","jsx"],"mappings":"6KAsCO,SAASA,EAAkB,CAC9B,OAAAC,EACA,QAAAC,EACA,QAAAC,EACA,gBAAAC,EACA,YAAAC,CACJ,EAA2B,CACvB,MAAMC,EAAUC,EAAAA,OAAuB,IAAI,EACrC,CAACC,EAAOC,CAAQ,EAAIC,EAAAA,SAAwB,IAAI,EA8DtD,OA5DAC,EAAAA,UAAU,IAAM,CACZ,IAAIC,EAAiC,KACjCC,EAAY,GAGhB,cADkB,WAEb,KAAMC,GAAqD,CACxD,GAAID,GAAa,CAACP,EAAQ,QAAS,OACnC,MAAMS,EAAmBD,EAAI,SAAWA,EAExCF,EAAMG,EAAE,IAAIT,EAAQ,QAAS,CAAE,mBAAoB,GAAM,EACzDS,EAAE,UAAUZ,EAAS,CACjB,YAAaC,GAAmB,GAChC,QAAS,EAAA,CACZ,EAAE,MAAMQ,CAAG,EAEZ,MAAMI,EAAUf,EAAO,IAAKgB,GAAwB,CAACA,EAAE,SAAUA,EAAE,SAAS,CAAC,EACzED,EAAQ,OAAS,IACjBD,EAAE,SAASC,EAAS,CAChB,MAAOX,GAAe,UACtB,OAAQ,CAAA,CACX,EAAE,MAAMO,CAAG,EACZG,EAAE,aAAaC,EAAQ,CAAC,EAAG,CAAE,OAAQ,EAAG,MAAO,SAAA,CAAW,EAAE,MAAMJ,CAAG,GAGzE,MAAMM,EAAShB,GAAWD,EAAOA,EAAO,OAAS,CAAC,EAC9CiB,GACAH,EAAE,aAAa,CAACG,EAAO,SAAUA,EAAO,SAAS,EAAG,CAChD,OAAQ,EACR,MAAOb,GAAe,SAAA,CACzB,EAAE,MAAMO,CAAG,EAGhB,MAAMO,EAAMC,cAAYlB,EAAU,CAAC,GAAGD,EAAQC,CAAO,EAAI,CAAC,GAAGD,CAAM,CAAC,EAChEkB,EACAP,EAAI,UACA,CACI,CAACO,EAAI,YAAaA,EAAI,YAAY,EAClC,CAACA,EAAI,YAAaA,EAAI,YAAY,CAAA,EAEtC,CAAE,QAAS,CAAC,GAAI,EAAE,CAAA,CAAE,EAGxBP,EAAI,QAAQ,CAAC,EAAG,CAAC,EAAG,CAAC,CAE7B,CAAC,EACA,MAAM,IAAM,CACJC,GACDJ,EACI,iGAAA,CAGZ,CAAC,EAEE,IAAM,CACTI,EAAY,GACZD,GAAK,OAAA,CACT,CACJ,EAAG,CAACX,EAAQC,EAASC,EAASC,EAAiBC,CAAW,CAAC,EAEvDG,EAEIa,EAAAA,IAAC,MAAA,CAAI,MAAO,CAAE,QAAS,GAAI,SAAU,GAAI,MAAO,0BAAA,EAC3C,SAAAb,CAAA,CACL,EAIDa,MAAC,MAAA,CAAI,IAAKf,EAAS,MAAO,CAAE,MAAO,OAAQ,OAAQ,MAAA,CAAO,CAAG,CACxE"}