From 30537cfa54461020ae2c522393b4f6111be111b6 Mon Sep 17 00:00:00 2001 From: maziggy Date: Sun, 25 Jan 2026 13:17:15 +0100 Subject: [PATCH] Add project import/export with ZIP file support Features: - Export single project as ZIP containing project.json and all files from linked library folders - Export all projects as JSON (metadata only) for bulk backup - Import from ZIP (creates folders and extracts files) or JSON - New /api/v1/projects/import/file endpoint for file uploads - Frontend buttons on Projects page and Project Detail page - BOM items are now fully editable (not just checkbox toggle) --- CHANGELOG.md | 9 + README.md | 1 + backend/app/api/routes/projects.py | 397 +++++++++++++++++- backend/app/models/library.py | 11 +- backend/app/schemas/project.py | 55 +++ .../tests/integration/test_projects_api.py | 327 +++++++++++++++ frontend/src/api/client.ts | 56 +++ frontend/src/pages/ProjectDetailPage.tsx | 270 +++++++++--- frontend/src/pages/ProjectsPage.tsx | 121 +++++- .../{index-BQzscOA-.js => index-CTmc90ua.js} | 126 +++--- static/index.html | 2 +- 11 files changed, 1236 insertions(+), 139 deletions(-) rename static/assets/{index-BQzscOA-.js => index-CTmc90ua.js} (56%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56dcdcc4c..7e4feffed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ All notable changes to Bambuddy will be documented in this file. ## [0.1.6] - 2026-01-24 ### New Features +- **Project Import/Export** - Export and import projects with full file support (Issue #152): + - Export single project as ZIP (includes project settings, BOM, and all files from linked library folders) + - Export all projects as JSON for metadata-only backup + - Import from ZIP (with files) or JSON (metadata only) + - Linked folders and files are automatically created on import + - Useful for sharing complete project bundles or migrating between instances +- **BOM Item Editing** - Bill of Materials items are now fully editable: + - Edit name, quantity, price, URL, and remarks after creation + - Pencil icon on each BOM item to enter edit mode - **External Link for Archives** - Add custom external links to archives for non-MakerWorld sources (Issue #151): - Link archives to Printables, Thingiverse, or any other URL - Globe button opens external link when set, falls back to auto-detected MakerWorld URL diff --git a/README.md b/README.md index 642c1c79a..605dbe7a4 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ - Auto-detect parts count from 3MF files - Color-coded project badges - Bulk assign archives via multi-select toolbar +- Import/Export projects as ZIP (includes files) or JSON diff --git a/backend/app/api/routes/projects.py b/backend/app/api/routes/projects.py index edab46e3b..b69d7d452 100644 --- a/backend/app/api/routes/projects.py +++ b/backend/app/api/routes/projects.py @@ -1,18 +1,23 @@ +import io +import json import logging import os import uuid +import zipfile from datetime import datetime from pathlib import Path from fastapi import APIRouter, Depends, File, HTTPException, UploadFile -from fastapi.responses import FileResponse +from fastapi.responses import FileResponse, StreamingResponse from sqlalchemy import case, func, select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload +from backend.app.api.routes.library import get_library_dir from backend.app.core.config import settings from backend.app.core.database import get_db from backend.app.models.archive import PrintArchive +from backend.app.models.library import LibraryFile, LibraryFolder from backend.app.models.print_queue import PrintQueueItem from backend.app.models.project import Project from backend.app.models.project_bom import ProjectBOMItem @@ -25,6 +30,7 @@ from backend.app.schemas.project import ( BOMItemUpdate, ProjectChildPreview, ProjectCreate, + ProjectImport, ProjectListResponse, ProjectResponse, ProjectStats, @@ -1322,3 +1328,392 @@ async def get_project_timeline( events.sort(key=lambda e: e.timestamp, reverse=True) return events[:limit] + + +# ============ Phase 10: Import/Export Endpoints ============ + + +@router.get("/{project_id}/export") +async def export_project( + project_id: int, + format: str = "zip", # "zip" (with files) or "json" (metadata only) + db: AsyncSession = Depends(get_db), +): + """Export a project. Use format=zip (default) for full export with files, or format=json for metadata only.""" + result = await db.execute(select(Project).where(Project.id == project_id)) + project = result.scalar_one_or_none() + + if not project: + raise HTTPException(status_code=404, detail="Project not found") + + # Get BOM items + bom_result = await db.execute( + select(ProjectBOMItem).where(ProjectBOMItem.project_id == project_id).order_by(ProjectBOMItem.sort_order) + ) + bom_items = bom_result.scalars().all() + + bom_export = [ + { + "name": item.name, + "quantity_needed": item.quantity_needed, + "quantity_acquired": item.quantity_acquired, + "unit_price": item.unit_price, + "sourcing_url": item.sourcing_url, + "stl_filename": item.stl_filename, + "remarks": item.remarks, + } + for item in bom_items + ] + + # Get linked folders and their files + folders_result = await db.execute( + select(LibraryFolder).where(LibraryFolder.project_id == project_id).order_by(LibraryFolder.name) + ) + linked_folders = folders_result.scalars().all() + + folders_export = [] + files_to_include = [] # (archive_path, zip_path) + + for folder in linked_folders: + # Get files in this folder + files_result = await db.execute( + select(LibraryFile).where(LibraryFile.folder_id == folder.id).order_by(LibraryFile.filename) + ) + files = files_result.scalars().all() + + folder_files = [] + for f in files: + folder_files.append( + { + "filename": f.filename, + "file_type": f.file_type, + "notes": f.notes, + } + ) + # Add file to include in ZIP + library_dir = get_library_dir() + file_path = library_dir / f.file_path + if file_path.exists(): + zip_path = f"files/{folder.name}/{f.filename}" + files_to_include.append((file_path, zip_path)) + # Also include thumbnail if exists + if f.thumbnail_path: + thumb_path = library_dir / f.thumbnail_path + if thumb_path.exists(): + thumb_zip_path = f"files/{folder.name}/.thumbnails/{f.filename}.png" + files_to_include.append((thumb_path, thumb_zip_path)) + + folders_export.append( + { + "name": folder.name, + "files": folder_files, + } + ) + + # Build project JSON + project_data = { + "name": project.name, + "description": project.description, + "color": project.color, + "status": project.status, + "target_count": project.target_count, + "target_parts_count": project.target_parts_count, + "notes": project.notes, + "tags": project.tags, + "due_date": project.due_date.isoformat() if project.due_date else None, + "priority": project.priority, + "budget": project.budget, + "bom_items": bom_export, + "linked_folders": folders_export, + } + + # Return JSON if requested (for bulk export) + if format == "json": + return project_data + + # Create ZIP in memory + zip_buffer = io.BytesIO() + with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zf: + # Add project.json + zf.writestr("project.json", json.dumps(project_data, indent=2)) + + # Add files + for file_path, zip_path in files_to_include: + zf.write(file_path, zip_path) + + zip_buffer.seek(0) + + # Generate filename + safe_name = "".join(c if c.isalnum() or c in "-_ " else "_" for c in project.name) + filename = f"{safe_name}_{datetime.now().strftime('%Y-%m-%d')}.zip" + + return StreamingResponse( + zip_buffer, + media_type="application/zip", + headers={"Content-Disposition": f'attachment; filename="{filename}"'}, + ) + + +@router.post("/import", response_model=ProjectResponse) +async def import_project( + data: ProjectImport, + db: AsyncSession = Depends(get_db), +): + """Import a project with optional BOM items and linked folders.""" + # Create the project + project = Project( + name=data.name, + description=data.description, + color=data.color, + status=data.status, + target_count=data.target_count, + target_parts_count=data.target_parts_count, + notes=data.notes, + tags=data.tags, + due_date=data.due_date, + priority=data.priority, + budget=data.budget, + ) + db.add(project) + await db.flush() + + # Create BOM items + for idx, bom_data in enumerate(data.bom_items): + bom_item = ProjectBOMItem( + project_id=project.id, + name=bom_data.name, + quantity_needed=bom_data.quantity_needed, + quantity_acquired=bom_data.quantity_acquired, + unit_price=bom_data.unit_price, + sourcing_url=bom_data.sourcing_url, + stl_filename=bom_data.stl_filename, + remarks=bom_data.remarks, + sort_order=idx, + ) + db.add(bom_item) + + # Create linked folders in library + for folder_data in data.linked_folders: + # Check if folder with this name already exists at root level + existing_result = await db.execute( + select(LibraryFolder).where( + LibraryFolder.name == folder_data.name, + LibraryFolder.parent_id.is_(None), + ) + ) + existing_folder = existing_result.scalar_one_or_none() + + if existing_folder: + # Link existing folder to project + existing_folder.project_id = project.id + else: + # Create new folder linked to project + new_folder = LibraryFolder( + name=folder_data.name, + project_id=project.id, + is_external=False, + external_readonly=False, + external_show_hidden=False, + ) + db.add(new_folder) + + await db.flush() + await db.refresh(project) + + stats = await compute_project_stats(db, project.id, project.target_count, project.target_parts_count) + + return ProjectResponse( + id=project.id, + name=project.name, + description=project.description, + color=project.color, + status=project.status, + target_count=project.target_count, + target_parts_count=project.target_parts_count, + notes=project.notes, + attachments=project.attachments, + tags=project.tags, + due_date=project.due_date, + priority=project.priority, + budget=project.budget, + is_template=project.is_template, + template_source_id=project.template_source_id, + parent_id=project.parent_id, + parent_name=None, + children=[], + created_at=project.created_at, + updated_at=project.updated_at, + stats=stats, + ) + + +@router.post("/import/file", response_model=ProjectResponse) +async def import_project_file( + file: UploadFile = File(...), + db: AsyncSession = Depends(get_db), +): + """Import a project from a ZIP or JSON file.""" + if not file.filename: + raise HTTPException(status_code=400, detail="No filename provided") + + # Determine file type + filename_lower = file.filename.lower() + content = await file.read() + + if filename_lower.endswith(".zip"): + # Extract project.json from ZIP + try: + with zipfile.ZipFile(io.BytesIO(content)) as zf: + if "project.json" not in zf.namelist(): + raise HTTPException(status_code=400, detail="ZIP must contain project.json") + project_json = zf.read("project.json") + data = json.loads(project_json) + + # Get list of files in the ZIP + zip_files = {name: zf.read(name) for name in zf.namelist() if name.startswith("files/")} + except zipfile.BadZipFile: + raise HTTPException(status_code=400, detail="Invalid ZIP file") + elif filename_lower.endswith(".json"): + try: + data = json.loads(content) + zip_files = {} + except json.JSONDecodeError: + raise HTTPException(status_code=400, detail="Invalid JSON file") + else: + raise HTTPException(status_code=400, detail="File must be .zip or .json") + + # Create the project + project = Project( + name=data.get("name", "Imported Project"), + description=data.get("description"), + color=data.get("color"), + status=data.get("status", "active"), + target_count=data.get("target_count"), + target_parts_count=data.get("target_parts_count"), + notes=data.get("notes"), + tags=data.get("tags"), + due_date=datetime.fromisoformat(data["due_date"]) if data.get("due_date") else None, + priority=data.get("priority", 0), + budget=data.get("budget"), + ) + db.add(project) + await db.flush() + + # Create BOM items + for idx, bom_data in enumerate(data.get("bom_items", [])): + bom_item = ProjectBOMItem( + project_id=project.id, + name=bom_data.get("name", "Unnamed"), + quantity_needed=bom_data.get("quantity_needed", 1), + quantity_acquired=bom_data.get("quantity_acquired", 0), + unit_price=bom_data.get("unit_price"), + sourcing_url=bom_data.get("sourcing_url"), + stl_filename=bom_data.get("stl_filename"), + remarks=bom_data.get("remarks"), + sort_order=idx, + ) + db.add(bom_item) + + # Create linked folders and files + library_dir = get_library_dir() + for folder_data in data.get("linked_folders", []): + folder_name = folder_data.get("name") + if not folder_name: + continue + + # Check if folder exists + existing_result = await db.execute( + select(LibraryFolder).where( + LibraryFolder.name == folder_name, + LibraryFolder.parent_id.is_(None), + ) + ) + existing_folder = existing_result.scalar_one_or_none() + + if existing_folder: + # Link existing folder to project + existing_folder.project_id = project.id + folder = existing_folder + else: + # Create new folder + folder = LibraryFolder( + name=folder_name, + project_id=project.id, + is_external=False, + external_readonly=False, + external_show_hidden=False, + ) + db.add(folder) + await db.flush() + + # Create folder on disk + folder_path = library_dir / folder_name + folder_path.mkdir(parents=True, exist_ok=True) + + # Import files for this folder from ZIP + folder_prefix = f"files/{folder_name}/" + for zip_path, file_content in zip_files.items(): + if not zip_path.startswith(folder_prefix): + continue + if "/.thumbnails/" in zip_path: + continue # Skip thumbnails, we'll regenerate them + + relative_path = zip_path[len(folder_prefix) :] + if not relative_path: + continue + + # Write file to disk + file_disk_path = library_dir / folder_name / relative_path + file_disk_path.parent.mkdir(parents=True, exist_ok=True) + file_disk_path.write_bytes(file_content) + + # Determine file type + ext = Path(relative_path).suffix.lower() + if ext in [".stl", ".3mf", ".obj"]: + file_type = "model" + elif ext in [".gcode"]: + file_type = "gcode" + elif ext in [".jpg", ".jpeg", ".png", ".gif", ".webp"]: + file_type = "image" + else: + file_type = "other" + + # Create library file record + lib_file = LibraryFile( + folder_id=folder.id, + filename=relative_path, + file_path=f"{folder_name}/{relative_path}", + file_type=file_type, + file_size=len(file_content), + is_external=False, + ) + db.add(lib_file) + + await db.flush() + await db.refresh(project) + + stats = await compute_project_stats(db, project.id, project.target_count, project.target_parts_count) + + return ProjectResponse( + id=project.id, + name=project.name, + description=project.description, + color=project.color, + status=project.status, + target_count=project.target_count, + target_parts_count=project.target_parts_count, + notes=project.notes, + attachments=project.attachments, + tags=project.tags, + due_date=project.due_date, + priority=project.priority, + budget=project.budget, + is_template=project.is_template, + template_source_id=project.template_source_id, + parent_id=project.parent_id, + parent_name=None, + children=[], + created_at=project.created_at, + updated_at=project.updated_at, + stats=stats, + ) diff --git a/backend/app/models/library.py b/backend/app/models/library.py index f138c827c..4e0023638 100644 --- a/backend/app/models/library.py +++ b/backend/app/models/library.py @@ -2,7 +2,7 @@ from datetime import datetime -from sqlalchemy import JSON, DateTime, ForeignKey, Integer, String, Text, func +from sqlalchemy import JSON, Boolean, DateTime, ForeignKey, Integer, String, Text, func from sqlalchemy.orm import Mapped, mapped_column, relationship from backend.app.core.database import Base @@ -17,6 +17,12 @@ class LibraryFolder(Base): name: Mapped[str] = mapped_column(String(255)) parent_id: Mapped[int | None] = mapped_column(ForeignKey("library_folders.id", ondelete="CASCADE"), nullable=True) + # External folder flags (for folders that point to external paths) + is_external: Mapped[bool] = mapped_column(Boolean, default=False) + external_readonly: Mapped[bool] = mapped_column(Boolean, default=False) + external_show_hidden: Mapped[bool] = mapped_column(Boolean, default=False) + external_path: Mapped[str | None] = mapped_column(String(500), nullable=True) + # Link to project or archive project_id: Mapped[int | None] = mapped_column(ForeignKey("projects.id", ondelete="SET NULL"), nullable=True) archive_id: Mapped[int | None] = mapped_column(ForeignKey("print_archives.id", ondelete="SET NULL"), nullable=True) @@ -55,6 +61,9 @@ class LibraryFile(Base): folder_id: Mapped[int | None] = mapped_column(ForeignKey("library_folders.id", ondelete="CASCADE"), nullable=True) project_id: Mapped[int | None] = mapped_column(ForeignKey("projects.id", ondelete="SET NULL"), nullable=True) + # External file flag + is_external: Mapped[bool] = mapped_column(Boolean, default=False) + # File info filename: Mapped[str] = mapped_column(String(255)) # Original filename file_path: Mapped[str] = mapped_column(String(500)) # Storage path diff --git a/backend/app/schemas/project.py b/backend/app/schemas/project.py index 1d3a54d49..74732b6cb 100644 --- a/backend/app/schemas/project.py +++ b/backend/app/schemas/project.py @@ -205,3 +205,58 @@ class TimelineEvent(BaseModel): title: str description: str | None = None metadata: dict | None = None # Additional event-specific data + + +# Phase 10: Import/Export Schemas +class BOMItemExport(BaseModel): + """Schema for exporting a BOM item.""" + + name: str + quantity_needed: int + quantity_acquired: int + unit_price: float | None + sourcing_url: str | None + stl_filename: str | None + remarks: str | None + + +class LinkedFolderExport(BaseModel): + """Schema for exporting a linked library folder.""" + + name: str + + +class ProjectExport(BaseModel): + """Schema for exporting a project.""" + + name: str + description: str | None + color: str | None + status: str + target_count: int | None + target_parts_count: int | None + notes: str | None + tags: str | None + due_date: datetime | None + priority: str + budget: float | None + bom_items: list[BOMItemExport] = [] + linked_folders: list[LinkedFolderExport] = [] + + +class ProjectImport(BaseModel): + """Schema for importing a project.""" + + name: str + description: str | None = None + color: str | None = None + status: str = "active" + target_count: int | None = None + target_parts_count: int | None = None + notes: str | None = None + tags: str | None = None + due_date: datetime | None = None + priority: str = "normal" + budget: float | None = None + bom_items: list[BOMItemExport] = [] + linked_folders: list[LinkedFolderExport] = [] diff --git a/backend/tests/integration/test_projects_api.py b/backend/tests/integration/test_projects_api.py index 1be7178ba..7ff1bc518 100644 --- a/backend/tests/integration/test_projects_api.py +++ b/backend/tests/integration/test_projects_api.py @@ -297,3 +297,330 @@ class TestProjectArchivesAPI: # Project should have an archive count (may be 0) data = response.json() assert "name" in data + + +class TestProjectExportImport: + """Tests for project export/import functionality.""" + + @pytest.fixture + async def project_factory(self, db_session): + """Factory to create test projects.""" + _counter = [0] + + async def _create_project(**kwargs): + from backend.app.models.project import Project + + _counter[0] += 1 + counter = _counter[0] + + defaults = { + "name": f"Export Test Project {counter}", + "description": "Test project for export", + "color": "#00FF00", + } + defaults.update(kwargs) + + project = Project(**defaults) + db_session.add(project) + await db_session.commit() + await db_session.refresh(project) + return project + + return _create_project + + @pytest.fixture + async def bom_item_factory(self, db_session): + """Factory to create test BOM items.""" + + async def _create_bom_item(project_id: int, **kwargs): + from backend.app.models.project_bom import ProjectBOMItem + + defaults = { + "project_id": project_id, + "name": "Test Part", + "quantity_needed": 1, + "quantity_acquired": 0, + "sort_order": 0, + } + defaults.update(kwargs) + + item = ProjectBOMItem(**defaults) + db_session.add(item) + await db_session.commit() + await db_session.refresh(item) + return item + + return _create_bom_item + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_export_project(self, async_client: AsyncClient, project_factory, bom_item_factory, db_session): + """Verify project export includes BOM items.""" + project = await project_factory( + name="Export Me", + description="A test project", + target_count=10, + target_parts_count=50, + budget=100.0, + ) + + # Add BOM items + await bom_item_factory(project.id, name="M3x8 Screws", quantity_needed=20, unit_price=0.10) + await bom_item_factory(project.id, name="Heat Inserts", quantity_needed=10, unit_price=0.25) + + # Test JSON format export + response = await async_client.get(f"/api/v1/projects/{project.id}/export?format=json") + assert response.status_code == 200 + + data = response.json() + assert data["name"] == "Export Me" + assert data["description"] == "A test project" + assert data["target_count"] == 10 + assert data["target_parts_count"] == 50 + assert data["budget"] == 100.0 + assert len(data["bom_items"]) == 2 + + # Check BOM items + bom_names = [item["name"] for item in data["bom_items"]] + assert "M3x8 Screws" in bom_names + assert "Heat Inserts" in bom_names + + # Test ZIP format export (default) + zip_response = await async_client.get(f"/api/v1/projects/{project.id}/export") + assert zip_response.status_code == 200 + assert zip_response.headers["content-type"] == "application/zip" + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_project(self, async_client: AsyncClient): + """Verify project can be imported with BOM items.""" + import_data = { + "name": "Imported Project", + "description": "Imported from JSON", + "color": "#FF00FF", + "target_count": 5, + "target_parts_count": 25, + "budget": 50.0, + "bom_items": [ + { + "name": "PTFE Tubes", + "quantity_needed": 4, + "quantity_acquired": 0, + "unit_price": 2.50, + "sourcing_url": "https://example.com", + "stl_filename": None, + "remarks": "Need 4mm ID", + }, + ], + } + + response = await async_client.post("/api/v1/projects/import", json=import_data) + assert response.status_code == 200 + + data = response.json() + assert data["name"] == "Imported Project" + assert data["description"] == "Imported from JSON" + assert data["target_count"] == 5 + assert data["target_parts_count"] == 25 + assert data["budget"] == 50.0 + assert data["id"] > 0 # Has a valid ID + # BOM stats should show 1 item imported + assert data["stats"]["bom_total_items"] == 1 + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_export_project_with_linked_folder(self, async_client: AsyncClient, project_factory, db_session): + """Verify project export includes linked folders.""" + from backend.app.models.library import LibraryFolder + + project = await project_factory(name="Project With Folder") + + # Create a linked folder + folder = LibraryFolder(name="Project Files", project_id=project.id) + db_session.add(folder) + await db_session.commit() + + response = await async_client.get(f"/api/v1/projects/{project.id}/export?format=json") + assert response.status_code == 200 + + data = response.json() + assert data["name"] == "Project With Folder" + assert len(data["linked_folders"]) == 1 + assert data["linked_folders"][0]["name"] == "Project Files" + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_project_with_linked_folder(self, async_client: AsyncClient): + """Verify project import accepts linked folders data.""" + import_data = { + "name": "Imported With Folders", + "linked_folders": [ + {"name": "STL Files"}, + {"name": "Documentation"}, + ], + } + + # Import should succeed with linked_folders + response = await async_client.post("/api/v1/projects/import", json=import_data) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "Imported With Folders" + assert data["id"] > 0 + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_project_from_json_file(self, async_client: AsyncClient): + """Verify project can be imported from JSON file upload.""" + import io + import json + + project_data = { + "name": "File Uploaded Project", + "description": "Imported from JSON file", + "color": "#123456", + } + + # Create a file-like object + file_content = json.dumps(project_data).encode() + files = {"file": ("project.json", io.BytesIO(file_content), "application/json")} + + response = await async_client.post("/api/v1/projects/import/file", files=files) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "File Uploaded Project" + assert data["description"] == "Imported from JSON file" + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_project_from_zip_file(self, async_client: AsyncClient): + """Verify project can be imported from ZIP file with files.""" + import io + import json + import zipfile + + project_data = { + "name": "ZIP Imported Project", + "description": "Imported from ZIP", + "linked_folders": [{"name": "TestFolder", "files": [{"filename": "test.txt"}]}], + } + + # Create a ZIP file in memory + zip_buffer = io.BytesIO() + with zipfile.ZipFile(zip_buffer, "w", zipfile.ZIP_DEFLATED) as zf: + zf.writestr("project.json", json.dumps(project_data)) + zf.writestr("files/TestFolder/test.txt", "Hello World") + + zip_buffer.seek(0) + files = {"file": ("project.zip", zip_buffer, "application/zip")} + + response = await async_client.post("/api/v1/projects/import/file", files=files) + assert response.status_code == 200 + data = response.json() + assert data["name"] == "ZIP Imported Project" + assert data["description"] == "Imported from ZIP" + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_export_zip_contains_files(self, async_client: AsyncClient, project_factory, db_session): + """Verify ZIP export contains actual files from linked folders.""" + import io + import json + import zipfile + from pathlib import Path + + from backend.app.api.routes.library import get_library_dir + from backend.app.models.library import LibraryFile, LibraryFolder + + project = await project_factory(name="Project With Files") + + # Create a linked folder with is_external fields + folder = LibraryFolder( + name="TestExportFolder", + project_id=project.id, + is_external=False, + external_readonly=False, + external_show_hidden=False, + ) + db_session.add(folder) + await db_session.flush() + + # Create a test file on disk + library_dir = get_library_dir() + folder_path = library_dir / "TestExportFolder" + folder_path.mkdir(parents=True, exist_ok=True) + test_file_path = folder_path / "test_export.txt" + test_file_path.write_text("Export test content") + + # Create library file record + lib_file = LibraryFile( + folder_id=folder.id, + filename="test_export.txt", + file_path="TestExportFolder/test_export.txt", + file_type="other", + file_size=19, + is_external=False, + ) + db_session.add(lib_file) + await db_session.commit() + + # Export as ZIP + response = await async_client.get(f"/api/v1/projects/{project.id}/export") + assert response.status_code == 200 + assert response.headers["content-type"] == "application/zip" + + # Verify ZIP contents + zip_buffer = io.BytesIO(response.content) + with zipfile.ZipFile(zip_buffer, "r") as zf: + assert "project.json" in zf.namelist() + assert "files/TestExportFolder/test_export.txt" in zf.namelist() + + # Verify file content + file_content = zf.read("files/TestExportFolder/test_export.txt").decode() + assert file_content == "Export test content" + + # Verify project.json + project_data = json.loads(zf.read("project.json")) + assert project_data["name"] == "Project With Files" + + # Cleanup + test_file_path.unlink(missing_ok=True) + folder_path.rmdir() + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_invalid_file_type(self, async_client: AsyncClient): + """Verify import rejects invalid file types.""" + import io + + files = {"file": ("project.txt", io.BytesIO(b"invalid"), "text/plain")} + response = await async_client.post("/api/v1/projects/import/file", files=files) + assert response.status_code == 400 + assert "must be .zip or .json" in response.json()["detail"] + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_zip_missing_project_json(self, async_client: AsyncClient): + """Verify import rejects ZIP without project.json.""" + import io + import zipfile + + zip_buffer = io.BytesIO() + with zipfile.ZipFile(zip_buffer, "w") as zf: + zf.writestr("other.txt", "no project.json here") + + zip_buffer.seek(0) + files = {"file": ("project.zip", zip_buffer, "application/zip")} + response = await async_client.post("/api/v1/projects/import/file", files=files) + assert response.status_code == 400 + assert "project.json" in response.json()["detail"] + + @pytest.mark.asyncio + @pytest.mark.integration + async def test_import_invalid_json(self, async_client: AsyncClient): + """Verify import rejects invalid JSON content.""" + import io + + files = {"file": ("project.json", io.BytesIO(b"not valid json"), "application/json")} + response = await async_client.post("/api/v1/projects/import/file", files=files) + assert response.status_code == 400 + assert "Invalid JSON" in response.json()["detail"] diff --git a/frontend/src/api/client.ts b/frontend/src/api/client.ts index 0c7f2a63e..99a788887 100644 --- a/frontend/src/api/client.ts +++ b/frontend/src/api/client.ts @@ -530,6 +530,53 @@ export interface BOMItemUpdate { remarks?: string; } +// Project Export/Import Types +export interface BOMItemExport { + name: string; + quantity_needed: number; + quantity_acquired: number; + unit_price: number | null; + sourcing_url: string | null; + stl_filename: string | null; + remarks: string | null; +} + +export interface LinkedFolderExport { + name: string; +} + +export interface ProjectExport { + name: string; + description: string | null; + color: string | null; + status: string; + target_count: number | null; + target_parts_count: number | null; + notes: string | null; + tags: string | null; + due_date: string | null; + priority: string; + budget: number | null; + bom_items: BOMItemExport[]; + linked_folders: LinkedFolderExport[]; +} + +export interface ProjectImport { + name: string; + description?: string; + color?: string; + status?: string; + target_count?: number; + target_parts_count?: number; + notes?: string; + tags?: string; + due_date?: string; + priority?: string; + budget?: number; + bom_items?: BOMItemExport[]; + linked_folders?: LinkedFolderExport[]; +} + // Timeline Types export interface TimelineEvent { event_type: string; @@ -2683,6 +2730,15 @@ export const api = { getProjectTimeline: (projectId: number, limit = 50) => request(`/projects/${projectId}/timeline?limit=${limit}`), + // Project Export/Import + exportProjectJson: (projectId: number) => + request(`/projects/${projectId}/export?format=json`), + importProject: (data: ProjectImport) => + request('/projects/import', { + method: 'POST', + body: JSON.stringify(data), + }), + // API Keys getAPIKeys: () => request('/api-keys/'), createAPIKey: (data: APIKeyCreate) => diff --git a/frontend/src/pages/ProjectDetailPage.tsx b/frontend/src/pages/ProjectDetailPage.tsx index 7bec16493..e9f8cc072 100644 --- a/frontend/src/pages/ProjectDetailPage.tsx +++ b/frontend/src/pages/ProjectDetailPage.tsx @@ -27,10 +27,12 @@ import { ExternalLink, ShoppingCart, FolderOpen, + Download, + Pencil, } from 'lucide-react'; import { api } from '../api/client'; import { parseUTCDate, formatDateOnly, formatDateTime, type TimeFormat } from '../utils/date'; -import type { Archive, ProjectUpdate, BOMItem, BOMItemCreate } from '../api/client'; +import type { Archive, ProjectUpdate, BOMItem, BOMItemCreate, BOMItemUpdate } from '../api/client'; import { Card, CardContent } from '../components/Card'; import { Button } from '../components/Button'; import { useToast } from '../contexts/ToastContext'; @@ -276,6 +278,12 @@ export function ProjectDetailPage() { const [newBomRemarks, setNewBomRemarks] = useState(''); const [showBomForm, setShowBomForm] = useState(false); const [hideBomCompleted, setHideBomCompleted] = useState(false); + const [editingBomItem, setEditingBomItem] = useState(null); + const [editBomName, setEditBomName] = useState(''); + const [editBomQty, setEditBomQty] = useState(1); + const [editBomPrice, setEditBomPrice] = useState(''); + const [editBomUrl, setEditBomUrl] = useState(''); + const [editBomRemarks, setEditBomRemarks] = useState(''); // Confirm modal state const [confirmModal, setConfirmModal] = useState<{ @@ -302,11 +310,12 @@ export function ProjectDetailPage() { }); const updateBomMutation = useMutation({ - mutationFn: ({ itemId, data }: { itemId: number; data: { quantity_acquired?: number } }) => + mutationFn: ({ itemId, data }: { itemId: number; data: BOMItemUpdate }) => api.updateBOMItem(projectId, itemId, data), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['project-bom', projectId] }); queryClient.invalidateQueries({ queryKey: ['project', projectId] }); + setEditingBomItem(null); }, onError: (error: Error) => showToast(error.message, 'error'), }); @@ -353,6 +362,57 @@ export function ProjectDetailPage() { }); }; + const handleEditBomItem = (item: BOMItem) => { + setEditingBomItem(item); + setEditBomName(item.name); + setEditBomQty(item.quantity_needed); + setEditBomPrice(item.unit_price?.toString() || ''); + setEditBomUrl(item.sourcing_url || ''); + setEditBomRemarks(item.remarks || ''); + }; + + const handleSaveBomEdit = (e: React.FormEvent) => { + e.preventDefault(); + if (!editingBomItem || !editBomName.trim()) return; + updateBomMutation.mutate({ + itemId: editingBomItem.id, + data: { + name: editBomName.trim(), + quantity_needed: editBomQty, + unit_price: editBomPrice ? parseFloat(editBomPrice) : undefined, + sourcing_url: editBomUrl.trim() || undefined, + remarks: editBomRemarks.trim() || undefined, + }, + }); + }; + + const handleCancelBomEdit = () => { + setEditingBomItem(null); + }; + + const handleExportProject = async () => { + try { + // Fetch ZIP file directly + const response = await fetch(`/api/v1/projects/${projectId}/export`); + if (!response.ok) { + throw new Error('Export failed'); + } + const blob = await response.blob(); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + // Get filename from Content-Disposition header or use default + const contentDisposition = response.headers.get('Content-Disposition'); + const filenameMatch = contentDisposition?.match(/filename="(.+)"/); + a.download = filenameMatch?.[1] || `${project?.name || 'project'}_${new Date().toISOString().split('T')[0]}.zip`; + a.click(); + URL.revokeObjectURL(url); + showToast('Project exported', 'success'); + } catch (error) { + showToast((error as Error).message, 'error'); + } + }; + // Template handlers const createTemplateMutation = useMutation({ mutationFn: () => api.createTemplateFromProject(projectId), @@ -433,10 +493,16 @@ export function ProjectDetailPage() { - +
+ + +
{/* Progress bars (if targets set) */} @@ -903,70 +969,140 @@ export function ProjectDetailPage() { item.is_complete ? 'bg-status-ok/10' : 'bg-bambu-dark' }`} > -
- -
-
-
-

- {item.name} - - x{item.quantity_needed} - -

- {item.unit_price !== null && ( - - {currency}{(item.unit_price * item.quantity_needed).toFixed(2)} - - )} + {editingBomItem?.id === item.id ? ( + // Edit form for this BOM item +
+
+ setEditBomName(e.target.value)} + className="bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded px-3 py-2 text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green" + placeholder="Part name" + autoFocus + /> +
+ setEditBomQty(parseInt(e.target.value) || 1)} + className="w-20 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded px-3 py-2 text-sm text-white focus:outline-none focus:border-bambu-green" + min="1" + placeholder="Qty" + /> + setEditBomPrice(e.target.value)} + className="flex-1 bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded px-3 py-2 text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green" + placeholder={`Price (${currency})`} + />
-
- {/* Sourcing URL */} - {item.sourcing_url && ( - e.stopPropagation()} - > - - - {(() => { - try { - return new URL(item.sourcing_url).hostname.replace('www.', ''); - } catch { - return item.sourcing_url; - } - })()} - - - )} - {/* Remarks */} - {item.remarks && ( -

- {item.remarks} -

- )} + setEditBomUrl(e.target.value)} + className="w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded px-3 py-2 text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green" + placeholder="Sourcing URL (optional)" + /> + setEditBomRemarks(e.target.value)} + className="w-full bg-bambu-dark-secondary border border-bambu-dark-tertiary rounded px-3 py-2 text-sm text-white placeholder-bambu-gray focus:outline-none focus:border-bambu-green" + placeholder="Remarks (optional)" + /> +
+ + +
+
+ ) : ( + // Display mode +
+ +
+
+
+

+ {item.name} + + x{item.quantity_needed} + +

+ {item.unit_price !== null && ( + + {currency}{(item.unit_price * item.quantity_needed).toFixed(2)} + + )} +
+
+ + +
+
+ {/* Sourcing URL */} + {item.sourcing_url && ( + e.stopPropagation()} + > + + + {(() => { + try { + return new URL(item.sourcing_url).hostname.replace('www.', ''); + } catch { + return item.sourcing_url; + } + })()} + + + )} + {/* Remarks */} + {item.remarks && ( +

+ {item.remarks} +

+ )} +
-
+ )}
))} {/* BOM Total */} diff --git a/frontend/src/pages/ProjectsPage.tsx b/frontend/src/pages/ProjectsPage.tsx index c8b1c937b..f3c810100 100644 --- a/frontend/src/pages/ProjectsPage.tsx +++ b/frontend/src/pages/ProjectsPage.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import { useNavigate } from 'react-router-dom'; import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; import { @@ -16,9 +16,11 @@ import { AlertTriangle, ChevronRight, MoreVertical, + Download, + Upload, } from 'lucide-react'; import { api } from '../api/client'; -import type { ProjectListItem, ProjectCreate, ProjectUpdate } from '../api/client'; +import type { ProjectListItem, ProjectCreate, ProjectUpdate, ProjectImport } from '../api/client'; import { Button } from '../components/Button'; import { ConfirmModal } from '../components/ConfirmModal'; import { useToast } from '../contexts/ToastContext'; @@ -613,6 +615,94 @@ export function ProjectsPage() { }, }); + const importMutation = useMutation({ + mutationFn: (data: ProjectImport) => api.importProject(data), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['projects'] }); + showToast('Project imported', 'success'); + }, + onError: (error: Error) => { + showToast(error.message, 'error'); + }, + }); + + const fileInputRef = useRef(null); + + const handleExportAll = async () => { + try { + // Export all projects as JSON (metadata only, no files) + const allProjects = await api.getProjects(); + const exports = await Promise.all( + allProjects.map(async (p) => { + const exported = await api.exportProjectJson(p.id); + return exported; + }) + ); + const blob = new Blob([JSON.stringify(exports, null, 2)], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `bambuddy_projects_${new Date().toISOString().split('T')[0]}.json`; + a.click(); + URL.revokeObjectURL(url); + showToast('Projects exported (metadata only)', 'success'); + } catch (error) { + showToast((error as Error).message, 'error'); + } + }; + + const handleImportClick = () => { + fileInputRef.current?.click(); + }; + + const handleFileChange = async (e: React.ChangeEvent) => { + const file = e.target.files?.[0]; + if (!file) return; + + try { + const filename = file.name.toLowerCase(); + + if (filename.endsWith('.zip')) { + // ZIP file: upload via file endpoint + const formData = new FormData(); + formData.append('file', file); + + const response = await fetch('/api/v1/projects/import/file', { + method: 'POST', + body: formData, + }); + + if (!response.ok) { + const errorData = await response.json(); + throw new Error(errorData.detail || 'Import failed'); + } + + queryClient.invalidateQueries({ queryKey: ['projects'] }); + showToast('Project imported', 'success'); + } else { + // JSON file: parse and handle bulk or single import + const text = await file.text(); + const data = JSON.parse(text); + + // Handle both single project and array of projects + const projectsToImport = Array.isArray(data) ? data : [data]; + + for (const project of projectsToImport) { + await importMutation.mutateAsync(project); + } + + if (projectsToImport.length > 1) { + showToast(`${projectsToImport.length} projects imported`, 'success'); + } + } + } catch (error) { + showToast(`Import failed: ${(error as Error).message}`, 'error'); + } + + // Reset file input + e.target.value = ''; + }; + const handleSave = (data: ProjectCreate | ProjectUpdate) => { if (editingProject) { updateMutation.mutate({ id: editingProject.id, data }); @@ -650,6 +740,15 @@ export function ProjectsPage() { return (
+ {/* Hidden file input for import */} + + {/* Header */}
@@ -663,10 +762,20 @@ export function ProjectsPage() { Organize and track your 3D printing projects

- +
+ + + +
{/* Filter tabs */} diff --git a/static/assets/index-BQzscOA-.js b/static/assets/index-CTmc90ua.js similarity index 56% rename from static/assets/index-BQzscOA-.js rename to static/assets/index-CTmc90ua.js index ac3169ec1..671e50d68 100644 --- a/static/assets/index-BQzscOA-.js +++ b/static/assets/index-CTmc90ua.js @@ -1,20 +1,20 @@ -function wae(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 Gv=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 gT={exports:{}},Bx={};var mU;function Sae(){if(mU)return Bx;mU=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 Bx.Fragment=e,Bx.jsx=n,Bx.jsxs=n,Bx}var pU;function Mae(){return pU||(pU=1,gT.exports=Sae()),gT.exports}var s=Mae(),xT={exports:{}},hn={};var gU;function Nae(){if(gU)return hn;gU=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(z){return z===null||typeof z!="object"?null:(z=m&&z[m]||z["@@iterator"],typeof z=="function"?z:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},y=Object.assign,b={};function v(z,G,ee){this.props=z,this.context=G,this.refs=b,this.updater=ee||x}v.prototype.isReactComponent={},v.prototype.setState=function(z,G){if(typeof z!="object"&&typeof z!="function"&&z!=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,z,G,"setState")},v.prototype.forceUpdate=function(z){this.updater.enqueueForceUpdate(this,z,"forceUpdate")};function M(){}M.prototype=v.prototype;function S(z,G,ee){this.props=z,this.context=G,this.refs=b,this.updater=ee||x}var T=S.prototype=new M;T.constructor=S,y(T,v.prototype),T.isPureReactComponent=!0;var E=Array.isArray;function k(){}var A={H:null,A:null,T:null,S:null},D=Object.prototype.hasOwnProperty;function C(z,G,ee){var ie=ee.ref;return{$$typeof:t,type:z,key:G,ref:ie!==void 0?ie:null,props:ee}}function P(z,G){return C(z.type,G,z.props)}function F(z){return typeof z=="object"&&z!==null&&z.$$typeof===t}function L(z){var G={"=":"=0",":":"=2"};return"$"+z.replace(/[=:]/g,function(ee){return G[ee]})}var X=/\/+/g;function R(z,G){return typeof z=="object"&&z!==null&&z.key!=null?L(""+z.key):G.toString(36)}function W(z){switch(z.status){case"fulfilled":return z.value;case"rejected":throw z.reason;default:switch(typeof z.status=="string"?z.then(k,k):(z.status="pending",z.then(function(G){z.status==="pending"&&(z.status="fulfilled",z.value=G)},function(G){z.status==="pending"&&(z.status="rejected",z.reason=G)})),z.status){case"fulfilled":return z.value;case"rejected":throw z.reason}}throw z}function Y(z,G,ee,ie,he){var fe=typeof z;(fe==="undefined"||fe==="boolean")&&(z=null);var ue=!1;if(z===null)ue=!0;else switch(fe){case"bigint":case"string":case"number":ue=!0;break;case"object":switch(z.$$typeof){case t:case e:ue=!0;break;case d:return ue=z._init,Y(ue(z._payload),G,ee,ie,he)}}if(ue)return he=he(z),ue=ie===""?"."+R(z,0):ie,E(he)?(ee="",ue!=null&&(ee=ue.replace(X,"$&/")+"/"),Y(he,G,ee,"",function(_e){return _e})):he!=null&&(F(he)&&(he=P(he,ee+(he.key==null||z&&z.key===he.key?"":(""+he.key).replace(X,"$&/")+"/")+ue)),G.push(he)),1;ue=0;var Se=ie===""?".":ie+":";if(E(z))for(var me=0;me>>1,ae=Y[ne];if(0>>1;nei(ee,J))iei(he,ee)?(Y[ne]=he,Y[ie]=J,ne=ie):(Y[ne]=ee,Y[G]=J,ne=G);else if(iei(he,J))Y[ne]=he,Y[ie]=J,ne=ie;else break e}}return q}function i(Y,q){var J=Y.sortIndex-q.sortIndex;return J!==0?J: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,x=!1,y=!1,b=!1,v=typeof setTimeout=="function"?setTimeout:null,M=typeof clearTimeout=="function"?clearTimeout:null,S=typeof setImmediate<"u"?setImmediate:null;function T(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 E(Y){if(y=!1,T(Y),!x)if(n(c)!==null)x=!0,k||(k=!0,L());else{var q=n(u);q!==null&&W(E,q.startTime-Y)}}var k=!1,A=-1,D=5,C=-1;function P(){return b?!0:!(t.unstable_now()-CY&&P());){var ne=f.callback;if(typeof ne=="function"){f.callback=null,m=f.priorityLevel;var ae=ne(f.expirationTime<=Y);if(Y=t.unstable_now(),typeof ae=="function"){f.callback=ae,T(Y),q=!0;break t}f===n(c)&&r(c),T(Y)}else r(c);f=n(c)}if(f!==null)q=!0;else{var z=n(u);z!==null&&W(E,z.startTime-Y),q=!1}}break e}finally{f=null,m=J,g=!1}q=void 0}}finally{q?L():k=!1}}}var L;if(typeof S=="function")L=function(){S(F)};else if(typeof MessageChannel<"u"){var X=new MessageChannel,R=X.port2;X.port1.onmessage=F,L=function(){R.postMessage(null)}}else L=function(){v(F,0)};function W(Y,q){A=v(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||125ne?(Y.sortIndex=J,e(u,Y),n(c)===null&&Y===n(u)&&(y?(M(A),A=-1):y=!0,W(E,J-ne))):(Y.sortIndex=ae,e(c,Y),x||g||(x=!0,k||(k=!0,L()))),Y},t.unstable_shouldYield=P,t.unstable_wrapCallback=function(Y){var q=m;return function(){var J=m;m=q;try{return Y.apply(this,arguments)}finally{m=J}}}})(vT)),vT}var yU;function Aae(){return yU||(yU=1,yT.exports=Tae()),yT.exports}var _T={exports:{}},_a={};var vU;function Cae(){if(vU)return _a;vU=1;var t=Tg();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(),_T.exports=Cae(),_T.exports}var wU;function kae(){if(wU)return $x;wU=1;var t=Aae(),e=Tg(),n=QG();function r(h){var p="https://react.dev/errors/"+h;if(1ae||(h.current=ne[ae],ne[ae]=null,ae--)}function ee(h,p){ae++,ne[ae]=h.current,h.current=p}var ie=z(null),he=z(null),fe=z(null),ue=z(null);function Se(h,p){switch(ee(fe,p),ee(he,h),ee(ie,null),p.nodeType){case 9:case 11:h=(h=p.documentElement)&&(h=h.namespaceURI)?IF(h):0;break;default:if(h=p.tagName,p=p.namespaceURI)p=IF(p),h=FF(p,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}G(ie),ee(ie,h)}function me(){G(ie),G(he),G(fe)}function _e(h){h.memoizedState!==null&&ee(ue,h);var p=ie.current,_=FF(p,h.type);p!==_&&(ee(he,h),ee(ie,_))}function je(h){he.current===h&&(G(ie),G(he)),ue.current===h&&(G(ue),Ix._currentValue=J)}var re,Qe;function B(h){if(re===void 0)try{throw Error()}catch(_){var p=_.stack.trim().match(/\n( *(at )?)/);re=p&&p[1]||"",Qe=-1<_.stack.indexOf(` +function wae(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 Gv=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 gT={exports:{}},Bx={};var mU;function Sae(){if(mU)return Bx;mU=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 Bx.Fragment=e,Bx.jsx=n,Bx.jsxs=n,Bx}var pU;function Mae(){return pU||(pU=1,gT.exports=Sae()),gT.exports}var s=Mae(),xT={exports:{}},hn={};var gU;function Nae(){if(gU)return hn;gU=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(z){return z===null||typeof z!="object"?null:(z=m&&z[m]||z["@@iterator"],typeof z=="function"?z:null)}var x={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},y=Object.assign,b={};function v(z,G,J){this.props=z,this.context=G,this.refs=b,this.updater=J||x}v.prototype.isReactComponent={},v.prototype.setState=function(z,G){if(typeof z!="object"&&typeof z!="function"&&z!=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,z,G,"setState")},v.prototype.forceUpdate=function(z){this.updater.enqueueForceUpdate(this,z,"forceUpdate")};function M(){}M.prototype=v.prototype;function S(z,G,J){this.props=z,this.context=G,this.refs=b,this.updater=J||x}var T=S.prototype=new M;T.constructor=S,y(T,v.prototype),T.isPureReactComponent=!0;var E=Array.isArray;function k(){}var A={H:null,A:null,T:null,S:null},D=Object.prototype.hasOwnProperty;function C(z,G,J){var re=J.ref;return{$$typeof:t,type:z,key:G,ref:re!==void 0?re:null,props:J}}function R(z,G){return C(z.type,G,z.props)}function F(z){return typeof z=="object"&&z!==null&&z.$$typeof===t}function O(z){var G={"=":"=0",":":"=2"};return"$"+z.replace(/[=:]/g,function(J){return G[J]})}var K=/\/+/g;function P(z,G){return typeof z=="object"&&z!==null&&z.key!=null?O(""+z.key):G.toString(36)}function W(z){switch(z.status){case"fulfilled":return z.value;case"rejected":throw z.reason;default:switch(typeof z.status=="string"?z.then(k,k):(z.status="pending",z.then(function(G){z.status==="pending"&&(z.status="fulfilled",z.value=G)},function(G){z.status==="pending"&&(z.status="rejected",z.reason=G)})),z.status){case"fulfilled":return z.value;case"rejected":throw z.reason}}throw z}function X(z,G,J,re,he){var fe=typeof z;(fe==="undefined"||fe==="boolean")&&(z=null);var ue=!1;if(z===null)ue=!0;else switch(fe){case"bigint":case"string":case"number":ue=!0;break;case"object":switch(z.$$typeof){case t:case e:ue=!0;break;case d:return ue=z._init,X(ue(z._payload),G,J,re,he)}}if(ue)return he=he(z),ue=re===""?"."+P(z,0):re,E(he)?(J="",ue!=null&&(J=ue.replace(K,"$&/")+"/"),X(he,G,J,"",function(we){return we})):he!=null&&(F(he)&&(he=R(he,J+(he.key==null||z&&z.key===he.key?"":(""+he.key).replace(K,"$&/")+"/")+ue)),G.push(he)),1;ue=0;var Ne=re===""?".":re+":";if(E(z))for(var me=0;me>>1,ie=X[ne];if(0>>1;nei(J,Z))rei(he,J)?(X[ne]=he,X[re]=Z,ne=re):(X[ne]=J,X[G]=Z,ne=G);else if(rei(he,Z))X[ne]=he,X[re]=Z,ne=re;else break e}}return q}function i(X,q){var Z=X.sortIndex-q.sortIndex;return Z!==0?Z:X.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,x=!1,y=!1,b=!1,v=typeof setTimeout=="function"?setTimeout:null,M=typeof clearTimeout=="function"?clearTimeout:null,S=typeof setImmediate<"u"?setImmediate:null;function T(X){for(var q=n(u);q!==null;){if(q.callback===null)r(u);else if(q.startTime<=X)r(u),q.sortIndex=q.expirationTime,e(c,q);else break;q=n(u)}}function E(X){if(y=!1,T(X),!x)if(n(c)!==null)x=!0,k||(k=!0,O());else{var q=n(u);q!==null&&W(E,q.startTime-X)}}var k=!1,A=-1,D=5,C=-1;function R(){return b?!0:!(t.unstable_now()-CX&&R());){var ne=f.callback;if(typeof ne=="function"){f.callback=null,m=f.priorityLevel;var ie=ne(f.expirationTime<=X);if(X=t.unstable_now(),typeof ie=="function"){f.callback=ie,T(X),q=!0;break t}f===n(c)&&r(c),T(X)}else r(c);f=n(c)}if(f!==null)q=!0;else{var z=n(u);z!==null&&W(E,z.startTime-X),q=!1}}break e}finally{f=null,m=Z,g=!1}q=void 0}}finally{q?O():k=!1}}}var O;if(typeof S=="function")O=function(){S(F)};else if(typeof MessageChannel<"u"){var K=new MessageChannel,P=K.port2;K.port1.onmessage=F,O=function(){P.postMessage(null)}}else O=function(){v(F,0)};function W(X,q){A=v(function(){X(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(X){X.callback=null},t.unstable_forceFrameRate=function(X){0>X||125ne?(X.sortIndex=Z,e(u,X),n(c)===null&&X===n(u)&&(y?(M(A),A=-1):y=!0,W(E,Z-ne))):(X.sortIndex=ie,e(c,X),x||g||(x=!0,k||(k=!0,O()))),X},t.unstable_shouldYield=R,t.unstable_wrapCallback=function(X){var q=m;return function(){var Z=m;m=q;try{return X.apply(this,arguments)}finally{m=Z}}}})(vT)),vT}var yU;function Aae(){return yU||(yU=1,yT.exports=Tae()),yT.exports}var _T={exports:{}},_a={};var vU;function Cae(){if(vU)return _a;vU=1;var t=Tg();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(),_T.exports=Cae(),_T.exports}var wU;function kae(){if(wU)return $x;wU=1;var t=Aae(),e=Tg(),n=QG();function r(h){var p="https://react.dev/errors/"+h;if(1ie||(h.current=ne[ie],ne[ie]=null,ie--)}function J(h,p){ie++,ne[ie]=h.current,h.current=p}var re=z(null),he=z(null),fe=z(null),ue=z(null);function Ne(h,p){switch(J(fe,p),J(he,h),J(re,null),p.nodeType){case 9:case 11:h=(h=p.documentElement)&&(h=h.namespaceURI)?IF(h):0;break;default:if(h=p.tagName,p=p.namespaceURI)p=IF(p),h=FF(p,h);else switch(h){case"svg":h=1;break;case"math":h=2;break;default:h=0}}G(re),J(re,h)}function me(){G(re),G(he),G(fe)}function we(h){h.memoizedState!==null&&J(ue,h);var p=re.current,_=FF(p,h.type);p!==_&&(J(he,h),J(re,_))}function Pe(h){he.current===h&&(G(re),G(he)),ue.current===h&&(G(ue),Ix._currentValue=Z)}var te,Ze;function B(h){if(te===void 0)try{throw Error()}catch(_){var p=_.stack.trim().match(/\n( *(at )?)/);te=p&&p[1]||"",Ze=-1<_.stack.indexOf(` at`)?" ()":-1<_.stack.indexOf("@")?"@unknown:0:0":""}return` -`+re+h+Qe}var H=!1;function K(h,p){if(!h||H)return"";H=!0;var _=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var N={DetermineComponentFrameRoot:function(){try{if(p){var yt=function(){throw Error()};if(Object.defineProperty(yt.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(yt,[])}catch(ot){var at=ot}Reflect.construct(h,[],yt)}else{try{yt.call()}catch(ot){at=ot}h.call(yt.prototype)}}else{try{throw Error()}catch(ot){at=ot}(yt=h())&&typeof yt.catch=="function"&&yt.catch(function(){})}}catch(ot){if(ot&&at&&typeof ot.stack=="string")return[ot.stack,at.stack]}return[null,null]}};N.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var j=Object.getOwnPropertyDescriptor(N.DetermineComponentFrameRoot,"name");j&&j.configurable&&Object.defineProperty(N.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var O=N.DetermineComponentFrameRoot(),te=O[0],pe=O[1];if(te&&pe){var Pe=te.split(` -`),rt=pe.split(` -`);for(j=N=0;Nj||Pe[N]!==rt[j]){var mt=` -`+Pe[N].replace(" at new "," at ");return h.displayName&&mt.includes("")&&(mt=mt.replace("",h.displayName)),mt}while(1<=N&&0<=j);break}}}finally{H=!1,Error.prepareStackTrace=_}return(_=h?h.displayName||h.name:"")?B(_):""}function U(h,p){switch(h.tag){case 26:case 27:case 5:return B(h.type);case 16:return B("Lazy");case 13:return h.child!==p&&p!==null?B("Suspense Fallback"):B("Suspense");case 19:return B("SuspenseList");case 0:case 15:return K(h.type,!1);case 11:return K(h.type.render,!1);case 1:return K(h.type,!0);case 31:return B("Activity");default:return""}}function V(h){try{var p="",_=null;do p+=U(h,_),_=h,h=h.return;while(h);return p}catch(N){return` +`+te+h+Ze}var H=!1;function Y(h,p){if(!h||H)return"";H=!0;var _=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var N={DetermineComponentFrameRoot:function(){try{if(p){var yt=function(){throw Error()};if(Object.defineProperty(yt.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(yt,[])}catch(lt){var st=lt}Reflect.construct(h,[],yt)}else{try{yt.call()}catch(lt){st=lt}h.call(yt.prototype)}}else{try{throw Error()}catch(lt){st=lt}(yt=h())&&typeof yt.catch=="function"&&yt.catch(function(){})}}catch(lt){if(lt&&st&&typeof lt.stack=="string")return[lt.stack,st.stack]}return[null,null]}};N.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var j=Object.getOwnPropertyDescriptor(N.DetermineComponentFrameRoot,"name");j&&j.configurable&&Object.defineProperty(N.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var L=N.DetermineComponentFrameRoot(),ee=L[0],ge=L[1];if(ee&&ge){var De=ee.split(` +`),it=ge.split(` +`);for(j=N=0;Nj||De[N]!==it[j]){var mt=` +`+De[N].replace(" at new "," at ");return h.displayName&&mt.includes("")&&(mt=mt.replace("",h.displayName)),mt}while(1<=N&&0<=j);break}}}finally{H=!1,Error.prepareStackTrace=_}return(_=h?h.displayName||h.name:"")?B(_):""}function U(h,p){switch(h.tag){case 26:case 27:case 5:return B(h.type);case 16:return B("Lazy");case 13:return h.child!==p&&p!==null?B("Suspense Fallback"):B("Suspense");case 19:return B("SuspenseList");case 0:case 15:return Y(h.type,!1);case 11:return Y(h.type.render,!1);case 1:return Y(h.type,!0);case 31:return B("Activity");default:return""}}function V(h){try{var p="",_=null;do p+=U(h,_),_=h,h=h.return;while(h);return p}catch(N){return` Error generating stack: `+N.message+` -`+N.stack}}var Q=Object.prototype.hasOwnProperty,Ee=t.unstable_scheduleCallback,ke=t.unstable_cancelCallback,Ne=t.unstable_shouldYield,$=t.unstable_requestPaint,I=t.unstable_now,Z=t.unstable_getCurrentPriorityLevel,xe=t.unstable_ImmediatePriority,ve=t.unstable_UserBlockingPriority,oe=t.unstable_NormalPriority,Ae=t.unstable_LowPriority,De=t.unstable_IdlePriority,Ze=t.log,ut=t.unstable_setDisableYieldValue,Ye=null,le=null;function Ve(h){if(typeof Ze=="function"&&ut(h),le&&typeof le.setStrictMode=="function")try{le.setStrictMode(Ye,h)}catch{}}var $e=Math.clz32?Math.clz32:se,qe=Math.log,it=Math.LN2;function se(h){return h>>>=0,h===0?32:31-(qe(h)/it|0)|0}var He=256,ye=262144,Ie=4194304;function Oe(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 N=h.pendingLanes;if(N===0)return 0;var j=0,O=h.suspendedLanes,te=h.pingedLanes;h=h.warmLanes;var pe=N&134217727;return pe!==0?(N=pe&~O,N!==0?j=Oe(N):(te&=pe,te!==0?j=Oe(te):_||(_=pe&~h,_!==0&&(j=Oe(_))))):(pe=N&~O,pe!==0?j=Oe(pe):te!==0?j=Oe(te):_||(_=N&~h,_!==0&&(j=Oe(_)))),j===0?0:p!==0&&p!==j&&(p&O)===0&&(O=j&-j,_=p&-p,O>=_||O===32&&(_&4194048)!==0)?p:j}function Ke(h,p){return(h.pendingLanes&~(h.suspendedLanes&~h.pingedLanes)&p)===0}function xt(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 jt(){var h=Ie;return Ie<<=1,(Ie&62914560)===0&&(Ie=4194304),h}function gt(h){for(var p=[],_=0;31>_;_++)p.push(h);return p}function Jt(h,p){h.pendingLanes|=p,p!==268435456&&(h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0)}function kt(h,p,_,N,j,O){var te=h.pendingLanes;h.pendingLanes=_,h.suspendedLanes=0,h.pingedLanes=0,h.warmLanes=0,h.expiredLanes&=_,h.entangledLanes&=_,h.errorRecoveryDisabledLanes&=_,h.shellSuspendCounter=0;var pe=h.entanglements,Pe=h.expirationTimes,rt=h.hiddenUpdates;for(_=te&~_;0<_;){var mt=31-$e(_),yt=1<"u")return null;try{return h.activeElement||h.body}catch{return h.body}}var Wn=/[\n"\\]/g;function Nn(h){return h.replace(Wn,function(p){return"\\"+p.charCodeAt(0).toString(16)+" "})}function Fn(h,p,_,N,j,O,te,pe){h.name="",te!=null&&typeof te!="function"&&typeof te!="symbol"&&typeof te!="boolean"?h.type=te:h.removeAttribute("type"),p!=null?te==="number"?(p===0&&h.value===""||h.value!=p)&&(h.value=""+gn(p)):h.value!==""+gn(p)&&(h.value=""+gn(p)):te!=="submit"&&te!=="reset"||h.removeAttribute("value"),p!=null?Ui(h,te,gn(p)):_!=null?Ui(h,te,gn(_)):N!=null&&h.removeAttribute("value"),j==null&&O!=null&&(h.defaultChecked=!!O),j!=null&&(h.checked=j&&typeof j!="function"&&typeof j!="symbol"),pe!=null&&typeof pe!="function"&&typeof pe!="symbol"&&typeof pe!="boolean"?h.name=""+gn(pe):h.removeAttribute("name")}function qn(h,p,_,N,j,O,te,pe){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)){Nt(h);return}_=_!=null?""+gn(_):"",p=p!=null?""+gn(p):_,pe||p===h.value||(h.value=p),h.defaultValue=p}N=N??j,N=typeof N!="function"&&typeof N!="symbol"&&!!N,h.checked=pe?h.checked:!!N,h.defaultChecked=!!N,te!=null&&typeof te!="function"&&typeof te!="symbol"&&typeof te!="boolean"&&(h.name=te),Nt(h)}function Ui(h,p,_){p==="number"&&nn(h.ownerDocument)===h||h.defaultValue===""+_||(h.defaultValue=""+_)}function Si(h,p,_,N){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"),gN=!1;if(Jl)try{var tx={};Object.defineProperty(tx,"passive",{get:function(){gN=!0}}),window.addEventListener("test",tx,tx),window.removeEventListener("test",tx,tx)}catch{gN=!1}var gu=null,xN=null,Iy=null;function FL(){if(Iy)return Iy;var h,p=xN,_=p.length,N,j="value"in gu?gu.value:gu.textContent,O=j.length;for(h=0;h<_&&p[h]===j[h];h++);var te=_-h;for(N=1;N<=te&&p[_-N]===j[O-N];N++);return Iy=j.slice(h,1=ix),VL=" ",GL=!1;function WL(h,p){switch(h){case"keyup":return Vre.indexOf(p.keyCode)!==-1;case"keydown":return p.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function qL(h){return h=h.detail,typeof h=="object"&&"data"in h?h.data:null}var Jf=!1;function Wre(h,p){switch(h){case"compositionend":return qL(p);case"keypress":return p.which!==32?null:(GL=!0,VL);case"textInput":return h=p.data,h===VL&&GL?null:h;default:return null}}function qre(h,p){if(Jf)return h==="compositionend"||!wN&&WL(h,p)?(h=FL(),Iy=xN=gu=null,Jf=!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=N}e:{for(;_;){if(_.nextSibling){_=_.nextSibling;break e}_=_.parentNode}_=void 0}_=tI(_)}}function rI(h,p){return h&&p?h===p?!0:h&&h.nodeType===3?!1:p&&p.nodeType===3?rI(h,p.parentNode):"contains"in h?h.contains(p):h.compareDocumentPosition?!!(h.compareDocumentPosition(p)&16):!1:!1}function iI(h){h=h!=null&&h.ownerDocument!=null&&h.ownerDocument.defaultView!=null?h.ownerDocument.defaultView:window;for(var p=nn(h.document);p instanceof h.HTMLIFrameElement;){try{var _=typeof p.contentWindow.location.href=="string"}catch{_=!1}if(_)h=p.contentWindow;else break;p=nn(h.document)}return p}function NN(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 tie=Jl&&"documentMode"in document&&11>=document.documentMode,em=null,EN=null,lx=null,TN=!1;function aI(h,p,_){var N=_.window===_?_.document:_.nodeType===9?_:_.ownerDocument;TN||em==null||em!==nn(N)||(N=em,"selectionStart"in N&&NN(N)?N={start:N.selectionStart,end:N.selectionEnd}:(N=(N.ownerDocument&&N.ownerDocument.defaultView||window).getSelection(),N={anchorNode:N.anchorNode,anchorOffset:N.anchorOffset,focusNode:N.focusNode,focusOffset:N.focusOffset}),lx&&ox(lx,N)||(lx=N,N=kv(EN,"onSelect"),0>=te,j-=te,fl=1<<32-$e(p)+j|_<pn?(Dn=Wt,Wt=null):Dn=Wt.sibling;var $n=at(Xe,Wt,nt[pn],pt);if($n===null){Wt===null&&(Wt=Dn);break}h&&Wt&&$n.alternate===null&&p(Xe,Wt),Ue=O($n,Ue,pn),Bn===null?Xt=$n:Bn.sibling=$n,Bn=$n,Wt=Dn}if(pn===nt.length)return _(Xe,Wt),Ln&&tc(Xe,pn),Xt;if(Wt===null){for(;pnpn?(Dn=Wt,Wt=null):Dn=Wt.sibling;var Fu=at(Xe,Wt,$n.value,pt);if(Fu===null){Wt===null&&(Wt=Dn);break}h&&Wt&&Fu.alternate===null&&p(Xe,Wt),Ue=O(Fu,Ue,pn),Bn===null?Xt=Fu:Bn.sibling=Fu,Bn=Fu,Wt=Dn}if($n.done)return _(Xe,Wt),Ln&&tc(Xe,pn),Xt;if(Wt===null){for(;!$n.done;pn++,$n=nt.next())$n=yt(Xe,$n.value,pt),$n!==null&&(Ue=O($n,Ue,pn),Bn===null?Xt=$n:Bn.sibling=$n,Bn=$n);return Ln&&tc(Xe,pn),Xt}for(Wt=N(Wt);!$n.done;pn++,$n=nt.next())$n=ot(Wt,Xe,pn,$n.value,pt),$n!==null&&(h&&$n.alternate!==null&&Wt.delete($n.key===null?pn:$n.key),Ue=O($n,Ue,pn),Bn===null?Xt=$n:Bn.sibling=$n,Bn=$n);return h&&Wt.forEach(function(_ae){return p(Xe,_ae)}),Ln&&tc(Xe,pn),Xt}function lr(Xe,Ue,nt,pt){if(typeof nt=="object"&&nt!==null&&nt.type===y&&nt.key===null&&(nt=nt.props.children),typeof nt=="object"&&nt!==null){switch(nt.$$typeof){case g:e:{for(var Xt=nt.key;Ue!==null;){if(Ue.key===Xt){if(Xt=nt.type,Xt===y){if(Ue.tag===7){_(Xe,Ue.sibling),pt=j(Ue,nt.props.children),pt.return=Xe,Xe=pt;break e}}else if(Ue.elementType===Xt||typeof Xt=="object"&&Xt!==null&&Xt.$$typeof===D&&fh(Xt)===Ue.type){_(Xe,Ue.sibling),pt=j(Ue,nt.props),mx(pt,nt),pt.return=Xe,Xe=pt;break e}_(Xe,Ue);break}else p(Xe,Ue);Ue=Ue.sibling}nt.type===y?(pt=lh(nt.props.children,Xe.mode,pt,nt.key),pt.return=Xe,Xe=pt):(pt=qy(nt.type,nt.key,nt.props,null,Xe.mode,pt),mx(pt,nt),pt.return=Xe,Xe=pt)}return te(Xe);case x:e:{for(Xt=nt.key;Ue!==null;){if(Ue.key===Xt)if(Ue.tag===4&&Ue.stateNode.containerInfo===nt.containerInfo&&Ue.stateNode.implementation===nt.implementation){_(Xe,Ue.sibling),pt=j(Ue,nt.children||[]),pt.return=Xe,Xe=pt;break e}else{_(Xe,Ue);break}else p(Xe,Ue);Ue=Ue.sibling}pt=DN(nt,Xe.mode,pt),pt.return=Xe,Xe=pt}return te(Xe);case D:return nt=fh(nt),lr(Xe,Ue,nt,pt)}if(W(nt))return Vt(Xe,Ue,nt,pt);if(L(nt)){if(Xt=L(nt),typeof Xt!="function")throw Error(r(150));return nt=Xt.call(nt),en(Xe,Ue,nt,pt)}if(typeof nt.then=="function")return lr(Xe,Ue,ev(nt),pt);if(nt.$$typeof===S)return lr(Xe,Ue,Yy(Xe,nt),pt);tv(Xe,nt)}return typeof nt=="string"&&nt!==""||typeof nt=="number"||typeof nt=="bigint"?(nt=""+nt,Ue!==null&&Ue.tag===6?(_(Xe,Ue.sibling),pt=j(Ue,nt),pt.return=Xe,Xe=pt):(_(Xe,Ue),pt=RN(nt,Xe.mode,pt),pt.return=Xe,Xe=pt),te(Xe)):_(Xe,Ue)}return function(Xe,Ue,nt,pt){try{fx=0;var Xt=lr(Xe,Ue,nt,pt);return dm=null,Xt}catch(Wt){if(Wt===um||Wt===Zy)throw Wt;var Bn=Ms(29,Wt,null,Xe.mode);return Bn.lanes=pt,Bn.return=Xe,Bn}finally{}}}var ph=AI(!0),CI=AI(!1),_u=!1;function WN(h){h.updateQueue={baseState:h.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function qN(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 wu(h){return{lane:h,tag:0,payload:null,callback:null,next:null}}function Su(h,p,_){var N=h.updateQueue;if(N===null)return null;if(N=N.shared,(Kn&2)!==0){var j=N.pending;return j===null?p.next=p:(p.next=j.next,j.next=p),N.pending=p,p=Wy(h),hI(h,null,_),p}return Gy(h,N,p,_),Wy(h)}function px(h,p,_){if(p=p.updateQueue,p!==null&&(p=p.shared,(_&4194048)!==0)){var N=p.lanes;N&=h.pendingLanes,_|=N,p.lanes=_,dt(h,_)}}function KN(h,p){var _=h.updateQueue,N=h.alternate;if(N!==null&&(N=N.updateQueue,_===N)){var j=null,O=null;if(_=_.firstBaseUpdate,_!==null){do{var te={lane:_.lane,tag:_.tag,payload:_.payload,callback:null,next:null};O===null?j=O=te:O=O.next=te,_=_.next}while(_!==null);O===null?j=O=p:O=O.next=p}else j=O=p;_={baseState:N.baseState,firstBaseUpdate:j,lastBaseUpdate:O,shared:N.shared,callbacks:N.callbacks},h.updateQueue=_;return}h=_.lastBaseUpdate,h===null?_.firstBaseUpdate=p:h.next=p,_.lastBaseUpdate=p}var XN=!1;function gx(){if(XN){var h=cm;if(h!==null)throw h}}function xx(h,p,_,N){XN=!1;var j=h.updateQueue;_u=!1;var O=j.firstBaseUpdate,te=j.lastBaseUpdate,pe=j.shared.pending;if(pe!==null){j.shared.pending=null;var Pe=pe,rt=Pe.next;Pe.next=null,te===null?O=rt:te.next=rt,te=Pe;var mt=h.alternate;mt!==null&&(mt=mt.updateQueue,pe=mt.lastBaseUpdate,pe!==te&&(pe===null?mt.firstBaseUpdate=rt:pe.next=rt,mt.lastBaseUpdate=Pe))}if(O!==null){var yt=j.baseState;te=0,mt=rt=Pe=null,pe=O;do{var at=pe.lane&-536870913,ot=at!==pe.lane;if(ot?(Rn&at)===at:(N&at)===at){at!==0&&at===lm&&(XN=!0),mt!==null&&(mt=mt.next={lane:0,tag:pe.tag,payload:pe.payload,callback:null,next:null});e:{var Vt=h,en=pe;at=p;var lr=_;switch(en.tag){case 1:if(Vt=en.payload,typeof Vt=="function"){yt=Vt.call(lr,yt,at);break e}yt=Vt;break e;case 3:Vt.flags=Vt.flags&-65537|128;case 0:if(Vt=en.payload,at=typeof Vt=="function"?Vt.call(lr,yt,at):Vt,at==null)break e;yt=f({},yt,at);break e;case 2:_u=!0}}at=pe.callback,at!==null&&(h.flags|=64,ot&&(h.flags|=8192),ot=j.callbacks,ot===null?j.callbacks=[at]:ot.push(at))}else ot={lane:at,tag:pe.tag,payload:pe.payload,callback:pe.callback,next:null},mt===null?(rt=mt=ot,Pe=yt):mt=mt.next=ot,te|=at;if(pe=pe.next,pe===null){if(pe=j.shared.pending,pe===null)break;ot=pe,pe=ot.next,ot.next=null,j.lastBaseUpdate=ot,j.shared.pending=null}}while(!0);mt===null&&(Pe=yt),j.baseState=Pe,j.firstBaseUpdate=rt,j.lastBaseUpdate=mt,O===null&&(j.shared.lanes=0),Au|=te,h.lanes=te,h.memoizedState=yt}}function kI(h,p){if(typeof h!="function")throw Error(r(191,h));h.call(p)}function jI(h,p){var _=h.callbacks;if(_!==null)for(h.callbacks=null,h=0;h<_.length;h++)kI(_[h],p)}var hm=z(null),nv=z(0);function PI(h,p){h=hc,ee(nv,h),ee(hm,p),hc=h|p.baseLanes}function YN(){ee(nv,hc),ee(hm,hm.current)}function QN(){hc=nv.current,G(hm),G(nv)}var Ns=z(null),eo=null;function Mu(h){var p=h.alternate;ee(ni,ni.current&1),ee(Ns,h),eo===null&&(p===null||hm.current!==null||p.memoizedState!==null)&&(eo=h)}function ZN(h){ee(ni,ni.current),ee(Ns,h),eo===null&&(eo=h)}function RI(h){h.tag===22?(ee(ni,ni.current),ee(Ns,h),eo===null&&(eo=h)):Nu()}function Nu(){ee(ni,ni.current),ee(Ns,Ns.current)}function Es(h){G(Ns),eo===h&&(eo=null),G(ni)}var ni=z(0);function rv(h){for(var p=h;p!==null;){if(p.tag===13){var _=p.memoizedState;if(_!==null&&(_=_.dehydrated,_===null||iT(_)||aT(_)))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 ic=0,fn=null,sr=null,ci=null,iv=!1,fm=!1,gh=!1,av=0,bx=0,mm=null,die=0;function Gr(){throw Error(r(321))}function JN(h,p){if(p===null)return!1;for(var _=0;_O?O:8;var te=Y.T,pe={};Y.T=pe,mE(h,!1,p,_);try{var Pe=j(),rt=Y.S;if(rt!==null&&rt(pe,Pe),Pe!==null&&typeof Pe=="object"&&typeof Pe.then=="function"){var mt=uie(Pe,N);vx(h,p,mt,Cs(h))}else vx(h,p,N,Cs(h))}catch(yt){vx(h,p,{then:function(){},status:"rejected",reason:yt},Cs())}finally{q.p=O,te!==null&&pe.types!==null&&(te.types=pe.types),Y.T=te}}function gie(){}function hE(h,p,_,N){if(h.tag!==5)throw Error(r(476));var j=c5(h).queue;l5(h,j,p,J,_===null?gie:function(){return u5(h),_(N)})}function c5(h){var p=h.memoizedState;if(p!==null)return p;p={memoizedState:J,baseState:J,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ac,lastRenderedState:J},next:null};var _={};return p.next={memoizedState:_,baseState:_,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:ac,lastRenderedState:_},next:null},h.memoizedState=p,h=h.alternate,h!==null&&(h.memoizedState=p),p}function u5(h){var p=c5(h);p.next===null&&(p=h.alternate.memoizedState),vx(h,p.next.queue,{},Cs())}function fE(){return aa(Ix)}function d5(){return ri().memoizedState}function h5(){return ri().memoizedState}function xie(h){for(var p=h.return;p!==null;){switch(p.tag){case 24:case 3:var _=Cs();h=wu(_);var N=Su(p,h,_);N!==null&&(is(N,p,_),px(N,p,_)),p={cache:$N()},h.payload=p;return}p=p.return}}function bie(h,p,_){var N=Cs();_={lane:N,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null},dv(h)?m5(p,_):(_=jN(h,p,_,N),_!==null&&(is(_,h,N),p5(_,p,N)))}function f5(h,p,_){var N=Cs();vx(h,p,_,N)}function vx(h,p,_,N){var j={lane:N,revertLane:0,gesture:null,action:_,hasEagerState:!1,eagerState:null,next:null};if(dv(h))m5(p,j);else{var O=h.alternate;if(h.lanes===0&&(O===null||O.lanes===0)&&(O=p.lastRenderedReducer,O!==null))try{var te=p.lastRenderedState,pe=O(te,_);if(j.hasEagerState=!0,j.eagerState=pe,Ss(pe,te))return Gy(h,p,j,0),xr===null&&Vy(),!1}catch{}finally{}if(_=jN(h,p,j,N),_!==null)return is(_,h,N),p5(_,p,N),!0}return!1}function mE(h,p,_,N){if(N={lane:2,revertLane:WE(),gesture:null,action:N,hasEagerState:!1,eagerState:null,next:null},dv(h)){if(p)throw Error(r(479))}else p=jN(h,_,N,2),p!==null&&is(p,h,2)}function dv(h){var p=h.alternate;return h===fn||p!==null&&p===fn}function m5(h,p){fm=iv=!0;var _=h.pending;_===null?p.next=p:(p.next=_.next,_.next=p),h.pending=p}function p5(h,p,_){if((_&4194048)!==0){var N=p.lanes;N&=h.pendingLanes,_|=N,p.lanes=_,dt(h,_)}}var _x={readContext:aa,use:ov,useCallback:Gr,useContext:Gr,useEffect:Gr,useImperativeHandle:Gr,useLayoutEffect:Gr,useInsertionEffect:Gr,useMemo:Gr,useReducer:Gr,useRef:Gr,useState:Gr,useDebugValue:Gr,useDeferredValue:Gr,useTransition:Gr,useSyncExternalStore:Gr,useId:Gr,useHostTransitionStatus:Gr,useFormState:Gr,useActionState:Gr,useOptimistic:Gr,useMemoCache:Gr,useCacheRefresh:Gr};_x.useEffectEvent=Gr;var g5={readContext:aa,use:ov,useCallback:function(h,p){return La().memoizedState=[h,p===void 0?null:p],h},useContext:aa,useEffect:JI,useImperativeHandle:function(h,p,_){_=_!=null?_.concat([h]):null,cv(4194308,4,r5.bind(null,p,h),_)},useLayoutEffect:function(h,p){return cv(4194308,4,h,p)},useInsertionEffect:function(h,p){cv(4,2,h,p)},useMemo:function(h,p){var _=La();p=p===void 0?null:p;var N=h();if(gh){Ve(!0);try{h()}finally{Ve(!1)}}return _.memoizedState=[N,p],N},useReducer:function(h,p,_){var N=La();if(_!==void 0){var j=_(p);if(gh){Ve(!0);try{_(p)}finally{Ve(!1)}}}else j=p;return N.memoizedState=N.baseState=j,h={pending:null,lanes:0,dispatch:null,lastRenderedReducer:h,lastRenderedState:j},N.queue=h,h=h.dispatch=bie.bind(null,fn,h),[N.memoizedState,h]},useRef:function(h){var p=La();return h={current:h},p.memoizedState=h},useState:function(h){h=oE(h);var p=h.queue,_=f5.bind(null,fn,p);return p.dispatch=_,[h.memoizedState,_]},useDebugValue:uE,useDeferredValue:function(h,p){var _=La();return dE(_,h,p)},useTransition:function(){var h=oE(!1);return h=l5.bind(null,fn,h.queue,!0,!1),La().memoizedState=h,[!1,h]},useSyncExternalStore:function(h,p,_){var N=fn,j=La();if(Ln){if(_===void 0)throw Error(r(407));_=_()}else{if(_=p(),xr===null)throw Error(r(349));(Rn&127)!==0||II(N,p,_)}j.memoizedState=_;var O={value:_,getSnapshot:p};return j.queue=O,JI(UI.bind(null,N,O,h),[h]),N.flags|=2048,pm(9,{destroy:void 0},FI.bind(null,N,O,_,p),null),_},useId:function(){var h=La(),p=xr.identifierPrefix;if(Ln){var _=ml,N=fl;_=(N&~(1<<32-$e(N)-1)).toString(32)+_,p="_"+p+"R_"+_,_=av++,0<_&&(p+="H"+_.toString(32)),p+="_"}else _=die++,p="_"+p+"r_"+_.toString(32)+"_";return h.memoizedState=p},useHostTransitionStatus:fE,useFormState:KI,useActionState:KI,useOptimistic:function(h){var p=La();p.memoizedState=p.baseState=h;var _={pending:null,lanes:0,dispatch:null,lastRenderedReducer:null,lastRenderedState:null};return p.queue=_,p=mE.bind(null,fn,!0,_),_.dispatch=p,[h,p]},useMemoCache:iE,useCacheRefresh:function(){return La().memoizedState=xie.bind(null,fn)},useEffectEvent:function(h){var p=La(),_={impl:h};return p.memoizedState=_,function(){if((Kn&2)!==0)throw Error(r(440));return _.impl.apply(void 0,arguments)}}},pE={readContext:aa,use:ov,useCallback:a5,useContext:aa,useEffect:cE,useImperativeHandle:i5,useInsertionEffect:t5,useLayoutEffect:n5,useMemo:s5,useReducer:lv,useRef:ZI,useState:function(){return lv(ac)},useDebugValue:uE,useDeferredValue:function(h,p){var _=ri();return o5(_,sr.memoizedState,h,p)},useTransition:function(){var h=lv(ac)[0],p=ri().memoizedState;return[typeof h=="boolean"?h:yx(h),p]},useSyncExternalStore:LI,useId:d5,useHostTransitionStatus:fE,useFormState:XI,useActionState:XI,useOptimistic:function(h,p){var _=ri();return $I(_,sr,h,p)},useMemoCache:iE,useCacheRefresh:h5};pE.useEffectEvent=e5;var x5={readContext:aa,use:ov,useCallback:a5,useContext:aa,useEffect:cE,useImperativeHandle:i5,useInsertionEffect:t5,useLayoutEffect:n5,useMemo:s5,useReducer:sE,useRef:ZI,useState:function(){return sE(ac)},useDebugValue:uE,useDeferredValue:function(h,p){var _=ri();return sr===null?dE(_,h,p):o5(_,sr.memoizedState,h,p)},useTransition:function(){var h=sE(ac)[0],p=ri().memoizedState;return[typeof h=="boolean"?h:yx(h),p]},useSyncExternalStore:LI,useId:d5,useHostTransitionStatus:fE,useFormState:QI,useActionState:QI,useOptimistic:function(h,p){var _=ri();return sr!==null?$I(_,sr,h,p):(_.baseState=h,[h,_.queue.dispatch])},useMemoCache:iE,useCacheRefresh:h5};x5.useEffectEvent=e5;function gE(h,p,_,N){p=h.memoizedState,_=_(N,p),_=_==null?p:f({},p,_),h.memoizedState=_,h.lanes===0&&(h.updateQueue.baseState=_)}var xE={enqueueSetState:function(h,p,_){h=h._reactInternals;var N=Cs(),j=wu(N);j.payload=p,_!=null&&(j.callback=_),p=Su(h,j,N),p!==null&&(is(p,h,N),px(p,h,N))},enqueueReplaceState:function(h,p,_){h=h._reactInternals;var N=Cs(),j=wu(N);j.tag=1,j.payload=p,_!=null&&(j.callback=_),p=Su(h,j,N),p!==null&&(is(p,h,N),px(p,h,N))},enqueueForceUpdate:function(h,p){h=h._reactInternals;var _=Cs(),N=wu(_);N.tag=2,p!=null&&(N.callback=p),p=Su(h,N,_),p!==null&&(is(p,h,_),px(p,h,_))}};function b5(h,p,_,N,j,O,te){return h=h.stateNode,typeof h.shouldComponentUpdate=="function"?h.shouldComponentUpdate(N,O,te):p.prototype&&p.prototype.isPureReactComponent?!ox(_,N)||!ox(j,O):!0}function y5(h,p,_,N){h=p.state,typeof p.componentWillReceiveProps=="function"&&p.componentWillReceiveProps(_,N),typeof p.UNSAFE_componentWillReceiveProps=="function"&&p.UNSAFE_componentWillReceiveProps(_,N),p.state!==h&&xE.enqueueReplaceState(p,p.state,null)}function xh(h,p){var _=p;if("ref"in p){_={};for(var N in p)N!=="ref"&&(_[N]=p[N])}if(h=h.defaultProps){_===p&&(_=f({},_));for(var j in h)_[j]===void 0&&(_[j]=h[j])}return _}function v5(h){Hy(h)}function _5(h){console.error(h)}function w5(h){Hy(h)}function hv(h,p){try{var _=h.onUncaughtError;_(p.value,{componentStack:p.stack})}catch(N){setTimeout(function(){throw N})}}function S5(h,p,_){try{var N=h.onCaughtError;N(_.value,{componentStack:_.stack,errorBoundary:p.tag===1?p.stateNode:null})}catch(j){setTimeout(function(){throw j})}}function bE(h,p,_){return _=wu(_),_.tag=3,_.payload={element:null},_.callback=function(){hv(h,p)},_}function M5(h){return h=wu(h),h.tag=3,h}function N5(h,p,_,N){var j=_.type.getDerivedStateFromError;if(typeof j=="function"){var O=N.value;h.payload=function(){return j(O)},h.callback=function(){S5(p,_,N)}}var te=_.stateNode;te!==null&&typeof te.componentDidCatch=="function"&&(h.callback=function(){S5(p,_,N),typeof j!="function"&&(Cu===null?Cu=new Set([this]):Cu.add(this));var pe=N.stack;this.componentDidCatch(N.value,{componentStack:pe!==null?pe:""})})}function yie(h,p,_,N,j){if(_.flags|=32768,N!==null&&typeof N=="object"&&typeof N.then=="function"){if(p=_.alternate,p!==null&&om(p,_,j,!0),_=Ns.current,_!==null){switch(_.tag){case 31:case 13:return eo===null?Mv():_.alternate===null&&Wr===0&&(Wr=3),_.flags&=-257,_.flags|=65536,_.lanes=j,N===Jy?_.flags|=16384:(p=_.updateQueue,p===null?_.updateQueue=new Set([N]):p.add(N),HE(h,N,j)),!1;case 22:return _.flags|=65536,N===Jy?_.flags|=16384:(p=_.updateQueue,p===null?(p={transitions:null,markerInstances:null,retryQueue:new Set([N])},_.updateQueue=p):(_=p.retryQueue,_===null?p.retryQueue=new Set([N]):_.add(N)),HE(h,N,j)),!1}throw Error(r(435,_.tag))}return HE(h,N,j),Mv(),!1}if(Ln)return p=Ns.current,p!==null?((p.flags&65536)===0&&(p.flags|=256),p.flags|=65536,p.lanes=j,N!==IN&&(h=Error(r(422),{cause:N}),ux(Ys(h,_)))):(N!==IN&&(p=Error(r(423),{cause:N}),ux(Ys(p,_))),h=h.current.alternate,h.flags|=65536,j&=-j,h.lanes|=j,N=Ys(N,_),j=bE(h.stateNode,N,j),KN(h,j),Wr!==4&&(Wr=2)),!1;var O=Error(r(520),{cause:N});if(O=Ys(O,_),Cx===null?Cx=[O]:Cx.push(O),Wr!==4&&(Wr=2),p===null)return!0;N=Ys(N,_),_=p;do{switch(_.tag){case 3:return _.flags|=65536,h=j&-j,_.lanes|=h,h=bE(_.stateNode,N,h),KN(_,h),!1;case 1:if(p=_.type,O=_.stateNode,(_.flags&128)===0&&(typeof p.getDerivedStateFromError=="function"||O!==null&&typeof O.componentDidCatch=="function"&&(Cu===null||!Cu.has(O))))return _.flags|=65536,j&=-j,_.lanes|=j,j=M5(j),N5(j,h,_,N),KN(_,j),!1}_=_.return}while(_!==null);return!1}var yE=Error(r(461)),ui=!1;function sa(h,p,_,N){p.child=h===null?CI(p,null,_,N):ph(p,h.child,_,N)}function E5(h,p,_,N,j){_=_.render;var O=p.ref;if("ref"in N){var te={};for(var pe in N)pe!=="ref"&&(te[pe]=N[pe])}else te=N;return dh(p),N=eE(h,p,_,te,O,j),pe=tE(),h!==null&&!ui?(nE(h,p,j),sc(h,p,j)):(Ln&&pe&&ON(p),p.flags|=1,sa(h,p,N,j),p.child)}function T5(h,p,_,N,j){if(h===null){var O=_.type;return typeof O=="function"&&!PN(O)&&O.defaultProps===void 0&&_.compare===null?(p.tag=15,p.type=O,A5(h,p,O,N,j)):(h=qy(_.type,null,N,p,p.mode,j),h.ref=p.ref,h.return=p,p.child=h)}if(O=h.child,!TE(h,j)){var te=O.memoizedProps;if(_=_.compare,_=_!==null?_:ox,_(te,N)&&h.ref===p.ref)return sc(h,p,j)}return p.flags|=1,h=ec(O,N),h.ref=p.ref,h.return=p,p.child=h}function A5(h,p,_,N,j){if(h!==null){var O=h.memoizedProps;if(ox(O,N)&&h.ref===p.ref)if(ui=!1,p.pendingProps=N=O,TE(h,j))(h.flags&131072)!==0&&(ui=!0);else return p.lanes=h.lanes,sc(h,p,j)}return vE(h,p,_,N,j)}function C5(h,p,_,N){var j=N.children,O=h!==null?h.memoizedState:null;if(h===null&&p.stateNode===null&&(p.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),N.mode==="hidden"){if((p.flags&128)!==0){if(O=O!==null?O.baseLanes|_:_,h!==null){for(N=p.child=h.child,j=0;N!==null;)j=j|N.lanes|N.childLanes,N=N.sibling;N=j&~O}else N=0,p.child=null;return k5(h,p,O,_,N)}if((_&536870912)!==0)p.memoizedState={baseLanes:0,cachePool:null},h!==null&&Qy(p,O!==null?O.cachePool:null),O!==null?PI(p,O):YN(),RI(p);else return N=p.lanes=536870912,k5(h,p,O!==null?O.baseLanes|_:_,_,N)}else O!==null?(Qy(p,O.cachePool),PI(p,O),Nu(),p.memoizedState=null):(h!==null&&Qy(p,null),YN(),Nu());return sa(h,p,j,_),p.child}function wx(h,p){return h!==null&&h.tag===22||p.stateNode!==null||(p.stateNode={_visibility:1,_pendingMarkers:null,_retryCache:null,_transitions:null}),p.sibling}function k5(h,p,_,N,j){var O=VN();return O=O===null?null:{parent:li._currentValue,pool:O},p.memoizedState={baseLanes:_,cachePool:O},h!==null&&Qy(p,null),YN(),RI(p),h!==null&&om(h,p,N,!0),p.childLanes=j,null}function fv(h,p){return p=pv({mode:p.mode,children:p.children},h.mode),p.ref=h.ref,h.child=p,p.return=h,p}function j5(h,p,_){return ph(p,h.child,null,_),h=fv(p,p.pendingProps),h.flags|=2,Es(p),p.memoizedState=null,h}function vie(h,p,_){var N=p.pendingProps,j=(p.flags&128)!==0;if(p.flags&=-129,h===null){if(Ln){if(N.mode==="hidden")return h=fv(p,N),p.lanes=536870912,wx(null,h);if(ZN(p),(h=Er)?(h=HF(h,Js),h=h!==null&&h.data==="&"?h:null,h!==null&&(p.memoizedState={dehydrated:h,treeContext:xu!==null?{id:fl,overflow:ml}:null,retryLane:536870912,hydrationErrors:null},_=mI(h),_.return=p,p.child=_,ia=p,Er=null)):h=null,h===null)throw yu(p);return p.lanes=536870912,null}return fv(p,N)}var O=h.memoizedState;if(O!==null){var te=O.dehydrated;if(ZN(p),j)if(p.flags&256)p.flags&=-257,p=j5(h,p,_);else if(p.memoizedState!==null)p.child=h.child,p.flags|=128,p=null;else throw Error(r(558));else if(ui||om(h,p,_,!1),j=(_&h.childLanes)!==0,ui||j){if(N=xr,N!==null&&(te=Gt(N,_),te!==0&&te!==O.retryLane))throw O.retryLane=te,oh(h,te),is(N,h,te),yE;Mv(),p=j5(h,p,_)}else h=O.treeContext,Er=to(te.nextSibling),ia=p,Ln=!0,bu=null,Js=!1,h!==null&&xI(p,h),p=fv(p,N),p.flags|=4096;return p}return h=ec(h.child,{mode:N.mode,children:N.children}),h.ref=p.ref,p.child=h,h.return=p,h}function mv(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 vE(h,p,_,N,j){return dh(p),_=eE(h,p,_,N,void 0,j),N=tE(),h!==null&&!ui?(nE(h,p,j),sc(h,p,j)):(Ln&&N&&ON(p),p.flags|=1,sa(h,p,_,j),p.child)}function P5(h,p,_,N,j,O){return dh(p),p.updateQueue=null,_=OI(p,N,_,j),DI(h),N=tE(),h!==null&&!ui?(nE(h,p,O),sc(h,p,O)):(Ln&&N&&ON(p),p.flags|=1,sa(h,p,_,O),p.child)}function R5(h,p,_,N,j){if(dh(p),p.stateNode===null){var O=rm,te=_.contextType;typeof te=="object"&&te!==null&&(O=aa(te)),O=new _(N,O),p.memoizedState=O.state!==null&&O.state!==void 0?O.state:null,O.updater=xE,p.stateNode=O,O._reactInternals=p,O=p.stateNode,O.props=N,O.state=p.memoizedState,O.refs={},WN(p),te=_.contextType,O.context=typeof te=="object"&&te!==null?aa(te):rm,O.state=p.memoizedState,te=_.getDerivedStateFromProps,typeof te=="function"&&(gE(p,_,te,N),O.state=p.memoizedState),typeof _.getDerivedStateFromProps=="function"||typeof O.getSnapshotBeforeUpdate=="function"||typeof O.UNSAFE_componentWillMount!="function"&&typeof O.componentWillMount!="function"||(te=O.state,typeof O.componentWillMount=="function"&&O.componentWillMount(),typeof O.UNSAFE_componentWillMount=="function"&&O.UNSAFE_componentWillMount(),te!==O.state&&xE.enqueueReplaceState(O,O.state,null),xx(p,N,O,j),gx(),O.state=p.memoizedState),typeof O.componentDidMount=="function"&&(p.flags|=4194308),N=!0}else if(h===null){O=p.stateNode;var pe=p.memoizedProps,Pe=xh(_,pe);O.props=Pe;var rt=O.context,mt=_.contextType;te=rm,typeof mt=="object"&&mt!==null&&(te=aa(mt));var yt=_.getDerivedStateFromProps;mt=typeof yt=="function"||typeof O.getSnapshotBeforeUpdate=="function",pe=p.pendingProps!==pe,mt||typeof O.UNSAFE_componentWillReceiveProps!="function"&&typeof O.componentWillReceiveProps!="function"||(pe||rt!==te)&&y5(p,O,N,te),_u=!1;var at=p.memoizedState;O.state=at,xx(p,N,O,j),gx(),rt=p.memoizedState,pe||at!==rt||_u?(typeof yt=="function"&&(gE(p,_,yt,N),rt=p.memoizedState),(Pe=_u||b5(p,_,Pe,N,at,rt,te))?(mt||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=N,p.memoizedState=rt),O.props=N,O.state=rt,O.context=te,N=Pe):(typeof O.componentDidMount=="function"&&(p.flags|=4194308),N=!1)}else{O=p.stateNode,qN(h,p),te=p.memoizedProps,mt=xh(_,te),O.props=mt,yt=p.pendingProps,at=O.context,rt=_.contextType,Pe=rm,typeof rt=="object"&&rt!==null&&(Pe=aa(rt)),pe=_.getDerivedStateFromProps,(rt=typeof pe=="function"||typeof O.getSnapshotBeforeUpdate=="function")||typeof O.UNSAFE_componentWillReceiveProps!="function"&&typeof O.componentWillReceiveProps!="function"||(te!==yt||at!==Pe)&&y5(p,O,N,Pe),_u=!1,at=p.memoizedState,O.state=at,xx(p,N,O,j),gx();var ot=p.memoizedState;te!==yt||at!==ot||_u||h!==null&&h.dependencies!==null&&Xy(h.dependencies)?(typeof pe=="function"&&(gE(p,_,pe,N),ot=p.memoizedState),(mt=_u||b5(p,_,mt,N,at,ot,Pe)||h!==null&&h.dependencies!==null&&Xy(h.dependencies))?(rt||typeof O.UNSAFE_componentWillUpdate!="function"&&typeof O.componentWillUpdate!="function"||(typeof O.componentWillUpdate=="function"&&O.componentWillUpdate(N,ot,Pe),typeof O.UNSAFE_componentWillUpdate=="function"&&O.UNSAFE_componentWillUpdate(N,ot,Pe)),typeof O.componentDidUpdate=="function"&&(p.flags|=4),typeof O.getSnapshotBeforeUpdate=="function"&&(p.flags|=1024)):(typeof O.componentDidUpdate!="function"||te===h.memoizedProps&&at===h.memoizedState||(p.flags|=4),typeof O.getSnapshotBeforeUpdate!="function"||te===h.memoizedProps&&at===h.memoizedState||(p.flags|=1024),p.memoizedProps=N,p.memoizedState=ot),O.props=N,O.state=ot,O.context=Pe,N=mt):(typeof O.componentDidUpdate!="function"||te===h.memoizedProps&&at===h.memoizedState||(p.flags|=4),typeof O.getSnapshotBeforeUpdate!="function"||te===h.memoizedProps&&at===h.memoizedState||(p.flags|=1024),N=!1)}return O=N,mv(h,p),N=(p.flags&128)!==0,O||N?(O=p.stateNode,_=N&&typeof _.getDerivedStateFromError!="function"?null:O.render(),p.flags|=1,h!==null&&N?(p.child=ph(p,h.child,null,j),p.child=ph(p,null,_,j)):sa(h,p,_,j),p.memoizedState=O.state,h=p.child):h=sc(h,p,j),h}function D5(h,p,_,N){return ch(),p.flags|=256,sa(h,p,_,N),p.child}var _E={dehydrated:null,treeContext:null,retryLane:0,hydrationErrors:null};function wE(h){return{baseLanes:h,cachePool:SI()}}function SE(h,p,_){return h=h!==null?h.childLanes&~_:0,p&&(h|=As),h}function O5(h,p,_){var N=p.pendingProps,j=!1,O=(p.flags&128)!==0,te;if((te=O)||(te=h!==null&&h.memoizedState===null?!1:(ni.current&2)!==0),te&&(j=!0,p.flags&=-129),te=(p.flags&32)!==0,p.flags&=-33,h===null){if(Ln){if(j?Mu(p):Nu(),(h=Er)?(h=HF(h,Js),h=h!==null&&h.data!=="&"?h:null,h!==null&&(p.memoizedState={dehydrated:h,treeContext:xu!==null?{id:fl,overflow:ml}:null,retryLane:536870912,hydrationErrors:null},_=mI(h),_.return=p,p.child=_,ia=p,Er=null)):h=null,h===null)throw yu(p);return aT(h)?p.lanes=32:p.lanes=536870912,null}var pe=N.children;return N=N.fallback,j?(Nu(),j=p.mode,pe=pv({mode:"hidden",children:pe},j),N=lh(N,j,_,null),pe.return=p,N.return=p,pe.sibling=N,p.child=pe,N=p.child,N.memoizedState=wE(_),N.childLanes=SE(h,te,_),p.memoizedState=_E,wx(null,N)):(Mu(p),ME(p,pe))}var Pe=h.memoizedState;if(Pe!==null&&(pe=Pe.dehydrated,pe!==null)){if(O)p.flags&256?(Mu(p),p.flags&=-257,p=NE(h,p,_)):p.memoizedState!==null?(Nu(),p.child=h.child,p.flags|=128,p=null):(Nu(),pe=N.fallback,j=p.mode,N=pv({mode:"visible",children:N.children},j),pe=lh(pe,j,_,null),pe.flags|=2,N.return=p,pe.return=p,N.sibling=pe,p.child=N,ph(p,h.child,null,_),N=p.child,N.memoizedState=wE(_),N.childLanes=SE(h,te,_),p.memoizedState=_E,p=wx(null,N));else if(Mu(p),aT(pe)){if(te=pe.nextSibling&&pe.nextSibling.dataset,te)var rt=te.dgst;te=rt,N=Error(r(419)),N.stack="",N.digest=te,ux({value:N,source:null,stack:null}),p=NE(h,p,_)}else if(ui||om(h,p,_,!1),te=(_&h.childLanes)!==0,ui||te){if(te=xr,te!==null&&(N=Gt(te,_),N!==0&&N!==Pe.retryLane))throw Pe.retryLane=N,oh(h,N),is(te,h,N),yE;iT(pe)||Mv(),p=NE(h,p,_)}else iT(pe)?(p.flags|=192,p.child=h.child,p=null):(h=Pe.treeContext,Er=to(pe.nextSibling),ia=p,Ln=!0,bu=null,Js=!1,h!==null&&xI(p,h),p=ME(p,N.children),p.flags|=4096);return p}return j?(Nu(),pe=N.fallback,j=p.mode,Pe=h.child,rt=Pe.sibling,N=ec(Pe,{mode:"hidden",children:N.children}),N.subtreeFlags=Pe.subtreeFlags&65011712,rt!==null?pe=ec(rt,pe):(pe=lh(pe,j,_,null),pe.flags|=2),pe.return=p,N.return=p,N.sibling=pe,p.child=N,wx(null,N),N=p.child,pe=h.child.memoizedState,pe===null?pe=wE(_):(j=pe.cachePool,j!==null?(Pe=li._currentValue,j=j.parent!==Pe?{parent:Pe,pool:Pe}:j):j=SI(),pe={baseLanes:pe.baseLanes|_,cachePool:j}),N.memoizedState=pe,N.childLanes=SE(h,te,_),p.memoizedState=_E,wx(h.child,N)):(Mu(p),_=h.child,h=_.sibling,_=ec(_,{mode:"visible",children:N.children}),_.return=p,_.sibling=null,h!==null&&(te=p.deletions,te===null?(p.deletions=[h],p.flags|=16):te.push(h)),p.child=_,p.memoizedState=null,_)}function ME(h,p){return p=pv({mode:"visible",children:p},h.mode),p.return=h,h.child=p}function pv(h,p){return h=Ms(22,h,null,p),h.lanes=0,h}function NE(h,p,_){return ph(p,h.child,null,_),h=ME(p,p.pendingProps.children),h.flags|=2,p.memoizedState=null,h}function L5(h,p,_){h.lanes|=p;var N=h.alternate;N!==null&&(N.lanes|=p),zN(h.return,p,_)}function EE(h,p,_,N,j,O){var te=h.memoizedState;te===null?h.memoizedState={isBackwards:p,rendering:null,renderingStartTime:0,last:N,tail:_,tailMode:j,treeForkCount:O}:(te.isBackwards=p,te.rendering=null,te.renderingStartTime=0,te.last=N,te.tail=_,te.tailMode=j,te.treeForkCount=O)}function I5(h,p,_){var N=p.pendingProps,j=N.revealOrder,O=N.tail;N=N.children;var te=ni.current,pe=(te&2)!==0;if(pe?(te=te&1|2,p.flags|=128):te&=1,ee(ni,te),sa(h,p,N,_),N=Ln?cx:0,!pe&&h!==null&&(h.flags&128)!==0)e:for(h=p.child;h!==null;){if(h.tag===13)h.memoizedState!==null&&L5(h,_,p);else if(h.tag===19)L5(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&&rv(h)===null&&(j=_),_=_.sibling;_=j,_===null?(j=p.child,p.child=null):(j=_.sibling,_.sibling=null),EE(p,!1,j,_,O,N);break;case"backwards":case"unstable_legacy-backwards":for(_=null,j=p.child,p.child=null;j!==null;){if(h=j.alternate,h!==null&&rv(h)===null){p.child=j;break}h=j.sibling,j.sibling=_,_=j,j=h}EE(p,!0,_,null,O,N);break;case"together":EE(p,!1,null,null,void 0,N);break;default:p.memoizedState=null}return p.child}function sc(h,p,_){if(h!==null&&(p.dependencies=h.dependencies),Au|=p.lanes,(_&p.childLanes)===0)if(h!==null){if(om(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,_=ec(h,h.pendingProps),p.child=_,_.return=p;h.sibling!==null;)h=h.sibling,_=_.sibling=ec(h,h.pendingProps),_.return=p;_.sibling=null}return p.child}function TE(h,p){return(h.lanes&p)!==0?!0:(h=h.dependencies,!!(h!==null&&Xy(h)))}function _ie(h,p,_){switch(p.tag){case 3:Se(p,p.stateNode.containerInfo),vu(p,li,h.memoizedState.cache),ch();break;case 27:case 5:_e(p);break;case 4:Se(p,p.stateNode.containerInfo);break;case 10:vu(p,p.type,p.memoizedProps.value);break;case 31:if(p.memoizedState!==null)return p.flags|=128,ZN(p),null;break;case 13:var N=p.memoizedState;if(N!==null)return N.dehydrated!==null?(Mu(p),p.flags|=128,null):(_&p.child.childLanes)!==0?O5(h,p,_):(Mu(p),h=sc(h,p,_),h!==null?h.sibling:null);Mu(p);break;case 19:var j=(h.flags&128)!==0;if(N=(_&p.childLanes)!==0,N||(om(h,p,_,!1),N=(_&p.childLanes)!==0),j){if(N)return I5(h,p,_);p.flags|=128}if(j=p.memoizedState,j!==null&&(j.rendering=null,j.tail=null,j.lastEffect=null),ee(ni,ni.current),N)break;return null;case 22:return p.lanes=0,C5(h,p,_,p.pendingProps);case 24:vu(p,li,h.memoizedState.cache)}return sc(h,p,_)}function F5(h,p,_){if(h!==null)if(h.memoizedProps!==p.pendingProps)ui=!0;else{if(!TE(h,_)&&(p.flags&128)===0)return ui=!1,_ie(h,p,_);ui=(h.flags&131072)!==0}else ui=!1,Ln&&(p.flags&1048576)!==0&&gI(p,cx,p.index);switch(p.lanes=0,p.tag){case 16:e:{var N=p.pendingProps;if(h=fh(p.elementType),p.type=h,typeof h=="function")PN(h)?(N=xh(h,N),p.tag=1,p=R5(null,p,h,N,_)):(p.tag=0,p=vE(null,p,h,N,_));else{if(h!=null){var j=h.$$typeof;if(j===T){p.tag=11,p=E5(null,p,h,N,_);break e}else if(j===A){p.tag=14,p=T5(null,p,h,N,_);break e}}throw p=R(h)||h,Error(r(306,p,""))}}return p;case 0:return vE(h,p,p.type,p.pendingProps,_);case 1:return N=p.type,j=xh(N,p.pendingProps),R5(h,p,N,j,_);case 3:e:{if(Se(p,p.stateNode.containerInfo),h===null)throw Error(r(387));N=p.pendingProps;var O=p.memoizedState;j=O.element,qN(h,p),xx(p,N,null,_);var te=p.memoizedState;if(N=te.cache,vu(p,li,N),N!==O.cache&&BN(p,[li],_,!0),gx(),N=te.element,O.isDehydrated)if(O={element:N,isDehydrated:!1,cache:te.cache},p.updateQueue.baseState=O,p.memoizedState=O,p.flags&256){p=D5(h,p,N,_);break e}else if(N!==j){j=Ys(Error(r(424)),p),ux(j),p=D5(h,p,N,_);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(Er=to(h.firstChild),ia=p,Ln=!0,bu=null,Js=!0,_=CI(p,null,N,_),p.child=_;_;)_.flags=_.flags&-3|4096,_=_.sibling}else{if(ch(),N===j){p=sc(h,p,_);break e}sa(h,p,N,_)}p=p.child}return p;case 26:return mv(h,p),h===null?(_=XF(p.type,null,p.pendingProps,null))?p.memoizedState=_:Ln||(_=p.type,h=p.pendingProps,N=jv(fe.current).createElement(_),N[gr]=p,N[bt]=h,oa(N,_,h),Le(N),p.stateNode=N):p.memoizedState=XF(p.type,h.memoizedProps,p.pendingProps,h.memoizedState),null;case 27:return _e(p),h===null&&Ln&&(N=p.stateNode=WF(p.type,p.pendingProps,fe.current),ia=p,Js=!0,j=Er,Ru(p.type)?(sT=j,Er=to(N.firstChild)):Er=j),sa(h,p,p.pendingProps.children,_),mv(h,p),h===null&&(p.flags|=4194304),p.child;case 5:return h===null&&Ln&&((j=N=Er)&&(N=Qie(N,p.type,p.pendingProps,Js),N!==null?(p.stateNode=N,ia=p,Er=to(N.firstChild),Js=!1,j=!0):j=!1),j||yu(p)),_e(p),j=p.type,O=p.pendingProps,te=h!==null?h.memoizedProps:null,N=O.children,tT(j,O)?N=null:te!==null&&tT(j,te)&&(p.flags|=32),p.memoizedState!==null&&(j=eE(h,p,hie,null,null,_),Ix._currentValue=j),mv(h,p),sa(h,p,N,_),p.child;case 6:return h===null&&Ln&&((h=_=Er)&&(_=Zie(_,p.pendingProps,Js),_!==null?(p.stateNode=_,ia=p,Er=null,h=!0):h=!1),h||yu(p)),null;case 13:return O5(h,p,_);case 4:return Se(p,p.stateNode.containerInfo),N=p.pendingProps,h===null?p.child=ph(p,null,N,_):sa(h,p,N,_),p.child;case 11:return E5(h,p,p.type,p.pendingProps,_);case 7:return sa(h,p,p.pendingProps,_),p.child;case 8:return sa(h,p,p.pendingProps.children,_),p.child;case 12:return sa(h,p,p.pendingProps.children,_),p.child;case 10:return N=p.pendingProps,vu(p,p.type,N.value),sa(h,p,N.children,_),p.child;case 9:return j=p.type._context,N=p.pendingProps.children,dh(p),j=aa(j),N=N(j),p.flags|=1,sa(h,p,N,_),p.child;case 14:return T5(h,p,p.type,p.pendingProps,_);case 15:return A5(h,p,p.type,p.pendingProps,_);case 19:return I5(h,p,_);case 31:return vie(h,p,_);case 22:return C5(h,p,_,p.pendingProps);case 24:return dh(p),N=aa(li),h===null?(j=VN(),j===null&&(j=xr,O=$N(),j.pooledCache=O,O.refCount++,O!==null&&(j.pooledCacheLanes|=_),j=O),p.memoizedState={parent:N,cache:j},WN(p),vu(p,li,j)):((h.lanes&_)!==0&&(qN(h,p),xx(p,null,null,_),gx()),j=h.memoizedState,O=p.memoizedState,j.parent!==N?(j={parent:N,cache:N},p.memoizedState=j,p.lanes===0&&(p.memoizedState=p.updateQueue.baseState=j),vu(p,li,N)):(N=O.cache,vu(p,li,N),N!==j.cache&&BN(p,[li],_,!0))),sa(h,p,p.pendingProps.children,_),p.child;case 29:throw p.pendingProps}throw Error(r(156,p.tag))}function oc(h){h.flags|=4}function AE(h,p,_,N,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(dF())h.flags|=8192;else throw mh=Jy,GN}else h.flags&=-16777217}function U5(h,p){if(p.type!=="stylesheet"||(p.state.loading&4)!==0)h.flags&=-16777217;else if(h.flags|=16777216,!eU(p))if(dF())h.flags|=8192;else throw mh=Jy,GN}function gv(h,p){p!==null&&(h.flags|=4),h.flags&16384&&(p=h.tag!==22?jt():536870912,h.lanes|=p,ym|=p)}function Sx(h,p){if(!Ln)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 N=null;_!==null;)_.alternate!==null&&(N=_),_=_.sibling;N===null?p||h.tail===null?h.tail=null:h.tail.sibling=null:N.sibling=null}}function Tr(h){var p=h.alternate!==null&&h.alternate.child===h.child,_=0,N=0;if(p)for(var j=h.child;j!==null;)_|=j.lanes|j.childLanes,N|=j.subtreeFlags&65011712,N|=j.flags&65011712,j.return=h,j=j.sibling;else for(j=h.child;j!==null;)_|=j.lanes|j.childLanes,N|=j.subtreeFlags,N|=j.flags,j.return=h,j=j.sibling;return h.subtreeFlags|=N,h.childLanes=_,p}function wie(h,p,_){var N=p.pendingProps;switch(LN(p),p.tag){case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return Tr(p),null;case 1:return Tr(p),null;case 3:return _=p.stateNode,N=null,h!==null&&(N=h.memoizedState.cache),p.memoizedState.cache!==N&&(p.flags|=2048),rc(li),me(),_.pendingContext&&(_.context=_.pendingContext,_.pendingContext=null),(h===null||h.child===null)&&(sm(p)?oc(p):h===null||h.memoizedState.isDehydrated&&(p.flags&256)===0||(p.flags|=1024,FN())),Tr(p),null;case 26:var j=p.type,O=p.memoizedState;return h===null?(oc(p),O!==null?(Tr(p),U5(p,O)):(Tr(p),AE(p,j,null,N,_))):O?O!==h.memoizedState?(oc(p),Tr(p),U5(p,O)):(Tr(p),p.flags&=-16777217):(h=h.memoizedProps,h!==N&&oc(p),Tr(p),AE(p,j,h,N,_)),null;case 27:if(je(p),_=fe.current,j=p.type,h!==null&&p.stateNode!=null)h.memoizedProps!==N&&oc(p);else{if(!N){if(p.stateNode===null)throw Error(r(166));return Tr(p),null}h=ie.current,sm(p)?bI(p):(h=WF(j,N,_),p.stateNode=h,oc(p))}return Tr(p),null;case 5:if(je(p),j=p.type,h!==null&&p.stateNode!=null)h.memoizedProps!==N&&oc(p);else{if(!N){if(p.stateNode===null)throw Error(r(166));return Tr(p),null}if(O=ie.current,sm(p))bI(p);else{var te=jv(fe.current);switch(O){case 1:O=te.createElementNS("http://www.w3.org/2000/svg",j);break;case 2:O=te.createElementNS("http://www.w3.org/1998/Math/MathML",j);break;default:switch(j){case"svg":O=te.createElementNS("http://www.w3.org/2000/svg",j);break;case"math":O=te.createElementNS("http://www.w3.org/1998/Math/MathML",j);break;case"script":O=te.createElement("div"),O.innerHTML=" +