From e1224316a77e7bea655d57d4a253f3630cef90ae Mon Sep 17 00:00:00 2001 From: maziggy Date: Tue, 20 Jan 2026 16:59:18 +0100 Subject: [PATCH] =?UTF-8?q?Add=20per-printer=20AMS=20mapping=20for=20multi?= =?UTF-8?q?-printer=20selection=20-=20New=20useMultiPrinterFilamentMapping?= =?UTF-8?q?=20hook=20for=20parallel=20printer=20status=20fetching=20-=20Pe?= =?UTF-8?q?r-printer=20custom=20slot=20configuration=20with=20"Custom=20ma?= =?UTF-8?q?pping"=20checkbox=20-=20Auto-configure=20using=20RFID=20data=20?= =?UTF-8?q?to=20match=20filaments=20by=20type/color=20-=20Match=20status?= =?UTF-8?q?=20indicator=20(exact/partial/missing)=20under=20each=20printer?= =?UTF-8?q?=20-=20Re-read=20button=20to=20refresh=20loaded=20filaments=20-?= =?UTF-8?q?=20New=20setting:=20"Expand=20custom=20mapping=20by=20default"?= =?UTF-8?q?=20in=20Settings=20=E2=86=92=20Filament=20-=20FilamentMapping?= =?UTF-8?q?=20component=20now=20accepts=20defaultExpanded=20prop?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Frontend: - PrinterSelector: Inline mapping editor for each selected printer - PrintModal: Fetches settings, auto-expands mapping when setting enabled - SettingsPage: Toggle for per_printer_mapping_expanded Backend: - Added per_printer_mapping_expanded to AppSettings schema - Added boolean parsing in settings routes - Added integration tests for new setting Closes #104 --- CHANGELOG.md | 30 +- README.md | 1 + backend/app/api/routes/settings.py | 1 + backend/app/schemas/settings.py | 6 + .../tests/integration/test_settings_api.py | 42 + frontend/src/api/client.ts | 2 + .../components/PrintModal/FilamentMapping.tsx | 5 +- .../components/PrintModal/PrinterSelector.tsx | 390 +- frontend/src/components/PrintModal/index.tsx | 86 +- .../hooks/useMultiPrinterFilamentMapping.ts | 385 + frontend/src/pages/SettingsPage.tsx | 29 + static/assets/index-Cw5WdZhp.js | 8665 +++++++++++++++++ static/assets/index-DsI-2RLx.js | 8665 ----------------- static/index.html | 2 +- 14 files changed, 9558 insertions(+), 8751 deletions(-) create mode 100644 frontend/src/hooks/useMultiPrinterFilamentMapping.ts create mode 100644 static/assets/index-Cw5WdZhp.js delete mode 100644 static/assets/index-DsI-2RLx.js diff --git a/CHANGELOG.md b/CHANGELOG.md index ffe705fa5..33ff4561b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,9 +23,15 @@ All notable changes to Bambuddy will be documented in this file. - **Multi-Printer Selection** - Send prints or queue items to multiple printers at once: - Checkbox selection for multiple printers in reprint and add-to-queue modes - "Select all" / "Clear" buttons for quick selection - - Same filament slot mapping applies to all selected printers - Progress indicator during multi-printer submission - Ideal for print farms with identical filament configurations +- **Per-Printer AMS Mapping** - Configure filament slot mapping individually for each printer: + - Enable "Custom mapping" checkbox under each selected printer + - Auto-configure uses RFID data to match filaments automatically + - Manual override for specific slot assignments + - Match status indicator shows exact/partial/missing matches + - Re-read button to refresh printer's loaded filaments + - New setting in Settings → Filament to expand custom mapping by default - **Enhanced Add-to-Queue** - Now includes plate selection and print options: - Configure all print settings upfront instead of editing afterward - Filament mapping with manual override capability @@ -38,20 +44,6 @@ All notable changes to Bambuddy will be documented in this file. - Archives are created automatically when prints start - Reduces clutter in Archives from unprinted queued files - Queue displays library file name, thumbnail, and print time - -### Changed -- **Edit Queue Item modal** - Single printer selection only (reassigns item, doesn't duplicate) -- **Edit Queue Item button** - Changed from "Print to X Printers" to "Save" - -### Fixed -- **File Manager folder navigation** - Fixed bug where opening a folder would briefly show files then jump back to root: - - Removed `selectedFolderId` from useEffect dependency array that was causing a reset loop - - Folder navigation now works correctly without resetting -- **Queue items with library files** - Fixed 500 errors when listing/updating queue items from File Manager - -## [0.1.6b10] - 2026-01-20 - -### New Features - **Expandable Color Picker** - Configure AMS Slot modal now has an expandable color palette: - 8 basic colors shown by default (White, Black, Red, Blue, Green, Yellow, Orange, Gray) - Click "+" to expand 24 additional colors (Cyan, Magenta, Purple, Pink, Brown, Beige, Navy, Teal, Lime, Gold, Silver, Maroon, Olive, Coral, Salmon, Turquoise, Violet, Indigo, Chocolate, Tan, Slate, Charcoal, Ivory, Cream) @@ -67,7 +59,15 @@ All notable changes to Bambuddy will be documented in this file. - Embedded viewer is draggable and resizable with persistent position/size - Configure in Settings → General → Camera section +### Changed +- **Edit Queue Item modal** - Single printer selection only (reassigns item, doesn't duplicate) +- **Edit Queue Item button** - Changed from "Print to X Printers" to "Save" + ### Fixed +- **File Manager folder navigation** - Fixed bug where opening a folder would briefly show files then jump back to root: + - Removed `selectedFolderId` from useEffect dependency array that was causing a reset loop + - Folder navigation now works correctly without resetting +- **Queue items with library files** - Fixed 500 errors when listing/updating queue items from File Manager - **User preset AMS configuration** - Fixed user presets (inheriting from Bambu presets) showing empty fields in Bambu Studio after configuration: - Now correctly derives `tray_info_idx` from the preset's `base_id` when `filament_id` is null - User presets that inherit from Bambu presets (e.g., "# Overture Matte PLA @BBL H2D") now work correctly diff --git a/README.md b/README.md index e79d5873a..8e4bebb6b 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,7 @@ ### ⏰ Scheduling & Automation - Print queue with drag-and-drop - Multi-printer selection (send to multiple printers at once) +- Per-printer AMS mapping (individual slot configuration for print farms) - Scheduled prints (date/time) - Queue Only mode (stage without auto-start) - Smart plug integration (Tasmota, Home Assistant) diff --git a/backend/app/api/routes/settings.py b/backend/app/api/routes/settings.py index 7db46c2f9..4517a870e 100644 --- a/backend/app/api/routes/settings.py +++ b/backend/app/api/routes/settings.py @@ -78,6 +78,7 @@ async def get_settings(db: AsyncSession = Depends(get_db)): "mqtt_enabled", "mqtt_use_tls", "ha_enabled", + "per_printer_mapping_expanded", ]: settings_dict[setting.key] = setting.value.lower() == "true" elif setting.key in [ diff --git a/backend/app/schemas/settings.py b/backend/app/schemas/settings.py index 9c2487923..41ee3cca7 100644 --- a/backend/app/schemas/settings.py +++ b/backend/app/schemas/settings.py @@ -41,6 +41,11 @@ class AppSettings(BaseModel): ) ams_history_retention_days: int = Field(default=30, description="Number of days to keep AMS sensor history data") + # Print modal settings + per_printer_mapping_expanded: bool = Field( + default=False, description="Expand custom filament mapping by default in print modal" + ) + # Date/time display format date_format: str = Field(default="system", description="Date format: system, us, eu, iso") time_format: str = Field(default="system", description="Time format: system, 12h, 24h") @@ -127,6 +132,7 @@ class AppSettingsUpdate(BaseModel): ams_temp_good: float | None = None ams_temp_fair: float | None = None ams_history_retention_days: int | None = None + per_printer_mapping_expanded: bool | None = None date_format: str | None = None time_format: str | None = None default_printer_id: int | None = None diff --git a/backend/tests/integration/test_settings_api.py b/backend/tests/integration/test_settings_api.py index 7ab4757b3..013b5b1ae 100644 --- a/backend/tests/integration/test_settings_api.py +++ b/backend/tests/integration/test_settings_api.py @@ -328,3 +328,45 @@ class TestSettingsAPI: assert "camera_view_mode" in result # Default is 'window' as defined in schema assert result["camera_view_mode"] in ["window", "embedded"] + + # ======================================================================== + # Per-printer mapping settings tests + # ======================================================================== + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_update_per_printer_mapping_expanded(self, async_client: AsyncClient): + """Verify per_printer_mapping_expanded can be updated.""" + response = await async_client.put("/api/v1/settings/", json={"per_printer_mapping_expanded": True}) + + assert response.status_code == 200 + assert response.json()["per_printer_mapping_expanded"] is True + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_per_printer_mapping_expanded_persists(self, async_client: AsyncClient): + """CRITICAL: Verify per_printer_mapping_expanded persists after update.""" + # Update to True + await async_client.put("/api/v1/settings/", json={"per_printer_mapping_expanded": True}) + + # Verify persistence in new request + response = await async_client.get("/api/v1/settings/") + assert response.json()["per_printer_mapping_expanded"] is True + + # Update back to False + await async_client.put("/api/v1/settings/", json={"per_printer_mapping_expanded": False}) + + # Verify persistence + response = await async_client.get("/api/v1/settings/") + assert response.json()["per_printer_mapping_expanded"] is False + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_per_printer_mapping_expanded_default(self, async_client: AsyncClient): + """Verify per_printer_mapping_expanded has correct default value.""" + response = await async_client.get("/api/v1/settings/") + result = response.json() + + assert "per_printer_mapping_expanded" in result + # Default is False as defined in schema + assert isinstance(result["per_printer_mapping_expanded"], bool) diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index f3178856b..021c0fe43 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -558,6 +558,8 @@ export interface AppSettings { ams_temp_good: number; // <= this is green/blue ams_temp_fair: number; // <= this is orange, > is red ams_history_retention_days: number; // days to keep AMS sensor history + // Print modal settings + per_printer_mapping_expanded: boolean; // Whether custom mapping is expanded by default in print modal // Date/time format settings date_format: 'system' | 'us' | 'eu' | 'iso'; time_format: 'system' | '12h' | '24h'; diff --git a/frontend/src/components/PrintModal/FilamentMapping.tsx b/frontend/src/components/PrintModal/FilamentMapping.tsx index 5d1145154..7ae5ce97c 100644 --- a/frontend/src/components/PrintModal/FilamentMapping.tsx +++ b/frontend/src/components/PrintModal/FilamentMapping.tsx @@ -15,10 +15,11 @@ export function FilamentMapping({ filamentReqs, manualMappings, onManualMappingChange, -}: FilamentMappingProps) { + defaultExpanded = false, +}: FilamentMappingProps & { defaultExpanded?: boolean }) { const queryClient = useQueryClient(); const [isRefreshing, setIsRefreshing] = useState(false); - const [isExpanded, setIsExpanded] = useState(false); + const [isExpanded, setIsExpanded] = useState(defaultExpanded); // Fetch printer status const { data: printerStatus } = useQuery({ diff --git a/frontend/src/components/PrintModal/PrinterSelector.tsx b/frontend/src/components/PrintModal/PrinterSelector.tsx index 614970b05..d363e1763 100644 --- a/frontend/src/components/PrintModal/PrinterSelector.tsx +++ b/frontend/src/components/PrintModal/PrinterSelector.tsx @@ -1,9 +1,205 @@ -import { Printer as PrinterIcon, Loader2, AlertCircle, Check } from 'lucide-react'; +import { useState } from 'react'; +import { useQueryClient } from '@tanstack/react-query'; +import { + Printer as PrinterIcon, + Loader2, + AlertCircle, + AlertTriangle, + Check, + Circle, + RefreshCw, + Wand2, +} from 'lucide-react'; +import { api } from '../../api/client'; +import { getColorName } from '../../utils/colors'; +import { + normalizeColorForCompare, + colorsAreSimilar, +} from '../../utils/amsHelpers'; import type { PrinterSelectorProps } from './types'; +import type { PrinterMappingResult, PerPrinterConfig } from '../../hooks/useMultiPrinterFilamentMapping'; +import type { FilamentRequirement, LoadedFilament } from '../../hooks/useFilamentMapping'; + +interface PrinterSelectorWithMappingProps extends PrinterSelectorProps { + /** Per-printer mapping results (only used when multiple printers selected) */ + printerMappingResults?: PrinterMappingResult[]; + /** Filament requirements for the print */ + filamentReqs?: { filaments: FilamentRequirement[] }; + /** Callback to auto-configure a printer */ + onAutoConfigurePrinter?: (printerId: number) => void; + /** Callback to update printer config */ + onUpdatePrinterConfig?: (printerId: number, config: Partial) => void; +} + +/** + * Inline AMS mapping editor for a single printer. + */ +function InlineMappingEditor({ + printerResult, + filamentReqs, + onUpdateConfig, +}: { + printerResult: PrinterMappingResult; + filamentReqs: FilamentRequirement[]; + onUpdateConfig: (config: Partial) => void; +}) { + const queryClient = useQueryClient(); + const [isRefreshing, setIsRefreshing] = useState(false); + + const handleSlotChange = (slotId: number, value: string) => { + if (slotId <= 0) return; + + const newMappings = { ...printerResult.config.manualMappings }; + if (value === '') { + delete newMappings[slotId]; + } else { + newMappings[slotId] = parseInt(value, 10); + } + + onUpdateConfig({ + useDefault: false, + manualMappings: newMappings, + autoConfigured: false, + }); + }; + + const handleRefresh = async () => { + setIsRefreshing(true); + try { + await api.refreshPrinterStatus(printerResult.printerId); + await new Promise((r) => setTimeout(r, 500)); + await queryClient.refetchQueries({ queryKey: ['printer-status', printerResult.printerId] }); + } finally { + setIsRefreshing(false); + } + }; + + // Compute current slot assignments + const slotAssignments = filamentReqs.map((req) => { + const slotId = req.slot_id || 0; + const currentMapping = printerResult.config.manualMappings[slotId]; + + let loaded: LoadedFilament | undefined; + let isManual = false; + + if (currentMapping !== undefined) { + loaded = printerResult.loadedFilaments.find((f) => f.globalTrayId === currentMapping); + isManual = true; + } else { + // Auto-match logic + const usedTrayIds = new Set(Object.values(printerResult.config.manualMappings)); + + const exactMatch = printerResult.loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + normalizeColorForCompare(f.color) === normalizeColorForCompare(req.color) + ); + const similarMatch = exactMatch + ? undefined + : printerResult.loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + colorsAreSimilar(f.color, req.color) + ); + const typeOnlyMatch = + exactMatch || similarMatch + ? undefined + : printerResult.loadedFilaments.find( + (f) => !usedTrayIds.has(f.globalTrayId) && f.type?.toUpperCase() === req.type?.toUpperCase() + ); + loaded = exactMatch ?? similarMatch ?? typeOnlyMatch; + } + + // Determine status + let status: 'match' | 'type_only' | 'mismatch' = 'mismatch'; + if (loaded) { + const typeMatch = loaded.type?.toUpperCase() === req.type?.toUpperCase(); + const colorMatch = + normalizeColorForCompare(loaded.color) === normalizeColorForCompare(req.color) || + colorsAreSimilar(loaded.color, req.color); + + if (typeMatch && colorMatch) { + status = 'match'; + } else if (typeMatch) { + status = 'type_only'; + } + } + + return { req, loaded, status, isManual }; + }); + + return ( +
+
+ Custom slot mapping + +
+ + {slotAssignments.map(({ req, loaded, status, isManual }, idx) => ( +
+ + + + + {req.type} ({req.used_grams}g) + + → + + {status === 'match' ? ( + + ) : status === 'type_only' ? ( + + + + ) : ( + + + + )} +
+ ))} +
+ ); +} /** * Printer selection component with grid-based UI. * Supports single or multi-select modes. + * When multiple printers are selected, shows per-printer mapping overrides. */ export function PrinterSelector({ printers, @@ -12,10 +208,22 @@ export function PrinterSelector({ isLoading = false, allowMultiple = false, showInactive = false, -}: PrinterSelectorProps) { + printerMappingResults, + filamentReqs, + onAutoConfigurePrinter, + onUpdatePrinterConfig, +}: PrinterSelectorWithMappingProps) { // Filter printers based on showInactive flag const displayPrinters = showInactive ? printers : printers.filter((p) => p.is_active); + const showMappingOptions = allowMultiple && + selectedPrinterIds.length > 1 && + printerMappingResults && + filamentReqs?.filaments && + filamentReqs.filaments.length > 0 && + onAutoConfigurePrinter && + onUpdatePrinterConfig; + if (isLoading) { return (
@@ -35,14 +243,12 @@ export function PrinterSelector({ const handlePrinterClick = (printerId: number) => { if (allowMultiple) { - // Multi-select mode: toggle printer in selection if (selectedPrinterIds.includes(printerId)) { onMultiSelect(selectedPrinterIds.filter((id) => id !== printerId)); } else { onMultiSelect([...selectedPrinterIds, printerId]); } } else { - // Single-select mode: replace selection onMultiSelect([printerId]); } }; @@ -55,10 +261,28 @@ export function PrinterSelector({ onMultiSelect([]); }; - const isSelected = (printerId: number) => selectedPrinterIds.includes(printerId); + const handleOverrideToggle = (printerId: number, enabled: boolean, e: React.MouseEvent) => { + e.stopPropagation(); + if (!onAutoConfigurePrinter || !onUpdatePrinterConfig) return; + if (enabled) { + onAutoConfigurePrinter(printerId); + } else { + onUpdatePrinterConfig(printerId, { + useDefault: true, + manualMappings: {}, + autoConfigured: false, + }); + } + }; + + const isSelected = (printerId: number) => selectedPrinterIds.includes(printerId); const selectedCount = selectedPrinterIds.length; + const getPrinterMappingResult = (printerId: number) => { + return printerMappingResults?.find((r) => r.printerId === printerId); + }; + return (
{/* Multi-select header */} @@ -92,51 +316,119 @@ export function PrinterSelector({
)} - {displayPrinters.map((printer) => ( -
- )} - - ))} +
+ +
+
+

+ {printer.name} + {!printer.is_active && (inactive)} +

+

+ {printer.model || 'Unknown model'} • {printer.ip_address} +

+
+ {allowMultiple && ( +
+ {selected && } +
+ )} + + + {/* Per-printer override checkbox + mapping (only when selected and multi-printer) */} + {selected && showMappingOptions && mappingResult && ( +
+ {/* Override checkbox row */} +
+ + + {/* Match status indicator */} + + ({mappingResult.exactMatches}/{mappingResult.totalSlots} matched) + + + {/* Loading indicator */} + {mappingResult.isLoading && ( + + )} + + {/* Auto-configure button (when override is enabled) */} + {hasOverride && ( + + )} +
+ + {/* Inline mapping editor (shown when override is checked) */} + {hasOverride && ( + onUpdatePrinterConfig!(printer.id, config)} + /> + )} +
+ )} + + ); + })} {/* Warning when no printer selected */} {selectedCount === 0 && ( diff --git a/frontend/src/components/PrintModal/index.tsx b/frontend/src/components/PrintModal/index.tsx index 1a9a2b885..8e473c07a 100644 --- a/frontend/src/components/PrintModal/index.tsx +++ b/frontend/src/components/PrintModal/index.tsx @@ -7,6 +7,7 @@ import { Card, CardContent } from '../Card'; import { Button } from '../Button'; import { useToast } from '../../contexts/ToastContext'; import { useFilamentMapping } from '../../hooks/useFilamentMapping'; +import { useMultiPrinterFilamentMapping, type PerPrinterConfig } from '../../hooks/useMultiPrinterFilamentMapping'; import { isPlaceholderDate } from '../../utils/amsHelpers'; import { PrinterSelector } from './PrinterSelector'; import { PlateSelector } from './PlateSelector'; @@ -99,7 +100,7 @@ export function PrintModal({ return DEFAULT_SCHEDULE_OPTIONS; }); - // Manual slot overrides: slot_id (1-indexed) -> globalTrayId + // Manual slot overrides: slot_id (1-indexed) -> globalTrayId (default mapping for single printer or all printers) const [manualMappings, setManualMappings] = useState>(() => { if (mode === 'edit-queue-item' && queueItem?.ams_mapping && Array.isArray(queueItem.ams_mapping)) { const mappings: Record = {}; @@ -113,6 +114,9 @@ export function PrintModal({ return {}; }); + // Per-printer override configs (for multi-printer selection) + const [perPrinterConfigs, setPerPrinterConfigs] = useState>({}); + // Track initial values for clearing mappings on change (edit mode only) const [initialPrinterIds] = useState(() => (mode === 'edit-queue-item' && queueItem?.printer_id ? [queueItem.printer_id] : [])); const [initialPlateId] = useState(() => (mode === 'edit-queue-item' && queueItem ? queueItem.plate_id : null)); @@ -127,6 +131,11 @@ export function PrintModal({ const effectivePrinterId = selectedPrinters.length > 0 ? selectedPrinters[0] : null; // Queries + const { data: settings } = useQuery({ + queryKey: ['settings'], + queryFn: api.getSettings, + }); + const { data: printers, isLoading: loadingPrinters } = useQuery({ queryKey: ['printers'], queryFn: api.getPrinters, @@ -181,6 +190,16 @@ export function PrintModal({ // Get AMS mapping from hook (only when single printer selected) const { amsMapping } = useFilamentMapping(effectiveFilamentReqs, printerStatus, manualMappings); + // Multi-printer filament mapping (for per-printer configuration) + const multiPrinterMapping = useMultiPrinterFilamentMapping( + selectedPrinters, + printers, + effectiveFilamentReqs, + manualMappings, + perPrinterConfigs, + setPerPrinterConfigs + ); + // Auto-select first plate for single-plate files useEffect(() => { if (platesData?.plates?.length === 1 && !selectedPlate) { @@ -198,19 +217,39 @@ export function PrintModal({ } }, [mode, printers, selectedPrinters.length]); - // Clear manual mappings when printer or plate changes + // Clear manual mappings and per-printer configs when printer or plate changes useEffect(() => { if (mode === 'edit-queue-item') { // For edit mode, clear mappings if printer selection or plate changed from initial const printersChanged = JSON.stringify(selectedPrinters.sort()) !== JSON.stringify(initialPrinterIds.sort()); if (printersChanged || selectedPlate !== initialPlateId) { setManualMappings({}); + setPerPrinterConfigs({}); } } else { setManualMappings({}); + setPerPrinterConfigs({}); } }, [mode, selectedPrinters, selectedPlate, initialPrinterIds, initialPlateId]); + // Auto-expand per-printer mapping when setting is enabled and multiple printers selected + useEffect(() => { + if (!settings?.per_printer_mapping_expanded) return; + if (selectedPrinters.length <= 1) return; + + // Check if any printer needs to be auto-configured + const printersNeedingConfig = selectedPrinters.filter( + printerId => !perPrinterConfigs[printerId] || perPrinterConfigs[printerId].useDefault + ); + + if (printersNeedingConfig.length > 0) { + // Auto-configure printers that don't have custom config + printersNeedingConfig.forEach(printerId => { + multiPrinterMapping.autoConfigurePrinter(printerId); + }); + } + }, [settings?.per_printer_mapping_expanded, selectedPrinters, perPrinterConfigs, multiPrinterMapping]); + // Close on Escape key useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { @@ -260,6 +299,18 @@ export function PrintModal({ errors: [], }; + // Get mapping for a specific printer (per-printer override or default) + const getMappingForPrinter = (printerId: number): number[] | undefined => { + // For multi-printer selection, check if this printer has an override + if (selectedPrinters.length > 1) { + const printerConfig = perPrinterConfigs[printerId]; + if (printerConfig && !printerConfig.useDefault) { + return multiPrinterMapping.getFinalMapping(printerId); + } + } + return amsMapping; + }; + // Common queue data for add-to-queue and edit modes const getQueueData = (printerId: number): PrintQueueItemCreate => ({ printer_id: printerId, @@ -269,7 +320,7 @@ export function PrintModal({ require_previous_success: scheduleOptions.requirePreviousSuccess, auto_off_after: scheduleOptions.autoOffAfter, manual_start: scheduleOptions.scheduleType === 'manual', - ams_mapping: amsMapping, + ams_mapping: getMappingForPrinter(printerId), plate_id: selectedPlate, scheduled_time: scheduleOptions.scheduleType === 'scheduled' && scheduleOptions.scheduledTime ? new Date(scheduleOptions.scheduledTime).toISOString() @@ -284,26 +335,28 @@ export function PrintModal({ try { if (mode === 'reprint') { // Reprint mode - start print immediately + const printerMapping = getMappingForPrinter(printerId); if (isLibraryFile) { await api.printLibraryFile(libraryFileId!, printerId, { - ams_mapping: amsMapping, + ams_mapping: printerMapping, ...printOptions, }); } else { await api.reprintArchive(archiveId!, printerId, { plate_id: selectedPlate ?? undefined, - ams_mapping: amsMapping, + ams_mapping: printerMapping, ...printOptions, }); } } else if (mode === 'edit-queue-item' && i === 0) { // Edit mode - update the original queue item for the first printer + const printerMapping = getMappingForPrinter(printerId); const updateData: PrintQueueItemUpdate = { printer_id: printerId, require_previous_success: scheduleOptions.requirePreviousSuccess, auto_off_after: scheduleOptions.autoOffAfter, manual_start: scheduleOptions.scheduleType === 'manual', - ams_mapping: amsMapping, + ams_mapping: printerMapping, plate_id: selectedPlate, scheduled_time: scheduleOptions.scheduleType === 'scheduled' && scheduleOptions.scheduledTime ? new Date(scheduleOptions.scheduledTime).toISOString() @@ -448,7 +501,7 @@ export function PrintModal({ )}

- {/* Printer selection */} + {/* Printer selection with per-printer mapping */} - {/* Multi-printer filament mapping note */} - {selectedPrinters.length > 1 && ( -
- -

- Slot mapping below applies to all {selectedPrinters.length} printers. Ensure they have matching filament configurations. -

-
- )} - {/* Plate selection */} )} - {/* Filament mapping - show when printer selected and filament requirements available */} - {showFilamentMapping && !archiveDataMissing && ( + {/* Filament mapping - only show when single printer selected */} + {showFilamentMapping && !archiveDataMissing && selectedPrinters.length === 1 && ( )} diff --git a/frontend/src/hooks/useMultiPrinterFilamentMapping.ts b/frontend/src/hooks/useMultiPrinterFilamentMapping.ts new file mode 100644 index 000000000..b8e62d45b --- /dev/null +++ b/frontend/src/hooks/useMultiPrinterFilamentMapping.ts @@ -0,0 +1,385 @@ +import { useMemo } from 'react'; +import { useQueries } from '@tanstack/react-query'; +import { api } from '../api/client'; +import type { PrinterStatus, Printer } from '../api/client'; +import { + buildLoadedFilaments, + computeAmsMapping, + type LoadedFilament, + type FilamentRequirement, +} from './useFilamentMapping'; +import { + normalizeColorForCompare, + colorsAreSimilar, +} from '../utils/amsHelpers'; + +/** + * Match status for a single printer's filament configuration. + */ +export type PrinterMatchStatus = 'full' | 'partial' | 'missing'; + +/** + * Per-printer configuration for AMS mapping. + */ +export interface PerPrinterConfig { + /** Whether this printer uses the default mapping or has custom config */ + useDefault: boolean; + /** Manual slot overrides for this printer (slot_id -> globalTrayId) */ + manualMappings: Record; + /** Whether this mapping was auto-configured */ + autoConfigured: boolean; +} + +/** + * Result of filament mapping for a single printer. + */ +export interface PrinterMappingResult { + printerId: number; + printerName: string; + /** Printer status data */ + status: PrinterStatus | undefined; + /** Whether status is still loading */ + isLoading: boolean; + /** List of loaded filaments in this printer */ + loadedFilaments: LoadedFilament[]; + /** Auto-computed AMS mapping for this printer */ + autoMapping: number[] | undefined; + /** Final AMS mapping (considering manual overrides) */ + finalMapping: number[] | undefined; + /** Match status: full (all exact), partial (some mismatches), missing (type not found) */ + matchStatus: PrinterMatchStatus; + /** Number of slots with exact match (type + color) */ + exactMatches: number; + /** Number of slots with type-only match */ + typeOnlyMatches: number; + /** Number of slots with missing type */ + missingTypes: number; + /** Total required slots */ + totalSlots: number; + /** Per-printer config */ + config: PerPrinterConfig; +} + +/** + * Result of the useMultiPrinterFilamentMapping hook. + */ +export interface UseMultiPrinterFilamentMappingResult { + /** Results for each selected printer */ + printerResults: PrinterMappingResult[]; + /** Whether any printer data is still loading */ + isLoading: boolean; + /** Per-printer configurations */ + perPrinterConfigs: Record; + /** Update config for a specific printer */ + updatePrinterConfig: (printerId: number, config: Partial) => void; + /** Auto-configure all printers based on their loaded filaments */ + autoConfigureAll: () => void; + /** Auto-configure a specific printer */ + autoConfigurePrinter: (printerId: number) => void; + /** Get final mapping for a specific printer (for submission) */ + getFinalMapping: (printerId: number) => number[] | undefined; + /** Check if all printers have acceptable mappings */ + allPrintersReady: boolean; +} + +/** + * Compute match details for a printer given filament requirements and loaded filaments. + */ +function computeMatchDetails( + filamentReqs: FilamentRequirement[] | undefined, + loadedFilaments: LoadedFilament[], + manualMappings: Record +): { exactMatches: number; typeOnlyMatches: number; missingTypes: number; totalSlots: number; status: PrinterMatchStatus } { + if (!filamentReqs || filamentReqs.length === 0) { + return { exactMatches: 0, typeOnlyMatches: 0, missingTypes: 0, totalSlots: 0, status: 'full' }; + } + + let exactMatches = 0; + let typeOnlyMatches = 0; + let missingTypes = 0; + const usedTrayIds = new Set(Object.values(manualMappings)); + + for (const req of filamentReqs) { + const slotId = req.slot_id || 0; + + // Check manual override first + if (slotId > 0 && manualMappings[slotId] !== undefined) { + const manualTrayId = manualMappings[slotId]; + const manualLoaded = loadedFilaments.find((f) => f.globalTrayId === manualTrayId); + + if (manualLoaded) { + const typeMatch = manualLoaded.type?.toUpperCase() === req.type?.toUpperCase(); + const colorMatch = + normalizeColorForCompare(manualLoaded.color) === normalizeColorForCompare(req.color) || + colorsAreSimilar(manualLoaded.color, req.color); + + if (typeMatch && colorMatch) { + exactMatches++; + } else if (typeMatch) { + typeOnlyMatches++; + } else { + missingTypes++; + } + continue; + } + } + + // Auto-match + const exactMatch = loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + normalizeColorForCompare(f.color) === normalizeColorForCompare(req.color) + ); + const similarMatch = exactMatch + ? undefined + : loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + colorsAreSimilar(f.color, req.color) + ); + const typeOnlyMatch = + exactMatch || similarMatch + ? undefined + : loadedFilaments.find( + (f) => !usedTrayIds.has(f.globalTrayId) && f.type?.toUpperCase() === req.type?.toUpperCase() + ); + const loaded = exactMatch ?? similarMatch ?? typeOnlyMatch; + + if (loaded) { + usedTrayIds.add(loaded.globalTrayId); + } + + if (exactMatch || similarMatch) { + exactMatches++; + } else if (typeOnlyMatch) { + typeOnlyMatches++; + } else { + missingTypes++; + } + } + + const totalSlots = filamentReqs.length; + let status: PrinterMatchStatus = 'full'; + if (missingTypes > 0) { + status = 'missing'; + } else if (typeOnlyMatches > 0) { + status = 'partial'; + } + + return { exactMatches, typeOnlyMatches, missingTypes, totalSlots, status }; +} + +/** + * Compute AMS mapping with manual overrides applied. + */ +function computeMappingWithOverrides( + filamentReqs: { filaments: FilamentRequirement[] } | undefined, + printerStatus: PrinterStatus | undefined, + manualMappings: Record +): number[] | undefined { + if (!filamentReqs?.filaments || filamentReqs.filaments.length === 0) return undefined; + + const loadedFilaments = buildLoadedFilaments(printerStatus); + if (loadedFilaments.length === 0) return undefined; + + const usedTrayIds = new Set(Object.values(manualMappings)); + const comparisons: { slot_id: number; globalTrayId: number }[] = []; + + for (const req of filamentReqs.filaments) { + const slotId = req.slot_id || 0; + + // Check manual override first + if (slotId > 0 && manualMappings[slotId] !== undefined) { + comparisons.push({ slot_id: slotId, globalTrayId: manualMappings[slotId] }); + continue; + } + + // Auto-match + const exactMatch = loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + normalizeColorForCompare(f.color) === normalizeColorForCompare(req.color) + ); + const similarMatch = exactMatch + ? undefined + : loadedFilaments.find( + (f) => + !usedTrayIds.has(f.globalTrayId) && + f.type?.toUpperCase() === req.type?.toUpperCase() && + colorsAreSimilar(f.color, req.color) + ); + const typeOnlyMatch = + exactMatch || similarMatch + ? undefined + : loadedFilaments.find( + (f) => !usedTrayIds.has(f.globalTrayId) && f.type?.toUpperCase() === req.type?.toUpperCase() + ); + const loaded = exactMatch ?? similarMatch ?? typeOnlyMatch; + + if (loaded) { + usedTrayIds.add(loaded.globalTrayId); + } + + comparisons.push({ slot_id: slotId, globalTrayId: loaded?.globalTrayId ?? -1 }); + } + + const maxSlotId = Math.max(...comparisons.map((f) => f.slot_id || 0)); + if (maxSlotId <= 0) return undefined; + + const mapping = new Array(maxSlotId).fill(-1); + comparisons.forEach((f) => { + if (f.slot_id && f.slot_id > 0) { + mapping[f.slot_id - 1] = f.globalTrayId; + } + }); + + return mapping; +} + +/** + * Default per-printer config (use default mapping). + */ +const DEFAULT_PRINTER_CONFIG: PerPrinterConfig = { + useDefault: true, + manualMappings: {}, + autoConfigured: false, +}; + +/** + * Hook to manage filament mapping for multiple printers. + * Fetches printer status for all selected printers and computes per-printer mappings. + */ +export function useMultiPrinterFilamentMapping( + selectedPrinterIds: number[], + printers: Printer[] | undefined, + filamentReqs: { filaments: FilamentRequirement[] } | undefined, + defaultMappings: Record, + perPrinterConfigs: Record, + setPerPrinterConfigs: React.Dispatch>> +): UseMultiPrinterFilamentMappingResult { + // Fetch printer status for all selected printers in parallel + const statusQueries = useQueries({ + queries: selectedPrinterIds.map((printerId) => ({ + queryKey: ['printer-status', printerId], + queryFn: () => api.getPrinterStatus(printerId), + enabled: selectedPrinterIds.length > 0, + staleTime: 5000, // Consider data fresh for 5 seconds + })), + }); + + // Build results for each printer + const printerResults = useMemo((): PrinterMappingResult[] => { + return selectedPrinterIds.map((printerId, index) => { + const query = statusQueries[index]; + const printerStatus = query?.data; + const printer = printers?.find((p) => p.id === printerId); + const printerName = printer?.name || `Printer ${printerId}`; + + const loadedFilaments = buildLoadedFilaments(printerStatus); + const config = perPrinterConfigs[printerId] || DEFAULT_PRINTER_CONFIG; + + // Compute auto mapping for this printer + const autoMapping = computeAmsMapping(filamentReqs, printerStatus); + + // Determine which mappings to use: + // If printer has override (useDefault=false), use its custom mappings + // Otherwise use the default mappings + const effectiveMappings = !config.useDefault + ? config.manualMappings + : defaultMappings; + + // Compute final mapping with overrides + const finalMapping = computeMappingWithOverrides(filamentReqs, printerStatus, effectiveMappings); + + // Compute match details + const matchDetails = computeMatchDetails( + filamentReqs?.filaments, + loadedFilaments, + effectiveMappings + ); + + return { + printerId, + printerName, + status: printerStatus, + isLoading: query?.isLoading ?? false, + loadedFilaments, + autoMapping, + finalMapping, + matchStatus: matchDetails.status, + exactMatches: matchDetails.exactMatches, + typeOnlyMatches: matchDetails.typeOnlyMatches, + missingTypes: matchDetails.missingTypes, + totalSlots: matchDetails.totalSlots, + config, + }; + }); + }, [selectedPrinterIds, statusQueries, printers, filamentReqs, perPrinterConfigs, defaultMappings]); + + const isLoading = statusQueries.some((q) => q.isLoading); + + // Update config for a specific printer + const updatePrinterConfig = (printerId: number, updates: Partial) => { + setPerPrinterConfigs((prev) => ({ + ...prev, + [printerId]: { + ...(prev[printerId] || DEFAULT_PRINTER_CONFIG), + ...updates, + }, + })); + }; + + // Auto-configure a specific printer based on its loaded filaments + const autoConfigurePrinter = (printerId: number) => { + const result = printerResults.find((r) => r.printerId === printerId); + if (!result || !result.status || !filamentReqs?.filaments) return; + + // Compute optimal mapping for this printer + const autoMapping = computeAmsMapping(filamentReqs, result.status); + if (!autoMapping) return; + + // Convert autoMapping array to manualMappings record + const manualMappings: Record = {}; + autoMapping.forEach((globalTrayId, index) => { + if (globalTrayId !== -1) { + manualMappings[index + 1] = globalTrayId; + } + }); + + updatePrinterConfig(printerId, { + useDefault: false, + manualMappings, + autoConfigured: true, + }); + }; + + // Auto-configure all printers + const autoConfigureAll = () => { + for (const printerId of selectedPrinterIds) { + autoConfigurePrinter(printerId); + } + }; + + // Get final mapping for a specific printer (for submission) + const getFinalMapping = (printerId: number): number[] | undefined => { + const result = printerResults.find((r) => r.printerId === printerId); + return result?.finalMapping; + }; + + // Check if all printers have acceptable mappings (no missing types) + const allPrintersReady = printerResults.every((r) => r.matchStatus !== 'missing'); + + return { + printerResults, + isLoading, + perPrinterConfigs, + updatePrinterConfig, + autoConfigureAll, + autoConfigurePrinter, + getFinalMapping, + allPrintersReady, + }; +} diff --git a/frontend/src/pages/SettingsPage.tsx b/frontend/src/pages/SettingsPage.tsx index 33b2e340e..a1a2b0545 100644 --- a/frontend/src/pages/SettingsPage.tsx +++ b/frontend/src/pages/SettingsPage.tsx @@ -361,6 +361,7 @@ export function SettingsPage() { settings.ams_temp_good !== localSettings.ams_temp_good || settings.ams_temp_fair !== localSettings.ams_temp_fair || settings.ams_history_retention_days !== localSettings.ams_history_retention_days || + settings.per_printer_mapping_expanded !== localSettings.per_printer_mapping_expanded || settings.date_format !== localSettings.date_format || settings.time_format !== localSettings.time_format || settings.default_printer_id !== localSettings.default_printer_id || @@ -420,6 +421,7 @@ export function SettingsPage() { ams_temp_good: localSettings.ams_temp_good, ams_temp_fair: localSettings.ams_temp_fair, ams_history_retention_days: localSettings.ams_history_retention_days, + per_printer_mapping_expanded: localSettings.per_printer_mapping_expanded, date_format: localSettings.date_format, time_format: localSettings.time_format, default_printer_id: localSettings.default_printer_id, @@ -2519,6 +2521,33 @@ export function SettingsPage() { Older humidity and temperature data will be automatically deleted

+ + {/* Per-Printer Mapping Default */} +
+
+ + Print Modal +
+
+
+ +

+ When printing to multiple printers, show per-printer AMS mapping expanded +

+
+ +
+
diff --git a/static/assets/index-Cw5WdZhp.js b/static/assets/index-Cw5WdZhp.js new file mode 100644 index 000000000..2b8dac6cb --- /dev/null +++ b/static/assets/index-Cw5WdZhp.js @@ -0,0 +1,8665 @@ +function sae(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 a of i)if(a.type==="childList")for(const o of a.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&r(o)}).observe(document,{childList:!0,subtree:!0});function n(i){const a={};return i.integrity&&(a.integrity=i.integrity),i.referrerPolicy&&(a.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?a.credentials="include":i.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(i){if(i.ep)return;i.ep=!0;const a=n(i);fetch(i.href,a)}})();var $v=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function ko(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var cA={exports:{}},Ix={};var nU;function oae(){if(nU)return Ix;nU=1;var t=Symbol.for("react.transitional.element"),e=Symbol.for("react.fragment");function n(r,i,a){var o=null;if(a!==void 0&&(o=""+a),i.key!==void 0&&(o=""+i.key),"key"in i){a={};for(var l in i)l!=="key"&&(a[l]=i[l])}else a=i;return i=a.ref,{$$typeof:t,type:r,key:o,ref:i!==void 0?i:null,props:a}}return Ix.Fragment=e,Ix.jsx=n,Ix.jsxs=n,Ix}var rU;function lae(){return rU||(rU=1,cA.exports=oae()),cA.exports}var s=lae(),uA={exports:{}},sn={};var iU;function cae(){if(iU)return sn;iU=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"),a=Symbol.for("react.consumer"),o=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),c=Symbol.for("react.suspense"),u=Symbol.for("react.memo"),d=Symbol.for("react.lazy"),f=Symbol.for("react.activity"),m=Symbol.iterator;function g(U){return U===null||typeof U!="object"?null:(U=m&&U[m]||U["@@iterator"],typeof U=="function"?U:null)}var b={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},v=Object.assign,x={};function y(U,G,te){this.props=U,this.context=G,this.refs=x,this.updater=te||b}y.prototype.isReactComponent={},y.prototype.setState=function(U,G){if(typeof U!="object"&&typeof U!="function"&&U!=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,U,G,"setState")},y.prototype.forceUpdate=function(U){this.updater.enqueueForceUpdate(this,U,"forceUpdate")};function M(){}M.prototype=y.prototype;function w(U,G,te){this.props=U,this.context=G,this.refs=x,this.updater=te||b}var A=w.prototype=new M;A.constructor=w,v(A,y.prototype),A.isPureReactComponent=!0;var N=Array.isArray;function k(){}var T={H:null,A:null,T:null,S:null},R=Object.prototype.hasOwnProperty;function C(U,G,te){var ie=te.ref;return{$$typeof:t,type:U,key:G,ref:ie!==void 0?ie:null,props:te}}function P(U,G){return C(U.type,G,U.props)}function F(U){return typeof U=="object"&&U!==null&&U.$$typeof===t}function L(U){var G={"=":"=0",":":"=2"};return"$"+U.replace(/[=:]/g,function(te){return G[te]})}var K=/\/+/g;function D(U,G){return typeof U=="object"&&U!==null&&U.key!=null?L(""+U.key):G.toString(36)}function W(U){switch(U.status){case"fulfilled":return U.value;case"rejected":throw U.reason;default:switch(typeof U.status=="string"?U.then(k,k):(U.status="pending",U.then(function(G){U.status==="pending"&&(U.status="fulfilled",U.value=G)},function(G){U.status==="pending"&&(U.status="rejected",U.reason=G)})),U.status){case"fulfilled":return U.value;case"rejected":throw U.reason}}throw U}function Y(U,G,te,ie,oe){var ce=typeof U;(ce==="undefined"||ce==="boolean")&&(U=null);var me=!1;if(U===null)me=!0;else switch(ce){case"bigint":case"string":case"number":me=!0;break;case"object":switch(U.$$typeof){case t:case e:me=!0;break;case d:return me=U._init,Y(me(U._payload),G,te,ie,oe)}}if(me)return oe=oe(U),me=ie===""?"."+D(U,0):ie,N(oe)?(te="",me!=null&&(te=me.replace(K,"$&/")+"/"),Y(oe,G,te,"",function(Ne){return Ne})):oe!=null&&(F(oe)&&(oe=P(oe,te+(oe.key==null||U&&U.key===oe.key?"":(""+oe.key).replace(K,"$&/")+"/")+me)),G.push(oe)),1;me=0;var Ae=ie===""?".":ie+":";if(N(U))for(var ge=0;ge>>1,ne=Y[re];if(0>>1;rei(te,Q))iei(oe,te)?(Y[re]=oe,Y[ie]=Q,re=ie):(Y[re]=te,Y[G]=Q,re=G);else if(iei(oe,Q))Y[re]=oe,Y[ie]=Q,re=ie;else break e}}return q}function i(Y,q){var Q=Y.sortIndex-q.sortIndex;return Q!==0?Q:Y.id-q.id}if(t.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var a=performance;t.unstable_now=function(){return a.now()}}else{var o=Date,l=o.now();t.unstable_now=function(){return o.now()-l}}var c=[],u=[],d=1,f=null,m=3,g=!1,b=!1,v=!1,x=!1,y=typeof setTimeout=="function"?setTimeout:null,M=typeof clearTimeout=="function"?clearTimeout:null,w=typeof setImmediate<"u"?setImmediate:null;function A(Y){for(var q=n(u);q!==null;){if(q.callback===null)r(u);else if(q.startTime<=Y)r(u),q.sortIndex=q.expirationTime,e(c,q);else break;q=n(u)}}function N(Y){if(v=!1,A(Y),!b)if(n(c)!==null)b=!0,k||(k=!0,L());else{var q=n(u);q!==null&&W(N,q.startTime-Y)}}var k=!1,T=-1,R=5,C=-1;function P(){return x?!0:!(t.unstable_now()-CY&&P());){var re=f.callback;if(typeof re=="function"){f.callback=null,m=f.priorityLevel;var ne=re(f.expirationTime<=Y);if(Y=t.unstable_now(),typeof ne=="function"){f.callback=ne,A(Y),q=!0;break t}f===n(c)&&r(c),A(Y)}else r(c);f=n(c)}if(f!==null)q=!0;else{var U=n(u);U!==null&&W(N,U.startTime-Y),q=!1}}break e}finally{f=null,m=Q,g=!1}q=void 0}}finally{q?L():k=!1}}}var L;if(typeof w=="function")L=function(){w(F)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,D=K.port2;K.port1.onmessage=F,L=function(){D.postMessage(null)}}else L=function(){y(F,0)};function W(Y,q){T=y(function(){Y(t.unstable_now())},q)}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(Y){Y.callback=null},t.unstable_forceFrameRate=function(Y){0>Y||125re?(Y.sortIndex=Q,e(u,Y),n(c)===null&&Y===n(u)&&(v?(M(T),T=-1):v=!0,W(N,Q-re))):(Y.sortIndex=ne,e(c,Y),b||g||(b=!0,k||(k=!0,L()))),Y},t.unstable_shouldYield=P,t.unstable_wrapCallback=function(Y){var q=m;return function(){var Q=m;m=q;try{return Y.apply(this,arguments)}finally{m=Q}}}})(fA)),fA}var oU;function hae(){return oU||(oU=1,hA.exports=dae()),hA.exports}var mA={exports:{}},ba={};var lU;function fae(){if(lU)return ba;lU=1;var t=Sg();function e(c){var u="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(),mA.exports=fae(),mA.exports}var uU;function mae(){if(uU)return Fx;uU=1;var t=hae(),e=Sg(),n=IG();function r(h){var p="https://react.dev/errors/"+h;if(1ne||(h.current=re[ne],re[ne]=null,ne--)}function te(h,p){ne++,re[ne]=h.current,h.current=p}var ie=U(null),oe=U(null),ce=U(null),me=U(null);function Ae(h,p){switch(te(ce,p),te(oe,h),te(ie,null),p.nodeType){case 9:case 11:h=(h=p.documentElement)&&(h=h.namespaceURI)?EF(h):0;break;default:if(h=p.tagName,p=p.namespaceURI)p=EF(p),h=NF(p,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}G(ie),te(ie,h)}function ge(){G(ie),G(oe),G(ce)}function Ne(h){h.memoizedState!==null&&te(me,h);var p=ie.current,_=NF(p,h.type);p!==_&&(te(oe,h),te(ie,_))}function Se(h){oe.current===h&&(G(ie),G(oe)),me.current===h&&(G(me),Rx._currentValue=Q)}var J,Ve;function H(h){if(J===void 0)try{throw Error()}catch(_){var p=_.stack.trim().match(/\n( *(at )?)/);J=p&&p[1]||"",Ve=-1<_.stack.indexOf(` + at`)?" ()":-1<_.stack.indexOf("@")?"@unknown:0:0":""}return` +`+J+h+Ve}var $=!1;function X(h,p){if(!h||$)return"";$=!0;var _=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var E={DetermineComponentFrameRoot:function(){try{if(p){var xt=function(){throw Error()};if(Object.defineProperty(xt.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(xt,[])}catch(ot){var it=ot}Reflect.construct(h,[],xt)}else{try{xt.call()}catch(ot){it=ot}h.call(xt.prototype)}}else{try{throw Error()}catch(ot){it=ot}(xt=h())&&typeof xt.catch=="function"&&xt.catch(function(){})}}catch(ot){if(ot&&it&&typeof ot.stack=="string")return[ot.stack,it.stack]}return[null,null]}};E.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var j=Object.getOwnPropertyDescriptor(E.DetermineComponentFrameRoot,"name");j&&j.configurable&&Object.defineProperty(E.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var O=E.DetermineComponentFrameRoot(),ee=O[0],fe=O[1];if(ee&&fe){var ke=ee.split(` +`),nt=fe.split(` +`);for(j=E=0;Ej||ke[E]!==nt[j]){var dt=` +`+ke[E].replace(" at new "," at ");return h.displayName&&dt.includes("")&&(dt=dt.replace("",h.displayName)),dt}while(1<=E&&0<=j);break}}}finally{$=!1,Error.prepareStackTrace=_}return(_=h?h.displayName||h.name:"")?H(_):""}function z(h,p){switch(h.tag){case 26:case 27:case 5:return H(h.type);case 16:return H("Lazy");case 13:return h.child!==p&&p!==null?H("Suspense Fallback"):H("Suspense");case 19:return H("SuspenseList");case 0:case 15:return X(h.type,!1);case 11:return X(h.type.render,!1);case 1:return X(h.type,!0);case 31:return H("Activity");default:return""}}function V(h){try{var p="",_=null;do p+=z(h,_),_=h,h=h.return;while(h);return p}catch(E){return` +Error generating stack: `+E.message+` +`+E.stack}}var Z=Object.prototype.hasOwnProperty,de=t.unstable_scheduleCallback,ve=t.unstable_cancelCallback,he=t.unstable_shouldYield,B=t.unstable_requestPaint,I=t.unstable_now,le=t.unstable_getCurrentPriorityLevel,_e=t.unstable_ImmediatePriority,Ee=t.unstable_UserBlockingPriority,we=t.unstable_NormalPriority,Ke=t.unstable_LowPriority,$e=t.unstable_IdlePriority,at=t.log,ut=t.unstable_setDisableYieldValue,Le=null,pe=null;function Xe(h){if(typeof at=="function"&&ut(h),pe&&typeof pe.setStrictMode=="function")try{pe.setStrictMode(Le,h)}catch{}}var Ye=Math.clz32?Math.clz32:se,Je=Math.log,ct=Math.LN2;function se(h){return h>>>=0,h===0?32:31-(Je(h)/ct|0)|0}var He=256,be=262144,Be=4194304;function De(h){var p=h&42;if(p!==0)return p;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 Te(h,p,_){var E=h.pendingLanes;if(E===0)return 0;var j=0,O=h.suspendedLanes,ee=h.pingedLanes;h=h.warmLanes;var fe=E&134217727;return fe!==0?(E=fe&~O,E!==0?j=De(E):(ee&=fe,ee!==0?j=De(ee):_||(_=fe&~h,_!==0&&(j=De(_))))):(fe=E&~O,fe!==0?j=De(fe):ee!==0?j=De(ee):_||(_=E&~h,_!==0&&(j=De(_)))),j===0?0:p!==0&&p!==j&&(p&O)===0&&(O=j&-j,_=p&-p,O>=_||O===32&&(_&4194048)!==0)?p:j}function Ge(h,p){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&p)===0}function pt(h,p){switch(h){case 1:case 2:case 4:case 8:case 64:return p+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 p+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 Nt(){var h=Be;return Be<<=1,(Be&62914560)===0&&(Be=4194304),h}function kt(h){for(var p=[],_=0;31>_;_++)p.push(h);return p}function Xt(h,p){h.pendingLanes|=p,p!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function Ot(h,p,_,E,j,O){var ee=h.pendingLanes;h.pendingLanes=_,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=_,h.entangledLanes&=_,h.errorRecoveryDisabledLanes&=_,h.shellSuspendCounter=0;var fe=h.entanglements,ke=h.expirationTimes,nt=h.hiddenUpdates;for(_=ee&~_;0<_;){var dt=31-Ye(_),xt=1<"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var ti=/[\n"\\]/g;function Hn(h){return h.replace(ti,function(p){return"\\"+p.charCodeAt(0).toString(16)+" "})}function Po(h,p,_,E,j,O,ee,fe){h.name="",ee!=null&&typeof ee!="function"&&typeof ee!="symbol"&&typeof ee!="boolean"?h.type=ee:h.removeAttribute("type"),p!=null?ee==="number"?(p===0&&h.value===""||h.value!=p)&&(h.value=""+vn(p)):h.value!==""+vn(p)&&(h.value=""+vn(p)):ee!=="submit"&&ee!=="reset"||h.removeAttribute("value"),p!=null?Ii(h,ee,vn(p)):_!=null?Ii(h,ee,vn(_)):E!=null&&h.removeAttribute("value"),j==null&&O!=null&&(h.defaultChecked=!!O),j!=null&&(h.checked=j&&typeof j!="function"&&typeof j!="symbol"),fe!=null&&typeof fe!="function"&&typeof fe!="symbol"&&typeof fe!="boolean"?h.name=""+vn(fe):h.removeAttribute("name")}function Kn(h,p,_,E,j,O,ee,fe){if(O!=null&&typeof O!="function"&&typeof O!="symbol"&&typeof O!="boolean"&&(h.type=O),p!=null||_!=null){if(!(O!=="submit"&&O!=="reset"||p!=null)){an(h);return}_=_!=null?""+vn(_):"",p=p!=null?""+vn(p):_,fe||p===h.value||(h.value=p),h.defaultValue=p}E=E??j,E=typeof E!="function"&&typeof E!="symbol"&&!!E,h.checked=fe?h.checked:!!E,h.defaultChecked=!!E,ee!=null&&typeof ee!="function"&&typeof ee!="symbol"&&typeof ee!="boolean"&&(h.name=ee),an(h)}function Ii(h,p,_){p==="number"&&Hr(h.ownerDocument)===h||h.defaultValue===""+_||(h.defaultValue=""+_)}function wi(h,p,_,E){if(h=h.options,p){p={};for(var j=0;j<_.length;j++)p["$"+_[j]]=!0;for(_=0;_"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),cE=!1;if(Yl)try{var Qg={};Object.defineProperty(Qg,"passive",{get:function(){cE=!0}}),window.addEventListener("test",Qg,Qg),window.removeEventListener("test",Qg,Qg)}catch{cE=!1}var pu=null,uE=null,Dy=null;function NL(){if(Dy)return Dy;var h,p=uE,_=p.length,E,j="value"in pu?pu.value:pu.textContent,O=j.length;for(h=0;h<_&&p[h]===j[h];h++);var ee=_-h;for(E=1;E<=ee&&p[_-E]===j[O-E];E++);return Dy=j.slice(h,1=ex),PL=" ",RL=!1;function DL(h,p){switch(h){case"keyup":return Tre.indexOf(p.keyCode)!==-1;case"keydown":return p.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function OL(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var Xf=!1;function kre(h,p){switch(h){case"compositionend":return OL(p);case"keypress":return p.which!==32?null:(RL=!0,PL);case"textInput":return h=p.data,h===PL&&RL?null:h;default:return null}}function jre(h,p){if(Xf)return h==="compositionend"||!pE&&DL(h,p)?(h=NL(),Dy=uE=pu=null,Xf=!1,h):null;switch(h){case"paste":return null;case"keypress":if(!(p.ctrlKey||p.altKey||p.metaKey)||p.ctrlKey&&p.altKey){if(p.char&&1=p)return{node:_,offset:p-h};h=E}e:{for(;_;){if(_.nextSibling){_=_.nextSibling;break e}_=_.parentNode}_=void 0}_=HL(_)}}function GL(h,p){return h&&p?h===p?!0:h&&h.nodeType===3?!1:p&&p.nodeType===3?GL(h,p.parentNode):"contains"in h?h.contains(p):h.compareDocumentPosition?!!(h.compareDocumentPosition(p)&16):!1:!1}function WL(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var p=Hr(h.document);p instanceof h.HTMLIFrameElement;){try{var _=typeof p.contentWindow.location.href=="string"}catch{_=!1}if(_)h=p.contentWindow;else break;p=Hr(h.document)}return p}function bE(h){var p=h&&h.nodeName&&h.nodeName.toLowerCase();return p&&(p==="input"&&(h.type==="text"||h.type==="search"||h.type==="tel"||h.type==="url"||h.type==="password")||p==="textarea"||h.contentEditable==="true")}var Ure=Yl&&"documentMode"in document&&11>=document.documentMode,Yf=null,yE=null,ix=null,vE=!1;function qL(h,p,_){var E=_.window===_?_.document:_.nodeType===9?_:_.ownerDocument;vE||Yf==null||Yf!==Hr(E)||(E=Yf,"selectionStart"in E&&bE(E)?E={start:E.selectionStart,end:E.selectionEnd}:(E=(E.ownerDocument&&E.ownerDocument.defaultView||window).getSelection(),E={anchorNode:E.anchorNode,anchorOffset:E.anchorOffset,focusNode:E.focusNode,focusOffset:E.focusOffset}),ix&&rx(ix,E)||(ix=E,E=Av(yE,"onSelect"),0>=ee,j-=ee,ol=1<<32-Ye(p)+j|_<un?(kn=Ut,Ut=null):kn=Ut.sibling;var Ln=it(We,Ut,tt[un],mt);if(Ln===null){Ut===null&&(Ut=kn);break}h&&Ut&&Ln.alternate===null&&p(We,Ut),Fe=O(Ln,Fe,un),On===null?Ht=Ln:On.sibling=Ln,On=Ln,Ut=kn}if(un===tt.length)return _(We,Ut),jn&&Zl(We,un),Ht;if(Ut===null){for(;unun?(kn=Ut,Ut=null):kn=Ut.sibling;var Iu=it(We,Ut,Ln.value,mt);if(Iu===null){Ut===null&&(Ut=kn);break}h&&Ut&&Iu.alternate===null&&p(We,Ut),Fe=O(Iu,Fe,un),On===null?Ht=Iu:On.sibling=Iu,On=Iu,Ut=kn}if(Ln.done)return _(We,Ut),jn&&Zl(We,un),Ht;if(Ut===null){for(;!Ln.done;un++,Ln=tt.next())Ln=xt(We,Ln.value,mt),Ln!==null&&(Fe=O(Ln,Fe,un),On===null?Ht=Ln:On.sibling=Ln,On=Ln);return jn&&Zl(We,un),Ht}for(Ut=E(Ut);!Ln.done;un++,Ln=tt.next())Ln=ot(Ut,We,un,Ln.value,mt),Ln!==null&&(h&&Ln.alternate!==null&&Ut.delete(Ln.key===null?un:Ln.key),Fe=O(Ln,Fe,un),On===null?Ht=Ln:On.sibling=Ln,On=Ln);return h&&Ut.forEach(function(aae){return p(We,aae)}),jn&&Zl(We,un),Ht}function ir(We,Fe,tt,mt){if(typeof tt=="object"&&tt!==null&&tt.type===v&&tt.key===null&&(tt=tt.props.children),typeof tt=="object"&&tt!==null){switch(tt.$$typeof){case g:e:{for(var Ht=tt.key;Fe!==null;){if(Fe.key===Ht){if(Ht=tt.type,Ht===v){if(Fe.tag===7){_(We,Fe.sibling),mt=j(Fe,tt.props.children),mt.return=We,We=mt;break e}}else if(Fe.elementType===Ht||typeof Ht=="object"&&Ht!==null&&Ht.$$typeof===R&&lh(Ht)===Fe.type){_(We,Fe.sibling),mt=j(Fe,tt.props),ux(mt,tt),mt.return=We,We=mt;break e}_(We,Fe);break}else p(We,Fe);Fe=Fe.sibling}tt.type===v?(mt=rh(tt.props.children,We.mode,mt,tt.key),mt.return=We,We=mt):(mt=Vy(tt.type,tt.key,tt.props,null,We.mode,mt),ux(mt,tt),mt.return=We,We=mt)}return ee(We);case b:e:{for(Ht=tt.key;Fe!==null;){if(Fe.key===Ht)if(Fe.tag===4&&Fe.stateNode.containerInfo===tt.containerInfo&&Fe.stateNode.implementation===tt.implementation){_(We,Fe.sibling),mt=j(Fe,tt.children||[]),mt.return=We,We=mt;break e}else{_(We,Fe);break}else p(We,Fe);Fe=Fe.sibling}mt=AE(tt,We.mode,mt),mt.return=We,We=mt}return ee(We);case R:return tt=lh(tt),ir(We,Fe,tt,mt)}if(W(tt))return It(We,Fe,tt,mt);if(L(tt)){if(Ht=L(tt),typeof Ht!="function")throw Error(r(150));return tt=Ht.call(tt),qt(We,Fe,tt,mt)}if(typeof tt.then=="function")return ir(We,Fe,Qy(tt),mt);if(tt.$$typeof===w)return ir(We,Fe,qy(We,tt),mt);Zy(We,tt)}return typeof tt=="string"&&tt!==""||typeof tt=="number"||typeof tt=="bigint"?(tt=""+tt,Fe!==null&&Fe.tag===6?(_(We,Fe.sibling),mt=j(Fe,tt),mt.return=We,We=mt):(_(We,Fe),mt=NE(tt,We.mode,mt),mt.return=We,We=mt),ee(We)):_(We,Fe)}return function(We,Fe,tt,mt){try{cx=0;var Ht=ir(We,Fe,tt,mt);return om=null,Ht}catch(Ut){if(Ut===sm||Ut===Xy)throw Ut;var On=ys(29,Ut,null,We.mode);return On.lanes=mt,On.return=We,On}finally{}}}var uh=gI(!0),xI=gI(!1),vu=!1;function UE(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function zE(h,p){h=h.updateQueue,p.updateQueue===h&&(p.updateQueue={baseState:h.baseState,firstBaseUpdate:h.firstBaseUpdate,lastBaseUpdate:h.lastBaseUpdate,shared:h.shared,callbacks:null})}function _u(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function wu(h,p,_){var E=h.updateQueue;if(E===null)return null;if(E=E.shared,(zn&2)!==0){var j=E.pending;return j===null?p.next=p:(p.next=j.next,j.next=p),E.pending=p,p=Hy(h),eI(h,null,_),p}return $y(h,E,p,_),Hy(h)}function dx(h,p,_){if(p=p.updateQueue,p!==null&&(p=p.shared,(_&4194048)!==0)){var E=p.lanes;E&=h.pendingLanes,_|=E,p.lanes=_,Bt(h,_)}}function BE(h,p){var _=h.updateQueue,E=h.alternate;if(E!==null&&(E=E.updateQueue,_===E)){var j=null,O=null;if(_=_.firstBaseUpdate,_!==null){do{var ee={lane:_.lane,tag:_.tag,payload:_.payload,callback:null,next:null};O===null?j=O=ee:O=O.next=ee,_=_.next}while(_!==null);O===null?j=O=p:O=O.next=p}else j=O=p;_={baseState:E.baseState,firstBaseUpdate:j,lastBaseUpdate:O,shared:E.shared,callbacks:E.callbacks},h.updateQueue=_;return}h=_.lastBaseUpdate,h===null?_.firstBaseUpdate=p:h.next=p,_.lastBaseUpdate=p}var $E=!1;function hx(){if($E){var h=am;if(h!==null)throw h}}function fx(h,p,_,E){$E=!1;var j=h.updateQueue;vu=!1;var O=j.firstBaseUpdate,ee=j.lastBaseUpdate,fe=j.shared.pending;if(fe!==null){j.shared.pending=null;var ke=fe,nt=ke.next;ke.next=null,ee===null?O=nt:ee.next=nt,ee=ke;var dt=h.alternate;dt!==null&&(dt=dt.updateQueue,fe=dt.lastBaseUpdate,fe!==ee&&(fe===null?dt.firstBaseUpdate=nt:fe.next=nt,dt.lastBaseUpdate=ke))}if(O!==null){var xt=j.baseState;ee=0,dt=nt=ke=null,fe=O;do{var it=fe.lane&-536870913,ot=it!==fe.lane;if(ot?(Cn&it)===it:(E&it)===it){it!==0&&it===im&&($E=!0),dt!==null&&(dt=dt.next={lane:0,tag:fe.tag,payload:fe.payload,callback:null,next:null});e:{var It=h,qt=fe;it=p;var ir=_;switch(qt.tag){case 1:if(It=qt.payload,typeof It=="function"){xt=It.call(ir,xt,it);break e}xt=It;break e;case 3:It.flags=It.flags&-65537|128;case 0:if(It=qt.payload,it=typeof It=="function"?It.call(ir,xt,it):It,it==null)break e;xt=f({},xt,it);break e;case 2:vu=!0}}it=fe.callback,it!==null&&(h.flags|=64,ot&&(h.flags|=8192),ot=j.callbacks,ot===null?j.callbacks=[it]:ot.push(it))}else ot={lane:it,tag:fe.tag,payload:fe.payload,callback:fe.callback,next:null},dt===null?(nt=dt=ot,ke=xt):dt=dt.next=ot,ee|=it;if(fe=fe.next,fe===null){if(fe=j.shared.pending,fe===null)break;ot=fe,fe=ot.next,ot.next=null,j.lastBaseUpdate=ot,j.shared.pending=null}}while(!0);dt===null&&(ke=xt),j.baseState=ke,j.firstBaseUpdate=nt,j.lastBaseUpdate=dt,O===null&&(j.shared.lanes=0),Au|=ee,h.lanes=ee,h.memoizedState=xt}}function bI(h,p){if(typeof h!="function")throw Error(r(191,h));h.call(p)}function yI(h,p){var _=h.callbacks;if(_!==null)for(h.callbacks=null,h=0;h<_.length;h++)bI(_[h],p)}var lm=U(null),Jy=U(0);function vI(h,p){h=cc,te(Jy,h),te(lm,p),cc=h|p.baseLanes}function HE(){te(Jy,cc),te(lm,lm.current)}function VE(){cc=Jy.current,G(lm),G(Jy)}var vs=U(null),Zs=null;function Su(h){var p=h.alternate;te(ni,ni.current&1),te(vs,h),Zs===null&&(p===null||lm.current!==null||p.memoizedState!==null)&&(Zs=h)}function GE(h){te(ni,ni.current),te(vs,h),Zs===null&&(Zs=h)}function _I(h){h.tag===22?(te(ni,ni.current),te(vs,h),Zs===null&&(Zs=h)):Mu()}function Mu(){te(ni,ni.current),te(vs,vs.current)}function _s(h){G(vs),Zs===h&&(Zs=null),G(ni)}var ni=U(0);function ev(h){for(var p=h;p!==null;){if(p.tag===13){var _=p.memoizedState;if(_!==null&&(_=_.dehydrated,_===null||QN(_)||ZN(_)))return p}else if(p.tag===19&&(p.memoizedProps.revealOrder==="forwards"||p.memoizedProps.revealOrder==="backwards"||p.memoizedProps.revealOrder==="unstable_legacy-backwards"||p.memoizedProps.revealOrder==="together")){if((p.flags&128)!==0)return p}else if(p.child!==null){p.child.return=p,p=p.child;continue}if(p===h)break;for(;p.sibling===null;){if(p.return===null||p.return===h)return null;p=p.return}p.sibling.return=p.return,p=p.sibling}return null}var tc=0,cn=null,nr=null,li=null,tv=!1,cm=!1,dh=!1,nv=0,mx=0,um=null,Xre=0;function Vr(){throw Error(r(321))}function WE(h,p){if(p===null)return!1;for(var _=0;_O?O:8;var ee=Y.T,fe={};Y.T=fe,oN(h,!1,p,_);try{var ke=j(),nt=Y.S;if(nt!==null&&nt(fe,ke),ke!==null&&typeof ke=="object"&&typeof ke.then=="function"){var dt=Kre(ke,E);gx(h,p,dt,Ms(h))}else gx(h,p,E,Ms(h))}catch(xt){gx(h,p,{then:function(){},status:"rejected",reason:xt},Ms())}finally{q.p=O,ee!==null&&fe.types!==null&&(ee.types=fe.types),Y.T=ee}}function eie(){}function aN(h,p,_,E){if(h.tag!==5)throw Error(r(476));var j=QI(h).queue;YI(h,j,p,Q,_===null?eie:function(){return ZI(h),_(E)})}function QI(h){var p=h.memoizedState;if(p!==null)return p;p={memoizedState:Q,baseState:Q,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:nc,lastRenderedState:Q},next:null};var _={};return p.next={memoizedState:_,baseState:_,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:nc,lastRenderedState:_},next:null},h.memoizedState=p,h=h.alternate,h!==null&&(h.memoizedState=p),p}function ZI(h){var p=QI(h);p.next===null&&(p=h.alternate.memoizedState),gx(h,p.next.queue,{},Ms())}function sN(){return ra(Rx)}function JI(){return ri().memoizedState}function e5(){return ri().memoizedState}function tie(h){for(var p=h.return;p!==null;){switch(p.tag){case 24:case 3:var _=Ms();h=_u(_);var E=wu(p,h,_);E!==null&&(es(E,p,_),dx(E,p,_)),p={cache:OE()},h.payload=p;return}p=p.return}}function nie(h,p,_){var E=Ms();_={lane:E,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null},lv(h)?n5(p,_):(_=ME(h,p,_,E),_!==null&&(es(_,h,E),r5(_,p,E)))}function t5(h,p,_){var E=Ms();gx(h,p,_,E)}function gx(h,p,_,E){var j={lane:E,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null};if(lv(h))n5(p,j);else{var O=h.alternate;if(h.lanes===0&&(O===null||O.lanes===0)&&(O=p.lastRenderedReducer,O!==null))try{var ee=p.lastRenderedState,fe=O(ee,_);if(j.hasEagerState=!0,j.eagerState=fe,bs(fe,ee))return $y(h,p,j,0),fr===null&&By(),!1}catch{}finally{}if(_=ME(h,p,j,E),_!==null)return es(_,h,E),r5(_,p,E),!0}return!1}function oN(h,p,_,E){if(E={lane:2,revertLane:UN(),gesture:null,action:E,hasEagerState:!1,eagerState:null,next:null},lv(h)){if(p)throw Error(r(479))}else p=ME(h,_,E,2),p!==null&&es(p,h,2)}function lv(h){var p=h.alternate;return h===cn||p!==null&&p===cn}function n5(h,p){cm=tv=!0;var _=h.pending;_===null?p.next=p:(p.next=_.next,_.next=p),h.pending=p}function r5(h,p,_){if((_&4194048)!==0){var E=p.lanes;E&=h.pendingLanes,_|=E,p.lanes=_,Bt(h,_)}}var xx={readContext:ra,use:iv,useCallback:Vr,useContext:Vr,useEffect:Vr,useImperativeHandle:Vr,useLayoutEffect:Vr,useInsertionEffect:Vr,useMemo:Vr,useReducer:Vr,useRef:Vr,useState:Vr,useDebugValue:Vr,useDeferredValue:Vr,useTransition:Vr,useSyncExternalStore:Vr,useId:Vr,useHostTransitionStatus:Vr,useFormState:Vr,useActionState:Vr,useOptimistic:Vr,useMemoCache:Vr,useCacheRefresh:Vr};xx.useEffectEvent=Vr;var i5={readContext:ra,use:iv,useCallback:function(h,p){return Ra().memoizedState=[h,p===void 0?null:p],h},useContext:ra,useEffect:BI,useImperativeHandle:function(h,p,_){_=_!=null?_.concat([h]):null,sv(4194308,4,GI.bind(null,p,h),_)},useLayoutEffect:function(h,p){return sv(4194308,4,h,p)},useInsertionEffect:function(h,p){sv(4,2,h,p)},useMemo:function(h,p){var _=Ra();p=p===void 0?null:p;var E=h();if(dh){Xe(!0);try{h()}finally{Xe(!1)}}return _.memoizedState=[E,p],E},useReducer:function(h,p,_){var E=Ra();if(_!==void 0){var j=_(p);if(dh){Xe(!0);try{_(p)}finally{Xe(!1)}}}else j=p;return E.memoizedState=E.baseState=j,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:j},E.queue=h,h=h.dispatch=nie.bind(null,cn,h),[E.memoizedState,h]},useRef:function(h){var p=Ra();return h={current:h},p.memoizedState=h},useState:function(h){h=eN(h);var p=h.queue,_=t5.bind(null,cn,p);return p.dispatch=_,[h.memoizedState,_]},useDebugValue:rN,useDeferredValue:function(h,p){var _=Ra();return iN(_,h,p)},useTransition:function(){var h=eN(!1);return h=YI.bind(null,cn,h.queue,!0,!1),Ra().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,p,_){var E=cn,j=Ra();if(jn){if(_===void 0)throw Error(r(407));_=_()}else{if(_=p(),fr===null)throw Error(r(349));(Cn&127)!==0||EI(E,p,_)}j.memoizedState=_;var O={value:_,getSnapshot:p};return j.queue=O,BI(AI.bind(null,E,O,h),[h]),E.flags|=2048,dm(9,{destroy:void 0},NI.bind(null,E,O,_,p),null),_},useId:function(){var h=Ra(),p=fr.identifierPrefix;if(jn){var _=ll,E=ol;_=(E&~(1<<32-Ye(E)-1)).toString(32)+_,p="_"+p+"R_"+_,_=nv++,0<_&&(p+="H"+_.toString(32)),p+="_"}else _=Xre++,p="_"+p+"r_"+_.toString(32)+"_";return h.memoizedState=p},useHostTransitionStatus:sN,useFormState:LI,useActionState:LI,useOptimistic:function(h){var p=Ra();p.memoizedState=p.baseState=h;var _={pending:null,lanes:0,dispatch:null,lastRenderedReducer:null,lastRenderedState:null};return p.queue=_,p=oN.bind(null,cn,!0,_),_.dispatch=p,[h,p]},useMemoCache:QE,useCacheRefresh:function(){return Ra().memoizedState=tie.bind(null,cn)},useEffectEvent:function(h){var p=Ra(),_={impl:h};return p.memoizedState=_,function(){if((zn&2)!==0)throw Error(r(440));return _.impl.apply(void 0,arguments)}}},lN={readContext:ra,use:iv,useCallback:qI,useContext:ra,useEffect:nN,useImperativeHandle:WI,useInsertionEffect:HI,useLayoutEffect:VI,useMemo:KI,useReducer:av,useRef:zI,useState:function(){return av(nc)},useDebugValue:rN,useDeferredValue:function(h,p){var _=ri();return XI(_,nr.memoizedState,h,p)},useTransition:function(){var h=av(nc)[0],p=ri().memoizedState;return[typeof h=="boolean"?h:px(h),p]},useSyncExternalStore:MI,useId:JI,useHostTransitionStatus:sN,useFormState:II,useActionState:II,useOptimistic:function(h,p){var _=ri();return kI(_,nr,h,p)},useMemoCache:QE,useCacheRefresh:e5};lN.useEffectEvent=$I;var a5={readContext:ra,use:iv,useCallback:qI,useContext:ra,useEffect:nN,useImperativeHandle:WI,useInsertionEffect:HI,useLayoutEffect:VI,useMemo:KI,useReducer:JE,useRef:zI,useState:function(){return JE(nc)},useDebugValue:rN,useDeferredValue:function(h,p){var _=ri();return nr===null?iN(_,h,p):XI(_,nr.memoizedState,h,p)},useTransition:function(){var h=JE(nc)[0],p=ri().memoizedState;return[typeof h=="boolean"?h:px(h),p]},useSyncExternalStore:MI,useId:JI,useHostTransitionStatus:sN,useFormState:UI,useActionState:UI,useOptimistic:function(h,p){var _=ri();return nr!==null?kI(_,nr,h,p):(_.baseState=h,[h,_.queue.dispatch])},useMemoCache:QE,useCacheRefresh:e5};a5.useEffectEvent=$I;function cN(h,p,_,E){p=h.memoizedState,_=_(E,p),_=_==null?p:f({},p,_),h.memoizedState=_,h.lanes===0&&(h.updateQueue.baseState=_)}var uN={enqueueSetState:function(h,p,_){h=h._reactInternals;var E=Ms(),j=_u(E);j.payload=p,_!=null&&(j.callback=_),p=wu(h,j,E),p!==null&&(es(p,h,E),dx(p,h,E))},enqueueReplaceState:function(h,p,_){h=h._reactInternals;var E=Ms(),j=_u(E);j.tag=1,j.payload=p,_!=null&&(j.callback=_),p=wu(h,j,E),p!==null&&(es(p,h,E),dx(p,h,E))},enqueueForceUpdate:function(h,p){h=h._reactInternals;var _=Ms(),E=_u(_);E.tag=2,p!=null&&(E.callback=p),p=wu(h,E,_),p!==null&&(es(p,h,_),dx(p,h,_))}};function s5(h,p,_,E,j,O,ee){return h=h.stateNode,typeof h.shouldComponentUpdate=="function"?h.shouldComponentUpdate(E,O,ee):p.prototype&&p.prototype.isPureReactComponent?!rx(_,E)||!rx(j,O):!0}function o5(h,p,_,E){h=p.state,typeof p.componentWillReceiveProps=="function"&&p.componentWillReceiveProps(_,E),typeof p.UNSAFE_componentWillReceiveProps=="function"&&p.UNSAFE_componentWillReceiveProps(_,E),p.state!==h&&uN.enqueueReplaceState(p,p.state,null)}function hh(h,p){var _=p;if("ref"in p){_={};for(var E in p)E!=="ref"&&(_[E]=p[E])}if(h=h.defaultProps){_===p&&(_=f({},_));for(var j in h)_[j]===void 0&&(_[j]=h[j])}return _}function l5(h){zy(h)}function c5(h){console.error(h)}function u5(h){zy(h)}function cv(h,p){try{var _=h.onUncaughtError;_(p.value,{componentStack:p.stack})}catch(E){setTimeout(function(){throw E})}}function d5(h,p,_){try{var E=h.onCaughtError;E(_.value,{componentStack:_.stack,errorBoundary:p.tag===1?p.stateNode:null})}catch(j){setTimeout(function(){throw j})}}function dN(h,p,_){return _=_u(_),_.tag=3,_.payload={element:null},_.callback=function(){cv(h,p)},_}function h5(h){return h=_u(h),h.tag=3,h}function f5(h,p,_,E){var j=_.type.getDerivedStateFromError;if(typeof j=="function"){var O=E.value;h.payload=function(){return j(O)},h.callback=function(){d5(p,_,E)}}var ee=_.stateNode;ee!==null&&typeof ee.componentDidCatch=="function"&&(h.callback=function(){d5(p,_,E),typeof j!="function"&&(Tu===null?Tu=new Set([this]):Tu.add(this));var fe=E.stack;this.componentDidCatch(E.value,{componentStack:fe!==null?fe:""})})}function rie(h,p,_,E,j){if(_.flags|=32768,E!==null&&typeof E=="object"&&typeof E.then=="function"){if(p=_.alternate,p!==null&&rm(p,_,j,!0),_=vs.current,_!==null){switch(_.tag){case 31:case 13:return Zs===null?_v():_.alternate===null&&Gr===0&&(Gr=3),_.flags&=-257,_.flags|=65536,_.lanes=j,E===Yy?_.flags|=16384:(p=_.updateQueue,p===null?_.updateQueue=new Set([E]):p.add(E),LN(h,E,j)),!1;case 22:return _.flags|=65536,E===Yy?_.flags|=16384:(p=_.updateQueue,p===null?(p={transitions:null,markerInstances:null,retryQueue:new Set([E])},_.updateQueue=p):(_=p.retryQueue,_===null?p.retryQueue=new Set([E]):_.add(E)),LN(h,E,j)),!1}throw Error(r(435,_.tag))}return LN(h,E,j),_v(),!1}if(jn)return p=vs.current,p!==null?((p.flags&65536)===0&&(p.flags|=256),p.flags|=65536,p.lanes=j,E!==kE&&(h=Error(r(422),{cause:E}),sx(Ks(h,_)))):(E!==kE&&(p=Error(r(423),{cause:E}),sx(Ks(p,_))),h=h.current.alternate,h.flags|=65536,j&=-j,h.lanes|=j,E=Ks(E,_),j=dN(h.stateNode,E,j),BE(h,j),Gr!==4&&(Gr=2)),!1;var O=Error(r(520),{cause:E});if(O=Ks(O,_),Ex===null?Ex=[O]:Ex.push(O),Gr!==4&&(Gr=2),p===null)return!0;E=Ks(E,_),_=p;do{switch(_.tag){case 3:return _.flags|=65536,h=j&-j,_.lanes|=h,h=dN(_.stateNode,E,h),BE(_,h),!1;case 1:if(p=_.type,O=_.stateNode,(_.flags&128)===0&&(typeof p.getDerivedStateFromError=="function"||O!==null&&typeof O.componentDidCatch=="function"&&(Tu===null||!Tu.has(O))))return _.flags|=65536,j&=-j,_.lanes|=j,j=h5(j),f5(j,h,_,E),BE(_,j),!1}_=_.return}while(_!==null);return!1}var hN=Error(r(461)),ci=!1;function ia(h,p,_,E){p.child=h===null?xI(p,null,_,E):uh(p,h.child,_,E)}function m5(h,p,_,E,j){_=_.render;var O=p.ref;if("ref"in E){var ee={};for(var fe in E)fe!=="ref"&&(ee[fe]=E[fe])}else ee=E;return sh(p),E=qE(h,p,_,ee,O,j),fe=KE(),h!==null&&!ci?(XE(h,p,j),rc(h,p,j)):(jn&&fe&&TE(p),p.flags|=1,ia(h,p,E,j),p.child)}function p5(h,p,_,E,j){if(h===null){var O=_.type;return typeof O=="function"&&!EE(O)&&O.defaultProps===void 0&&_.compare===null?(p.tag=15,p.type=O,g5(h,p,O,E,j)):(h=Vy(_.type,null,E,p,p.mode,j),h.ref=p.ref,h.return=p,p.child=h)}if(O=h.child,!vN(h,j)){var ee=O.memoizedProps;if(_=_.compare,_=_!==null?_:rx,_(ee,E)&&h.ref===p.ref)return rc(h,p,j)}return p.flags|=1,h=Ql(O,E),h.ref=p.ref,h.return=p,p.child=h}function g5(h,p,_,E,j){if(h!==null){var O=h.memoizedProps;if(rx(O,E)&&h.ref===p.ref)if(ci=!1,p.pendingProps=E=O,vN(h,j))(h.flags&131072)!==0&&(ci=!0);else return p.lanes=h.lanes,rc(h,p,j)}return fN(h,p,_,E,j)}function x5(h,p,_,E){var j=E.children,O=h!==null?h.memoizedState:null;if(h===null&&p.stateNode===null&&(p.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),E.mode==="hidden"){if((p.flags&128)!==0){if(O=O!==null?O.baseLanes|_:_,h!==null){for(E=p.child=h.child,j=0;E!==null;)j=j|E.lanes|E.childLanes,E=E.sibling;E=j&~O}else E=0,p.child=null;return b5(h,p,O,_,E)}if((_&536870912)!==0)p.memoizedState={baseLanes:0,cachePool:null},h!==null&&Ky(p,O!==null?O.cachePool:null),O!==null?vI(p,O):HE(),_I(p);else return E=p.lanes=536870912,b5(h,p,O!==null?O.baseLanes|_:_,_,E)}else O!==null?(Ky(p,O.cachePool),vI(p,O),Mu(),p.memoizedState=null):(h!==null&&Ky(p,null),HE(),Mu());return ia(h,p,j,_),p.child}function bx(h,p){return h!==null&&h.tag===22||p.stateNode!==null||(p.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),p.sibling}function b5(h,p,_,E,j){var O=IE();return O=O===null?null:{parent:oi._currentValue,pool:O},p.memoizedState={baseLanes:_,cachePool:O},h!==null&&Ky(p,null),HE(),_I(p),h!==null&&rm(h,p,E,!0),p.childLanes=j,null}function uv(h,p){return p=hv({mode:p.mode,children:p.children},h.mode),p.ref=h.ref,h.child=p,p.return=h,p}function y5(h,p,_){return uh(p,h.child,null,_),h=uv(p,p.pendingProps),h.flags|=2,_s(p),p.memoizedState=null,h}function iie(h,p,_){var E=p.pendingProps,j=(p.flags&128)!==0;if(p.flags&=-129,h===null){if(jn){if(E.mode==="hidden")return h=uv(p,E),p.lanes=536870912,bx(null,h);if(GE(p),(h=Sr)?(h=jF(h,Qs),h=h!==null&&h.data==="&"?h:null,h!==null&&(p.memoizedState={dehydrated:h,treeContext:gu!==null?{id:ol,overflow:ll}:null,retryLane:536870912,hydrationErrors:null},_=nI(h),_.return=p,p.child=_,na=p,Sr=null)):h=null,h===null)throw bu(p);return p.lanes=536870912,null}return uv(p,E)}var O=h.memoizedState;if(O!==null){var ee=O.dehydrated;if(GE(p),j)if(p.flags&256)p.flags&=-257,p=y5(h,p,_);else if(p.memoizedState!==null)p.child=h.child,p.flags|=128,p=null;else throw Error(r(558));else if(ci||rm(h,p,_,!1),j=(_&h.childLanes)!==0,ci||j){if(E=fr,E!==null&&(ee=Wn(E,_),ee!==0&&ee!==O.retryLane))throw O.retryLane=ee,nh(h,ee),es(E,h,ee),hN;_v(),p=y5(h,p,_)}else h=O.treeContext,Sr=Js(ee.nextSibling),na=p,jn=!0,xu=null,Qs=!1,h!==null&&aI(p,h),p=uv(p,E),p.flags|=4096;return p}return h=Ql(h.child,{mode:E.mode,children:E.children}),h.ref=p.ref,p.child=h,h.return=p,h}function dv(h,p){var _=p.ref;if(_===null)h!==null&&h.ref!==null&&(p.flags|=4194816);else{if(typeof _!="function"&&typeof _!="object")throw Error(r(284));(h===null||h.ref!==_)&&(p.flags|=4194816)}}function fN(h,p,_,E,j){return sh(p),_=qE(h,p,_,E,void 0,j),E=KE(),h!==null&&!ci?(XE(h,p,j),rc(h,p,j)):(jn&&E&&TE(p),p.flags|=1,ia(h,p,_,j),p.child)}function v5(h,p,_,E,j,O){return sh(p),p.updateQueue=null,_=SI(p,E,_,j),wI(h),E=KE(),h!==null&&!ci?(XE(h,p,O),rc(h,p,O)):(jn&&E&&TE(p),p.flags|=1,ia(h,p,_,O),p.child)}function _5(h,p,_,E,j){if(sh(p),p.stateNode===null){var O=Jf,ee=_.contextType;typeof ee=="object"&&ee!==null&&(O=ra(ee)),O=new _(E,O),p.memoizedState=O.state!==null&&O.state!==void 0?O.state:null,O.updater=uN,p.stateNode=O,O._reactInternals=p,O=p.stateNode,O.props=E,O.state=p.memoizedState,O.refs={},UE(p),ee=_.contextType,O.context=typeof ee=="object"&&ee!==null?ra(ee):Jf,O.state=p.memoizedState,ee=_.getDerivedStateFromProps,typeof ee=="function"&&(cN(p,_,ee,E),O.state=p.memoizedState),typeof _.getDerivedStateFromProps=="function"||typeof O.getSnapshotBeforeUpdate=="function"||typeof O.UNSAFE_componentWillMount!="function"&&typeof O.componentWillMount!="function"||(ee=O.state,typeof O.componentWillMount=="function"&&O.componentWillMount(),typeof O.UNSAFE_componentWillMount=="function"&&O.UNSAFE_componentWillMount(),ee!==O.state&&uN.enqueueReplaceState(O,O.state,null),fx(p,E,O,j),hx(),O.state=p.memoizedState),typeof O.componentDidMount=="function"&&(p.flags|=4194308),E=!0}else if(h===null){O=p.stateNode;var fe=p.memoizedProps,ke=hh(_,fe);O.props=ke;var nt=O.context,dt=_.contextType;ee=Jf,typeof dt=="object"&&dt!==null&&(ee=ra(dt));var xt=_.getDerivedStateFromProps;dt=typeof xt=="function"||typeof O.getSnapshotBeforeUpdate=="function",fe=p.pendingProps!==fe,dt||typeof O.UNSAFE_componentWillReceiveProps!="function"&&typeof O.componentWillReceiveProps!="function"||(fe||nt!==ee)&&o5(p,O,E,ee),vu=!1;var it=p.memoizedState;O.state=it,fx(p,E,O,j),hx(),nt=p.memoizedState,fe||it!==nt||vu?(typeof xt=="function"&&(cN(p,_,xt,E),nt=p.memoizedState),(ke=vu||s5(p,_,ke,E,it,nt,ee))?(dt||typeof O.UNSAFE_componentWillMount!="function"&&typeof O.componentWillMount!="function"||(typeof O.componentWillMount=="function"&&O.componentWillMount(),typeof O.UNSAFE_componentWillMount=="function"&&O.UNSAFE_componentWillMount()),typeof O.componentDidMount=="function"&&(p.flags|=4194308)):(typeof O.componentDidMount=="function"&&(p.flags|=4194308),p.memoizedProps=E,p.memoizedState=nt),O.props=E,O.state=nt,O.context=ee,E=ke):(typeof O.componentDidMount=="function"&&(p.flags|=4194308),E=!1)}else{O=p.stateNode,zE(h,p),ee=p.memoizedProps,dt=hh(_,ee),O.props=dt,xt=p.pendingProps,it=O.context,nt=_.contextType,ke=Jf,typeof nt=="object"&&nt!==null&&(ke=ra(nt)),fe=_.getDerivedStateFromProps,(nt=typeof fe=="function"||typeof O.getSnapshotBeforeUpdate=="function")||typeof O.UNSAFE_componentWillReceiveProps!="function"&&typeof O.componentWillReceiveProps!="function"||(ee!==xt||it!==ke)&&o5(p,O,E,ke),vu=!1,it=p.memoizedState,O.state=it,fx(p,E,O,j),hx();var ot=p.memoizedState;ee!==xt||it!==ot||vu||h!==null&&h.dependencies!==null&&Wy(h.dependencies)?(typeof fe=="function"&&(cN(p,_,fe,E),ot=p.memoizedState),(dt=vu||s5(p,_,dt,E,it,ot,ke)||h!==null&&h.dependencies!==null&&Wy(h.dependencies))?(nt||typeof O.UNSAFE_componentWillUpdate!="function"&&typeof O.componentWillUpdate!="function"||(typeof O.componentWillUpdate=="function"&&O.componentWillUpdate(E,ot,ke),typeof O.UNSAFE_componentWillUpdate=="function"&&O.UNSAFE_componentWillUpdate(E,ot,ke)),typeof O.componentDidUpdate=="function"&&(p.flags|=4),typeof O.getSnapshotBeforeUpdate=="function"&&(p.flags|=1024)):(typeof O.componentDidUpdate!="function"||ee===h.memoizedProps&&it===h.memoizedState||(p.flags|=4),typeof O.getSnapshotBeforeUpdate!="function"||ee===h.memoizedProps&&it===h.memoizedState||(p.flags|=1024),p.memoizedProps=E,p.memoizedState=ot),O.props=E,O.state=ot,O.context=ke,E=dt):(typeof O.componentDidUpdate!="function"||ee===h.memoizedProps&&it===h.memoizedState||(p.flags|=4),typeof O.getSnapshotBeforeUpdate!="function"||ee===h.memoizedProps&&it===h.memoizedState||(p.flags|=1024),E=!1)}return O=E,dv(h,p),E=(p.flags&128)!==0,O||E?(O=p.stateNode,_=E&&typeof _.getDerivedStateFromError!="function"?null:O.render(),p.flags|=1,h!==null&&E?(p.child=uh(p,h.child,null,j),p.child=uh(p,null,_,j)):ia(h,p,_,j),p.memoizedState=O.state,h=p.child):h=rc(h,p,j),h}function w5(h,p,_,E){return ih(),p.flags|=256,ia(h,p,_,E),p.child}var mN={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function pN(h){return{baseLanes:h,cachePool:dI()}}function gN(h,p,_){return h=h!==null?h.childLanes&~_:0,p&&(h|=Ss),h}function S5(h,p,_){var E=p.pendingProps,j=!1,O=(p.flags&128)!==0,ee;if((ee=O)||(ee=h!==null&&h.memoizedState===null?!1:(ni.current&2)!==0),ee&&(j=!0,p.flags&=-129),ee=(p.flags&32)!==0,p.flags&=-33,h===null){if(jn){if(j?Su(p):Mu(),(h=Sr)?(h=jF(h,Qs),h=h!==null&&h.data!=="&"?h:null,h!==null&&(p.memoizedState={dehydrated:h,treeContext:gu!==null?{id:ol,overflow:ll}:null,retryLane:536870912,hydrationErrors:null},_=nI(h),_.return=p,p.child=_,na=p,Sr=null)):h=null,h===null)throw bu(p);return ZN(h)?p.lanes=32:p.lanes=536870912,null}var fe=E.children;return E=E.fallback,j?(Mu(),j=p.mode,fe=hv({mode:"hidden",children:fe},j),E=rh(E,j,_,null),fe.return=p,E.return=p,fe.sibling=E,p.child=fe,E=p.child,E.memoizedState=pN(_),E.childLanes=gN(h,ee,_),p.memoizedState=mN,bx(null,E)):(Su(p),xN(p,fe))}var ke=h.memoizedState;if(ke!==null&&(fe=ke.dehydrated,fe!==null)){if(O)p.flags&256?(Su(p),p.flags&=-257,p=bN(h,p,_)):p.memoizedState!==null?(Mu(),p.child=h.child,p.flags|=128,p=null):(Mu(),fe=E.fallback,j=p.mode,E=hv({mode:"visible",children:E.children},j),fe=rh(fe,j,_,null),fe.flags|=2,E.return=p,fe.return=p,E.sibling=fe,p.child=E,uh(p,h.child,null,_),E=p.child,E.memoizedState=pN(_),E.childLanes=gN(h,ee,_),p.memoizedState=mN,p=bx(null,E));else if(Su(p),ZN(fe)){if(ee=fe.nextSibling&&fe.nextSibling.dataset,ee)var nt=ee.dgst;ee=nt,E=Error(r(419)),E.stack="",E.digest=ee,sx({value:E,source:null,stack:null}),p=bN(h,p,_)}else if(ci||rm(h,p,_,!1),ee=(_&h.childLanes)!==0,ci||ee){if(ee=fr,ee!==null&&(E=Wn(ee,_),E!==0&&E!==ke.retryLane))throw ke.retryLane=E,nh(h,E),es(ee,h,E),hN;QN(fe)||_v(),p=bN(h,p,_)}else QN(fe)?(p.flags|=192,p.child=h.child,p=null):(h=ke.treeContext,Sr=Js(fe.nextSibling),na=p,jn=!0,xu=null,Qs=!1,h!==null&&aI(p,h),p=xN(p,E.children),p.flags|=4096);return p}return j?(Mu(),fe=E.fallback,j=p.mode,ke=h.child,nt=ke.sibling,E=Ql(ke,{mode:"hidden",children:E.children}),E.subtreeFlags=ke.subtreeFlags&65011712,nt!==null?fe=Ql(nt,fe):(fe=rh(fe,j,_,null),fe.flags|=2),fe.return=p,E.return=p,E.sibling=fe,p.child=E,bx(null,E),E=p.child,fe=h.child.memoizedState,fe===null?fe=pN(_):(j=fe.cachePool,j!==null?(ke=oi._currentValue,j=j.parent!==ke?{parent:ke,pool:ke}:j):j=dI(),fe={baseLanes:fe.baseLanes|_,cachePool:j}),E.memoizedState=fe,E.childLanes=gN(h,ee,_),p.memoizedState=mN,bx(h.child,E)):(Su(p),_=h.child,h=_.sibling,_=Ql(_,{mode:"visible",children:E.children}),_.return=p,_.sibling=null,h!==null&&(ee=p.deletions,ee===null?(p.deletions=[h],p.flags|=16):ee.push(h)),p.child=_,p.memoizedState=null,_)}function xN(h,p){return p=hv({mode:"visible",children:p},h.mode),p.return=h,h.child=p}function hv(h,p){return h=ys(22,h,null,p),h.lanes=0,h}function bN(h,p,_){return uh(p,h.child,null,_),h=xN(p,p.pendingProps.children),h.flags|=2,p.memoizedState=null,h}function M5(h,p,_){h.lanes|=p;var E=h.alternate;E!==null&&(E.lanes|=p),RE(h.return,p,_)}function yN(h,p,_,E,j,O){var ee=h.memoizedState;ee===null?h.memoizedState={isBackwards:p,rendering:null,renderingStartTime:0,last:E,tail:_,tailMode:j,treeForkCount:O}:(ee.isBackwards=p,ee.rendering=null,ee.renderingStartTime=0,ee.last=E,ee.tail=_,ee.tailMode=j,ee.treeForkCount=O)}function E5(h,p,_){var E=p.pendingProps,j=E.revealOrder,O=E.tail;E=E.children;var ee=ni.current,fe=(ee&2)!==0;if(fe?(ee=ee&1|2,p.flags|=128):ee&=1,te(ni,ee),ia(h,p,E,_),E=jn?ax:0,!fe&&h!==null&&(h.flags&128)!==0)e:for(h=p.child;h!==null;){if(h.tag===13)h.memoizedState!==null&&M5(h,_,p);else if(h.tag===19)M5(h,_,p);else if(h.child!==null){h.child.return=h,h=h.child;continue}if(h===p)break e;for(;h.sibling===null;){if(h.return===null||h.return===p)break e;h=h.return}h.sibling.return=h.return,h=h.sibling}switch(j){case"forwards":for(_=p.child,j=null;_!==null;)h=_.alternate,h!==null&&ev(h)===null&&(j=_),_=_.sibling;_=j,_===null?(j=p.child,p.child=null):(j=_.sibling,_.sibling=null),yN(p,!1,j,_,O,E);break;case"backwards":case"unstable_legacy-backwards":for(_=null,j=p.child,p.child=null;j!==null;){if(h=j.alternate,h!==null&&ev(h)===null){p.child=j;break}h=j.sibling,j.sibling=_,_=j,j=h}yN(p,!0,_,null,O,E);break;case"together":yN(p,!1,null,null,void 0,E);break;default:p.memoizedState=null}return p.child}function rc(h,p,_){if(h!==null&&(p.dependencies=h.dependencies),Au|=p.lanes,(_&p.childLanes)===0)if(h!==null){if(rm(h,p,_,!1),(_&p.childLanes)===0)return null}else return null;if(h!==null&&p.child!==h.child)throw Error(r(153));if(p.child!==null){for(h=p.child,_=Ql(h,h.pendingProps),p.child=_,_.return=p;h.sibling!==null;)h=h.sibling,_=_.sibling=Ql(h,h.pendingProps),_.return=p;_.sibling=null}return p.child}function vN(h,p){return(h.lanes&p)!==0?!0:(h=h.dependencies,!!(h!==null&&Wy(h)))}function aie(h,p,_){switch(p.tag){case 3:Ae(p,p.stateNode.containerInfo),yu(p,oi,h.memoizedState.cache),ih();break;case 27:case 5:Ne(p);break;case 4:Ae(p,p.stateNode.containerInfo);break;case 10:yu(p,p.type,p.memoizedProps.value);break;case 31:if(p.memoizedState!==null)return p.flags|=128,GE(p),null;break;case 13:var E=p.memoizedState;if(E!==null)return E.dehydrated!==null?(Su(p),p.flags|=128,null):(_&p.child.childLanes)!==0?S5(h,p,_):(Su(p),h=rc(h,p,_),h!==null?h.sibling:null);Su(p);break;case 19:var j=(h.flags&128)!==0;if(E=(_&p.childLanes)!==0,E||(rm(h,p,_,!1),E=(_&p.childLanes)!==0),j){if(E)return E5(h,p,_);p.flags|=128}if(j=p.memoizedState,j!==null&&(j.rendering=null,j.tail=null,j.lastEffect=null),te(ni,ni.current),E)break;return null;case 22:return p.lanes=0,x5(h,p,_,p.pendingProps);case 24:yu(p,oi,h.memoizedState.cache)}return rc(h,p,_)}function N5(h,p,_){if(h!==null)if(h.memoizedProps!==p.pendingProps)ci=!0;else{if(!vN(h,_)&&(p.flags&128)===0)return ci=!1,aie(h,p,_);ci=(h.flags&131072)!==0}else ci=!1,jn&&(p.flags&1048576)!==0&&iI(p,ax,p.index);switch(p.lanes=0,p.tag){case 16:e:{var E=p.pendingProps;if(h=lh(p.elementType),p.type=h,typeof h=="function")EE(h)?(E=hh(h,E),p.tag=1,p=_5(null,p,h,E,_)):(p.tag=0,p=fN(null,p,h,E,_));else{if(h!=null){var j=h.$$typeof;if(j===A){p.tag=11,p=m5(null,p,h,E,_);break e}else if(j===T){p.tag=14,p=p5(null,p,h,E,_);break e}}throw p=D(h)||h,Error(r(306,p,""))}}return p;case 0:return fN(h,p,p.type,p.pendingProps,_);case 1:return E=p.type,j=hh(E,p.pendingProps),_5(h,p,E,j,_);case 3:e:{if(Ae(p,p.stateNode.containerInfo),h===null)throw Error(r(387));E=p.pendingProps;var O=p.memoizedState;j=O.element,zE(h,p),fx(p,E,null,_);var ee=p.memoizedState;if(E=ee.cache,yu(p,oi,E),E!==O.cache&&DE(p,[oi],_,!0),hx(),E=ee.element,O.isDehydrated)if(O={element:E,isDehydrated:!1,cache:ee.cache},p.updateQueue.baseState=O,p.memoizedState=O,p.flags&256){p=w5(h,p,E,_);break e}else if(E!==j){j=Ks(Error(r(424)),p),sx(j),p=w5(h,p,E,_);break e}else{switch(h=p.stateNode.containerInfo,h.nodeType){case 9:h=h.body;break;default:h=h.nodeName==="HTML"?h.ownerDocument.body:h}for(Sr=Js(h.firstChild),na=p,jn=!0,xu=null,Qs=!0,_=xI(p,null,E,_),p.child=_;_;)_.flags=_.flags&-3|4096,_=_.sibling}else{if(ih(),E===j){p=rc(h,p,_);break e}ia(h,p,E,_)}p=p.child}return p;case 26:return dv(h,p),h===null?(_=IF(p.type,null,p.pendingProps,null))?p.memoizedState=_:jn||(_=p.type,h=p.pendingProps,E=Tv(ce.current).createElement(_),E[Dn]=p,E[gt]=h,aa(E,_,h),Oe(E),p.stateNode=E):p.memoizedState=IF(p.type,h.memoizedProps,p.pendingProps,h.memoizedState),null;case 27:return Ne(p),h===null&&jn&&(E=p.stateNode=DF(p.type,p.pendingProps,ce.current),na=p,Qs=!0,j=Sr,Pu(p.type)?(JN=j,Sr=Js(E.firstChild)):Sr=j),ia(h,p,p.pendingProps.children,_),dv(h,p),h===null&&(p.flags|=4194304),p.child;case 5:return h===null&&jn&&((j=E=Sr)&&(E=Oie(E,p.type,p.pendingProps,Qs),E!==null?(p.stateNode=E,na=p,Sr=Js(E.firstChild),Qs=!1,j=!0):j=!1),j||bu(p)),Ne(p),j=p.type,O=p.pendingProps,ee=h!==null?h.memoizedProps:null,E=O.children,KN(j,O)?E=null:ee!==null&&KN(j,ee)&&(p.flags|=32),p.memoizedState!==null&&(j=qE(h,p,Yre,null,null,_),Rx._currentValue=j),dv(h,p),ia(h,p,E,_),p.child;case 6:return h===null&&jn&&((h=_=Sr)&&(_=Lie(_,p.pendingProps,Qs),_!==null?(p.stateNode=_,na=p,Sr=null,h=!0):h=!1),h||bu(p)),null;case 13:return S5(h,p,_);case 4:return Ae(p,p.stateNode.containerInfo),E=p.pendingProps,h===null?p.child=uh(p,null,E,_):ia(h,p,E,_),p.child;case 11:return m5(h,p,p.type,p.pendingProps,_);case 7:return ia(h,p,p.pendingProps,_),p.child;case 8:return ia(h,p,p.pendingProps.children,_),p.child;case 12:return ia(h,p,p.pendingProps.children,_),p.child;case 10:return E=p.pendingProps,yu(p,p.type,E.value),ia(h,p,E.children,_),p.child;case 9:return j=p.type._context,E=p.pendingProps.children,sh(p),j=ra(j),E=E(j),p.flags|=1,ia(h,p,E,_),p.child;case 14:return p5(h,p,p.type,p.pendingProps,_);case 15:return g5(h,p,p.type,p.pendingProps,_);case 19:return E5(h,p,_);case 31:return iie(h,p,_);case 22:return x5(h,p,_,p.pendingProps);case 24:return sh(p),E=ra(oi),h===null?(j=IE(),j===null&&(j=fr,O=OE(),j.pooledCache=O,O.refCount++,O!==null&&(j.pooledCacheLanes|=_),j=O),p.memoizedState={parent:E,cache:j},UE(p),yu(p,oi,j)):((h.lanes&_)!==0&&(zE(h,p),fx(p,null,null,_),hx()),j=h.memoizedState,O=p.memoizedState,j.parent!==E?(j={parent:E,cache:E},p.memoizedState=j,p.lanes===0&&(p.memoizedState=p.updateQueue.baseState=j),yu(p,oi,E)):(E=O.cache,yu(p,oi,E),E!==j.cache&&DE(p,[oi],_,!0))),ia(h,p,p.pendingProps.children,_),p.child;case 29:throw p.pendingProps}throw Error(r(156,p.tag))}function ic(h){h.flags|=4}function _N(h,p,_,E,j){if((p=(h.mode&32)!==0)&&(p=!1),p){if(h.flags|=16777216,(j&335544128)===j)if(h.stateNode.complete)h.flags|=8192;else if(J5())h.flags|=8192;else throw ch=Yy,FE}else h.flags&=-16777217}function A5(h,p){if(p.type!=="stylesheet"||(p.state.loading&4)!==0)h.flags&=-16777217;else if(h.flags|=16777216,!$F(p))if(J5())h.flags|=8192;else throw ch=Yy,FE}function fv(h,p){p!==null&&(h.flags|=4),h.flags&16384&&(p=h.tag!==22?Nt():536870912,h.lanes|=p,pm|=p)}function yx(h,p){if(!jn)switch(h.tailMode){case"hidden":p=h.tail;for(var _=null;p!==null;)p.alternate!==null&&(_=p),p=p.sibling;_===null?h.tail=null:_.sibling=null;break;case"collapsed":_=h.tail;for(var E=null;_!==null;)_.alternate!==null&&(E=_),_=_.sibling;E===null?p||h.tail===null?h.tail=null:h.tail.sibling=null:E.sibling=null}}function Mr(h){var p=h.alternate!==null&&h.alternate.child===h.child,_=0,E=0;if(p)for(var j=h.child;j!==null;)_|=j.lanes|j.childLanes,E|=j.subtreeFlags&65011712,E|=j.flags&65011712,j.return=h,j=j.sibling;else for(j=h.child;j!==null;)_|=j.lanes|j.childLanes,E|=j.subtreeFlags,E|=j.flags,j.return=h,j=j.sibling;return h.subtreeFlags|=E,h.childLanes=_,p}function sie(h,p,_){var E=p.pendingProps;switch(CE(p),p.tag){case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Mr(p),null;case 1:return Mr(p),null;case 3:return _=p.stateNode,E=null,h!==null&&(E=h.memoizedState.cache),p.memoizedState.cache!==E&&(p.flags|=2048),ec(oi),ge(),_.pendingContext&&(_.context=_.pendingContext,_.pendingContext=null),(h===null||h.child===null)&&(nm(p)?ic(p):h===null||h.memoizedState.isDehydrated&&(p.flags&256)===0||(p.flags|=1024,jE())),Mr(p),null;case 26:var j=p.type,O=p.memoizedState;return h===null?(ic(p),O!==null?(Mr(p),A5(p,O)):(Mr(p),_N(p,j,null,E,_))):O?O!==h.memoizedState?(ic(p),Mr(p),A5(p,O)):(Mr(p),p.flags&=-16777217):(h=h.memoizedProps,h!==E&&ic(p),Mr(p),_N(p,j,h,E,_)),null;case 27:if(Se(p),_=ce.current,j=p.type,h!==null&&p.stateNode!=null)h.memoizedProps!==E&&ic(p);else{if(!E){if(p.stateNode===null)throw Error(r(166));return Mr(p),null}h=ie.current,nm(p)?sI(p):(h=DF(j,E,_),p.stateNode=h,ic(p))}return Mr(p),null;case 5:if(Se(p),j=p.type,h!==null&&p.stateNode!=null)h.memoizedProps!==E&&ic(p);else{if(!E){if(p.stateNode===null)throw Error(r(166));return Mr(p),null}if(O=ie.current,nm(p))sI(p);else{var ee=Tv(ce.current);switch(O){case 1:O=ee.createElementNS("http://www.w3.org/2000/svg",j);break;case 2:O=ee.createElementNS("http://www.w3.org/1998/Math/MathML",j);break;default:switch(j){case"svg":O=ee.createElementNS("http://www.w3.org/2000/svg",j);break;case"math":O=ee.createElementNS("http://www.w3.org/1998/Math/MathML",j);break;case"script":O=ee.createElement("div"),O.innerHTML=" +