diff --git a/CHANGELOG.md b/CHANGELOG.md index c29811efa..1ae57b8e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ All notable changes to Bambuddy will be documented in this file. ## [0.2.4b2] - Unreleased +### Added +- **Filament Track Switch (FTS) support — print modal filament dropdown is no longer empty when an X2D / H2D has the FTS accessory installed** ([#1162](https://github.com/maziggy/bambuddy/issues/1162), reported by @mkavalecz) — When the FTS accessory is installed the printer's MQTT changes one nibble of the per-AMS `info` bitmask: bits 8-11 flip from a fixed extruder ID (0x0 / 0x1) to `0xE` ("uninitialized"), because the AMS is no longer wired to a single nozzle — the FTS dynamically routes any slot to either extruder. Bambuddy's MQTT parser already skipped 0xE entries when building `ams_extruder_map` (matching BambuStudio's reading for boot-time transient state), so with the FTS installed the map ended up empty and the print modal's filament dropdown — which filters by `extruderId === nozzle_id` to prevent cross-nozzle assignment ("position of left hotend is abnormal" failures) — filtered out *every* loaded slot. Net effect: empty Filament Mapping dropdown on every dual-nozzle print with the FTS, even when the AMS was fully loaded with the right material. Detection comes from a new MQTT field — `print.device.fila_switch` — which is non-null only when the accessory is installed; it carries the routing topology as two arrays: `in[track] = currently fed slot (-1 = empty)` and `out[track] = extruder this track terminates at`. The fix surfaces this through a new `FilaSwitchState` dataclass on `PrinterState` (`installed`, `in_slots`, `out_extruders`, `stat`, `info`) and the equivalent `FilaSwitchResponse` Pydantic schema on the `GET /printers/{id}/status` route. Frontend (`useFilamentMapping.ts` + `FilamentMapping.tsx`) skips the per-extruder filter when `printerStatus.fila_switch?.installed === true` so any compatible AMS slot can satisfy any nozzle's filament requirement, since the FTS handles the routing. Slots currently fed into a track also get a routing badge in the dropdown — `[L]` or `[R]` — so the user can tell at a glance which slot the FTS is currently routing where (idle slots get no badge: they can be routed to either extruder on demand). The hard "no cross-nozzle assignment" filter on real dual-nozzle printers without the FTS stays untouched (still trips the same way it always has — `fila_switch == null` keeps the existing behaviour). 4 backend tests in `test_bambu_mqtt.py::TestFilamentTrackSwitchDetection` (default-not-installed, detect-from-MQTT-using-the-reporter's-bundle, no-fila_switch-field-stays-not-installed, missing-in-out-arrays-don't-crash) and 2 frontend tests in `useFilamentMapping.test.ts` (FTS-active drops the nozzle filter; explicit `fila_switch: null` keeps the filter applied). Upstream fila_switch payloads with anything other than the documented shape are tolerated — `installed` flips on the *presence* of the field, the routing arrays default to empty lists if missing, and the dropdown skips the badge for slots not currently in `in_slots`. + ### Fixed - **AMS slot configuration intermittently fails to reach the printer after several configs in a row** ([#1164](https://github.com/maziggy/bambuddy/issues/1164), reported by @RosdasHH) — Configuring AMS slots a handful of times (the reporter saw it almost every 6th change) would silently stop reaching the printer; ~1 minute later the filament colours on the printer would briefly jump between slots, then settle. Root cause was the zombie-session watchdog at `bambu_mqtt.py:861` introduced for [#887](https://github.com/maziggy/bambuddy/issues/887). When an `ams_filament_setting` response took >10 s (normal under load — concurrent K-profile fetches, busy printer, network jitter) the watchdog incremented an `_ams_cmd_unanswered` counter and zeroed `_last_ams_cmd_time` so it wouldn't re-trigger on the next status push. The bug: the response handler that reset the counter was guarded by `and self._last_ams_cmd_time > 0` — so when the late response *did* arrive (after the watchdog had already zeroed the timer), the counter stayed armed at 1. The next slow response on any `ams_filament_setting` command — possibly minutes or hours later, on an entirely unrelated config attempt — would take the counter to 2 and trigger `force_reconnect_stale_session()`. The user-visible symptoms match exactly: configs stop landing (because MQTT reconnects mid-publish, dropping the in-flight command and surfacing as `Cannot set AMS filament setting: not connected` if the user retries during the ~1 min reconnect window), then the queued state finally lands when the reconnect completes (the "filament colours jumping around" the reporter described). Fix is to drop the `_last_ams_cmd_time > 0` guard: any `ams_filament_setting` response — late or not — proves the channel is alive, so the counter must reset. Watchdog still trips on a real zombie session (no responses at all for two consecutive >10 s windows). Regression test in `test_bambu_mqtt.py::TestZombieSessionDetection::test_late_response_after_watchdog_clears_counter_issue_1164` simulates the exact sequence (watchdog fires → late response arrives → second slow response on a fresh command) and asserts the counter resets to 0 on the late response and the second command doesn't tip the threshold to 2. Other 10 zombie-detection tests still pass unchanged. diff --git a/README.md b/README.md index 2ef744578..fe05b953d 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Perfect for remote print farms, traveling makers, or accessing your home printer - Duplicate detection & full-text search - Photo attachments & failure analysis - Timelapse editor (trim, speed, music) with automatic AVI-to-MP4 conversion for P1-series printers, manual upload & remove -- Re-print to any connected printer with AMS mapping (auto-match or manual slot selection, multi-plate support, nozzle-aware matching for dual-nozzle H2D/H2D Pro) +- Re-print to any connected printer with AMS mapping (auto-match or manual slot selection, multi-plate support, nozzle-aware matching for dual-nozzle H2D/H2D Pro, **Filament Track Switch (FTS) support** — when the FTS accessory is installed the per-nozzle filter is suppressed since the FTS routes any AMS slot to either extruder) - Plate thumbnail browsing for multi-plate archives (hover to navigate between plates) - Archive comparison (side-by-side diff) - Tag management (rename/delete across all archives) diff --git a/backend/app/api/routes/printers.py b/backend/app/api/routes/printers.py index 4fc0e1552..abd96ff4c 100644 --- a/backend/app/api/routes/printers.py +++ b/backend/app/api/routes/printers.py @@ -19,6 +19,7 @@ from backend.app.schemas.printer import ( AmsLabelBody, AMSTray, AMSUnit, + FilaSwitchResponse, HMSErrorResponse, NozzleInfoResponse, NozzleRackSlot, @@ -635,6 +636,17 @@ async def get_printer_status( supports_drying=supports_drying(printer.model, state.firmware_version), current_archive_id=current_archive_id, current_plate_id=current_plate_id, + fila_switch=( + FilaSwitchResponse( + installed=state.fila_switch.installed, + in_slots=list(state.fila_switch.in_slots), + out_extruders=list(state.fila_switch.out_extruders), + stat=state.fila_switch.stat, + info=state.fila_switch.info, + ) + if state.fila_switch and state.fila_switch.installed + else None + ), ) diff --git a/backend/app/schemas/printer.py b/backend/app/schemas/printer.py index dc15d6463..f5a02a185 100644 --- a/backend/app/schemas/printer.py +++ b/backend/app/schemas/printer.py @@ -179,6 +179,24 @@ class AmsLabelBody(BaseModel): ams_serial: str = Field(default="", max_length=50) +class FilaSwitchResponse(BaseModel): + """Filament Track Switch (FTS) state — accessory that mediates AMS-to-extruder routing. + + When installed, the AMS info field reports bits 8-11 = 0xE (uninitialized) + because slots are dynamically routed via the FTS rather than tied to a + specific extruder. Frontend uses `installed` to suppress the per-extruder + slot filter in the print modal. See #1162. + """ + + installed: bool = False + # in[track] = currently loaded slot for that track (-1 = empty) + in_slots: list[int] = [] + # out[track] = extruder this track terminates at (0 = right, 1 = left) + out_extruders: list[int] = [] + stat: int = 0 + info: int = 0 + + class PrintOptionsResponse(BaseModel): """AI detection and print options from xcam data.""" @@ -245,6 +263,9 @@ class PrinterStatus(BaseModel): ams_mapping: list[int] = [] # Per-AMS extruder map: {ams_id: extruder_id} where 0=right, 1=left ams_extruder_map: dict[str, int] = {} + # Filament Track Switch (FTS) accessory — when installed, AMS reports + # bits 8-11 = 0xE (uninitialized) and routing is dynamic via the FTS. See #1162. + fila_switch: FilaSwitchResponse | None = None # Currently loaded tray (global ID): 254 = external spool, 255 = no filament tray_now: int = 255 # AMS status for filament change tracking diff --git a/backend/app/services/bambu_mqtt.py b/backend/app/services/bambu_mqtt.py index e01078a04..60a0e6d52 100644 --- a/backend/app/services/bambu_mqtt.py +++ b/backend/app/services/bambu_mqtt.py @@ -90,6 +90,26 @@ class NozzleInfo: nozzle_diameter: str = "" # e.g., "0.4" +@dataclass +class FilaSwitchState: + """Filament Track Switch (FTS) accessory state. + + The FTS is an external accessory that mediates filament routing between an + AMS and the printer's extruders. When installed, the AMS no longer has a + fixed extruder assignment — any slot can be routed to any extruder via the + track switch. Detected from print.device.fila_switch in MQTT. + """ + + installed: bool = False + # in[track] = currently loaded slot for that track (-1 = empty). The slot + # value is reported as observed in MQTT (treated as a global tray ID). + in_slots: list[int] = field(default_factory=list) + # out[track] = extruder this track terminates at (0 = right/main, 1 = left) + out_extruders: list[int] = field(default_factory=list) + stat: int = 0 # status flags (0 = idle) + info: int = 0 # info flags + + @dataclass class PrintOptions: """AI detection and print options from xcam data.""" @@ -170,6 +190,9 @@ class PrinterState: ams_mapping: list = field(default_factory=list) # Per-AMS extruder map: {ams_id: extruder_id} where 0=right/main, 1=left/deputy ams_extruder_map: dict = field(default_factory=dict) + # Filament Track Switch (FTS) accessory — when installed, AMS info reports + # bits 8-11 = 0xE (uninitialized) because routing is dynamic. See #1162. + fila_switch: "FilaSwitchState" = field(default_factory=lambda: FilaSwitchState()) # H2D per-extruder tray_now from snow field: {extruder_id: normalized_global_tray_id} # snow encodes AMS ID in high byte: ams_id = snow >> 8, slot = snow & 0xFF h2d_extruder_snow: dict = field(default_factory=dict) @@ -1922,6 +1945,22 @@ class BambuMQTTClient: # Log 'cur' field if present (might indicate current/active extruder) if "cur" in ext_data: logger.debug("[%s] device.extruder.cur: %s", self.serial_number, ext_data["cur"]) + + # Filament Track Switch (FTS) detection — #1162. Presence of + # device.fila_switch in MQTT means the FTS accessory is installed. + if "device" in data and isinstance(data.get("device"), dict): + fs_data = data["device"].get("fila_switch") + if isinstance(fs_data, dict): + in_raw = fs_data.get("in") + out_raw = fs_data.get("out") + self.state.fila_switch = FilaSwitchState( + installed=True, + in_slots=list(in_raw) if isinstance(in_raw, list) else [], + out_extruders=list(out_raw) if isinstance(out_raw, list) else [], + stat=int(fs_data.get("stat", 0) or 0), + info=int(fs_data.get("info", 0) or 0), + ) + if "bed_temper" in data: temps["bed"] = float(data["bed_temper"]) if "bed_target_temper" in data: diff --git a/backend/tests/integration/test_printers_api.py b/backend/tests/integration/test_printers_api.py index 143451fa9..e9cce9e41 100644 --- a/backend/tests/integration/test_printers_api.py +++ b/backend/tests/integration/test_printers_api.py @@ -257,6 +257,78 @@ class TestPrintersAPI: assert response.status_code == 404 + @pytest.mark.asyncio + @pytest.mark.integration + async def test_get_printer_status_includes_fila_switch_when_installed( + self, async_client: AsyncClient, printer_factory, db_session + ): + """When the FTS accessory is installed, the status response must include + the fila_switch object with the routing arrays. See #1162. + + The accessory is detected from print.device.fila_switch in MQTT; + we feed a PrinterState with FilaSwitchState(installed=True, ...) and + confirm it survives the schema serialization round-trip. + """ + from unittest.mock import MagicMock, patch + + from backend.app.services.bambu_mqtt import FilaSwitchState, PrinterState + + printer = await printer_factory() + + state = PrinterState() + state.connected = True + state.state = "IDLE" + state.fila_switch = FilaSwitchState( + installed=True, + in_slots=[-1, 2], + out_extruders=[0, 1], + stat=0, + info=2, + ) + + with patch("backend.app.api.routes.printers.printer_manager") as mock_pm: + mock_pm.get_status = MagicMock(return_value=state) + mock_pm.is_awaiting_plate_clear = MagicMock(return_value=False) + + response = await async_client.get(f"/api/v1/printers/{printer.id}/status") + + assert response.status_code == 200 + result = response.json() + assert result["fila_switch"] is not None + assert result["fila_switch"]["installed"] is True + assert result["fila_switch"]["in_slots"] == [-1, 2] + assert result["fila_switch"]["out_extruders"] == [0, 1] + assert result["fila_switch"]["stat"] == 0 + assert result["fila_switch"]["info"] == 2 + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_get_printer_status_omits_fila_switch_when_not_installed( + self, async_client: AsyncClient, printer_factory, db_session + ): + """Without the FTS accessory, fila_switch must be null so the frontend + keeps applying the per-extruder filter on regular dual-nozzle printers.""" + from unittest.mock import MagicMock, patch + + from backend.app.services.bambu_mqtt import PrinterState + + printer = await printer_factory() + + state = PrinterState() + state.connected = True + state.state = "IDLE" + # default fila_switch — installed = False + + with patch("backend.app.api.routes.printers.printer_manager") as mock_pm: + mock_pm.get_status = MagicMock(return_value=state) + mock_pm.is_awaiting_plate_clear = MagicMock(return_value=False) + + response = await async_client.get(f"/api/v1/printers/{printer.id}/status") + + assert response.status_code == 200 + result = response.json() + assert result["fila_switch"] is None + # ======================================================================== # Test connection endpoint # ======================================================================== diff --git a/backend/tests/unit/services/test_bambu_mqtt.py b/backend/tests/unit/services/test_bambu_mqtt.py index df60b7f9b..f2fcd19b7 100644 --- a/backend/tests/unit/services/test_bambu_mqtt.py +++ b/backend/tests/unit/services/test_bambu_mqtt.py @@ -4391,3 +4391,79 @@ class TestHardResetClientDirect: # loop_stop is still attempted after the disconnect failure. original.loop_stop.assert_called() assert mqtt_client._client is None + + +class TestFilamentTrackSwitchDetection: + """Tests for Filament Track Switch (FTS) accessory detection (#1162). + + The FTS is an accessory that sits between an AMS and the printer's + extruders, dynamically routing any slot to either nozzle. When installed, + each AMS unit reports info bits 8-11 = 0xE (uninitialized) since slots are + no longer tied to a specific extruder. Detection comes from the presence of + the print.device.fila_switch object in MQTT push_status. + """ + + @pytest.fixture + def mqtt_client(self): + from backend.app.services.bambu_mqtt import BambuMQTTClient + + return BambuMQTTClient( + ip_address="192.168.1.100", + serial_number="TEST123", + access_code="12345678", + ) + + def test_fts_default_not_installed(self, mqtt_client): + """Without any MQTT data, fila_switch.installed must be False so the + frontend keeps applying the per-extruder filter on regular dual-nozzle + printers.""" + assert mqtt_client.state.fila_switch.installed is False + assert mqtt_client.state.fila_switch.in_slots == [] + assert mqtt_client.state.fila_switch.out_extruders == [] + + def test_fts_detected_from_device_fila_switch(self, mqtt_client): + """A push_status with print.device.fila_switch present must mark FTS + installed and capture its routing arrays. Mirrors the user's MQTT + bundle in #1162.""" + data = { + "gcode_state": "RUNNING", + "device": { + "fila_switch": { + "in": [-1, 2], + "info": 2, + "out": [0, 1], + "stat": 0, + } + }, + } + mqtt_client._update_state(data) + fs = mqtt_client.state.fila_switch + assert fs.installed is True + assert fs.in_slots == [-1, 2] + assert fs.out_extruders == [0, 1] + assert fs.stat == 0 + assert fs.info == 2 + + def test_fts_absent_when_no_fila_switch_field(self, mqtt_client): + """A push_status that has device.* but no fila_switch must leave + fila_switch.installed = False — only that specific field flips it on.""" + data = { + "gcode_state": "IDLE", + "device": {"extruder": {"state": 0}}, + } + mqtt_client._update_state(data) + assert mqtt_client.state.fila_switch.installed is False + + def test_fts_handles_missing_in_out_arrays(self, mqtt_client): + """If the firmware sends fila_switch with missing or non-list in/out, + we must still mark it installed (presence is the signal) and default + the arrays to empty lists rather than crashing.""" + data = { + "gcode_state": "IDLE", + "device": {"fila_switch": {"stat": 0, "info": 0}}, + } + mqtt_client._update_state(data) + fs = mqtt_client.state.fila_switch + assert fs.installed is True + assert fs.in_slots == [] + assert fs.out_extruders == [] diff --git a/frontend/src/__tests__/components/FilamentMapping.test.tsx b/frontend/src/__tests__/components/FilamentMapping.test.tsx new file mode 100644 index 000000000..0b9283244 --- /dev/null +++ b/frontend/src/__tests__/components/FilamentMapping.test.tsx @@ -0,0 +1,148 @@ +/** + * Tests for the FilamentMapping component's Filament Track Switch (FTS) + * handling (#1162). + * + * The FTS accessory routes any AMS slot to either extruder dynamically. When + * present (printer status `fila_switch.installed === true`), the per-extruder + * dropdown filter must be suppressed — otherwise the print modal's filament + * dropdown is empty since the printer reports info bits 8-11 = 0xE + * (uninitialized) for every AMS unit. + */ + +import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; +import { screen, waitFor, cleanup } from '@testing-library/react'; +import { http, HttpResponse } from 'msw'; +import { render } from '../utils'; +import { server } from '../mocks/server'; +import { FilamentMapping } from '../../components/PrintModal/FilamentMapping'; +import type { PrinterStatus } from '../../api/client'; + +const mockFilamentReqs = { + filaments: [ + // Required filament asks for the LEFT extruder (nozzle_id=1). + // Without FTS the dropdown filter would only allow slots with extruderId=1. + { slot_id: 1, type: 'PETG', color: '#00FF00', used_grams: 25, used_meters: 8.5, nozzle_id: 1 }, + ], +}; + +function createStatus(overrides: Partial): PrinterStatus { + return { + id: 1, + name: 'X2D', + connected: true, + state: 'IDLE', + ams: [ + { + id: 0, + // Realistic FTS-installed bundle: AMS reports extruder bits 8-11 = 0xE, + // so ams_extruder_map ends up empty. + tray: [ + { id: 0, tray_type: 'PLA', tray_color: 'FF0000', tray_info_idx: 'GFA00', tray_sub_brands: 'Bambu PLA' }, + { id: 1, tray_type: 'PETG', tray_color: '00FF00', tray_info_idx: 'GFG00', tray_sub_brands: 'Bambu PETG' }, + ], + }, + ], + vt_tray: [], + ams_extruder_map: {}, + ...overrides, + } as PrinterStatus; +} + +afterEach(() => { + cleanup(); + vi.clearAllMocks(); +}); + +describe('FilamentMapping — FTS routing', () => { + beforeEach(() => { + server.use( + http.get('/api/v1/printers/:id/spool-assignments', () => HttpResponse.json([])), + ); + }); + + it('shows all loaded slots in the dropdown when FTS is installed', async () => { + server.use( + http.get( + '/api/v1/printers/:id/status', + () => + HttpResponse.json( + createStatus({ + fila_switch: { + installed: true, + in_slots: [-1, 1], + out_extruders: [0, 1], + stat: 0, + info: 2, + }, + }), + ), + ), + ); + + render( + {}} + currencySymbol="$" + defaultCostPerKg={0} + defaultExpanded + />, + ); + + // Both PLA and PETG slots must appear in the dropdown despite ams_extruder_map + // being empty and the requirement asking for nozzle 1. Without the FTS guard + // the dropdown would render only the "-- Select slot --" placeholder. + await waitFor(() => { + expect(screen.getByText(/Bambu PLA/)).toBeInTheDocument(); + }); + expect(screen.getByText(/Bambu PETG/)).toBeInTheDocument(); + + // The slot currently fed into a track gets an [L]/[R] badge. AMS-0 slot 1 + // (global tray ID 1) is in fila_switch.in_slots[1], whose track terminates + // at extruder 1 → the LEFT-nozzle short label appears in that option. + const petgOption = screen.getByText(/Bambu PETG/); + expect(petgOption.textContent).toMatch(/\[L\]/); + + // AMS-0 slot 0 (global tray ID 0) is NOT currently fed into any track — + // FTS routes it on demand, so no badge. + const plaOption = screen.getByText(/Bambu PLA/); + expect(plaOption.textContent).not.toMatch(/\[[LR]\]/); + }); + + it('still applies the per-nozzle filter when FTS is null', async () => { + server.use( + http.get( + '/api/v1/printers/:id/status', + () => + HttpResponse.json( + createStatus({ + fila_switch: null, + ams_extruder_map: { '0': 0 }, // AMS 0 → right nozzle (extruder 0) + }), + ), + ), + ); + + render( + {}} + currencySymbol="$" + defaultCostPerKg={0} + defaultExpanded + />, + ); + + // Required nozzle is 1 (LEFT) but AMS 0 is on extruder 0 (RIGHT) — neither + // slot should appear in the dropdown. + await waitFor(() => { + // Wait for component to render — the slot label should NOT be present + expect(screen.queryByText(/Bambu PLA/)).not.toBeInTheDocument(); + expect(screen.queryByText(/Bambu PETG/)).not.toBeInTheDocument(); + }); + }); +}); diff --git a/frontend/src/__tests__/hooks/useFilamentMapping.test.ts b/frontend/src/__tests__/hooks/useFilamentMapping.test.ts index 371596c43..470a3cfd6 100644 --- a/frontend/src/__tests__/hooks/useFilamentMapping.test.ts +++ b/frontend/src/__tests__/hooks/useFilamentMapping.test.ts @@ -569,6 +569,62 @@ describe('computeAmsMapping - nozzle filtering', () => { expect(result).toEqual([0, 4]); // Left gets AMS0-T0, Right gets AMS1-T0 }); + + // FTS (Filament Track Switch) — when present, AMS slots aren't tied to a + // specific extruder. The track switch routes any slot to either extruder, so + // the per-nozzle hard filter must NOT apply. See #1162. + it('ignores nozzle_id when FTS is installed', () => { + // Required filament asks for nozzle 1 (left). Without FTS this would force + // AMS 0 (which is on the left nozzle). With FTS we accept any AMS slot + // matching by type/color since the FTS routes it to whichever extruder. + const reqs = { + filaments: [ + { slot_id: 1, type: 'PETG', color: '#00FF00', used_grams: 10, nozzle_id: 1 }, + ], + }; + const status = createPrinterStatus([ + { + id: 0, // Without FTS, this AMS would be left/extruder 1; ams_extruder_map + // is empty because the printer reports info bits 8-11 = 0xE. + tray: [ + { id: 0, tray_type: 'PLA', tray_color: 'FF0000' }, + { id: 1, tray_type: 'PETG', tray_color: '00FF00' }, + ], + }, + ]); + (status as any).ams_extruder_map = {}; + (status as any).fila_switch = { + installed: true, + in_slots: [-1, 1], + out_extruders: [0, 1], + stat: 0, + info: 2, + }; + + const result = computeAmsMapping(reqs, status); + + expect(result).toEqual([1]); // Picks AMS 0 tray 1 (PETG green) regardless of nozzle + }); + + it('still applies nozzle filter when FTS object is null', () => { + // Sanity check: explicit null fila_switch behaves like no FTS — nozzle + // filter still applies on real dual-nozzle printers. + const reqs = { + filaments: [ + { slot_id: 1, type: 'PLA', color: '#FF0000', used_grams: 10, nozzle_id: 1 }, + ], + }; + const status = createPrinterStatus([ + { id: 0, tray: [{ id: 0, tray_type: 'PLA', tray_color: 'FF0000' }] }, + { id: 1, tray: [{ id: 0, tray_type: 'PLA', tray_color: 'FF0000' }] }, + ]); + (status as any).ams_extruder_map = { '0': 1, '1': 0 }; + (status as any).fila_switch = null; + + const result = computeAmsMapping(reqs, status); + + expect(result).toEqual([0]); // AMS 0 (left/extruder 1) + }); }); // ============================================================================ diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index bc5db070d..a605bde3d 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -238,6 +238,16 @@ export interface PrintOptions { filament_tangle_detect: boolean; } +export interface FilaSwitchState { + installed: boolean; + // in[track] = currently loaded slot for that track (-1 = empty) + in_slots: number[]; + // out[track] = extruder this track terminates at (0 = right, 1 = left) + out_extruders: number[]; + stat: number; + info: number; +} + export interface PrinterStatus { id: number; name: string; @@ -299,6 +309,10 @@ export interface PrinterStatus { // Format: {ams_id: extruder_id} where extruder 0=right, 1=left // Note: JSON keys are always strings ams_extruder_map: Record; + // Filament Track Switch accessory — null when not installed. When present, + // AMS slots aren't tied to a specific extruder; the FTS routes any slot to + // either extruder, so per-extruder slot filtering must be skipped. + fila_switch: FilaSwitchState | null; // Currently loaded tray (global tray ID, 255 = no filament loaded, 254 = external spool) tray_now: number; // AMS status for filament change tracking (0=idle, 1=filament_change, 2=rfid_identifying, 3=assist, 4=calibration) diff --git a/frontend/src/components/PrintModal/FilamentMapping.tsx b/frontend/src/components/PrintModal/FilamentMapping.tsx index 2bda98cf3..86590b103 100644 --- a/frontend/src/components/PrintModal/FilamentMapping.tsx +++ b/frontend/src/components/PrintModal/FilamentMapping.tsx @@ -88,6 +88,19 @@ export function FilamentMapping({ const hasFilamentReqs = filamentReqs?.filaments && filamentReqs.filaments.length > 0; const isDualNozzle = filamentReqs?.filaments?.some((f) => f.nozzle_id != null) ?? false; + // Filament Track Switch: when installed, AMS-to-extruder mapping is dynamic + // (any slot can be routed to either extruder), so the per-nozzle dropdown + // filter is suppressed. fila_switch.in_slots[track] = currently fed slot, + // fila_switch.out_extruders[track] = extruder that track terminates at. See #1162. + const ftsInstalled = printerStatus?.fila_switch?.installed === true; + const ftsExtruderForSlot = (globalTrayId: number): number | null => { + const fs = printerStatus?.fila_switch; + if (!fs?.installed) return null; + const track = fs.in_slots.indexOf(globalTrayId); + if (track < 0) return null; + return fs.out_extruders[track] ?? null; + }; + // Don't render if no filament requirements if (!hasFilamentReqs) { return null; @@ -212,7 +225,12 @@ export function FilamentMapping({ -- Select slot -- {loadedFilaments - .filter((f) => item.nozzle_id == null || f.extruderId === item.nozzle_id) + .filter( + (f) => + item.nozzle_id == null || + ftsInstalled || + f.extruderId === item.nozzle_id, + ) .map((f) => { const remainingWeight = trayRemainingWeightMap.get(f.globalTrayId); const remainingLabel = remainingWeight != null @@ -221,9 +239,19 @@ export function FilamentMapping({ defaultValue: ` - ${remainingWeight}g left`, }) : ''; + // FTS routing badge: if this slot is currently fed into an FTS + // track, show the destination extruder. Idle (not-loaded) slots + // get no badge — they can be routed to either extruder on demand. + const ftsTargetExtruder = ftsInstalled + ? ftsExtruderForSlot(f.globalTrayId) + : null; + const ftsBadge = + ftsTargetExtruder == null + ? '' + : ` [${ftsTargetExtruder === 1 ? t('printModal.leftNozzle') : t('printModal.rightNozzle')}]`; return ( ); })} diff --git a/frontend/src/hooks/useFilamentMapping.ts b/frontend/src/hooks/useFilamentMapping.ts index 79b1d88d8..3857944f1 100644 --- a/frontend/src/hooks/useFilamentMapping.ts +++ b/frontend/src/hooks/useFilamentMapping.ts @@ -96,6 +96,10 @@ export function computeAmsMapping( const loadedFilaments = buildLoadedFilaments(printerStatus); if (loadedFilaments.length === 0) return undefined; + // FTS routes any AMS slot to any extruder, so per-nozzle slot restriction + // doesn't apply when it's installed (#1162). + const ftsActive = printerStatus?.fila_switch?.installed === true; + // Track which trays have been assigned to avoid duplicates const usedTrayIds = new Set(); @@ -108,7 +112,8 @@ export function computeAmsMapping( // Nozzle-aware filtering: restrict to trays on the correct nozzle. // This is a hard filter — cross-nozzle assignment causes print failures // ("position of left hotend is abnormal"), so we never fall back to wrong-nozzle trays. - if (req.nozzle_id != null) { + // Skip when an FTS is installed: it can route any slot to either extruder. + if (req.nozzle_id != null && !ftsActive) { available = available.filter((f) => f.extruderId === req.nozzle_id); } @@ -311,6 +316,10 @@ export function useFilamentMapping( ): UseFilamentMappingResult { const loadedFilaments = useLoadedFilaments(printerStatus); + // FTS routes any AMS slot to any extruder, so per-nozzle slot restriction + // doesn't apply when it's installed (#1162). + const ftsActive = printerStatus?.fila_switch?.installed === true; + const filamentComparison = useMemo(() => { if (!filamentReqs?.filaments || filamentReqs.filaments.length === 0) return []; @@ -363,7 +372,8 @@ export function useFilamentMapping( // Nozzle-aware filtering: restrict to trays on the correct nozzle. // This is a hard filter — cross-nozzle assignment causes print failures. - if (req.nozzle_id != null) { + // Skip when an FTS is installed: it can route any slot to either extruder. + if (req.nozzle_id != null && !ftsActive) { available = available.filter((f) => f.extruderId === req.nozzle_id); } @@ -469,7 +479,7 @@ export function useFilamentMapping( isManual: false, }; }); - }, [filamentReqs, loadedFilaments, manualMappings, preferLowest]); + }, [filamentReqs, loadedFilaments, manualMappings, preferLowest, ftsActive]); // Build AMS mapping from matched filaments // Format: array matching 3MF filament slot structure diff --git a/static/assets/index-CXX0Eh7g.js b/static/assets/index-CTxVw43p.js similarity index 91% rename from static/assets/index-CXX0Eh7g.js rename to static/assets/index-CTxVw43p.js index 10404f247..cc09f4659 100644 --- a/static/assets/index-CXX0Eh7g.js +++ b/static/assets/index-CTxVw43p.js @@ -1,12 +1,12 @@ -function cue(t,e){for(var n=0;nr[i]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}})();var Z_=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function gc(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var kM={exports:{}},Ev={};var X8;function due(){if(X8)return Ev;X8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function n(r,i,s){var o=null;if(s!==void 0&&(o=""+s),i.key!==void 0&&(o=""+i.key),"key"in i){s={};for(var l in i)l!=="key"&&(s[l]=i[l])}else s=i;return i=s.ref,{$$typeof:t,type:r,key:o,ref:i!==void 0?i:null,props:s}}return Ev.Fragment=e,Ev.jsx=n,Ev.jsxs=n,Ev}var Y8;function uue(){return Y8||(Y8=1,kM.exports=due()),kM.exports}var a=uue(),NM={exports:{}},Wn={};var Q8;function mue(){if(Q8)return Wn;Q8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.consumer"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),u=Symbol.for("react.lazy"),m=Symbol.for("react.activity"),p=Symbol.iterator;function f(X){return X===null||typeof X!="object"?null:(X=p&&X[p]||X["@@iterator"],typeof X=="function"?X:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},v=Object.assign,g={};function b(X,ae,pe){this.props=X,this.context=ae,this.refs=g,this.updater=pe||x}b.prototype.isReactComponent={},b.prototype.setState=function(X,ae){if(typeof X!="object"&&typeof X!="function"&&X!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,X,ae,"setState")},b.prototype.forceUpdate=function(X){this.updater.enqueueForceUpdate(this,X,"forceUpdate")};function S(){}S.prototype=b.prototype;function N(X,ae,pe){this.props=X,this.context=ae,this.refs=g,this.updater=pe||x}var P=N.prototype=new S;P.constructor=N,v(P,b.prototype),P.isPureReactComponent=!0;var C=Array.isArray;function A(){}var T={H:null,A:null,T:null,S:null},F=Object.prototype.hasOwnProperty;function k(X,ae,pe){var be=pe.ref;return{$$typeof:t,type:X,key:ae,ref:be!==void 0?be:null,props:pe}}function D(X,ae){return k(X.type,ae,X.props)}function $(X){return typeof X=="object"&&X!==null&&X.$$typeof===t}function O(X){var ae={"=":"=0",":":"=2"};return"$"+X.replace(/[=:]/g,function(pe){return ae[pe]})}var K=/\/+/g;function L(X,ae){return typeof X=="object"&&X!==null&&X.key!=null?O(""+X.key):ae.toString(36)}function ne(X){switch(X.status){case"fulfilled":return X.value;case"rejected":throw X.reason;default:switch(typeof X.status=="string"?X.then(A,A):(X.status="pending",X.then(function(ae){X.status==="pending"&&(X.status="fulfilled",X.value=ae)},function(ae){X.status==="pending"&&(X.status="rejected",X.reason=ae)})),X.status){case"fulfilled":return X.value;case"rejected":throw X.reason}}throw X}function re(X,ae,pe,be,fe){var B=typeof X;(B==="undefined"||B==="boolean")&&(X=null);var Y=!1;if(X===null)Y=!0;else switch(B){case"bigint":case"string":case"number":Y=!0;break;case"object":switch(X.$$typeof){case t:case e:Y=!0;break;case u:return Y=X._init,re(Y(X._payload),ae,pe,be,fe)}}if(Y)return fe=fe(X),Y=be===""?"."+L(X,0):be,C(fe)?(pe="",Y!=null&&(pe=Y.replace(K,"$&/")+"/"),re(fe,ae,pe,"",function(U){return U})):fe!=null&&($(fe)&&(fe=D(fe,pe+(fe.key==null||X&&X.key===fe.key?"":(""+fe.key).replace(K,"$&/")+"/")+Y)),ae.push(fe)),1;Y=0;var E=be===""?".":be+":";if(C(X))for(var M=0;M>>1,se=re[ie];if(0>>1;iei(pe,ue))bei(fe,pe)?(re[ie]=fe,re[be]=ue,ie=be):(re[ie]=pe,re[ae]=ue,ie=ae);else if(bei(fe,ue))re[ie]=fe,re[be]=ue,ie=be;else break e}}return Z}function i(re,Z){var ue=re.sortIndex-Z.sortIndex;return ue!==0?ue:re.id-Z.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var s=performance;t.unstable_now=function(){return s.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],d=[],u=1,m=null,p=3,f=!1,x=!1,v=!1,g=!1,b=typeof setTimeout=="function"?setTimeout:null,S=typeof clearTimeout=="function"?clearTimeout:null,N=typeof setImmediate<"u"?setImmediate:null;function P(re){for(var Z=n(d);Z!==null;){if(Z.callback===null)r(d);else if(Z.startTime<=re)r(d),Z.sortIndex=Z.expirationTime,e(c,Z);else break;Z=n(d)}}function C(re){if(v=!1,P(re),!x)if(n(c)!==null)x=!0,A||(A=!0,O());else{var Z=n(d);Z!==null&&ne(C,Z.startTime-re)}}var A=!1,T=-1,F=5,k=-1;function D(){return g?!0:!(t.unstable_now()-kre&&D());){var ie=m.callback;if(typeof ie=="function"){m.callback=null,p=m.priorityLevel;var se=ie(m.expirationTime<=re);if(re=t.unstable_now(),typeof se=="function"){m.callback=se,P(re),Z=!0;break t}m===n(c)&&r(c),P(re)}else r(c);m=n(c)}if(m!==null)Z=!0;else{var X=n(d);X!==null&&ne(C,X.startTime-re),Z=!1}}break e}finally{m=null,p=ue,f=!1}Z=void 0}}finally{Z?O():A=!1}}}var O;if(typeof N=="function")O=function(){N($)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,L=K.port2;K.port1.onmessage=$,O=function(){L.postMessage(null)}}else O=function(){b($,0)};function ne(re,Z){T=b(function(){re(t.unstable_now())},Z)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(re){re.callback=null},t.unstable_forceFrameRate=function(re){0>re||125ie?(re.sortIndex=ue,e(d,re),n(c)===null&&re===n(d)&&(v?(S(T),T=-1):v=!0,ne(C,ue-ie))):(re.sortIndex=se,e(c,re),x||f||(x=!0,A||(A=!0,O()))),re},t.unstable_shouldYield=D,t.unstable_wrapCallback=function(re){var Z=p;return function(){var ue=p;p=Z;try{return re.apply(this,arguments)}finally{p=ue}}}})(TM)),TM}var eH;function fue(){return eH||(eH=1,PM.exports=pue()),PM.exports}var AM={exports:{}},Ds={};var tH;function gue(){if(tH)return Ds;tH=1;var t=Bg();function e(c){var d="https://react.dev/errors/"+c;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),AM.exports=gue(),AM.exports}var rH;function bue(){if(rH)return Dv;rH=1;var t=fue(),e=Bg(),n=dQ();function r(h){var y="https://react.dev/errors/"+h;if(1se||(h.current=ie[se],ie[se]=null,se--)}function pe(h,y){se++,ie[se]=h.current,h.current=y}var be=X(null),fe=X(null),B=X(null),Y=X(null);function E(h,y){switch(pe(B,y),pe(fe,h),pe(be,null),y.nodeType){case 9:case 11:h=(h=y.documentElement)&&(h=h.namespaceURI)?x8(h):0;break;default:if(h=y.tagName,y=y.namespaceURI)y=x8(y),h=y8(y,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}ae(be),pe(be,h)}function M(){ae(be),ae(fe),ae(B)}function U(h){h.memoizedState!==null&&pe(Y,h);var y=be.current,_=y8(y,h.type);y!==_&&(pe(fe,h),pe(be,_))}function Q(h){fe.current===h&&(ae(be),ae(fe)),Y.current===h&&(ae(Y),Tv._currentValue=ue)}var z,ce;function I(h){if(z===void 0)try{throw Error()}catch(_){var y=_.stack.trim().match(/\n( *(at )?)/);z=y&&y[1]||"",ce=-1<_.stack.indexOf(` +function cue(t,e){for(var n=0;nr[i]})}}}return Object.freeze(Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}))}(function(){const e=document.createElement("link").relList;if(e&&e.supports&&e.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))r(i);new MutationObserver(i=>{for(const s of i)if(s.type==="childList")for(const o of s.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const s={};return i.integrity&&(s.integrity=i.integrity),i.referrerPolicy&&(s.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?s.credentials="include":i.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function r(i){if(i.ep)return;i.ep=!0;const s=n(i);fetch(i.href,s)}})();var Z_=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function gc(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var kM={exports:{}},Ev={};var X8;function due(){if(X8)return Ev;X8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function n(r,i,s){var o=null;if(s!==void 0&&(o=""+s),i.key!==void 0&&(o=""+i.key),"key"in i){s={};for(var l in i)l!=="key"&&(s[l]=i[l])}else s=i;return i=s.ref,{$$typeof:t,type:r,key:o,ref:i!==void 0?i:null,props:s}}return Ev.Fragment=e,Ev.jsx=n,Ev.jsxs=n,Ev}var Y8;function uue(){return Y8||(Y8=1,kM.exports=due()),kM.exports}var a=uue(),NM={exports:{}},Wn={};var Q8;function mue(){if(Q8)return Wn;Q8=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),r=Symbol.for("react.strict_mode"),i=Symbol.for("react.profiler"),s=Symbol.for("react.consumer"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),d=Symbol.for("react.memo"),u=Symbol.for("react.lazy"),m=Symbol.for("react.activity"),p=Symbol.iterator;function f(K){return K===null||typeof K!="object"?null:(K=p&&K[p]||K["@@iterator"],typeof K=="function"?K:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},v=Object.assign,b={};function g(K,ae,pe){this.props=K,this.context=ae,this.refs=b,this.updater=pe||x}g.prototype.isReactComponent={},g.prototype.setState=function(K,ae){if(typeof K!="object"&&typeof K!="function"&&K!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,K,ae,"setState")},g.prototype.forceUpdate=function(K){this.updater.enqueueForceUpdate(this,K,"forceUpdate")};function S(){}S.prototype=g.prototype;function N(K,ae,pe){this.props=K,this.context=ae,this.refs=b,this.updater=pe||x}var P=N.prototype=new S;P.constructor=N,v(P,g.prototype),P.isPureReactComponent=!0;var C=Array.isArray;function A(){}var T={H:null,A:null,T:null,S:null},F=Object.prototype.hasOwnProperty;function k(K,ae,pe){var be=pe.ref;return{$$typeof:t,type:K,key:ae,ref:be!==void 0?be:null,props:pe}}function E(K,ae){return k(K.type,ae,K.props)}function $(K){return typeof K=="object"&&K!==null&&K.$$typeof===t}function z(K){var ae={"=":"=0",":":"=2"};return"$"+K.replace(/[=:]/g,function(pe){return ae[pe]})}var X=/\/+/g;function R(K,ae){return typeof K=="object"&&K!==null&&K.key!=null?z(""+K.key):ae.toString(36)}function ne(K){switch(K.status){case"fulfilled":return K.value;case"rejected":throw K.reason;default:switch(typeof K.status=="string"?K.then(A,A):(K.status="pending",K.then(function(ae){K.status==="pending"&&(K.status="fulfilled",K.value=ae)},function(ae){K.status==="pending"&&(K.status="rejected",K.reason=ae)})),K.status){case"fulfilled":return K.value;case"rejected":throw K.reason}}throw K}function re(K,ae,pe,be,fe){var B=typeof K;(B==="undefined"||B==="boolean")&&(K=null);var Y=!1;if(K===null)Y=!0;else switch(B){case"bigint":case"string":case"number":Y=!0;break;case"object":switch(K.$$typeof){case t:case e:Y=!0;break;case u:return Y=K._init,re(Y(K._payload),ae,pe,be,fe)}}if(Y)return fe=fe(K),Y=be===""?"."+R(K,0):be,C(fe)?(pe="",Y!=null&&(pe=Y.replace(X,"$&/")+"/"),re(fe,ae,pe,"",function(U){return U})):fe!=null&&($(fe)&&(fe=E(fe,pe+(fe.key==null||K&&K.key===fe.key?"":(""+fe.key).replace(X,"$&/")+"/")+Y)),ae.push(fe)),1;Y=0;var D=be===""?".":be+":";if(C(K))for(var M=0;M>>1,se=re[ie];if(0>>1;iei(pe,ue))bei(fe,pe)?(re[ie]=fe,re[be]=ue,ie=be):(re[ie]=pe,re[ae]=ue,ie=ae);else if(bei(fe,ue))re[ie]=fe,re[be]=ue,ie=be;else break e}}return J}function i(re,J){var ue=re.sortIndex-J.sortIndex;return ue!==0?ue:re.id-J.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var s=performance;t.unstable_now=function(){return s.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],d=[],u=1,m=null,p=3,f=!1,x=!1,v=!1,b=!1,g=typeof setTimeout=="function"?setTimeout:null,S=typeof clearTimeout=="function"?clearTimeout:null,N=typeof setImmediate<"u"?setImmediate:null;function P(re){for(var J=n(d);J!==null;){if(J.callback===null)r(d);else if(J.startTime<=re)r(d),J.sortIndex=J.expirationTime,e(c,J);else break;J=n(d)}}function C(re){if(v=!1,P(re),!x)if(n(c)!==null)x=!0,A||(A=!0,z());else{var J=n(d);J!==null&&ne(C,J.startTime-re)}}var A=!1,T=-1,F=5,k=-1;function E(){return b?!0:!(t.unstable_now()-kre&&E());){var ie=m.callback;if(typeof ie=="function"){m.callback=null,p=m.priorityLevel;var se=ie(m.expirationTime<=re);if(re=t.unstable_now(),typeof se=="function"){m.callback=se,P(re),J=!0;break t}m===n(c)&&r(c),P(re)}else r(c);m=n(c)}if(m!==null)J=!0;else{var K=n(d);K!==null&&ne(C,K.startTime-re),J=!1}}break e}finally{m=null,p=ue,f=!1}J=void 0}}finally{J?z():A=!1}}}var z;if(typeof N=="function")z=function(){N($)};else if(typeof MessageChannel<"u"){var X=new MessageChannel,R=X.port2;X.port1.onmessage=$,z=function(){R.postMessage(null)}}else z=function(){g($,0)};function ne(re,J){T=g(function(){re(t.unstable_now())},J)}t.unstable_IdlePriority=5,t.unstable_ImmediatePriority=1,t.unstable_LowPriority=4,t.unstable_NormalPriority=3,t.unstable_Profiling=null,t.unstable_UserBlockingPriority=2,t.unstable_cancelCallback=function(re){re.callback=null},t.unstable_forceFrameRate=function(re){0>re||125ie?(re.sortIndex=ue,e(d,re),n(c)===null&&re===n(d)&&(v?(S(T),T=-1):v=!0,ne(C,ue-ie))):(re.sortIndex=se,e(c,re),x||f||(x=!0,A||(A=!0,z()))),re},t.unstable_shouldYield=E,t.unstable_wrapCallback=function(re){var J=p;return function(){var ue=p;p=J;try{return re.apply(this,arguments)}finally{p=ue}}}})(TM)),TM}var eH;function fue(){return eH||(eH=1,PM.exports=pue()),PM.exports}var AM={exports:{}},Ds={};var tH;function gue(){if(tH)return Ds;tH=1;var t=Bg();function e(c){var d="https://react.dev/errors/"+c;if(1"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(t)}catch(e){console.error(e)}}return t(),AM.exports=gue(),AM.exports}var rH;function bue(){if(rH)return Dv;rH=1;var t=fue(),e=Bg(),n=dQ();function r(h){var y="https://react.dev/errors/"+h;if(1se||(h.current=ie[se],ie[se]=null,se--)}function pe(h,y){se++,ie[se]=h.current,h.current=y}var be=K(null),fe=K(null),B=K(null),Y=K(null);function D(h,y){switch(pe(B,y),pe(fe,h),pe(be,null),y.nodeType){case 9:case 11:h=(h=y.documentElement)&&(h=h.namespaceURI)?x8(h):0;break;default:if(h=y.tagName,y=y.namespaceURI)y=x8(y),h=y8(y,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}ae(be),pe(be,h)}function M(){ae(be),ae(fe),ae(B)}function U(h){h.memoizedState!==null&&pe(Y,h);var y=be.current,_=y8(y,h.type);y!==_&&(pe(fe,h),pe(be,_))}function Q(h){fe.current===h&&(ae(be),ae(fe)),Y.current===h&&(ae(Y),Tv._currentValue=ue)}var O,ce;function I(h){if(O===void 0)try{throw Error()}catch(_){var y=_.stack.trim().match(/\n( *(at )?)/);O=y&&y[1]||"",ce=-1<_.stack.indexOf(` at`)?" ()":-1<_.stack.indexOf("@")?"@unknown:0:0":""}return` -`+z+h+ce}var G=!1;function q(h,y){if(!h||G)return"";G=!0;var _=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var j={DetermineComponentFrameRoot:function(){try{if(y){var Ut=function(){throw Error()};if(Object.defineProperty(Ut.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(Ut,[])}catch(At){var kt=At}Reflect.construct(h,[],Ut)}else{try{Ut.call()}catch(At){kt=At}h.call(Ut.prototype)}}else{try{throw Error()}catch(At){kt=At}(Ut=h())&&typeof Ut.catch=="function"&&Ut.catch(function(){})}}catch(At){if(At&&kt&&typeof At.stack=="string")return[At.stack,kt.stack]}return[null,null]}};j.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var V=Object.getOwnPropertyDescriptor(j.DetermineComponentFrameRoot,"name");V&&V.configurable&&Object.defineProperty(j.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var J=j.DetermineComponentFrameRoot(),Ne=J[0],qe=J[1];if(Ne&&qe){var lt=Ne.split(` +`+O+h+ce}var G=!1;function q(h,y){if(!h||G)return"";G=!0;var _=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var j={DetermineComponentFrameRoot:function(){try{if(y){var Ut=function(){throw Error()};if(Object.defineProperty(Ut.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(Ut,[])}catch(At){var kt=At}Reflect.construct(h,[],Ut)}else{try{Ut.call()}catch(At){kt=At}h.call(Ut.prototype)}}else{try{throw Error()}catch(At){kt=At}(Ut=h())&&typeof Ut.catch=="function"&&Ut.catch(function(){})}}catch(At){if(At&&kt&&typeof At.stack=="string")return[At.stack,kt.stack]}return[null,null]}};j.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var V=Object.getOwnPropertyDescriptor(j.DetermineComponentFrameRoot,"name");V&&V.configurable&&Object.defineProperty(j.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var Z=j.DetermineComponentFrameRoot(),Ne=Z[0],qe=Z[1];if(Ne&&qe){var lt=Ne.split(` `),vt=qe.split(` `);for(V=j=0;jV||lt[j]!==vt[V]){var Rt=` `+lt[j].replace(" at new "," at ");return h.displayName&&Rt.includes("")&&(Rt=Rt.replace("",h.displayName)),Rt}while(1<=j&&0<=V);break}}}finally{G=!1,Error.prepareStackTrace=_}return(_=h?h.displayName||h.name:"")?I(_):""}function W(h,y){switch(h.tag){case 26:case 27:case 5:return I(h.type);case 16:return I("Lazy");case 13:return h.child!==y&&y!==null?I("Suspense Fallback"):I("Suspense");case 19:return I("SuspenseList");case 0:case 15:return q(h.type,!1);case 11:return q(h.type.render,!1);case 1:return q(h.type,!0);case 31:return I("Activity");default:return""}}function te(h){try{var y="",_=null;do y+=W(h,_),_=h,h=h.return;while(h);return y}catch(j){return` Error generating stack: `+j.message+` -`+j.stack}}var le=Object.prototype.hasOwnProperty,ye=t.unstable_scheduleCallback,he=t.unstable_cancelCallback,me=t.unstable_shouldYield,H=t.unstable_requestPaint,R=t.unstable_now,ee=t.unstable_getCurrentPriorityLevel,ge=t.unstable_ImmediatePriority,ke=t.unstable_UserBlockingPriority,je=t.unstable_NormalPriority,Te=t.unstable_LowPriority,xe=t.unstable_IdlePriority,Fe=t.log,Be=t.unstable_setDisableYieldValue,Ce=null,ze=null;function Me(h){if(typeof Fe=="function"&&Be(h),ze&&typeof ze.setStrictMode=="function")try{ze.setStrictMode(Ce,h)}catch{}}var Oe=Math.clz32?Math.clz32:ve,Ge=Math.log,et=Math.LN2;function ve(h){return h>>>=0,h===0?32:31-(Ge(h)/et|0)|0}var Xe=256,Pe=262144,Ve=4194304;function we(h){var y=h&42;if(y!==0)return y;switch(h&-h){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return h&261888;case 262144:case 524288:case 1048576:case 2097152:return h&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return h&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return h}}function de(h,y,_){var j=h.pendingLanes;if(j===0)return 0;var V=0,J=h.suspendedLanes,Ne=h.pingedLanes;h=h.warmLanes;var qe=j&134217727;return qe!==0?(j=qe&~J,j!==0?V=we(j):(Ne&=qe,Ne!==0?V=we(Ne):_||(_=qe&~h,_!==0&&(V=we(_))))):(qe=j&~J,qe!==0?V=we(qe):Ne!==0?V=we(Ne):_||(_=j&~h,_!==0&&(V=we(_)))),V===0?0:y!==0&&y!==V&&(y&J)===0&&(J=V&-V,_=y&-y,J>=_||J===32&&(_&4194048)!==0)?y:V}function Se(h,y){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&y)===0}function $e(h,y){switch(h){case 1:case 2:case 4:case 8:case 64:return y+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return y+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function st(){var h=Ve;return Ve<<=1,(Ve&62914560)===0&&(Ve=4194304),h}function He(h){for(var y=[],_=0;31>_;_++)y.push(h);return y}function at(h,y){h.pendingLanes|=y,y!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function ht(h,y,_,j,V,J){var Ne=h.pendingLanes;h.pendingLanes=_,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=_,h.entangledLanes&=_,h.errorRecoveryDisabledLanes&=_,h.shellSuspendCounter=0;var qe=h.entanglements,lt=h.expirationTimes,vt=h.hiddenUpdates;for(_=Ne&~_;0<_;){var Rt=31-Oe(_),Ut=1<"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Tr=/[\n"\\]/g;function On(h){return h.replace(Tr,function(y){return"\\"+y.charCodeAt(0).toString(16)+" "})}function Ra(h,y,_,j,V,J,Ne,qe){h.name="",Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"?h.type=Ne:h.removeAttribute("type"),y!=null?Ne==="number"?(y===0&&h.value===""||h.value!=y)&&(h.value=""+on(y)):h.value!==""+on(y)&&(h.value=""+on(y)):Ne!=="submit"&&Ne!=="reset"||h.removeAttribute("value"),y!=null?Br(h,Ne,on(y)):_!=null?Br(h,Ne,on(_)):j!=null&&h.removeAttribute("value"),V==null&&J!=null&&(h.defaultChecked=!!J),V!=null&&(h.checked=V&&typeof V!="function"&&typeof V!="symbol"),qe!=null&&typeof qe!="function"&&typeof qe!="symbol"&&typeof qe!="boolean"?h.name=""+on(qe):h.removeAttribute("name")}function $n(h,y,_,j,V,J,Ne,qe){if(J!=null&&typeof J!="function"&&typeof J!="symbol"&&typeof J!="boolean"&&(h.type=J),y!=null||_!=null){if(!(J!=="submit"&&J!=="reset"||y!=null)){_n(h);return}_=_!=null?""+on(_):"",y=y!=null?""+on(y):_,qe||y===h.value||(h.value=y),h.defaultValue=y}j=j??V,j=typeof j!="function"&&typeof j!="symbol"&&!!j,h.checked=qe?h.checked:!!j,h.defaultChecked=!!j,Ne!=null&&typeof Ne!="function"&&typeof Ne!="symbol"&&typeof Ne!="boolean"&&(h.name=Ne),_n(h)}function Br(h,y,_){y==="number"&&br(h.ownerDocument)===h||h.defaultValue===""+_||(h.defaultValue=""+_)}function Kr(h,y,_,j){if(h=h.options,y){y={};for(var V=0;V<_.length;V++)y["$"+_[V]]=!0;for(_=0;_"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),zi=!1;if($o)try{var wl={};Object.defineProperty(wl,"passive",{get:function(){zi=!0}}),window.addEventListener("test",wl,wl),window.removeEventListener("test",wl,wl)}catch{zi=!1}var wo=null,ha=null,vc=null;function Im(){if(vc)return vc;var h,y=ha,_=y.length,j,V="value"in wo?wo.value:wo.textContent,J=V.length;for(h=0;h<_&&y[h]===V[h];h++);var Ne=_-h;for(j=1;j<=Ne&&y[_-j]===V[J-j];j++);return vc=V.slice(h,1=it),ct=" ",Mn=!1;function xr(h,y){switch(h){case"keyup":return Fn.indexOf(y.keyCode)!==-1;case"keydown":return y.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function lr(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var Or=!1;function La(h,y){switch(h){case"compositionend":return lr(y);case"keypress":return y.which!==32?null:(Mn=!0,ct);case"textInput":return h=y.data,h===ct&&Mn?null:h;default:return null}}function un(h,y){if(Or)return h==="compositionend"||!kn&&xr(h,y)?(h=Im(),vc=ha=wo=null,Or=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(y.ctrlKey||y.altKey||y.metaKey)||y.ctrlKey&&y.altKey){if(y.char&&1=y)return{node:_,offset:y-h};h=j}e:{for(;_;){if(_.nextSibling){_=_.nextSibling;break e}_=_.parentNode}_=void 0}_=Yp(_)}}function Jy(h,y){return h&&y?h===y?!0:h&&h.nodeType===3?!1:y&&y.nodeType===3?Jy(h,y.parentNode):"contains"in h?h.contains(y):h.compareDocumentPosition?!!(h.compareDocumentPosition(y)&16):!1:!1}function YS(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var y=br(h.document);y instanceof h.HTMLIFrameElement;){try{var _=typeof y.contentWindow.location.href=="string"}catch{_=!1}if(_)h=y.contentWindow;else break;y=br(h.document)}return y}function DA(h){var y=h&&h.nodeName&&h.nodeName.toLowerCase();return y&&(y==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||y==="textarea"||h.contentEditable==="true")}var Hce=$o&&"documentMode"in document&&11>=document.documentMode,tb=null,FA=null,Zy=null,RA=!1;function U5(h,y,_){var j=_.window===_?_.document:_.nodeType===9?_:_.ownerDocument;RA||tb==null||tb!==br(j)||(j=tb,"selectionStart"in j&&DA(j)?j={start:j.selectionStart,end:j.selectionEnd}:(j=(j.ownerDocument&&j.ownerDocument.defaultView||window).getSelection(),j={anchorNode:j.anchorNode,anchorOffset:j.anchorOffset,focusNode:j.focusNode,focusOffset:j.focusOffset}),Zy&&Vm(Zy,j)||(Zy=j,j=O_(FA,"onSelect"),0>=Ne,V-=Ne,ld=1<<32-Oe(y)+V|_<Qn?(vr=vn,vn=null):vr=vn.sibling;var Dr=kt(gt,vn,yt[Qn],It);if(Dr===null){vn===null&&(vn=vr);break}h&&vn&&Dr.alternate===null&&y(gt,vn),pt=J(Dr,pt,Qn),Er===null?An=Dr:Er.sibling=Dr,Er=Dr,vn=vr}if(Qn===yt.length)return _(gt,vn),Sr&&du(gt,Qn),An;if(vn===null){for(;QnQn?(vr=vn,vn=null):vr=vn.sibling;var hh=kt(gt,vn,Dr.value,It);if(hh===null){vn===null&&(vn=vr);break}h&&vn&&hh.alternate===null&&y(gt,vn),pt=J(hh,pt,Qn),Er===null?An=hh:Er.sibling=hh,Er=hh,vn=vr}if(Dr.done)return _(gt,vn),Sr&&du(gt,Qn),An;if(vn===null){for(;!Dr.done;Qn++,Dr=yt.next())Dr=Ut(gt,Dr.value,It),Dr!==null&&(pt=J(Dr,pt,Qn),Er===null?An=Dr:Er.sibling=Dr,Er=Dr);return Sr&&du(gt,Qn),An}for(vn=j(vn);!Dr.done;Qn++,Dr=yt.next())Dr=At(vn,gt,Qn,Dr.value,It),Dr!==null&&(h&&Dr.alternate!==null&&vn.delete(Dr.key===null?Qn:Dr.key),pt=J(Dr,pt,Qn),Er===null?An=Dr:Er.sibling=Dr,Er=Dr);return h&&vn.forEach(function(lue){return y(gt,lue)}),Sr&&du(gt,Qn),An}function Qr(gt,pt,yt,It){if(typeof yt=="object"&&yt!==null&&yt.type===v&&yt.key===null&&(yt=yt.props.children),typeof yt=="object"&&yt!==null){switch(yt.$$typeof){case f:e:{for(var An=yt.key;pt!==null;){if(pt.key===An){if(An=yt.type,An===v){if(pt.tag===7){_(gt,pt.sibling),It=V(pt,yt.props.children),It.return=gt,gt=It;break e}}else if(pt.elementType===An||typeof An=="object"&&An!==null&&An.$$typeof===F&&sf(An)===pt.type){_(gt,pt.sibling),It=V(pt,yt.props),iv(It,yt),It.return=gt,gt=It;break e}_(gt,pt);break}else y(gt,pt);pt=pt.sibling}yt.type===v?(It=ef(yt.props.children,gt.mode,It,yt.key),It.return=gt,gt=It):(It=t_(yt.type,yt.key,yt.props,null,gt.mode,It),iv(It,yt),It.return=gt,gt=It)}return Ne(gt);case x:e:{for(An=yt.key;pt!==null;){if(pt.key===An)if(pt.tag===4&&pt.stateNode.containerInfo===yt.containerInfo&&pt.stateNode.implementation===yt.implementation){_(gt,pt.sibling),It=V(pt,yt.children||[]),It.return=gt,gt=It;break e}else{_(gt,pt);break}else y(gt,pt);pt=pt.sibling}It=HA(yt,gt.mode,It),It.return=gt,gt=It}return Ne(gt);case F:return yt=sf(yt),Qr(gt,pt,yt,It)}if(ne(yt))return bn(gt,pt,yt,It);if(O(yt)){if(An=O(yt),typeof An!="function")throw Error(r(150));return yt=An.call(yt),In(gt,pt,yt,It)}if(typeof yt.then=="function")return Qr(gt,pt,l_(yt),It);if(yt.$$typeof===N)return Qr(gt,pt,a_(gt,yt),It);c_(gt,yt)}return typeof yt=="string"&&yt!==""||typeof yt=="number"||typeof yt=="bigint"?(yt=""+yt,pt!==null&&pt.tag===6?(_(gt,pt.sibling),It=V(pt,yt),It.return=gt,gt=It):(_(gt,pt),It=BA(yt,gt.mode,It),It.return=gt,gt=It),Ne(gt)):_(gt,pt)}return function(gt,pt,yt,It){try{av=0;var An=Qr(gt,pt,yt,It);return mb=null,An}catch(vn){if(vn===ub||vn===s_)throw vn;var Er=Ko(29,vn,null,gt.mode);return Er.lanes=It,Er.return=gt,Er}}}var lf=cU(!0),dU=cU(!1),Ym=!1;function ej(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function tj(h,y){h=h.updateQueue,y.updateQueue===h&&(y.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function Qm(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Jm(h,y,_){var j=h.updateQueue;if(j===null)return null;if(j=j.shared,(Lr&2)!==0){var V=j.pending;return V===null?y.next=y:(y.next=V.next,V.next=y),j.pending=y,y=e_(h),W5(h,null,_),y}return ZS(h,j,y,_),e_(h)}function sv(h,y,_){if(y=y.updateQueue,y!==null&&(y=y.shared,(_&4194048)!==0)){var j=y.lanes;j&=h.pendingLanes,_|=j,y.lanes=_,qt(h,_)}}function nj(h,y){var _=h.updateQueue,j=h.alternate;if(j!==null&&(j=j.updateQueue,_===j)){var V=null,J=null;if(_=_.firstBaseUpdate,_!==null){do{var Ne={lane:_.lane,tag:_.tag,payload:_.payload,callback:null,next:null};J===null?V=J=Ne:J=J.next=Ne,_=_.next}while(_!==null);J===null?V=J=y:J=J.next=y}else V=J=y;_={baseState:j.baseState,firstBaseUpdate:V,lastBaseUpdate:J,shared:j.shared,callbacks:j.callbacks},h.updateQueue=_;return}h=_.lastBaseUpdate,h===null?_.firstBaseUpdate=y:h.next=y,_.lastBaseUpdate=y}var rj=!1;function ov(){if(rj){var h=db;if(h!==null)throw h}}function lv(h,y,_,j){rj=!1;var V=h.updateQueue;Ym=!1;var J=V.firstBaseUpdate,Ne=V.lastBaseUpdate,qe=V.shared.pending;if(qe!==null){V.shared.pending=null;var lt=qe,vt=lt.next;lt.next=null,Ne===null?J=vt:Ne.next=vt,Ne=lt;var Rt=h.alternate;Rt!==null&&(Rt=Rt.updateQueue,qe=Rt.lastBaseUpdate,qe!==Ne&&(qe===null?Rt.firstBaseUpdate=vt:qe.next=vt,Rt.lastBaseUpdate=lt))}if(J!==null){var Ut=V.baseState;Ne=0,Rt=vt=lt=null,qe=J;do{var kt=qe.lane&-536870913,At=kt!==qe.lane;if(At?(yr&kt)===kt:(j&kt)===kt){kt!==0&&kt===cb&&(rj=!0),Rt!==null&&(Rt=Rt.next={lane:0,tag:qe.tag,payload:qe.payload,callback:null,next:null});e:{var bn=h,In=qe;kt=y;var Qr=_;switch(In.tag){case 1:if(bn=In.payload,typeof bn=="function"){Ut=bn.call(Qr,Ut,kt);break e}Ut=bn;break e;case 3:bn.flags=bn.flags&-65537|128;case 0:if(bn=In.payload,kt=typeof bn=="function"?bn.call(Qr,Ut,kt):bn,kt==null)break e;Ut=m({},Ut,kt);break e;case 2:Ym=!0}}kt=qe.callback,kt!==null&&(h.flags|=64,At&&(h.flags|=8192),At=V.callbacks,At===null?V.callbacks=[kt]:At.push(kt))}else At={lane:kt,tag:qe.tag,payload:qe.payload,callback:qe.callback,next:null},Rt===null?(vt=Rt=At,lt=Ut):Rt=Rt.next=At,Ne|=kt;if(qe=qe.next,qe===null){if(qe=V.shared.pending,qe===null)break;At=qe,qe=At.next,At.next=null,V.lastBaseUpdate=At,V.shared.pending=null}}while(!0);Rt===null&&(lt=Ut),V.baseState=lt,V.firstBaseUpdate=vt,V.lastBaseUpdate=Rt,J===null&&(V.shared.lanes=0),rh|=Ne,h.lanes=Ne,h.memoizedState=Ut}}function uU(h,y){if(typeof h!="function")throw Error(r(191,h));h.call(y)}function mU(h,y){var _=h.callbacks;if(_!==null)for(h.callbacks=null,h=0;h<_.length;h++)uU(_[h],y)}var hb=X(null),d_=X(0);function hU(h,y){h=wu,pe(d_,h),pe(hb,y),wu=h|y.baseLanes}function aj(){pe(d_,wu),pe(hb,hb.current)}function ij(){wu=d_.current,ae(hb),ae(d_)}var Xo=X(null),Dl=null;function Zm(h){var y=h.alternate;pe(ai,ai.current&1),pe(Xo,h),Dl===null&&(y===null||hb.current!==null||y.memoizedState!==null)&&(Dl=h)}function sj(h){pe(ai,ai.current),pe(Xo,h),Dl===null&&(Dl=h)}function pU(h){h.tag===22?(pe(ai,ai.current),pe(Xo,h),Dl===null&&(Dl=h)):eh()}function eh(){pe(ai,ai.current),pe(Xo,Xo.current)}function Yo(h){ae(Xo),Dl===h&&(Dl=null),ae(ai)}var ai=X(0);function u_(h){for(var y=h;y!==null;){if(y.tag===13){var _=y.memoizedState;if(_!==null&&(_=_.dehydrated,_===null||mM(_)||hM(_)))return y}else if(y.tag===19&&(y.memoizedProps.revealOrder==="forwards"||y.memoizedProps.revealOrder==="backwards"||y.memoizedProps.revealOrder==="unstable_legacy-backwards"||y.memoizedProps.revealOrder==="together")){if((y.flags&128)!==0)return y}else if(y.child!==null){y.child.return=y,y=y.child;continue}if(y===h)break;for(;y.sibling===null;){if(y.return===null||y.return===h)return null;y=y.return}y.sibling.return=y.return,y=y.sibling}return null}var hu=0,Xn=null,Xr=null,mi=null,m_=!1,pb=!1,cf=!1,h_=0,cv=0,fb=null,Jce=0;function $a(){throw Error(r(321))}function oj(h,y){if(y===null)return!1;for(var _=0;_J?J:8;var Ne=re.T,qe={};re.T=qe,Sj(h,!1,y,_);try{var lt=V(),vt=re.S;if(vt!==null&&vt(qe,lt),lt!==null&&typeof lt=="object"&&typeof lt.then=="function"){var Rt=Qce(lt,j);uv(h,y,Rt,Zo(h))}else uv(h,y,j,Zo(h))}catch(Ut){uv(h,y,{then:function(){},status:"rejected",reason:Ut},Zo())}finally{Z.p=J,Ne!==null&&qe.types!==null&&(Ne.types=qe.types),re.T=Ne}}function rde(){}function vj(h,y,_,j){if(h.tag!==5)throw Error(r(476));var V=$U(h).queue;qU(h,V,y,ue,_===null?rde:function(){return VU(h),_(j)})}function $U(h){var y=h.memoizedState;if(y!==null)return y;y={memoizedState:ue,baseState:ue,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:pu,lastRenderedState:ue},next:null};var _={};return y.next={memoizedState:_,baseState:_,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:pu,lastRenderedState:_},next:null},h.memoizedState=y,h=h.alternate,h!==null&&(h.memoizedState=y),y}function VU(h){var y=$U(h);y.next===null&&(y=h.alternate.memoizedState),uv(h,y.next.queue,{},Zo())}function wj(){return ds(Tv)}function GU(){return ii().memoizedState}function WU(){return ii().memoizedState}function ade(h){for(var y=h.return;y!==null;){switch(y.tag){case 24:case 3:var _=Zo();h=Qm(_);var j=Jm(y,h,_);j!==null&&(To(j,y,_),sv(j,y,_)),y={cache:YA()},h.payload=y;return}y=y.return}}function ide(h,y,_){var j=Zo();_={lane:j,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null},y_(h)?XU(y,_):(_=zA(h,y,_,j),_!==null&&(To(_,h,j),YU(_,y,j)))}function KU(h,y,_){var j=Zo();uv(h,y,_,j)}function uv(h,y,_,j){var V={lane:j,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null};if(y_(h))XU(y,V);else{var J=h.alternate;if(h.lanes===0&&(J===null||J.lanes===0)&&(J=y.lastRenderedReducer,J!==null))try{var Ne=y.lastRenderedState,qe=J(Ne,_);if(V.hasEagerState=!0,V.eagerState=qe,_o(qe,Ne))return ZS(h,y,V,0),oa===null&&JS(),!1}catch{}if(_=zA(h,y,V,j),_!==null)return To(_,h,j),YU(_,y,j),!0}return!1}function Sj(h,y,_,j){if(j={lane:2,revertLane:eM(),gesture:null,action:j,hasEagerState:!1,eagerState:null,next:null},y_(h)){if(y)throw Error(r(479))}else y=zA(h,_,j,2),y!==null&&To(y,h,2)}function y_(h){var y=h.alternate;return h===Xn||y!==null&&y===Xn}function XU(h,y){pb=m_=!0;var _=h.pending;_===null?y.next=y:(y.next=_.next,_.next=y),h.pending=y}function YU(h,y,_){if((_&4194048)!==0){var j=y.lanes;j&=h.pendingLanes,_|=j,y.lanes=_,qt(h,_)}}var mv={readContext:ds,use:f_,useCallback:$a,useContext:$a,useEffect:$a,useImperativeHandle:$a,useLayoutEffect:$a,useInsertionEffect:$a,useMemo:$a,useReducer:$a,useRef:$a,useState:$a,useDebugValue:$a,useDeferredValue:$a,useTransition:$a,useSyncExternalStore:$a,useId:$a,useHostTransitionStatus:$a,useFormState:$a,useActionState:$a,useOptimistic:$a,useMemoCache:$a,useCacheRefresh:$a};mv.useEffectEvent=$a;var QU={readContext:ds,use:f_,useCallback:function(h,y){return Zs().memoizedState=[h,y===void 0?null:y],h},useContext:ds,useEffect:FU,useImperativeHandle:function(h,y,_){_=_!=null?_.concat([h]):null,b_(4194308,4,OU.bind(null,y,h),_)},useLayoutEffect:function(h,y){return b_(4194308,4,h,y)},useInsertionEffect:function(h,y){b_(4,2,h,y)},useMemo:function(h,y){var _=Zs();y=y===void 0?null:y;var j=h();if(cf){Me(!0);try{h()}finally{Me(!1)}}return _.memoizedState=[j,y],j},useReducer:function(h,y,_){var j=Zs();if(_!==void 0){var V=_(y);if(cf){Me(!0);try{_(y)}finally{Me(!1)}}}else V=y;return j.memoizedState=j.baseState=V,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:V},j.queue=h,h=h.dispatch=ide.bind(null,Xn,h),[j.memoizedState,h]},useRef:function(h){var y=Zs();return h={current:h},y.memoizedState=h},useState:function(h){h=fj(h);var y=h.queue,_=KU.bind(null,Xn,y);return y.dispatch=_,[h.memoizedState,_]},useDebugValue:xj,useDeferredValue:function(h,y){var _=Zs();return yj(_,h,y)},useTransition:function(){var h=fj(!1);return h=qU.bind(null,Xn,h.queue,!0,!1),Zs().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,y,_){var j=Xn,V=Zs();if(Sr){if(_===void 0)throw Error(r(407));_=_()}else{if(_=y(),oa===null)throw Error(r(349));(yr&127)!==0||xU(j,y,_)}V.memoizedState=_;var J={value:_,getSnapshot:y};return V.queue=J,FU(vU.bind(null,j,J,h),[h]),j.flags|=2048,gb(9,{destroy:void 0},yU.bind(null,j,J,_,y),null),_},useId:function(){var h=Zs(),y=oa.identifierPrefix;if(Sr){var _=cd,j=ld;_=(j&~(1<<32-Oe(j)-1)).toString(32)+_,y="_"+y+"R_"+_,_=h_++,0<_&&(y+="H"+_.toString(32)),y+="_"}else _=Jce++,y="_"+y+"r_"+_.toString(32)+"_";return h.memoizedState=y},useHostTransitionStatus:wj,useFormState:AU,useActionState:AU,useOptimistic:function(h){var y=Zs();y.memoizedState=y.baseState=h;var _={pending:null,lanes:0,dispatch:null,lastRenderedReducer:null,lastRenderedState:null};return y.queue=_,y=Sj.bind(null,Xn,!0,_),_.dispatch=y,[h,y]},useMemoCache:mj,useCacheRefresh:function(){return Zs().memoizedState=ade.bind(null,Xn)},useEffectEvent:function(h){var y=Zs(),_={impl:h};return y.memoizedState=_,function(){if((Lr&2)!==0)throw Error(r(440));return _.impl.apply(void 0,arguments)}}},_j={readContext:ds,use:f_,useCallback:UU,useContext:ds,useEffect:bj,useImperativeHandle:zU,useInsertionEffect:LU,useLayoutEffect:IU,useMemo:BU,useReducer:g_,useRef:DU,useState:function(){return g_(pu)},useDebugValue:xj,useDeferredValue:function(h,y){var _=ii();return HU(_,Xr.memoizedState,h,y)},useTransition:function(){var h=g_(pu)[0],y=ii().memoizedState;return[typeof h=="boolean"?h:dv(h),y]},useSyncExternalStore:bU,useId:GU,useHostTransitionStatus:wj,useFormState:jU,useActionState:jU,useOptimistic:function(h,y){var _=ii();return _U(_,Xr,h,y)},useMemoCache:mj,useCacheRefresh:WU};_j.useEffectEvent=RU;var JU={readContext:ds,use:f_,useCallback:UU,useContext:ds,useEffect:bj,useImperativeHandle:zU,useInsertionEffect:LU,useLayoutEffect:IU,useMemo:BU,useReducer:pj,useRef:DU,useState:function(){return pj(pu)},useDebugValue:xj,useDeferredValue:function(h,y){var _=ii();return Xr===null?yj(_,h,y):HU(_,Xr.memoizedState,h,y)},useTransition:function(){var h=pj(pu)[0],y=ii().memoizedState;return[typeof h=="boolean"?h:dv(h),y]},useSyncExternalStore:bU,useId:GU,useHostTransitionStatus:wj,useFormState:EU,useActionState:EU,useOptimistic:function(h,y){var _=ii();return Xr!==null?_U(_,Xr,h,y):(_.baseState=h,[h,_.queue.dispatch])},useMemoCache:mj,useCacheRefresh:WU};JU.useEffectEvent=RU;function kj(h,y,_,j){y=h.memoizedState,_=_(j,y),_=_==null?y:m({},y,_),h.memoizedState=_,h.lanes===0&&(h.updateQueue.baseState=_)}var Nj={enqueueSetState:function(h,y,_){h=h._reactInternals;var j=Zo(),V=Qm(j);V.payload=y,_!=null&&(V.callback=_),y=Jm(h,V,j),y!==null&&(To(y,h,j),sv(y,h,j))},enqueueReplaceState:function(h,y,_){h=h._reactInternals;var j=Zo(),V=Qm(j);V.tag=1,V.payload=y,_!=null&&(V.callback=_),y=Jm(h,V,j),y!==null&&(To(y,h,j),sv(y,h,j))},enqueueForceUpdate:function(h,y){h=h._reactInternals;var _=Zo(),j=Qm(_);j.tag=2,y!=null&&(j.callback=y),y=Jm(h,j,_),y!==null&&(To(y,h,_),sv(y,h,_))}};function ZU(h,y,_,j,V,J,Ne){return h=h.stateNode,typeof h.shouldComponentUpdate=="function"?h.shouldComponentUpdate(j,J,Ne):y.prototype&&y.prototype.isPureReactComponent?!Vm(_,j)||!Vm(V,J):!0}function eB(h,y,_,j){h=y.state,typeof y.componentWillReceiveProps=="function"&&y.componentWillReceiveProps(_,j),typeof y.UNSAFE_componentWillReceiveProps=="function"&&y.UNSAFE_componentWillReceiveProps(_,j),y.state!==h&&Nj.enqueueReplaceState(y,y.state,null)}function df(h,y){var _=y;if("ref"in y){_={};for(var j in y)j!=="ref"&&(_[j]=y[j])}if(h=h.defaultProps){_===y&&(_=m({},_));for(var V in h)_[V]===void 0&&(_[V]=h[V])}return _}function tB(h){QS(h)}function nB(h){console.error(h)}function rB(h){QS(h)}function v_(h,y){try{var _=h.onUncaughtError;_(y.value,{componentStack:y.stack})}catch(j){setTimeout(function(){throw j})}}function aB(h,y,_){try{var j=h.onCaughtError;j(_.value,{componentStack:_.stack,errorBoundary:y.tag===1?y.stateNode:null})}catch(V){setTimeout(function(){throw V})}}function Cj(h,y,_){return _=Qm(_),_.tag=3,_.payload={element:null},_.callback=function(){v_(h,y)},_}function iB(h){return h=Qm(h),h.tag=3,h}function sB(h,y,_,j){var V=_.type.getDerivedStateFromError;if(typeof V=="function"){var J=j.value;h.payload=function(){return V(J)},h.callback=function(){aB(y,_,j)}}var Ne=_.stateNode;Ne!==null&&typeof Ne.componentDidCatch=="function"&&(h.callback=function(){aB(y,_,j),typeof V!="function"&&(ah===null?ah=new Set([this]):ah.add(this));var qe=j.stack;this.componentDidCatch(j.value,{componentStack:qe!==null?qe:""})})}function sde(h,y,_,j,V){if(_.flags|=32768,j!==null&&typeof j=="object"&&typeof j.then=="function"){if(y=_.alternate,y!==null&&lb(y,_,V,!0),_=Xo.current,_!==null){switch(_.tag){case 31:case 13:return Dl===null?E_():_.alternate===null&&Va===0&&(Va=3),_.flags&=-257,_.flags|=65536,_.lanes=V,j===o_?_.flags|=16384:(y=_.updateQueue,y===null?_.updateQueue=new Set([j]):y.add(j),Qj(h,j,V)),!1;case 22:return _.flags|=65536,j===o_?_.flags|=16384:(y=_.updateQueue,y===null?(y={transitions:null,markerInstances:null,retryQueue:new Set([j])},_.updateQueue=y):(_=y.retryQueue,_===null?y.retryQueue=new Set([j]):_.add(j)),Qj(h,j,V)),!1}throw Error(r(435,_.tag))}return Qj(h,j,V),E_(),!1}if(Sr)return y=Xo.current,y!==null?((y.flags&65536)===0&&(y.flags|=256),y.flags|=65536,y.lanes=V,j!==VA&&(h=Error(r(422),{cause:j}),tv(Al(h,_)))):(j!==VA&&(y=Error(r(423),{cause:j}),tv(Al(y,_))),h=h.current.alternate,h.flags|=65536,V&=-V,h.lanes|=V,j=Al(j,_),V=Cj(h.stateNode,j,V),nj(h,V),Va!==4&&(Va=2)),!1;var J=Error(r(520),{cause:j});if(J=Al(J,_),vv===null?vv=[J]:vv.push(J),Va!==4&&(Va=2),y===null)return!0;j=Al(j,_),_=y;do{switch(_.tag){case 3:return _.flags|=65536,h=V&-V,_.lanes|=h,h=Cj(_.stateNode,j,h),nj(_,h),!1;case 1:if(y=_.type,J=_.stateNode,(_.flags&128)===0&&(typeof y.getDerivedStateFromError=="function"||J!==null&&typeof J.componentDidCatch=="function"&&(ah===null||!ah.has(J))))return _.flags|=65536,V&=-V,_.lanes|=V,V=iB(V),sB(V,h,_,j),nj(_,V),!1}_=_.return}while(_!==null);return!1}var Pj=Error(r(461)),hi=!1;function us(h,y,_,j){y.child=h===null?dU(y,null,_,j):lf(y,h.child,_,j)}function oB(h,y,_,j,V){_=_.render;var J=y.ref;if("ref"in j){var Ne={};for(var qe in j)qe!=="ref"&&(Ne[qe]=j[qe])}else Ne=j;return rf(y),j=lj(h,y,_,Ne,J,V),qe=cj(),h!==null&&!hi?(dj(h,y,V),fu(h,y,V)):(Sr&&qe&&qA(y),y.flags|=1,us(h,y,j,V),y.child)}function lB(h,y,_,j,V){if(h===null){var J=_.type;return typeof J=="function"&&!UA(J)&&J.defaultProps===void 0&&_.compare===null?(y.tag=15,y.type=J,cB(h,y,J,j,V)):(h=t_(_.type,null,j,y,y.mode,V),h.ref=y.ref,h.return=y,y.child=h)}if(J=h.child,!Rj(h,V)){var Ne=J.memoizedProps;if(_=_.compare,_=_!==null?_:Vm,_(Ne,j)&&h.ref===y.ref)return fu(h,y,V)}return y.flags|=1,h=cu(J,j),h.ref=y.ref,h.return=y,y.child=h}function cB(h,y,_,j,V){if(h!==null){var J=h.memoizedProps;if(Vm(J,j)&&h.ref===y.ref)if(hi=!1,y.pendingProps=j=J,Rj(h,V))(h.flags&131072)!==0&&(hi=!0);else return y.lanes=h.lanes,fu(h,y,V)}return Tj(h,y,_,j,V)}function dB(h,y,_,j){var V=j.children,J=h!==null?h.memoizedState:null;if(h===null&&y.stateNode===null&&(y.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),j.mode==="hidden"){if((y.flags&128)!==0){if(J=J!==null?J.baseLanes|_:_,h!==null){for(j=y.child=h.child,V=0;j!==null;)V=V|j.lanes|j.childLanes,j=j.sibling;j=V&~J}else j=0,y.child=null;return uB(h,y,J,_,j)}if((_&536870912)!==0)y.memoizedState={baseLanes:0,cachePool:null},h!==null&&i_(y,J!==null?J.cachePool:null),J!==null?hU(y,J):aj(),pU(y);else return j=y.lanes=536870912,uB(h,y,J!==null?J.baseLanes|_:_,_,j)}else J!==null?(i_(y,J.cachePool),hU(y,J),eh(),y.memoizedState=null):(h!==null&&i_(y,null),aj(),eh());return us(h,y,V,_),y.child}function hv(h,y){return h!==null&&h.tag===22||y.stateNode!==null||(y.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),y.sibling}function uB(h,y,_,j,V){var J=JA();return J=J===null?null:{parent:ui._currentValue,pool:J},y.memoizedState={baseLanes:_,cachePool:J},h!==null&&i_(y,null),aj(),pU(y),h!==null&&lb(h,y,j,!0),y.childLanes=V,null}function w_(h,y){return y=__({mode:y.mode,children:y.children},h.mode),y.ref=h.ref,h.child=y,y.return=h,y}function mB(h,y,_){return lf(y,h.child,null,_),h=w_(y,y.pendingProps),h.flags|=2,Yo(y),y.memoizedState=null,h}function ode(h,y,_){var j=y.pendingProps,V=(y.flags&128)!==0;if(y.flags&=-129,h===null){if(Sr){if(j.mode==="hidden")return h=w_(y,j),y.lanes=536870912,hv(null,h);if(sj(y),(h=xa)?(h=k8(h,El),h=h!==null&&h.data==="&"?h:null,h!==null&&(y.memoizedState={dehydrated:h,treeContext:Gm!==null?{id:ld,overflow:cd}:null,retryLane:536870912,hydrationErrors:null},_=X5(h),_.return=y,y.child=_,cs=y,xa=null)):h=null,h===null)throw Km(y);return y.lanes=536870912,null}return w_(y,j)}var J=h.memoizedState;if(J!==null){var Ne=J.dehydrated;if(sj(y),V)if(y.flags&256)y.flags&=-257,y=mB(h,y,_);else if(y.memoizedState!==null)y.child=h.child,y.flags|=128,y=null;else throw Error(r(558));else if(hi||lb(h,y,_,!1),V=(_&h.childLanes)!==0,hi||V){if(j=oa,j!==null&&(Ne=Vt(j,_),Ne!==0&&Ne!==J.retryLane))throw J.retryLane=Ne,Zp(h,Ne),To(j,h,Ne),Pj;E_(),y=mB(h,y,_)}else h=J.treeContext,xa=Fl(Ne.nextSibling),cs=y,Sr=!0,Wm=null,El=!1,h!==null&&J5(y,h),y=w_(y,j),y.flags|=4096;return y}return h=cu(h.child,{mode:j.mode,children:j.children}),h.ref=y.ref,y.child=h,h.return=y,h}function S_(h,y){var _=y.ref;if(_===null)h!==null&&h.ref!==null&&(y.flags|=4194816);else{if(typeof _!="function"&&typeof _!="object")throw Error(r(284));(h===null||h.ref!==_)&&(y.flags|=4194816)}}function Tj(h,y,_,j,V){return rf(y),_=lj(h,y,_,j,void 0,V),j=cj(),h!==null&&!hi?(dj(h,y,V),fu(h,y,V)):(Sr&&j&&qA(y),y.flags|=1,us(h,y,_,V),y.child)}function hB(h,y,_,j,V,J){return rf(y),y.updateQueue=null,_=gU(y,j,_,V),fU(h),j=cj(),h!==null&&!hi?(dj(h,y,J),fu(h,y,J)):(Sr&&j&&qA(y),y.flags|=1,us(h,y,_,J),y.child)}function pB(h,y,_,j,V){if(rf(y),y.stateNode===null){var J=ab,Ne=_.contextType;typeof Ne=="object"&&Ne!==null&&(J=ds(Ne)),J=new _(j,J),y.memoizedState=J.state!==null&&J.state!==void 0?J.state:null,J.updater=Nj,y.stateNode=J,J._reactInternals=y,J=y.stateNode,J.props=j,J.state=y.memoizedState,J.refs={},ej(y),Ne=_.contextType,J.context=typeof Ne=="object"&&Ne!==null?ds(Ne):ab,J.state=y.memoizedState,Ne=_.getDerivedStateFromProps,typeof Ne=="function"&&(kj(y,_,Ne,j),J.state=y.memoizedState),typeof _.getDerivedStateFromProps=="function"||typeof J.getSnapshotBeforeUpdate=="function"||typeof J.UNSAFE_componentWillMount!="function"&&typeof J.componentWillMount!="function"||(Ne=J.state,typeof J.componentWillMount=="function"&&J.componentWillMount(),typeof J.UNSAFE_componentWillMount=="function"&&J.UNSAFE_componentWillMount(),Ne!==J.state&&Nj.enqueueReplaceState(J,J.state,null),lv(y,j,J,V),ov(),J.state=y.memoizedState),typeof J.componentDidMount=="function"&&(y.flags|=4194308),j=!0}else if(h===null){J=y.stateNode;var qe=y.memoizedProps,lt=df(_,qe);J.props=lt;var vt=J.context,Rt=_.contextType;Ne=ab,typeof Rt=="object"&&Rt!==null&&(Ne=ds(Rt));var Ut=_.getDerivedStateFromProps;Rt=typeof Ut=="function"||typeof J.getSnapshotBeforeUpdate=="function",qe=y.pendingProps!==qe,Rt||typeof J.UNSAFE_componentWillReceiveProps!="function"&&typeof J.componentWillReceiveProps!="function"||(qe||vt!==Ne)&&eB(y,J,j,Ne),Ym=!1;var kt=y.memoizedState;J.state=kt,lv(y,j,J,V),ov(),vt=y.memoizedState,qe||kt!==vt||Ym?(typeof Ut=="function"&&(kj(y,_,Ut,j),vt=y.memoizedState),(lt=Ym||ZU(y,_,lt,j,kt,vt,Ne))?(Rt||typeof J.UNSAFE_componentWillMount!="function"&&typeof J.componentWillMount!="function"||(typeof J.componentWillMount=="function"&&J.componentWillMount(),typeof J.UNSAFE_componentWillMount=="function"&&J.UNSAFE_componentWillMount()),typeof J.componentDidMount=="function"&&(y.flags|=4194308)):(typeof J.componentDidMount=="function"&&(y.flags|=4194308),y.memoizedProps=j,y.memoizedState=vt),J.props=j,J.state=vt,J.context=Ne,j=lt):(typeof J.componentDidMount=="function"&&(y.flags|=4194308),j=!1)}else{J=y.stateNode,tj(h,y),Ne=y.memoizedProps,Rt=df(_,Ne),J.props=Rt,Ut=y.pendingProps,kt=J.context,vt=_.contextType,lt=ab,typeof vt=="object"&&vt!==null&&(lt=ds(vt)),qe=_.getDerivedStateFromProps,(vt=typeof qe=="function"||typeof J.getSnapshotBeforeUpdate=="function")||typeof J.UNSAFE_componentWillReceiveProps!="function"&&typeof J.componentWillReceiveProps!="function"||(Ne!==Ut||kt!==lt)&&eB(y,J,j,lt),Ym=!1,kt=y.memoizedState,J.state=kt,lv(y,j,J,V),ov();var At=y.memoizedState;Ne!==Ut||kt!==At||Ym||h!==null&&h.dependencies!==null&&r_(h.dependencies)?(typeof qe=="function"&&(kj(y,_,qe,j),At=y.memoizedState),(Rt=Ym||ZU(y,_,Rt,j,kt,At,lt)||h!==null&&h.dependencies!==null&&r_(h.dependencies))?(vt||typeof J.UNSAFE_componentWillUpdate!="function"&&typeof J.componentWillUpdate!="function"||(typeof J.componentWillUpdate=="function"&&J.componentWillUpdate(j,At,lt),typeof J.UNSAFE_componentWillUpdate=="function"&&J.UNSAFE_componentWillUpdate(j,At,lt)),typeof J.componentDidUpdate=="function"&&(y.flags|=4),typeof J.getSnapshotBeforeUpdate=="function"&&(y.flags|=1024)):(typeof J.componentDidUpdate!="function"||Ne===h.memoizedProps&&kt===h.memoizedState||(y.flags|=4),typeof J.getSnapshotBeforeUpdate!="function"||Ne===h.memoizedProps&&kt===h.memoizedState||(y.flags|=1024),y.memoizedProps=j,y.memoizedState=At),J.props=j,J.state=At,J.context=lt,j=Rt):(typeof J.componentDidUpdate!="function"||Ne===h.memoizedProps&&kt===h.memoizedState||(y.flags|=4),typeof J.getSnapshotBeforeUpdate!="function"||Ne===h.memoizedProps&&kt===h.memoizedState||(y.flags|=1024),j=!1)}return J=j,S_(h,y),j=(y.flags&128)!==0,J||j?(J=y.stateNode,_=j&&typeof _.getDerivedStateFromError!="function"?null:J.render(),y.flags|=1,h!==null&&j?(y.child=lf(y,h.child,null,V),y.child=lf(y,null,_,V)):us(h,y,_,V),y.memoizedState=J.state,h=y.child):h=fu(h,y,V),h}function fB(h,y,_,j){return tf(),y.flags|=256,us(h,y,_,j),y.child}var Aj={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function jj(h){return{baseLanes:h,cachePool:aU()}}function Mj(h,y,_){return h=h!==null?h.childLanes&~_:0,y&&(h|=Jo),h}function gB(h,y,_){var j=y.pendingProps,V=!1,J=(y.flags&128)!==0,Ne;if((Ne=J)||(Ne=h!==null&&h.memoizedState===null?!1:(ai.current&2)!==0),Ne&&(V=!0,y.flags&=-129),Ne=(y.flags&32)!==0,y.flags&=-33,h===null){if(Sr){if(V?Zm(y):eh(),(h=xa)?(h=k8(h,El),h=h!==null&&h.data!=="&"?h:null,h!==null&&(y.memoizedState={dehydrated:h,treeContext:Gm!==null?{id:ld,overflow:cd}:null,retryLane:536870912,hydrationErrors:null},_=X5(h),_.return=y,y.child=_,cs=y,xa=null)):h=null,h===null)throw Km(y);return hM(h)?y.lanes=32:y.lanes=536870912,null}var qe=j.children;return j=j.fallback,V?(eh(),V=y.mode,qe=__({mode:"hidden",children:qe},V),j=ef(j,V,_,null),qe.return=y,j.return=y,qe.sibling=j,y.child=qe,j=y.child,j.memoizedState=jj(_),j.childLanes=Mj(h,Ne,_),y.memoizedState=Aj,hv(null,j)):(Zm(y),Ej(y,qe))}var lt=h.memoizedState;if(lt!==null&&(qe=lt.dehydrated,qe!==null)){if(J)y.flags&256?(Zm(y),y.flags&=-257,y=Dj(h,y,_)):y.memoizedState!==null?(eh(),y.child=h.child,y.flags|=128,y=null):(eh(),qe=j.fallback,V=y.mode,j=__({mode:"visible",children:j.children},V),qe=ef(qe,V,_,null),qe.flags|=2,j.return=y,qe.return=y,j.sibling=qe,y.child=j,lf(y,h.child,null,_),j=y.child,j.memoizedState=jj(_),j.childLanes=Mj(h,Ne,_),y.memoizedState=Aj,y=hv(null,j));else if(Zm(y),hM(qe)){if(Ne=qe.nextSibling&&qe.nextSibling.dataset,Ne)var vt=Ne.dgst;Ne=vt,j=Error(r(419)),j.stack="",j.digest=Ne,tv({value:j,source:null,stack:null}),y=Dj(h,y,_)}else if(hi||lb(h,y,_,!1),Ne=(_&h.childLanes)!==0,hi||Ne){if(Ne=oa,Ne!==null&&(j=Vt(Ne,_),j!==0&&j!==lt.retryLane))throw lt.retryLane=j,Zp(h,j),To(Ne,h,j),Pj;mM(qe)||E_(),y=Dj(h,y,_)}else mM(qe)?(y.flags|=192,y.child=h.child,y=null):(h=lt.treeContext,xa=Fl(qe.nextSibling),cs=y,Sr=!0,Wm=null,El=!1,h!==null&&J5(y,h),y=Ej(y,j.children),y.flags|=4096);return y}return V?(eh(),qe=j.fallback,V=y.mode,lt=h.child,vt=lt.sibling,j=cu(lt,{mode:"hidden",children:j.children}),j.subtreeFlags=lt.subtreeFlags&65011712,vt!==null?qe=cu(vt,qe):(qe=ef(qe,V,_,null),qe.flags|=2),qe.return=y,j.return=y,j.sibling=qe,y.child=j,hv(null,j),j=y.child,qe=h.child.memoizedState,qe===null?qe=jj(_):(V=qe.cachePool,V!==null?(lt=ui._currentValue,V=V.parent!==lt?{parent:lt,pool:lt}:V):V=aU(),qe={baseLanes:qe.baseLanes|_,cachePool:V}),j.memoizedState=qe,j.childLanes=Mj(h,Ne,_),y.memoizedState=Aj,hv(h.child,j)):(Zm(y),_=h.child,h=_.sibling,_=cu(_,{mode:"visible",children:j.children}),_.return=y,_.sibling=null,h!==null&&(Ne=y.deletions,Ne===null?(y.deletions=[h],y.flags|=16):Ne.push(h)),y.child=_,y.memoizedState=null,_)}function Ej(h,y){return y=__({mode:"visible",children:y},h.mode),y.return=h,h.child=y}function __(h,y){return h=Ko(22,h,null,y),h.lanes=0,h}function Dj(h,y,_){return lf(y,h.child,null,_),h=Ej(y,y.pendingProps.children),h.flags|=2,y.memoizedState=null,h}function bB(h,y,_){h.lanes|=y;var j=h.alternate;j!==null&&(j.lanes|=y),KA(h.return,y,_)}function Fj(h,y,_,j,V,J){var Ne=h.memoizedState;Ne===null?h.memoizedState={isBackwards:y,rendering:null,renderingStartTime:0,last:j,tail:_,tailMode:V,treeForkCount:J}:(Ne.isBackwards=y,Ne.rendering=null,Ne.renderingStartTime=0,Ne.last=j,Ne.tail=_,Ne.tailMode=V,Ne.treeForkCount=J)}function xB(h,y,_){var j=y.pendingProps,V=j.revealOrder,J=j.tail;j=j.children;var Ne=ai.current,qe=(Ne&2)!==0;if(qe?(Ne=Ne&1|2,y.flags|=128):Ne&=1,pe(ai,Ne),us(h,y,j,_),j=Sr?ev:0,!qe&&h!==null&&(h.flags&128)!==0)e:for(h=y.child;h!==null;){if(h.tag===13)h.memoizedState!==null&&bB(h,_,y);else if(h.tag===19)bB(h,_,y);else if(h.child!==null){h.child.return=h,h=h.child;continue}if(h===y)break e;for(;h.sibling===null;){if(h.return===null||h.return===y)break e;h=h.return}h.sibling.return=h.return,h=h.sibling}switch(V){case"forwards":for(_=y.child,V=null;_!==null;)h=_.alternate,h!==null&&u_(h)===null&&(V=_),_=_.sibling;_=V,_===null?(V=y.child,y.child=null):(V=_.sibling,_.sibling=null),Fj(y,!1,V,_,J,j);break;case"backwards":case"unstable_legacy-backwards":for(_=null,V=y.child,y.child=null;V!==null;){if(h=V.alternate,h!==null&&u_(h)===null){y.child=V;break}h=V.sibling,V.sibling=_,_=V,V=h}Fj(y,!0,_,null,J,j);break;case"together":Fj(y,!1,null,null,void 0,j);break;default:y.memoizedState=null}return y.child}function fu(h,y,_){if(h!==null&&(y.dependencies=h.dependencies),rh|=y.lanes,(_&y.childLanes)===0)if(h!==null){if(lb(h,y,_,!1),(_&y.childLanes)===0)return null}else return null;if(h!==null&&y.child!==h.child)throw Error(r(153));if(y.child!==null){for(h=y.child,_=cu(h,h.pendingProps),y.child=_,_.return=y;h.sibling!==null;)h=h.sibling,_=_.sibling=cu(h,h.pendingProps),_.return=y;_.sibling=null}return y.child}function Rj(h,y){return(h.lanes&y)!==0?!0:(h=h.dependencies,!!(h!==null&&r_(h)))}function lde(h,y,_){switch(y.tag){case 3:E(y,y.stateNode.containerInfo),Xm(y,ui,h.memoizedState.cache),tf();break;case 27:case 5:U(y);break;case 4:E(y,y.stateNode.containerInfo);break;case 10:Xm(y,y.type,y.memoizedProps.value);break;case 31:if(y.memoizedState!==null)return y.flags|=128,sj(y),null;break;case 13:var j=y.memoizedState;if(j!==null)return j.dehydrated!==null?(Zm(y),y.flags|=128,null):(_&y.child.childLanes)!==0?gB(h,y,_):(Zm(y),h=fu(h,y,_),h!==null?h.sibling:null);Zm(y);break;case 19:var V=(h.flags&128)!==0;if(j=(_&y.childLanes)!==0,j||(lb(h,y,_,!1),j=(_&y.childLanes)!==0),V){if(j)return xB(h,y,_);y.flags|=128}if(V=y.memoizedState,V!==null&&(V.rendering=null,V.tail=null,V.lastEffect=null),pe(ai,ai.current),j)break;return null;case 22:return y.lanes=0,dB(h,y,_,y.pendingProps);case 24:Xm(y,ui,h.memoizedState.cache)}return fu(h,y,_)}function yB(h,y,_){if(h!==null)if(h.memoizedProps!==y.pendingProps)hi=!0;else{if(!Rj(h,_)&&(y.flags&128)===0)return hi=!1,lde(h,y,_);hi=(h.flags&131072)!==0}else hi=!1,Sr&&(y.flags&1048576)!==0&&Q5(y,ev,y.index);switch(y.lanes=0,y.tag){case 16:e:{var j=y.pendingProps;if(h=sf(y.elementType),y.type=h,typeof h=="function")UA(h)?(j=df(h,j),y.tag=1,y=pB(null,y,h,j,_)):(y.tag=0,y=Tj(null,y,h,j,_));else{if(h!=null){var V=h.$$typeof;if(V===P){y.tag=11,y=oB(null,y,h,j,_);break e}else if(V===T){y.tag=14,y=lB(null,y,h,j,_);break e}}throw y=L(h)||h,Error(r(306,y,""))}}return y;case 0:return Tj(h,y,y.type,y.pendingProps,_);case 1:return j=y.type,V=df(j,y.pendingProps),pB(h,y,j,V,_);case 3:e:{if(E(y,y.stateNode.containerInfo),h===null)throw Error(r(387));j=y.pendingProps;var J=y.memoizedState;V=J.element,tj(h,y),lv(y,j,null,_);var Ne=y.memoizedState;if(j=Ne.cache,Xm(y,ui,j),j!==J.cache&&XA(y,[ui],_,!0),ov(),j=Ne.element,J.isDehydrated)if(J={element:j,isDehydrated:!1,cache:Ne.cache},y.updateQueue.baseState=J,y.memoizedState=J,y.flags&256){y=fB(h,y,j,_);break e}else if(j!==V){V=Al(Error(r(424)),y),tv(V),y=fB(h,y,j,_);break e}else for(h=y.stateNode.containerInfo,h.nodeType===9?h=h.body:h=h.nodeName==="HTML"?h.ownerDocument.body:h,xa=Fl(h.firstChild),cs=y,Sr=!0,Wm=null,El=!0,_=dU(y,null,j,_),y.child=_;_;)_.flags=_.flags&-3|4096,_=_.sibling;else{if(tf(),j===V){y=fu(h,y,_);break e}us(h,y,j,_)}y=y.child}return y;case 26:return S_(h,y),h===null?(_=j8(y.type,null,y.pendingProps,null))?y.memoizedState=_:Sr||(_=y.type,h=y.pendingProps,j=z_(B.current).createElement(_),j[jt]=y,j[Jt]=h,ms(j,_,h),nt(j),y.stateNode=j):y.memoizedState=j8(y.type,h.memoizedProps,y.pendingProps,h.memoizedState),null;case 27:return U(y),h===null&&Sr&&(j=y.stateNode=P8(y.type,y.pendingProps,B.current),cs=y,El=!0,V=xa,lh(y.type)?(pM=V,xa=Fl(j.firstChild)):xa=V),us(h,y,y.pendingProps.children,_),S_(h,y),h===null&&(y.flags|=4194304),y.child;case 5:return h===null&&Sr&&((V=j=xa)&&(j=Ode(j,y.type,y.pendingProps,El),j!==null?(y.stateNode=j,cs=y,xa=Fl(j.firstChild),El=!1,V=!0):V=!1),V||Km(y)),U(y),V=y.type,J=y.pendingProps,Ne=h!==null?h.memoizedProps:null,j=J.children,cM(V,J)?j=null:Ne!==null&&cM(V,Ne)&&(y.flags|=32),y.memoizedState!==null&&(V=lj(h,y,Zce,null,null,_),Tv._currentValue=V),S_(h,y),us(h,y,j,_),y.child;case 6:return h===null&&Sr&&((h=_=xa)&&(_=zde(_,y.pendingProps,El),_!==null?(y.stateNode=_,cs=y,xa=null,h=!0):h=!1),h||Km(y)),null;case 13:return gB(h,y,_);case 4:return E(y,y.stateNode.containerInfo),j=y.pendingProps,h===null?y.child=lf(y,null,j,_):us(h,y,j,_),y.child;case 11:return oB(h,y,y.type,y.pendingProps,_);case 7:return us(h,y,y.pendingProps,_),y.child;case 8:return us(h,y,y.pendingProps.children,_),y.child;case 12:return us(h,y,y.pendingProps.children,_),y.child;case 10:return j=y.pendingProps,Xm(y,y.type,j.value),us(h,y,j.children,_),y.child;case 9:return V=y.type._context,j=y.pendingProps.children,rf(y),V=ds(V),j=j(V),y.flags|=1,us(h,y,j,_),y.child;case 14:return lB(h,y,y.type,y.pendingProps,_);case 15:return cB(h,y,y.type,y.pendingProps,_);case 19:return xB(h,y,_);case 31:return ode(h,y,_);case 22:return dB(h,y,_,y.pendingProps);case 24:return rf(y),j=ds(ui),h===null?(V=JA(),V===null&&(V=oa,J=YA(),V.pooledCache=J,J.refCount++,J!==null&&(V.pooledCacheLanes|=_),V=J),y.memoizedState={parent:j,cache:V},ej(y),Xm(y,ui,V)):((h.lanes&_)!==0&&(tj(h,y),lv(y,null,null,_),ov()),V=h.memoizedState,J=y.memoizedState,V.parent!==j?(V={parent:j,cache:j},y.memoizedState=V,y.lanes===0&&(y.memoizedState=y.updateQueue.baseState=V),Xm(y,ui,j)):(j=J.cache,Xm(y,ui,j),j!==V.cache&&XA(y,[ui],_,!0))),us(h,y,y.pendingProps.children,_),y.child;case 29:throw y.pendingProps}throw Error(r(156,y.tag))}function gu(h){h.flags|=4}function Lj(h,y,_,j,V){if((y=(h.mode&32)!==0)&&(y=!1),y){if(h.flags|=16777216,(V&335544128)===V)if(h.stateNode.complete)h.flags|=8192;else if(GB())h.flags|=8192;else throw of=o_,ZA}else h.flags&=-16777217}function vB(h,y){if(y.type!=="stylesheet"||(y.state.loading&4)!==0)h.flags&=-16777217;else if(h.flags|=16777216,!R8(y))if(GB())h.flags|=8192;else throw of=o_,ZA}function k_(h,y){y!==null&&(h.flags|=4),h.flags&16384&&(y=h.tag!==22?st():536870912,h.lanes|=y,vb|=y)}function pv(h,y){if(!Sr)switch(h.tailMode){case"hidden":y=h.tail;for(var _=null;y!==null;)y.alternate!==null&&(_=y),y=y.sibling;_===null?h.tail=null:_.sibling=null;break;case"collapsed":_=h.tail;for(var j=null;_!==null;)_.alternate!==null&&(j=_),_=_.sibling;j===null?y||h.tail===null?h.tail=null:h.tail.sibling=null:j.sibling=null}}function ya(h){var y=h.alternate!==null&&h.alternate.child===h.child,_=0,j=0;if(y)for(var V=h.child;V!==null;)_|=V.lanes|V.childLanes,j|=V.subtreeFlags&65011712,j|=V.flags&65011712,V.return=h,V=V.sibling;else for(V=h.child;V!==null;)_|=V.lanes|V.childLanes,j|=V.subtreeFlags,j|=V.flags,V.return=h,V=V.sibling;return h.subtreeFlags|=j,h.childLanes=_,y}function cde(h,y,_){var j=y.pendingProps;switch($A(y),y.tag){case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return ya(y),null;case 1:return ya(y),null;case 3:return _=y.stateNode,j=null,h!==null&&(j=h.memoizedState.cache),y.memoizedState.cache!==j&&(y.flags|=2048),mu(ui),M(),_.pendingContext&&(_.context=_.pendingContext,_.pendingContext=null),(h===null||h.child===null)&&(ob(y)?gu(y):h===null||h.memoizedState.isDehydrated&&(y.flags&256)===0||(y.flags|=1024,GA())),ya(y),null;case 26:var V=y.type,J=y.memoizedState;return h===null?(gu(y),J!==null?(ya(y),vB(y,J)):(ya(y),Lj(y,V,null,j,_))):J?J!==h.memoizedState?(gu(y),ya(y),vB(y,J)):(ya(y),y.flags&=-16777217):(h=h.memoizedProps,h!==j&&gu(y),ya(y),Lj(y,V,h,j,_)),null;case 27:if(Q(y),_=B.current,V=y.type,h!==null&&y.stateNode!=null)h.memoizedProps!==j&&gu(y);else{if(!j){if(y.stateNode===null)throw Error(r(166));return ya(y),null}h=be.current,ob(y)?Z5(y):(h=P8(V,j,_),y.stateNode=h,gu(y))}return ya(y),null;case 5:if(Q(y),V=y.type,h!==null&&y.stateNode!=null)h.memoizedProps!==j&&gu(y);else{if(!j){if(y.stateNode===null)throw Error(r(166));return ya(y),null}if(J=be.current,ob(y))Z5(y);else{var Ne=z_(B.current);switch(J){case 1:J=Ne.createElementNS("http://www.w3.org/2000/svg",V);break;case 2:J=Ne.createElementNS("http://www.w3.org/1998/Math/MathML",V);break;default:switch(V){case"svg":J=Ne.createElementNS("http://www.w3.org/2000/svg",V);break;case"math":J=Ne.createElementNS("http://www.w3.org/1998/Math/MathML",V);break;case"script":J=Ne.createElement("div"),J.innerHTML=" +