From ef264bbece63c87be67dc83668dba8db0f70ac13 Mon Sep 17 00:00:00 2001 From: Markos Gogoulos Date: Fri, 23 May 2025 16:52:21 +0300 Subject: [PATCH] text --- .../src/components/TimelineControls.tsx | 1345 ++++++++--------- static/video_editor/video-editor.js | 52 +- static/video_editor/video-editor.js.map | 2 +- 3 files changed, 699 insertions(+), 700 deletions(-) diff --git a/frontend-tools/video-editor/client/src/components/TimelineControls.tsx b/frontend-tools/video-editor/client/src/components/TimelineControls.tsx index d6666fac..7522c767 100644 --- a/frontend-tools/video-editor/client/src/components/TimelineControls.tsx +++ b/frontend-tools/video-editor/client/src/components/TimelineControls.tsx @@ -57,20 +57,20 @@ const constrainTooltipPosition = (positionPercent: number) => { // Default position logic (centered) let leftValue = `${positionPercent}%`; let transform = 'translateX(-50%)'; - + // Near left edge (first 17%) if (positionPercent < 17) { // Position the left edge of tooltip at 0%, no transform leftValue = '0%'; transform = 'none'; } - // Near right edge (last 17%) + // Near right edge (last 17%) else if (positionPercent > 83) { // Position the right edge of tooltip at 100% leftValue = '100%'; transform = 'translateX(-100%)'; } - + return { left: leftValue, transform }; }; @@ -116,33 +116,33 @@ const TimelineControls = ({ // Reference for the scrollable container const scrollContainerRef = useRef(null); - + // Helper function for time adjustment buttons to maintain playback state const handleTimeAdjustment = (offsetSeconds: number) => (e: React.MouseEvent) => { e.stopPropagation(); - + // Calculate new time based on offset (positive or negative) const newTime = offsetSeconds < 0 ? Math.max(0, clickedTime + offsetSeconds) // For negative offsets (going back) : Math.min(duration, clickedTime + offsetSeconds); // For positive offsets (going forward) - + // Save the current playing state before seeking const wasPlaying = isPlayingSegment; - + // Seek to the new time onSeek(newTime); - + // Update both clicked time and display time setClickedTime(newTime); setDisplayTime(newTime); - + // Resume playback if it was playing before if (wasPlaying && videoRef.current) { videoRef.current.play(); setIsPlayingSegment(true); } }; - + // Enhanced helper for continuous time adjustment when button is held down const handleContinuousTimeAdjustment = (offsetSeconds: number) => { // Fixed adjustment amount - exactly 50ms each time @@ -152,27 +152,27 @@ const TimelineControls = ({ let continuousTimer: NodeJS.Timeout | null = null; // Store the last time value to correctly calculate the next increment let lastTimeValue = clickedTime; - + // Function to perform time adjustment const adjustTime = () => { // Calculate new time based on fixed offset (positive or negative) const newTime = adjustmentValue < 0 ? Math.max(0, lastTimeValue + adjustmentValue) // For negative offsets (going back) : Math.min(duration, lastTimeValue + adjustmentValue); // For positive offsets (going forward) - + // Update our last time value for next adjustment lastTimeValue = newTime; - + // Save the current playing state before seeking const wasPlaying = isPlayingSegment; - + // Seek to the new time onSeek(newTime); - + // Update both clicked time and display time setClickedTime(newTime); setDisplayTime(newTime); - + // Update tooltip position if (timelineRef.current) { const rect = timelineRef.current.getBoundingClientRect(); @@ -200,32 +200,32 @@ const TimelineControls = ({ setShowEmptySpaceTooltip(true); } } - + // Resume playback if it was playing before if (wasPlaying && videoRef.current) { videoRef.current.play(); setIsPlayingSegment(true); } }; - + // Return mouse event handlers with touch support return { onMouseDown: (e: React.MouseEvent) => { e.stopPropagation(); e.preventDefault(); - + // Update the initial last time value lastTimeValue = clickedTime; - + // Perform initial adjustment adjustTime(); - + // Start continuous adjustment after 1.5s hold holdTimer = setTimeout(() => { // After 1.5s delay, start adjusting at a slower pace (every 200ms) continuousTimer = setInterval(adjustTime, 200); }, 750); - + // Add mouse up and leave handlers to document to ensure we catch the release const clearTimers = () => { if (holdTimer) { @@ -239,26 +239,26 @@ const TimelineControls = ({ document.removeEventListener('mouseup', clearTimers); document.removeEventListener('mouseleave', clearTimers); }; - + document.addEventListener('mouseup', clearTimers); document.addEventListener('mouseleave', clearTimers); }, onTouchStart: (e: React.TouchEvent) => { e.stopPropagation(); e.preventDefault();21 - + // Update the initial last time value lastTimeValue = clickedTime; - + // Perform initial adjustment adjustTime(); - + // Start continuous adjustment after 1.5s hold holdTimer = setTimeout(() => { // After 1.5s delay, start adjusting at a slower pace (every 200ms) continuousTimer = setInterval(adjustTime, 200); }, 750); - + // Add touch end handler to ensure we catch the release const clearTimers = () => { if (holdTimer) { @@ -272,7 +272,7 @@ const TimelineControls = ({ document.removeEventListener('touchend', clearTimers); document.removeEventListener('touchcancel', clearTimers); }; - + document.addEventListener('touchend', clearTimers); document.addEventListener('touchcancel', clearTimers); }, @@ -282,7 +282,7 @@ const TimelineControls = ({ } }; }; - + // Modal states const [showSaveModal, setShowSaveModal] = useState(false); const [showSaveAsModal, setShowSaveAsModal] = useState(false); @@ -294,14 +294,14 @@ const TimelineControls = ({ const [errorMessage, setErrorMessage] = useState(""); const [redirectUrl, setRedirectUrl] = useState(""); const [saveType, setSaveType] = useState<"save" | "copy" | "segments">("save"); - + // Calculate positions as percentages const currentTimePercent = duration > 0 ? (currentTime / duration) * 100 : 0; const trimStartPercent = duration > 0 ? (trimStart / duration) * 100 : 0; const trimEndPercent = duration > 0 ? (trimEnd / duration) * 100 : 0; - + // No need for an extra effect here as we handle displayTime updates in the segment playback effect - + // Save and API handlers const handleSaveConfirm = async () => { // Close confirmation modal and show processing modal @@ -318,11 +318,11 @@ const TimelineControls = ({ const mediaId = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.mediaId || null; const redirectURL = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.redirectURL || null; - + // Log the request details for debugging logger.debug("Save request:", { mediaId, segments, saveAsCopy: false, redirectURL }); - - const response = await trimVideo(mediaId, { + + const response = await trimVideo(mediaId, { segments, saveAsCopy: false }); @@ -332,16 +332,16 @@ const TimelineControls = ({ // Hide processing modal setShowProcessingModal(false); - + // Check if response indicates success (200 OK) if (response.status === 200) { // For "Save", use the redirectURL from the window or response const finalRedirectUrl = redirectURL || response.url_redirect; logger.debug("Using redirect URL:", finalRedirectUrl); - + setRedirectUrl(finalRedirectUrl); setSuccessMessage("Video saved successfully!"); - + // Show success modal setShowSuccessModal(true); } else if (response.status === 400) { @@ -359,7 +359,7 @@ const TimelineControls = ({ } catch (error) { logger.error("Error processing video:", error); setShowProcessingModal(false); - + // Set error message and show error modal const errorMsg = error instanceof Error ? error.message : "An error occurred during processing"; logger.debug("Save error (exception):", errorMsg); @@ -383,30 +383,30 @@ const TimelineControls = ({ const mediaId = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.mediaId || null; const redirectUserMediaURL = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.redirectUserMediaURL || null; - + // Log the request details for debugging logger.debug("Save as copy request:", { mediaId, segments, saveAsCopy: true, redirectUserMediaURL }); - const response = await trimVideo(mediaId, { + const response = await trimVideo(mediaId, { segments, saveAsCopy: true }); - + // Log the response for debugging logger.debug("Save as copy response:", response); // Hide processing modal setShowProcessingModal(false); - + // Check if response indicates success (200 OK) if (response.status === 200) { // For "Save As Copy", use the redirectUserMediaURL from the window const finalRedirectUrl = redirectUserMediaURL || response.url_redirect; logger.debug("Using redirect user media URL:", finalRedirectUrl); - + setRedirectUrl(finalRedirectUrl); setSuccessMessage("Video saved as a new copy!"); - + // Show success modal setShowSuccessModal(true); } else if (response.status === 400) { @@ -424,7 +424,7 @@ const TimelineControls = ({ } catch (error) { logger.error("Error processing video:", error); setShowProcessingModal(false); - + // Set error message and show error modal const errorMsg = error instanceof Error ? error.message : "An error occurred during processing"; logger.debug("Save as copy error (exception):", errorMsg); @@ -432,7 +432,7 @@ const TimelineControls = ({ setShowErrorModal(true); } }; - + const handleSaveSegmentsConfirm = async () => { // Close confirmation modal and show processing modal setShowSaveSegmentsModal(false); @@ -449,37 +449,37 @@ const TimelineControls = ({ const mediaId = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.mediaId || null; const redirectUserMediaURL = typeof window !== 'undefined' && (window as any).MEDIA_DATA?.redirectUserMediaURL || null; - - // Log the request details for debugging - logger.debug("Save segments request:", { - mediaId, - segments, - saveAsCopy: true, - saveIndividualSegments: true, - redirectUserMediaURL - }); - const response = await trimVideo(mediaId, { + // Log the request details for debugging + logger.debug("Save segments request:", { + mediaId, segments, saveAsCopy: true, - saveIndividualSegments: true + saveIndividualSegments: true, + redirectUserMediaURL }); - + + const response = await trimVideo(mediaId, { + segments, + saveAsCopy: true, + saveIndividualSegments: true + }); + // Log the response for debugging logger.debug("Save segments response:", response); // Hide processing modal setShowProcessingModal(false); - + // Check if response indicates success (200 OK) if (response.status === 200) { // For "Save Segments", use the redirectUserMediaURL from the window const finalRedirectUrl = redirectUserMediaURL || response.url_redirect; logger.debug("Using redirect user media URL for segments:", finalRedirectUrl); - + setRedirectUrl(finalRedirectUrl); setSuccessMessage(`${segments.length} segments saved successfully!`); - + // Show success modal setShowSuccessModal(true); } else if (response.status === 400) { @@ -498,7 +498,7 @@ const TimelineControls = ({ // Handle errors logger.error("Error processing video segments:", error); setShowProcessingModal(false); - + // Set error message and show error modal const errorMsg = error instanceof Error ? error.message : "An error occurred during processing"; logger.debug("Save segments error (exception):", errorMsg); @@ -506,32 +506,32 @@ const TimelineControls = ({ setShowErrorModal(true); } }; - + // Auto-scroll and update tooltip position when seeking to a different time useEffect(() => { if (scrollContainerRef.current && timelineRef.current && zoomLevel > 1) { const containerWidth = scrollContainerRef.current.clientWidth; const timelineWidth = timelineRef.current.clientWidth; const markerPosition = (currentTime / duration) * timelineWidth; - + // Calculate the position where we want the marker to be visible // (center of the viewport when possible) const desiredScrollPosition = Math.max(0, markerPosition - containerWidth / 2); - + // Smooth scroll to the desired position scrollContainerRef.current.scrollTo({ left: desiredScrollPosition, behavior: 'smooth' }); - + // Update tooltip position to stay with the marker const rect = timelineRef.current.getBoundingClientRect(); - + // Calculate the visible position of the marker after scrolling const containerRect = scrollContainerRef.current.getBoundingClientRect(); const visibleTimelineLeft = rect.left - scrollContainerRef.current.scrollLeft; const markerX = visibleTimelineLeft + (currentTimePercent / 100 * rect.width); - + // Only update if we have a tooltip showing if (selectedSegmentId !== null || showEmptySpaceTooltip) { setTooltipPosition({ @@ -542,7 +542,7 @@ const TimelineControls = ({ } } }, [currentTime, zoomLevel, duration, selectedSegmentId, showEmptySpaceTooltip, currentTimePercent]); - + // Effect to check active segment boundaries during playback useEffect(() => { // Skip if no video or no active segment @@ -555,32 +555,32 @@ const TimelineControls = ({ else if (isPreviewMode) logger.debug("Skipping segment boundary check in preview mode"); return; } - + // Skip boundary checking when playing all segments if (isPlayingSegments) { logger.debug("Skipping segment boundary check during segments playback"); return; } - - logger.debug("Segment boundary check ACTIVATED for segment:", - activeSegment.id, - "Start:", formatDetailedTime(activeSegment.startTime), + + logger.debug("Segment boundary check ACTIVATED for segment:", + activeSegment.id, + "Start:", formatDetailedTime(activeSegment.startTime), "End:", formatDetailedTime(activeSegment.endTime) ); - + const handleTimeUpdate = () => { const timeLeft = activeSegment.endTime - video.currentTime; - + // Log every second to show we're actually checking if (Math.round(timeLeft * 10) % 10 === 0) { - logger.debug("Segment playback - time remaining:", - formatDetailedTime(timeLeft), + logger.debug("Segment playback - time remaining:", + formatDetailedTime(timeLeft), "Current:", formatDetailedTime(video.currentTime), "End:", formatDetailedTime(activeSegment.endTime), "ContinuePastBoundary:", continuePastBoundary ); } - + // If we've already passed the segment end, stop immediately if (video.currentTime > activeSegment.endTime) { video.pause(); @@ -591,7 +591,7 @@ const TimelineControls = ({ logger.debug("Passed segment end - setting back to exact boundary:", formatDetailedTime(activeSegment.endTime)); return; } - + // If we've reached very close to the end of the active segment // Use a small tolerance to ensure we stop as close as possible to boundary // But not exactly at the boundary to avoid rounding errors @@ -602,11 +602,11 @@ const TimelineControls = ({ video.currentTime = activeSegment.endTime; setIsPlayingSegment(false); logger.debug("Paused at segment end boundary:", formatDetailedTime(activeSegment.endTime)); - + // Look for the next segment after this one (for potential continuation) const sortedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime); const nextSegment = sortedSegments.find(seg => seg.startTime > activeSegment.endTime); - + // If there's a next segment immediately after this one, update the tooltip to show that segment if (nextSegment && Math.abs(nextSegment.startTime - activeSegment.endTime) < 0.1) { logger.debug("Found adjacent next segment:", nextSegment.id); @@ -619,7 +619,7 @@ const TimelineControls = ({ } else { // We're continuing past the boundary logger.debug("Continuing past segment boundary:", formatDetailedTime(activeSegment.endTime)); - + // Reset the flag after we've passed the boundary to ensure we stop at the next boundary if (video.currentTime > activeSegment.endTime) { setContinuePastBoundary(false); @@ -631,10 +631,10 @@ const TimelineControls = ({ } } }; - + // Add event listener for timeupdate to check segment boundaries video.addEventListener('timeupdate', handleTimeUpdate); - + return () => { video.removeEventListener('timeupdate', handleTimeUpdate); logger.debug("Segment boundary check DEACTIVATED"); @@ -648,23 +648,23 @@ const TimelineControls = ({ // If video is playing, always update the displayed time in the tooltip if (!videoRef.current.paused) { setDisplayTime(currentTime); - + // Also update clicked time to keep them in sync when playing // This ensures correct time is shown when pausing setClickedTime(currentTime); - + if (selectedSegmentId !== null) { setIsPlayingSegment(true); } - + // While playing, continuously check if we're in a segment or empty space // to update the tooltip accordingly, regardless of where we started playing - + // Check if we're in any segment at current time const segmentAtCurrentTime = clipSegments.find( seg => currentTime >= seg.startTime && currentTime <= seg.endTime ); - + // Update tooltip position based on current time percentage const newTimePercent = (currentTime / duration) * 100; if (timelineRef.current) { @@ -675,24 +675,24 @@ const TimelineControls = ({ y: timelineRef.current.getBoundingClientRect().top - 10 }); } - + // Check for the special "continue past segment" state in sessionStorage const isContinuingPastSegment = sessionStorage.getItem('continuingPastSegment') === 'true'; - + // If we're in a segment now if (segmentAtCurrentTime) { // Get video element reference for boundary checks const video = videoRef.current; - + // Special check for virtual segments (cutaway playback) // If we have an active virtual segment (negative ID) and we're in a regular segment now, // we need to STOP at the start of this segment - that's the boundary of our cutaway const isPlayingVirtualSegment = activeSegment && activeSegment.id < 0 && isPlayingSegment; - + // If the active segment is different from the current segment and it's not a virtual segment // and we're not in "continue past boundary" mode, set this segment as the active segment - if (activeSegment?.id !== segmentAtCurrentTime.id && - !isPlayingVirtualSegment && + if (activeSegment?.id !== segmentAtCurrentTime.id && + !isPlayingVirtualSegment && !isContinuingPastSegment && !continuePastBoundary) { // We've entered a new segment during normal playback @@ -704,7 +704,7 @@ const TimelineControls = ({ setContinuePastBoundary(false); sessionStorage.removeItem('continuingPastSegment'); } - + // If we're playing a virtual segment and enter a real segment, we've reached our boundary // We should stop playback if (isPlayingVirtualSegment && video && segmentAtCurrentTime) { @@ -720,43 +720,43 @@ const TimelineControls = ({ // Also update tooltip time displays setDisplayTime(segmentAtCurrentTime.startTime); setClickedTime(segmentAtCurrentTime.startTime); - + // Reset continuePastBoundary when reaching a segment boundary setContinuePastBoundary(false); - + // Update tooltip to show segment tooltip at boundary setSelectedSegmentId(segmentAtCurrentTime.id); setShowEmptySpaceTooltip(false); - + // Force multiple adjustments to ensure exact precision const verifyPosition = () => { if (videoRef.current) { // Always force the exact time in every verification videoRef.current.currentTime = segmentAtCurrentTime.startTime; - + // Make sure we update the UI to reflect the corrected position onSeek(segmentAtCurrentTime.startTime); - + // Update the displayTime and clickedTime state to match exact position setDisplayTime(segmentAtCurrentTime.startTime); setClickedTime(segmentAtCurrentTime.startTime); - + logger.debug(`Position corrected to exact segment boundary: ${formatDetailedTime(videoRef.current.currentTime)} (target: ${formatDetailedTime(segmentAtCurrentTime.startTime)})`); } }; - + // Apply multiple correction attempts with increasing delays setTimeout(verifyPosition, 10); // Immediate correction setTimeout(verifyPosition, 20); // First correction setTimeout(verifyPosition, 50); // Second correction setTimeout(verifyPosition, 100); // Third correction setTimeout(verifyPosition, 200); // Final correction - + // Also add event listeners to ensure position is corrected whenever video state changes videoRef.current.addEventListener('seeked', verifyPosition); videoRef.current.addEventListener('canplay', verifyPosition); videoRef.current.addEventListener('waiting', verifyPosition); - + // Remove these event listeners after a short time setTimeout(() => { if (videoRef.current) { @@ -771,28 +771,28 @@ const TimelineControls = ({ setActiveSegment(null); return; // Exit early, we've handled this case } - + // Only update active segment if we're not in "continue past segment" mode // or if we're in a virtual cutaway segment - const continuingPastSegment = - (activeSegment === null && isPlayingSegment === true) || - isContinuingPastSegment || + const continuingPastSegment = + (activeSegment === null && isPlayingSegment === true) || + isContinuingPastSegment || isPlayingVirtualSegment; - + if (continuingPastSegment) { // We're in the special case where we're continuing past a segment boundary // or playing a cutaway area // Just update the tooltip, but don't reactivate boundary checking if (selectedSegmentId !== segmentAtCurrentTime.id || showEmptySpaceTooltip) { - logger.debug("Tooltip updated for segment during continued playback:", segmentAtCurrentTime.id, + logger.debug("Tooltip updated for segment during continued playback:", segmentAtCurrentTime.id, isPlayingVirtualSegment ? "(cutaway playback - keeping virtual segment)" : ""); setSelectedSegmentId(segmentAtCurrentTime.id); setShowEmptySpaceTooltip(false); - + // If we're in a different segment now, clear the continuation flag // but only if it's not the same segment we were in before // AND we're not playing a cutaway area - if (!isPlayingVirtualSegment && + if (!isPlayingVirtualSegment && sessionStorage.getItem('lastSegmentId') !== segmentAtCurrentTime.id.toString()) { logger.debug("Moved to a different segment - ending continuation mode"); sessionStorage.removeItem('continuingPastSegment'); @@ -805,12 +805,12 @@ const TimelineControls = ({ setSelectedSegmentId(segmentAtCurrentTime.id); setActiveSegment(segmentAtCurrentTime); setShowEmptySpaceTooltip(false); - + // Store the current segment ID for comparison later sessionStorage.setItem('lastSegmentId', segmentAtCurrentTime.id.toString()); } } - } + } // If we're in empty space now else { // Check if we need to change the tooltip (we were in a segment before) @@ -818,11 +818,11 @@ const TimelineControls = ({ logger.debug("Playback moved to empty space"); setSelectedSegmentId(null); setActiveSegment(null); - + // Calculate available space for new segment before showing tooltip const availableSpace = calculateAvailableSpace(currentTime); setAvailableSegmentDuration(availableSpace); - + // Show empty space tooltip if there's enough space if (availableSpace >= 0.5) { setShowEmptySpaceTooltip(true); @@ -837,14 +837,14 @@ const TimelineControls = ({ setDisplayTime(currentTime); setClickedTime(currentTime); setIsPlayingSegment(false); - + // Log the stopping point logger.debug("Video paused at:", formatDetailedTime(currentTime)); } } // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentTime, isPlayingSegment, activeSegment, selectedSegmentId, clipSegments]); - + // Close zoom dropdown when clicking outside useEffect(() => { const handleClickOutside = (event: MouseEvent) => { @@ -853,18 +853,18 @@ const TimelineControls = ({ setIsZoomDropdownOpen(false); } }; - + document.addEventListener('mousedown', handleClickOutside); return () => { document.removeEventListener('mousedown', handleClickOutside); }; }, [isZoomDropdownOpen]); - + // Global click handler to close tooltips when clicking outside useEffect(() => { // Remove the global click handler that closes tooltips // This keeps the popup always visible, even when clicking outside the timeline - + // Keeping the dependency array to avoid linting errors return () => {}; }, [selectedSegmentId, showEmptySpaceTooltip, isPlayingSegment]); @@ -874,38 +874,38 @@ const TimelineControls = ({ const leftHandle = leftHandleRef.current; const rightHandle = rightHandleRef.current; const timeline = timelineRef.current; - + if (!leftHandle || !rightHandle || !timeline) return; const initDrag = (isLeft: boolean) => (e: MouseEvent) => { e.preventDefault(); - + const timelineRect = timeline.getBoundingClientRect(); let isDragging = true; let finalTime = isLeft ? trimStart : trimEnd; // Track the final time for history recording - + // Use custom events to indicate drag state const createCustomEvent = (type: string) => { return new CustomEvent('trim-handle-event', { detail: { type, isStart: isLeft } }); }; - + // Dispatch start drag event to signal not to record history during drag document.dispatchEvent(createCustomEvent('drag-start')); - + const onMouseMove = (moveEvent: MouseEvent) => { if (!isDragging) return; - + const timelineWidth = timelineRect.width; const position = Math.max(0, Math.min(1, (moveEvent.clientX - timelineRect.left) / timelineWidth)); const newTime = position * duration; - + // Store position globally for iOS Safari if (typeof window !== 'undefined') { window.lastSeekedPosition = newTime; } - + if (isLeft) { if (newTime < trimEnd) { // Don't record in history during drag - this avoids multiple history entries @@ -929,7 +929,7 @@ const TimelineControls = ({ isDragging = false; document.removeEventListener('mousemove', onMouseMove); document.removeEventListener('mouseup', onMouseUp); - + // Now record the final position in history with action type if (isLeft) { // Final update with history recording @@ -951,7 +951,7 @@ const TimelineControls = ({ } })); } - + // Dispatch end drag event document.dispatchEvent(createCustomEvent('drag-end')); }; @@ -973,21 +973,21 @@ const TimelineControls = ({ const renderThumbnails = () => { // Create thumbnail sections even if we don't have actual thumbnail data const numSections = thumbnails.length || 10; // Default to 10 sections if no thumbnails - + return Array.from({ length: numSections }).map((_, index) => { const segmentDuration = duration / numSections; const segmentStartTime = index * segmentDuration; const segmentEndTime = segmentStartTime + segmentDuration; const midpointTime = (segmentStartTime + segmentEndTime) / 2; - + // Get a solid color based on the segment position const backgroundColor = generateSolidColor(midpointTime, duration); - + return ( -
{ const pointPercent = (point / duration) * 100; return ( -
{ // Always return at least 0.1 seconds to ensure tooltip shows const MIN_SPACE = 0.1; - + // Determine the amount of available space: // 1. Check remaining space until the end of video const remainingDuration = Math.max(0, duration - startTime); - + // 2. Find the next segment (if any) const sortedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime); - + // Find the next and previous segments const nextSegment = sortedSegments.find(seg => seg.startTime > startTime); const prevSegment = [...sortedSegments].reverse().find(seg => seg.endTime < startTime); - + // Calculate the actual available space let availableSpace; if (nextSegment) { @@ -1036,7 +1036,7 @@ const TimelineControls = ({ // Space until end of video availableSpace = duration - startTime; } - + // Log the space calculation for debugging logger.debug("Space calculation:", { position: formatDetailedTime(startTime), @@ -1044,7 +1044,7 @@ const TimelineControls = ({ prevSegment: prevSegment ? formatDetailedTime(prevSegment.endTime) : "none", availableSpace: formatDetailedTime(Math.max(MIN_SPACE, availableSpace)) }); - + // Always return at least MIN_SPACE to ensure tooltip shows return Math.max(MIN_SPACE, availableSpace); }; @@ -1115,21 +1115,21 @@ const TimelineControls = ({ if (isPlayingSegments) return; if (!timelineRef.current || !scrollContainerRef.current) return; - + // If on mobile device and video hasn't been initialized, don't handle timeline clicks if (isIOSUninitialized) { return; } - + // Check if video is globally playing before the click const wasPlaying = videoRef.current && !videoRef.current.paused; logger.debug("Video was playing before timeline click:", wasPlaying); - + // Reset continuation flag when clicking on timeline - ensures proper boundary detection setContinuePastBoundary(false); - + const rect = timelineRef.current.getBoundingClientRect(); - + // Account for scroll position when calculating the click position let position; if (zoomLevel > 1) { @@ -1141,25 +1141,25 @@ const TimelineControls = ({ // Normal calculation for 1x zoom position = (e.clientX - rect.left) / rect.width; } - + const newTime = position * duration; - + // Log the position for debugging - logger.debug("Timeline clicked at:", formatDetailedTime(newTime), + logger.debug("Timeline clicked at:", formatDetailedTime(newTime), "distance from end:", formatDetailedTime(duration - newTime)); - + // Store position globally for iOS Safari (this is critical for first-time visits) if (typeof window !== 'undefined') { window.lastSeekedPosition = newTime; } - + // Seek to the clicked position immediately for all clicks onSeek(newTime); - + // Always update both clicked time and display time for tooltip actions setClickedTime(newTime); setDisplayTime(newTime); - + // Find if we clicked in a segment with a small tolerance for boundaries const segmentAtClickedTime = clipSegments.find(seg => { // Standard check for being inside a segment @@ -1167,15 +1167,15 @@ const TimelineControls = ({ // Additional checks for being exactly at the start or end boundary (with small tolerance) const isAtStart = Math.abs(newTime - seg.startTime) < 0.01; const isAtEnd = Math.abs(newTime - seg.endTime) < 0.01; - + return isInside || isAtStart || isAtEnd; }); - + // Handle active segment assignment for boundary checking if (segmentAtClickedTime) { setActiveSegment(segmentAtClickedTime); } - + // Resume playback in two cases: // 1. If it was playing before (regular playback) // 2. If we're in preview mode (regardless of previous playing state) @@ -1191,7 +1191,7 @@ const TimelineControls = ({ setIsPlayingSegment(false); }); } - + // Only process tooltip display if clicked on the timeline background or thumbnails, not on other UI elements if (e.target === timelineRef.current || (e.target as HTMLElement).classList.contains('timeline-thumbnail')) { // Check if there's a segment at the clicked position @@ -1201,11 +1201,11 @@ const TimelineControls = ({ } else { // We're in a cutaway area - always show tooltip setSelectedSegmentId(null); - + // Calculate the available space for a new segment const availableSpace = calculateAvailableSpace(newTime); setAvailableSegmentDuration(availableSpace); - + // Calculate and set tooltip position correctly for zoomed timeline let xPos; if (zoomLevel > 1) { @@ -1217,20 +1217,20 @@ const TimelineControls = ({ // For 1x zoom, use the client X xPos = e.clientX; } - - setTooltipPosition({ - x: xPos, + + setTooltipPosition({ + x: xPos, y: rect.top - 10 // Position tooltip above the timeline }); - + // Always show the empty space tooltip in cutaway areas setShowEmptySpaceTooltip(true); - + // Log the cutaway area details const sortedSegments = [...clipSegments].sort((a, b) => a.startTime - b.startTime); const prevSegment = [...sortedSegments].reverse().find(seg => seg.endTime < newTime); const nextSegment = sortedSegments.find(seg => seg.startTime > newTime); - + logger.debug("Clicked in cutaway area:", { position: formatDetailedTime(newTime), availableSpace: formatDetailedTime(availableSpace), @@ -1240,7 +1240,7 @@ const TimelineControls = ({ } } }; - + // Handle segment resize - works with both mouse and touch events const handleSegmentResize = (segmentId: number, isLeft: boolean) => (e: React.MouseEvent | React.TouchEvent) => { // Prevent interaction if segments are playing @@ -1248,25 +1248,25 @@ const TimelineControls = ({ e.preventDefault(); e.stopPropagation(); // Prevent triggering parent's events - + if (!timelineRef.current) return; - + const timelineRect = timelineRef.current.getBoundingClientRect(); const timelineWidth = timelineRect.width; - + // Find the segment that's being resized const segment = clipSegments.find(seg => seg.id === segmentId); if (!segment) return; - + const originalStartTime = segment.startTime; const originalEndTime = segment.endTime; - + // Store the original segment state to compare after dragging const segmentBeforeDrag = {...segment}; - + // Add a visual indicator that we're in resize mode (for mouse devices) document.body.style.cursor = 'ew-resize'; - + // Add a temporary overlay to help with dragging outside the element const overlay = document.createElement('div'); overlay.style.position = 'fixed'; @@ -1277,22 +1277,22 @@ const TimelineControls = ({ overlay.style.zIndex = '1000'; overlay.style.cursor = 'ew-resize'; document.body.appendChild(overlay); - + // Track dragging state and final positions let isDragging = true; let finalStartTime = originalStartTime; let finalEndTime = originalEndTime; - + // Dispatch an event to signal drag start document.dispatchEvent(new CustomEvent('segment-drag-start', { detail: { segmentId } })); - + // Keep the tooltip visible during drag // Function to handle both mouse and touch movements const handleDragMove = (clientX: number) => { if (!isDragging || !timelineRef.current) return; - + const updatedTimelineRect = timelineRef.current.getBoundingClientRect(); const position = Math.max(0, Math.min(1, (clientX - updatedTimelineRect.left) / updatedTimelineRect.width)); const newTime = position * duration; @@ -1305,7 +1305,7 @@ const TimelineControls = ({ name: '', thumbnail: '' }; - + // Check if the current marker position intersects with where the segment will be const currentSegmentStart = isLeft ? newTime : originalStartTime; const currentSegmentEnd = isLeft ? originalEndTime : newTime; @@ -1327,63 +1327,63 @@ const TimelineControls = ({ // Find neighboring segments (exclude the current one) const otherSegments = clipSegments.filter(seg => seg.id !== segmentId); - + // Calculate new start/end times based on drag direction let newStartTime = originalStartTime; let newEndTime = originalEndTime; - + if (isLeft) { // Dragging left handle - adjust start time newStartTime = Math.min(newTime, originalEndTime - 0.5); - + // Find the closest left neighbor const leftNeighbors = otherSegments .filter(seg => seg.endTime <= originalStartTime) .sort((a, b) => b.endTime - a.endTime); - + const leftNeighbor = leftNeighbors[0]; - + // Prevent overlapping with left neighbor if (leftNeighbor && newStartTime < leftNeighbor.endTime) { newStartTime = leftNeighbor.endTime; } - + // Snap to the nearest segment with a small threshold const snapThreshold = 0.3; // seconds - + if (leftNeighbor && Math.abs(newStartTime - leftNeighbor.endTime) < snapThreshold) { newStartTime = leftNeighbor.endTime; } - + // Update final value for history recording finalStartTime = newStartTime; } else { // Dragging right handle - adjust end time newEndTime = Math.max(newTime, originalStartTime + 0.5); - + // Find the closest right neighbor const rightNeighbors = otherSegments .filter(seg => seg.startTime >= originalEndTime) .sort((a, b) => a.startTime - b.startTime); - + const rightNeighbor = rightNeighbors[0]; - + // Prevent overlapping with right neighbor if (rightNeighbor && newEndTime > rightNeighbor.startTime) { newEndTime = rightNeighbor.startTime; } - + // Snap to the nearest segment with a small threshold const snapThreshold = 0.3; // seconds - + if (rightNeighbor && Math.abs(newEndTime - rightNeighbor.startTime) < snapThreshold) { newEndTime = rightNeighbor.startTime; } - + // Update final value for history recording finalEndTime = newEndTime; } - + // Create a new segments array with the updated segment const updatedSegments = clipSegments.map(seg => { if (seg.id === segmentId) { @@ -1395,28 +1395,28 @@ const TimelineControls = ({ } return seg; }); - + // Create a custom event to update the segments WITHOUT recording in history during drag - const updateEvent = new CustomEvent('update-segments', { - detail: { + const updateEvent = new CustomEvent('update-segments', { + detail: { segments: updatedSegments, recordHistory: false // Don't record intermediate states - } + } }); document.dispatchEvent(updateEvent); - + // During dragging, check if the current tooltip needs to be updated based on segment position if (selectedSegmentId === segmentId && videoRef.current) { const currentTime = videoRef.current.currentTime; const segment = updatedSegments.find(seg => seg.id === segmentId); - + if (segment) { // Check if playhead position is now outside the segment after dragging const isInsideSegment = currentTime >= segment.startTime && currentTime <= segment.endTime; - + // Log the current position information for debugging logger.debug(`During drag - playhead at ${formatDetailedTime(currentTime)} is ${isInsideSegment ? 'inside' : 'outside'} segment (${formatDetailedTime(segment.startTime)} - ${formatDetailedTime(segment.endTime)})`); - + if (!isInsideSegment && isPlayingSegment) { logger.debug("Playhead position is outside segment after dragging - updating tooltip"); // Stop playback if we were playing and dragged the segment away from playhead @@ -1424,44 +1424,44 @@ const TimelineControls = ({ setIsPlayingSegment(false); setActiveSegment(null); } - + // Update display time to stay in bounds of the segment if (currentTime < segment.startTime) { logger.debug(`Adjusting display time to segment start: ${formatDetailedTime(segment.startTime)}`); setDisplayTime(segment.startTime); - + // Update UI state to reflect that playback will be from segment start setClickedTime(segment.startTime); } else if (currentTime > segment.endTime) { logger.debug(`Adjusting display time to segment end: ${formatDetailedTime(segment.endTime)}`); setDisplayTime(segment.endTime); - + // Update UI state to reflect that playback will be from segment end setClickedTime(segment.endTime); } } } }; - + // Function to handle the end of dragging (for both mouse and touch) const handleDragEnd = () => { if (!isDragging) return; - + isDragging = false; - + // Clean up event listeners for both mouse and touch document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); document.removeEventListener('touchmove', handleTouchMove); document.removeEventListener('touchend', handleTouchEnd); document.removeEventListener('touchcancel', handleTouchEnd); - + // Reset styles document.body.style.cursor = ''; if (document.body.contains(overlay)) { document.body.removeChild(overlay); } - + // Record the final position in history as a single action const finalSegments = clipSegments.map(seg => { if (seg.id === segmentId) { @@ -1473,32 +1473,32 @@ const TimelineControls = ({ } return seg; }); - + // Now we can create a history record for the complete drag operation const actionType = isLeft ? 'adjust_segment_start' : 'adjust_segment_end'; - document.dispatchEvent(new CustomEvent('update-segments', { - detail: { + document.dispatchEvent(new CustomEvent('update-segments', { + detail: { segments: finalSegments, recordHistory: true, action: actionType - } + } })); - + // After drag is complete, do a final check to see if playhead is inside the segment if (selectedSegmentId === segmentId && videoRef.current) { const currentTime = videoRef.current.currentTime; const segment = finalSegments.find(seg => seg.id === segmentId); - + if (segment) { const isInsideSegment = currentTime >= segment.startTime && currentTime <= segment.endTime; - + logger.debug(`Drag complete - playhead at ${formatDetailedTime(currentTime)} is ${isInsideSegment ? 'inside' : 'outside'} segment (${formatDetailedTime(segment.startTime)} - ${formatDetailedTime(segment.endTime)})`); - + // Check if playhead status changed during drag const wasInsideSegmentBefore = currentTime >= segmentBeforeDrag.startTime && currentTime <= segmentBeforeDrag.endTime; - + logger.debug(`Playhead was ${wasInsideSegmentBefore ? 'inside' : 'outside'} segment before drag, now ${isInsideSegment ? 'inside' : 'outside'}`); - + // Update UI elements based on segment position if (!isInsideSegment) { // If we were playing and the playhead is now outside the segment, stop playback @@ -1509,7 +1509,7 @@ const TimelineControls = ({ setContinuePastBoundary(false); logger.debug("Stopped playback because playhead is outside segment after drag completion"); } - + // Update display time to be within the segment's bounds if (currentTime < segment.startTime) { logger.debug(`Final adjustment - setting display time to segment start: ${formatDetailedTime(segment.startTime)}`); @@ -1520,7 +1520,7 @@ const TimelineControls = ({ setDisplayTime(segment.endTime); setClickedTime(segment.endTime); } - } + } // Special case: playhead was outside segment before, but now it's inside - can start playback else if (!wasInsideSegmentBefore && isInsideSegment) { logger.debug("Playhead moved INTO segment during drag - can start playback"); @@ -1538,7 +1538,7 @@ const TimelineControls = ({ } } // Another special case: playhead was inside segment before, but now is also inside but at a different position - else if (wasInsideSegmentBefore && isInsideSegment && + else if (wasInsideSegmentBefore && isInsideSegment && (segment.startTime !== segmentBeforeDrag.startTime || segment.endTime !== segmentBeforeDrag.endTime)) { logger.debug("Segment boundaries changed while playhead remained inside - updating activeSegment"); // Update the active segment reference to ensure boundary detection works with new bounds @@ -1547,16 +1547,16 @@ const TimelineControls = ({ } } }; - + // Mouse-specific event handlers const handleMouseMove = (moveEvent: MouseEvent) => { handleDragMove(moveEvent.clientX); }; - + const handleMouseUp = () => { handleDragEnd(); }; - + // Touch-specific event handlers const handleTouchMove = (moveEvent: TouchEvent) => { if (moveEvent.touches.length > 0) { @@ -1564,11 +1564,11 @@ const TimelineControls = ({ handleDragMove(moveEvent.touches[0].clientX); } }; - + const handleTouchEnd = () => { handleDragEnd(); }; - + // Register event listeners for both mouse and touch document.addEventListener('mousemove', handleMouseMove, { passive: false }); document.addEventListener('mouseup', handleMouseUp); @@ -1576,7 +1576,7 @@ const TimelineControls = ({ document.addEventListener('touchend', handleTouchEnd); document.addEventListener('touchcancel', handleTouchEnd); }; - + // Handle segment click to show the tooltip const handleSegmentClick = (segmentId: number) => (e: React.MouseEvent) => { // Prevent interaction if segments are playing @@ -1586,53 +1586,53 @@ const TimelineControls = ({ if ((e.target as HTMLElement).classList.contains('clip-segment-handle')) { return; } - + e.preventDefault(); e.stopPropagation(); - + logger.debug("Segment clicked:", segmentId); - + // Reset continuation flag when selecting a segment - ensures proper boundary detection setContinuePastBoundary(false); - + // Check if video is currently playing before clicking const wasPlaying = videoRef.current && !videoRef.current.paused; logger.debug("seekVideo: Was playing before:", wasPlaying); - + // Set the current segment as selected setSelectedSegmentId(segmentId); - + // Find the segment in our data const segment = clipSegments.find(seg => seg.id === segmentId); if (!segment) return; - + // Find the segment element in the DOM const segmentElement = e.currentTarget as HTMLElement; const segmentRect = segmentElement.getBoundingClientRect(); - + // Calculate relative click position within the segment (0 to 1) const relativeX = (e.clientX - segmentRect.left) / segmentRect.width; - + // Convert to time based on segment's start and end times const clickTime = segment.startTime + (relativeX * (segment.endTime - segment.startTime)); - + // Ensure time is within segment bounds const boundedTime = Math.max(segment.startTime, Math.min(segment.endTime, clickTime)); - + // Set both clicked time and display time for UI setClickedTime(boundedTime); setDisplayTime(boundedTime); - + // Check if the video's current time is inside or outside the segment // This helps with updating the tooltip correctly after dragging operations if (videoRef.current) { const currentVideoTime = videoRef.current.currentTime; - const isPlayheadInsideSegment = - currentVideoTime >= segment.startTime && + const isPlayheadInsideSegment = + currentVideoTime >= segment.startTime && currentVideoTime <= segment.endTime; - + logger.debug(`Segment click - playhead at ${formatDetailedTime(currentVideoTime)} is ${isPlayheadInsideSegment ? 'inside' : 'outside'} segment (${formatDetailedTime(segment.startTime)} - ${formatDetailedTime(segment.endTime)})`); - + // If playhead is outside the segment, update the display time to segment boundary if (!isPlayheadInsideSegment) { // Adjust the display time based on which end is closer to the playhead @@ -1649,10 +1649,10 @@ const TimelineControls = ({ } } } - + // Seek to this position (this will update the video's current time) onSeek(boundedTime); - + // If video was playing before OR we're in preview mode, ensure it continues playing if ((wasPlaying || isPreviewMode) && videoRef.current) { // Set current segment as active segment for boundary checking @@ -1669,7 +1669,7 @@ const TimelineControls = ({ console.error("Error resuming playback after segment click:", err); }); } - + // Always continue playback in preview mode, even if video was paused when clicking if (isPreviewMode && videoRef.current) { setActiveSegment(segment); @@ -1682,34 +1682,34 @@ const TimelineControls = ({ console.error("Error continuing preview playback:", err); }); } - + // Calculate tooltip position directly above click point const tooltipX = e.clientX; const tooltipY = segmentRect.top - 10; - + setTooltipPosition({ x: tooltipX, y: tooltipY }); - + // Auto-scroll to center the clicked position for zoomed timeline if (zoomLevel > 1 && timelineRef.current && scrollContainerRef.current) { const timelineRect = timelineRef.current.getBoundingClientRect(); const timelineWidth = timelineRef.current.clientWidth; const containerWidth = scrollContainerRef.current.clientWidth; - + // Calculate pixel position of clicked time const clickedPosPixel = (boundedTime / duration) * timelineWidth; - + // Center the view on the clicked position const targetScrollLeft = Math.max(0, clickedPosPixel - (containerWidth / 2)); - + // Smooth scroll to the clicked point scrollContainerRef.current.scrollTo({ left: targetScrollLeft, behavior: 'smooth' }); - + // Update tooltip position after scrolling completes setTimeout(() => { if (timelineRef.current && scrollContainerRef.current) { @@ -1717,7 +1717,7 @@ const TimelineControls = ({ const updatedRect = timelineRef.current.getBoundingClientRect(); const timePercent = boundedTime / duration; const newPosition = (timePercent * timelineWidth) - scrollContainerRef.current.scrollLeft + updatedRect.left; - + setTooltipPosition({ x: newPosition, y: tooltipY @@ -1725,31 +1725,31 @@ const TimelineControls = ({ } }, 300); // Wait for smooth scrolling to complete } - + // We no longer need a local click handler as we have a global one // that handles closing tooltips when clicking outside }; - + // Show tooltip for the segment const setShowTooltip = (show: boolean, segmentId: number, x: number, y: number) => { setSelectedSegmentId(show ? segmentId : null); setTooltipPosition({ x, y }); }; - + // Render the clip segments on the timeline const renderClipSegments = () => { return clipSegments.map((segment, index) => { const startPercent = (segment.startTime / duration) * 100; const widthPercent = ((segment.endTime - segment.startTime) / duration) * 100; - + // Generate a solid background color based on segment position const backgroundColor = generateSolidColor( - (segment.startTime + segment.endTime) / 2, + (segment.startTime + segment.endTime) / 2, duration ); - + return ( -
{formatTime(segment.startTime)} - {formatTime(segment.endTime)}
Duration: {formatTime(segment.endTime - segment.startTime)}
- + {/* Resize handles with both mouse and touch support */} -
{ @@ -1781,7 +1781,7 @@ const TimelineControls = ({ handleSegmentResize(segment.id, true)(e); }} >
-
{ @@ -1802,7 +1802,7 @@ const TimelineControls = ({ useEffect(() => { const handleSegmentDelete = (event: CustomEvent) => { const { segmentId } = event.detail; - + // Check if this was the last segment before deletion const remainingSegments = clipSegments.filter(seg => seg.id !== segmentId); if (remainingSegments.length === 0) { @@ -1814,35 +1814,35 @@ const TimelineControls = ({ endTime: duration, thumbnail: '' }; - + // Create and dispatch the update event to replace all segments with the full video segment - const updateEvent = new CustomEvent('update-segments', { - detail: { + const updateEvent = new CustomEvent('update-segments', { + detail: { segments: [fullVideoSegment], recordHistory: true, action: 'create_full_video_segment' - } + } }); document.dispatchEvent(updateEvent); - + // Update UI to show the segment tooltip setSelectedSegmentId(fullVideoSegment.id); setShowEmptySpaceTooltip(false); setClickedTime(currentTime); setDisplayTime(currentTime); setActiveSegment(fullVideoSegment); - + // Calculate tooltip position at current time if (timelineRef.current) { const rect = timelineRef.current.getBoundingClientRect(); const posPercent = (currentTime / duration) * 100; const xPosition = rect.left + (rect.width * (posPercent / 100)); - + setTooltipPosition({ x: xPosition, y: rect.top - 10 }); - + logger.debug("Created full video segment:", { id: fullVideoSegment.id, duration: formatDetailedTime(duration), @@ -1853,26 +1853,26 @@ const TimelineControls = ({ // Handle normal segment deletion const deletedSegment = clipSegments.find(seg => seg.id === segmentId); if (!deletedSegment) return; - + // Calculate available space after deletion const availableSpace = calculateAvailableSpace(currentTime); - + // Update UI to show cutaway tooltip setSelectedSegmentId(null); setShowEmptySpaceTooltip(true); setAvailableSegmentDuration(availableSpace); - + // Calculate tooltip position if (timelineRef.current) { const rect = timelineRef.current.getBoundingClientRect(); const posPercent = (currentTime / duration) * 100; const xPosition = rect.left + (rect.width * (posPercent / 100)); - + setTooltipPosition({ x: xPosition, y: rect.top - 10 }); - + logger.debug("Segment deleted, showing cutaway tooltip:", { position: formatDetailedTime(currentTime), availableSpace: formatDetailedTime(availableSpace) @@ -1880,10 +1880,10 @@ const TimelineControls = ({ } } }; - + // Add event listener for the custom delete-segment event document.addEventListener('delete-segment', handleSegmentDelete as EventListener); - + // Clean up event listener on component unmount return () => { document.removeEventListener('delete-segment', handleSegmentDelete as EventListener); @@ -1894,21 +1894,21 @@ const TimelineControls = ({ useEffect(() => { const video = videoRef.current; if (!video) return; - + const handlePlay = () => { if (!videoRef.current) return; - + const video = videoRef.current; const currentPosition = video.currentTime; - + // Reset continuePastBoundary flag when starting new playback setContinuePastBoundary(false); - + // Find the next stopping point based on current position let stopTime = duration; let currentSegment = null; let nextSegment = null; - + // First, check if we're inside a segment with high precision currentSegment = clipSegments.find(seg => { const isWithinSegment = currentPosition >= seg.startTime && currentPosition <= seg.endTime; @@ -1916,7 +1916,7 @@ const TimelineControls = ({ const isAtExactEnd = Math.abs(currentPosition - seg.endTime) < 0.001; // Within 1ms of end return isWithinSegment || isAtExactStart || isAtExactEnd; }); - + // Find the next segment with high precision nextSegment = clipSegments .filter(seg => { @@ -1925,7 +1925,7 @@ const TimelineControls = ({ return isAfterCurrent && isNotAtExactPosition; }) .sort((a, b) => a.startTime - b.startTime)[0]; - + // Determine where to stop based on position if (currentSegment) { // If we're in a segment, stop at its end @@ -1936,42 +1936,42 @@ const TimelineControls = ({ stopTime = nextSegment.startTime; // Don't set active segment since we're in a cutaway } - + // Create a boundary checker function with high precision const checkBoundary = () => { if (!video) return; - + const currentPosition = video.currentTime; const timeLeft = stopTime - currentPosition; - + // If we're approaching the boundary (within 1ms) or have passed it if (timeLeft <= 0.001 || currentPosition >= stopTime) { // First pause playback video.pause(); - + // Force exact position with multiple verification attempts const setExactPosition = () => { if (!video) return; - + // Set to exact boundary time video.currentTime = stopTime; onSeek(stopTime); setDisplayTime(stopTime); setClickedTime(stopTime); - + logger.debug("Position verification:", { target: formatDetailedTime(stopTime), actual: formatDetailedTime(video.currentTime), difference: Math.abs(video.currentTime - stopTime).toFixed(3) }); }; - + // Multiple attempts to ensure precision setExactPosition(); setTimeout(setExactPosition, 10); setTimeout(setExactPosition, 20); setTimeout(setExactPosition, 50); - + // Update UI based on where we stopped if (currentSegment) { setSelectedSegmentId(currentSegment.id); @@ -1985,7 +1985,7 @@ const TimelineControls = ({ setShowEmptySpaceTooltip(true); setActiveSegment(null); } - + // Remove our boundary checker video.removeEventListener('timeupdate', checkBoundary); setIsPlaying(false); @@ -1995,10 +1995,10 @@ const TimelineControls = ({ return; } }; - + // Start our boundary checker video.addEventListener('timeupdate', checkBoundary); - + // Start playing video.play() .then(() => { @@ -2015,15 +2015,15 @@ const TimelineControls = ({ console.error("Error playing video:", err); }); }; - + const handlePause = () => { logger.debug("Video paused from external control"); setIsPlayingSegment(false); }; - + video.addEventListener('play', handlePlay); video.addEventListener('pause', handlePause); - + return () => { video.removeEventListener('play', handlePlay); video.removeEventListener('pause', handlePause); @@ -2033,14 +2033,14 @@ const TimelineControls = ({ // Handle mouse movement over timeline to remember position const handleTimelineMouseMove = (e: React.MouseEvent) => { if (!timelineRef.current) return; - + const rect = timelineRef.current.getBoundingClientRect(); const position = (e.clientX - rect.left) / rect.width; const time = position * duration; - + // Ensure time is within bounds const boundedTime = Math.max(0, Math.min(duration, time)); - + // Store position globally for iOS Safari if (typeof window !== 'undefined') { window.lastSeekedPosition = boundedTime; @@ -2060,24 +2060,24 @@ const TimelineControls = ({ if (isIOSUninitialized) { return; } - + e.stopPropagation(); // Don't trigger the timeline click e.preventDefault(); // Prevent text selection during drag - + setIsDragging(true); isDraggingRef.current = true; // Use ref for immediate value access - + // Show tooltip immediately when starting to drag updateTooltipForPosition(currentTime); - + // Handle mouse events const handleMouseMove = (moveEvent: MouseEvent) => { if (!timelineRef.current || !scrollContainerRef.current) return; - + // Calculate the position based on mouse or touch coordinates const rect = timelineRef.current.getBoundingClientRect(); let position; - + if (zoomLevel > 1) { // When zoomed, account for scroll position const scrollLeft = scrollContainerRef.current.scrollLeft; @@ -2087,29 +2087,29 @@ const TimelineControls = ({ // Normal calculation for 1x zoom position = (moveEvent.clientX - rect.left) / rect.width; } - + // Constrain position between 0 and 1 position = Math.max(0, Math.min(1, position)); - + // Convert to time and seek const newTime = position * duration; - + // Update both clicked time and display time setClickedTime(newTime); setDisplayTime(newTime); - + // Update tooltip state based on new position updateTooltipForPosition(newTime); - + // Store position globally for iOS Safari if (typeof window !== 'undefined') { (window as any).lastSeekedPosition = newTime; } - + // Seek to the new position onSeek(newTime); }; - + // Handle mouse up to stop dragging const handleMouseUp = () => { setIsDragging(false); @@ -2117,7 +2117,7 @@ const TimelineControls = ({ document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }; - + // Add event listeners to track movement and release document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); @@ -2129,24 +2129,24 @@ const TimelineControls = ({ if (isIOSUninitialized) { return; } - + e.stopPropagation(); // Don't trigger the timeline click e.preventDefault(); // Prevent text selection during drag - + setIsDragging(true); isDraggingRef.current = true; // Use ref for immediate value access - + // Show tooltip immediately when starting to drag updateTooltipForPosition(currentTime); - + // Handle touch move events const handleTouchMove = (moveEvent: TouchEvent) => { if (!timelineRef.current || !scrollContainerRef.current || !moveEvent.touches[0]) return; - + // Calculate the position based on touch coordinates const rect = timelineRef.current.getBoundingClientRect(); let position; - + if (zoomLevel > 1) { // When zoomed, account for scroll position const scrollLeft = scrollContainerRef.current.scrollLeft; @@ -2156,29 +2156,29 @@ const TimelineControls = ({ // Normal calculation for 1x zoom position = (moveEvent.touches[0].clientX - rect.left) / rect.width; } - + // Constrain position between 0 and 1 position = Math.max(0, Math.min(1, position)); - + // Convert to time and seek const newTime = position * duration; - + // Update both clicked time and display time setClickedTime(newTime); setDisplayTime(newTime); - + // Update tooltip state based on new position updateTooltipForPosition(newTime); - + // Store position globally for mobile browsers if (typeof window !== 'undefined') { (window as any).lastSeekedPosition = newTime; } - + // Seek to the new position onSeek(newTime); }; - + // Handle touch end to stop dragging const handleTouchEnd = () => { setIsDragging(false); @@ -2187,7 +2187,7 @@ const TimelineControls = ({ document.removeEventListener('touchend', handleTouchEnd); document.removeEventListener('touchcancel', handleTouchEnd); }; - + // Add event listeners to track movement and release document.addEventListener('touchmove', handleTouchMove, { passive: false }); document.addEventListener('touchend', handleTouchEnd); @@ -2209,11 +2209,11 @@ const TimelineControls = ({ useEffect(() => { let countdownInterval: NodeJS.Timeout; let redirectTimeout: NodeJS.Timeout; - + if (showSuccessModal && redirectUrl) { // Start countdown timer let secondsLeft = 10; - + // Update the countdown every second countdownInterval = setInterval(() => { secondsLeft--; @@ -2221,23 +2221,23 @@ const TimelineControls = ({ if (countdownElement) { countdownElement.textContent = secondsLeft.toString(); } - + if (secondsLeft <= 0) { clearInterval(countdownInterval); } }, 1000); - + // Set redirect timeout redirectTimeout = setTimeout(() => { // Reset unsaved changes flag before navigating away if (onSave) onSave(); - + // Redirect to the URL logger.debug('Automatically redirecting to:', redirectUrl); window.location.href = redirectUrl; }, 10000); // 10 seconds } - + // Cleanup on unmount or when success modal closes return () => { if (countdownInterval) clearInterval(countdownInterval); @@ -2257,43 +2257,43 @@ const TimelineControls = ({ Total Segments: {formatDetailedTime(clipSegments.reduce((sum, segment) => sum + (segment.endTime - segment.startTime), 0))}
- + {/* Timeline Container with Scrollable Wrapper */} -
1 ? 'auto' : 'hidden' }} > -
{/* Current Position Marker */} -
{/* Top circle for popup toggle */} -
{ // Prevent event propagation to avoid triggering the timeline container click e.stopPropagation(); - + // For ensuring accurate segment detection, refresh clipSegments first // This helps when clicking right after creating a new segment const refreshedSegmentAtCurrentTime = clipSegments.find( seg => currentTime >= seg.startTime && currentTime <= seg.endTime ); - + // Toggle tooltip visibility with a single click if (selectedSegmentId || showEmptySpaceTooltip) { // When tooltip is open and - icon is clicked, simply close the tooltips @@ -2313,9 +2313,9 @@ const TimelineControls = ({ {selectedSegmentId || showEmptySpaceTooltip ? '-' : '+'}
- + {/* Bottom circle for dragging */} -
â‹®
- + {/* Trim Line Markers - hidden when segments exist */} {clipSegments.length === 0 && ( <> -
-
@@ -2341,19 +2341,19 @@ const TimelineControls = ({
)} - + {/* Clip Segments */} {renderClipSegments()} - + {/* Split Points */} {renderSplitPoints()} - + {/* Thumbnails */} {renderThumbnails()} - + {/* Segment Tooltip */} {selectedSegmentId !== null && ( -
{/* First row with time adjustment buttons */}
-
- + {/* Second row with action buttons */}
- - - - {/* */} {/* Play/Pause button for empty space - Same as main play/pause button */} - - - -
)} - + {/* Empty space tooltip - positioned absolutely within timeline container */} {showEmptySpaceTooltip && selectedSegmentId === null && ( -
{/* First row with time adjustment buttons - same as segment tooltip */}
-
- + {/* Second row with action buttons similar to segment tooltip */}
{/* New segment button - Moved to first position */} {availableSegmentDuration >= 0.5 && ( - )} - + {/* Go to start button - play from beginning of cutaway (until next segment) */} - - + {/* Play/Pause button for empty space */} - {/* */} {/* Play/Pause button for empty space - Same as main play/pause button */} - - + {/* Segment end adjustment button (always shown) */} - - + {/* Segment start adjustment button (always shown) */} -
)}
- + {/* Precise Time Navigation & Zoom Controls */}
{/* Precise Time Input */}
Go to Time:
- { @@ -3634,7 +3634,7 @@ const TimelineControls = ({ // Parse time format like "00:30:15.250" or "30:15.250" or "30:15" const parts = input.split(':'); let hours = 0, minutes = 0, seconds = 0, milliseconds = 0; - + if (parts.length === 3) { // Format: HH:MM:SS.ms hours = parseInt(parts[0]); @@ -3649,11 +3649,11 @@ const TimelineControls = ({ seconds = parseInt(secParts[0]); if (secParts.length > 1) milliseconds = parseInt(secParts[1].padEnd(3, '0').substring(0, 3)); } - + const totalSeconds = hours * 3600 + minutes * 60 + seconds + milliseconds / 1000; if (!isNaN(totalSeconds) && totalSeconds >= 0 && totalSeconds <= duration) { onSeek(totalSeconds); - + // Create a helper function to show tooltip that uses the same logic as the millisecond buttons const showTooltipAtTime = (timeInSeconds: number) => { // Find the segment at the given time using improved matching @@ -3663,14 +3663,14 @@ const TimelineControls = ({ const isAtExactEnd = Math.abs(timeInSeconds - seg.endTime) < 0.001; // Within 1ms of end return isWithinSegment || isAtExactStart || isAtExactEnd; }); - + // Calculate position for tooltip if (timelineRef.current && scrollContainerRef.current) { const rect = timelineRef.current.getBoundingClientRect(); - + // Handle zoomed timeline by accounting for scroll position let xPos; - + if (zoomLevel > 1) { // For zoomed timeline, calculate position based on visible area const visibleTimelineLeft = rect.left - scrollContainerRef.current.scrollLeft; @@ -3681,10 +3681,10 @@ const TimelineControls = ({ const positionPercent = (timeInSeconds / duration); xPos = rect.left + (rect.width * positionPercent); } - + setTooltipPosition({ x: xPos, y: rect.top - 10 }); setClickedTime(timeInSeconds); - + if (segmentAtTime) { // Show segment tooltip setSelectedSegmentId(segmentAtTime.id); @@ -3696,7 +3696,7 @@ const TimelineControls = ({ } } }; - + // Show tooltip after a slight delay to ensure UI updates setTimeout(() => showTooltipAtTime(totalSeconds), 10); } @@ -3719,14 +3719,14 @@ const TimelineControls = ({ const isAtExactEnd = Math.abs(currentTime - seg.endTime) < 0.001; // Within 1ms of end return isWithinSegment || isAtExactStart || isAtExactEnd; }); - + // Calculate position for tooltip (above the timeline where the marker is) if (timelineRef.current && scrollContainerRef.current) { const rect = timelineRef.current.getBoundingClientRect(); - + // Handle zoomed timeline by accounting for scroll position let xPos; - + if (zoomLevel > 1) { // For zoomed timeline, calculate position based on visible area const visibleTimelineLeft = rect.left - scrollContainerRef.current.scrollLeft; @@ -3737,10 +3737,10 @@ const TimelineControls = ({ const positionPercent = (currentTime / duration); xPos = rect.left + (rect.width * positionPercent); } - + setTooltipPosition({ x: xPos, y: rect.top - 10 }); setClickedTime(currentTime); - + if (segmentAtCurrentTime) { // Show segment tooltip setSelectedSegmentId(segmentAtCurrentTime.id); @@ -3749,7 +3749,7 @@ const TimelineControls = ({ // Calculate available space for new segment before showing tooltip const availableSpace = calculateAvailableSpace(currentTime); setAvailableSegmentDuration(availableSpace); - + // Only show tooltip if there's enough space for a minimal segment if (availableSpace >= 0.5) { // Show empty space tooltip @@ -3763,10 +3763,10 @@ const TimelineControls = ({ } } }; - + return ( <> - - - -
- + {/* Zoom Dropdown Control and Save Buttons */}
- - + {isZoomDropdownOpen && (
{[1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096].map(level => ( -
{ onZoomChange(level); @@ -3856,15 +3856,15 @@ const TimelineControls = ({ }} > {zoomLevel === level && ( - @@ -3876,11 +3876,11 @@ const TimelineControls = ({
)}
- + {/* Save Buttons Row */}
{onSave && ( - )} - + {onSaveACopy && ( - )} - + {onSaveSegments && ( - )}
- + {/* Save Confirmation Modal */} - - - -
- + {/* Error Modal */}
-
- + {/* Dropdown was moved inside the container element */} - + {/* Mobile Uninitialized Overlay - Show only when on mobile and video hasn't been played yet */} {isIOSUninitialized && (
diff --git a/static/video_editor/video-editor.js b/static/video_editor/video-editor.js index e743e618..8b9b5dcf 100644 --- a/static/video_editor/video-editor.js +++ b/static/video_editor/video-editor.js @@ -6,7 +6,7 @@ * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */(function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var ve="18.3.1",be=Symbol.for("react.element"),pe=Symbol.for("react.portal"),Oe=Symbol.for("react.fragment"),d=Symbol.for("react.strict_mode"),Z=Symbol.for("react.profiler"),Se=Symbol.for("react.provider"),ne=Symbol.for("react.context"),nt=Symbol.for("react.forward_ref"),G=Symbol.for("react.suspense"),N=Symbol.for("react.suspense_list"),ae=Symbol.for("react.memo"),Ue=Symbol.for("react.lazy"),Ft=Symbol.for("react.offscreen"),xt=Symbol.iterator,Rt="@@iterator";function Ge(s){if(s===null||typeof s!="object")return null;var h=xt&&s[xt]||s[Rt];return typeof h=="function"?h:null}var Ce={current:null},mt={transition:null},xe={current:null,isBatchingLegacy:!1,didScheduleLegacyUpdate:!1},et={current:null},B={},kt=null;function tt(s){kt=s}B.setExtraStackFrame=function(s){kt=s},B.getCurrentStack=null,B.getStackAddendum=function(){var s="";kt&&(s+=kt);var h=B.getCurrentStack;return h&&(s+=h()||""),s};var He=!1,J=!1,Ze=!1,X=!1,Ot=!1,Xe={ReactCurrentDispatcher:Ce,ReactCurrentBatchConfig:mt,ReactCurrentOwner:et};Xe.ReactDebugCurrentFrame=B,Xe.ReactCurrentActQueue=xe;function $(s){{for(var h=arguments.length,M=new Array(h>1?h-1:0),O=1;O1?h-1:0),O=1;O1){for(var Wt=Array(jt),qt=0;qt1){for(var ot=Array(qt),nn=0;nn is not supported and will be removed in a future major release. Did you mean to render instead?")),h.Provider},set:function(ge){h.Provider=ge}},_currentValue:{get:function(){return h._currentValue},set:function(ge){h._currentValue=ge}},_currentValue2:{get:function(){return h._currentValue2},set:function(ge){h._currentValue2=ge}},_threadCount:{get:function(){return h._threadCount},set:function(ge){h._threadCount=ge}},Consumer:{get:function(){return M||(M=!0,I("Rendering is not supported and will be removed in a future major release. Did you mean to render instead?")),h.Consumer}},displayName:{get:function(){return h.displayName},set:function(ge){K||($("Setting `displayName` on Context.Consumer has no effect. You should set it directly on the context with Context.displayName = '%s'.",ge),K=!0)}}}),h.Consumer=ke}return h._currentRenderer=null,h._currentRenderer2=null,h}var ya=-1,Kn=0,g=1,F=2;function k(s){if(s._status===ya){var h=s._result,M=h();if(M.then(function(ke){if(s._status===Kn||s._status===ya){var ge=s;ge._status=g,ge._result=ke}},function(ke){if(s._status===Kn||s._status===ya){var ge=s;ge._status=F,ge._result=ke}}),s._status===ya){var O=s;O._status=Kn,O._result=M}}if(s._status===g){var K=s._result;return K===void 0&&I(`lazy: Expected the result of a dynamic import() call. Instead received: %s + */(function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var ve="18.3.1",be=Symbol.for("react.element"),pe=Symbol.for("react.portal"),Oe=Symbol.for("react.fragment"),d=Symbol.for("react.strict_mode"),Z=Symbol.for("react.profiler"),Se=Symbol.for("react.provider"),ne=Symbol.for("react.context"),nt=Symbol.for("react.forward_ref"),G=Symbol.for("react.suspense"),N=Symbol.for("react.suspense_list"),ae=Symbol.for("react.memo"),Ue=Symbol.for("react.lazy"),Vt=Symbol.for("react.offscreen"),xt=Symbol.iterator,Rt="@@iterator";function Ge(s){if(s===null||typeof s!="object")return null;var h=xt&&s[xt]||s[Rt];return typeof h=="function"?h:null}var Ce={current:null},mt={transition:null},xe={current:null,isBatchingLegacy:!1,didScheduleLegacyUpdate:!1},et={current:null},B={},kt=null;function tt(s){kt=s}B.setExtraStackFrame=function(s){kt=s},B.getCurrentStack=null,B.getStackAddendum=function(){var s="";kt&&(s+=kt);var h=B.getCurrentStack;return h&&(s+=h()||""),s};var He=!1,J=!1,Ze=!1,X=!1,Ot=!1,Xe={ReactCurrentDispatcher:Ce,ReactCurrentBatchConfig:mt,ReactCurrentOwner:et};Xe.ReactDebugCurrentFrame=B,Xe.ReactCurrentActQueue=xe;function $(s){{for(var h=arguments.length,M=new Array(h>1?h-1:0),O=1;O1?h-1:0),O=1;O1){for(var Wt=Array(jt),qt=0;qt1){for(var ot=Array(qt),nn=0;nn is not supported and will be removed in a future major release. Did you mean to render instead?")),h.Provider},set:function(ge){h.Provider=ge}},_currentValue:{get:function(){return h._currentValue},set:function(ge){h._currentValue=ge}},_currentValue2:{get:function(){return h._currentValue2},set:function(ge){h._currentValue2=ge}},_threadCount:{get:function(){return h._threadCount},set:function(ge){h._threadCount=ge}},Consumer:{get:function(){return M||(M=!0,I("Rendering is not supported and will be removed in a future major release. Did you mean to render instead?")),h.Consumer}},displayName:{get:function(){return h.displayName},set:function(ge){K||($("Setting `displayName` on Context.Consumer has no effect. You should set it directly on the context with Context.displayName = '%s'.",ge),K=!0)}}}),h.Consumer=ke}return h._currentRenderer=null,h._currentRenderer2=null,h}var ya=-1,Kn=0,g=1,V=2;function k(s){if(s._status===ya){var h=s._result,M=h();if(M.then(function(ke){if(s._status===Kn||s._status===ya){var ge=s;ge._status=g,ge._result=ke}},function(ke){if(s._status===Kn||s._status===ya){var ge=s;ge._status=V,ge._result=ke}}),s._status===ya){var O=s;O._status=Kn,O._result=M}}if(s._status===g){var K=s._result;return K===void 0&&I(`lazy: Expected the result of a dynamic import() call. Instead received: %s Your code should look like: const MyComponent = lazy(() => import('./MyComponent')) @@ -14,11 +14,11 @@ Your code should look like: Did you accidentally put curly braces around the import?`,K),"default"in K||I(`lazy: Expected the result of a dynamic import() call. Instead received: %s Your code should look like: - const MyComponent = lazy(() => import('./MyComponent'))`,K),K.default}else throw s._result}function S(s){var h={_status:ya,_result:s},M={$$typeof:Ue,_payload:h,_init:k};{var O,K;Object.defineProperties(M,{defaultProps:{configurable:!0,get:function(){return O},set:function(ke){I("React.lazy(...): It is not supported to assign `defaultProps` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),O=ke,Object.defineProperty(M,"defaultProps",{enumerable:!0})}},propTypes:{configurable:!0,get:function(){return K},set:function(ke){I("React.lazy(...): It is not supported to assign `propTypes` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),K=ke,Object.defineProperty(M,"propTypes",{enumerable:!0})}}})}return M}function x(s){s!=null&&s.$$typeof===ae?I("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof s!="function"?I("forwardRef requires a render function but was given %s.",s===null?"null":typeof s):s.length!==0&&s.length!==2&&I("forwardRef render functions accept exactly two parameters: props and ref. %s",s.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),s!=null&&(s.defaultProps!=null||s.propTypes!=null)&&I("forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?");var h={$$typeof:nt,render:s};{var M;Object.defineProperty(h,"displayName",{enumerable:!1,configurable:!0,get:function(){return M},set:function(O){M=O,!s.name&&!s.displayName&&(s.displayName=O)}})}return h}var c;c=Symbol.for("react.module.reference");function p(s){return!!(typeof s=="string"||typeof s=="function"||s===Oe||s===Z||Ot||s===d||s===G||s===N||X||s===Ft||He||J||Ze||typeof s=="object"&&s!==null&&(s.$$typeof===Ue||s.$$typeof===ae||s.$$typeof===Se||s.$$typeof===ne||s.$$typeof===nt||s.$$typeof===c||s.getModuleId!==void 0))}function T(s,h){p(s)||I("memo: The first argument must be a component. Instead received: %s",s===null?"null":typeof s);var M={$$typeof:ae,type:s,compare:h===void 0?null:h};{var O;Object.defineProperty(M,"displayName",{enumerable:!1,configurable:!0,get:function(){return O},set:function(K){O=K,!s.name&&!s.displayName&&(s.displayName=K)}})}return M}function R(){var s=Ce.current;return s===null&&I(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: + const MyComponent = lazy(() => import('./MyComponent'))`,K),K.default}else throw s._result}function S(s){var h={_status:ya,_result:s},M={$$typeof:Ue,_payload:h,_init:k};{var O,K;Object.defineProperties(M,{defaultProps:{configurable:!0,get:function(){return O},set:function(ke){I("React.lazy(...): It is not supported to assign `defaultProps` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),O=ke,Object.defineProperty(M,"defaultProps",{enumerable:!0})}},propTypes:{configurable:!0,get:function(){return K},set:function(ke){I("React.lazy(...): It is not supported to assign `propTypes` to a lazy component import. Either specify them where the component is defined, or create a wrapping component around it."),K=ke,Object.defineProperty(M,"propTypes",{enumerable:!0})}}})}return M}function x(s){s!=null&&s.$$typeof===ae?I("forwardRef requires a render function but received a `memo` component. Instead of forwardRef(memo(...)), use memo(forwardRef(...))."):typeof s!="function"?I("forwardRef requires a render function but was given %s.",s===null?"null":typeof s):s.length!==0&&s.length!==2&&I("forwardRef render functions accept exactly two parameters: props and ref. %s",s.length===1?"Did you forget to use the ref parameter?":"Any additional parameter will be undefined."),s!=null&&(s.defaultProps!=null||s.propTypes!=null)&&I("forwardRef render functions do not support propTypes or defaultProps. Did you accidentally pass a React component?");var h={$$typeof:nt,render:s};{var M;Object.defineProperty(h,"displayName",{enumerable:!1,configurable:!0,get:function(){return M},set:function(O){M=O,!s.name&&!s.displayName&&(s.displayName=O)}})}return h}var c;c=Symbol.for("react.module.reference");function p(s){return!!(typeof s=="string"||typeof s=="function"||s===Oe||s===Z||Ot||s===d||s===G||s===N||X||s===Vt||He||J||Ze||typeof s=="object"&&s!==null&&(s.$$typeof===Ue||s.$$typeof===ae||s.$$typeof===Se||s.$$typeof===ne||s.$$typeof===nt||s.$$typeof===c||s.getModuleId!==void 0))}function T(s,h){p(s)||I("memo: The first argument must be a component. Instead received: %s",s===null?"null":typeof s);var M={$$typeof:ae,type:s,compare:h===void 0?null:h};{var O;Object.defineProperty(M,"displayName",{enumerable:!1,configurable:!0,get:function(){return O},set:function(K){O=K,!s.name&&!s.displayName&&(s.displayName=K)}})}return M}function R(){var s=Ce.current;return s===null&&I(`Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app -See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.`),s}function P(s){var h=R();if(s._context!==void 0){var M=s._context;M.Consumer===s?I("Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be removed in a future major release. Did you mean to call useContext(Context) instead?"):M.Provider===s&&I("Calling useContext(Context.Provider) is not supported. Did you mean to call useContext(Context) instead?")}return h.useContext(s)}function re(s){var h=R();return h.useState(s)}function z(s,h,M){var O=R();return O.useReducer(s,h,M)}function ce(s){var h=R();return h.useRef(s)}function ut(s,h){var M=R();return M.useEffect(s,h)}function Le(s,h){var M=R();return M.useInsertionEffect(s,h)}function it(s,h){var M=R();return M.useLayoutEffect(s,h)}function fn(s,h){var M=R();return M.useCallback(s,h)}function _n(s,h){var M=R();return M.useMemo(s,h)}function en(s,h,M){var O=R();return O.useImperativeHandle(s,h,M)}function zt(s,h){{var M=R();return M.useDebugValue(s,h)}}function De(){var s=R();return s.useTransition()}function Dt(s){var h=R();return h.useDeferredValue(s)}function Zn(){var s=R();return s.useId()}function yr(s,h,M){var O=R();return O.useSyncExternalStore(s,h,M)}var Fa=0,Br,ga,ba,$r,gi,dn,_t;function Sa(){}Sa.__reactDisabledLog=!0;function Ta(){{if(Fa===0){Br=console.log,ga=console.info,ba=console.warn,$r=console.error,gi=console.group,dn=console.groupCollapsed,_t=console.groupEnd;var s={configurable:!0,enumerable:!0,value:Sa,writable:!0};Object.defineProperties(console,{info:s,log:s,warn:s,error:s,group:s,groupCollapsed:s,groupEnd:s})}Fa++}}function sa(){{if(Fa--,Fa===0){var s={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:Ke({},s,{value:Br}),info:Ke({},s,{value:ga}),warn:Ke({},s,{value:ba}),error:Ke({},s,{value:$r}),group:Ke({},s,{value:gi}),groupCollapsed:Ke({},s,{value:dn}),groupEnd:Ke({},s,{value:_t})})}Fa<0&&I("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}}var bi=Xe.ReactCurrentDispatcher,Yr;function ao(s,h,M){{if(Yr===void 0)try{throw Error()}catch(K){var O=K.stack.trim().match(/\n( *(at )?)/);Yr=O&&O[1]||""}return` +See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.`),s}function P(s){var h=R();if(s._context!==void 0){var M=s._context;M.Consumer===s?I("Calling useContext(Context.Consumer) is not supported, may cause bugs, and will be removed in a future major release. Did you mean to call useContext(Context) instead?"):M.Provider===s&&I("Calling useContext(Context.Provider) is not supported. Did you mean to call useContext(Context) instead?")}return h.useContext(s)}function re(s){var h=R();return h.useState(s)}function z(s,h,M){var O=R();return O.useReducer(s,h,M)}function ce(s){var h=R();return h.useRef(s)}function ut(s,h){var M=R();return M.useEffect(s,h)}function Le(s,h){var M=R();return M.useInsertionEffect(s,h)}function it(s,h){var M=R();return M.useLayoutEffect(s,h)}function fn(s,h){var M=R();return M.useCallback(s,h)}function _n(s,h){var M=R();return M.useMemo(s,h)}function en(s,h,M){var O=R();return O.useImperativeHandle(s,h,M)}function zt(s,h){{var M=R();return M.useDebugValue(s,h)}}function De(){var s=R();return s.useTransition()}function Dt(s){var h=R();return h.useDeferredValue(s)}function Zn(){var s=R();return s.useId()}function yr(s,h,M){var O=R();return O.useSyncExternalStore(s,h,M)}var Va=0,Br,ga,ba,$r,gi,dn,_t;function Sa(){}Sa.__reactDisabledLog=!0;function Ta(){{if(Va===0){Br=console.log,ga=console.info,ba=console.warn,$r=console.error,gi=console.group,dn=console.groupCollapsed,_t=console.groupEnd;var s={configurable:!0,enumerable:!0,value:Sa,writable:!0};Object.defineProperties(console,{info:s,log:s,warn:s,error:s,group:s,groupCollapsed:s,groupEnd:s})}Va++}}function sa(){{if(Va--,Va===0){var s={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:Ke({},s,{value:Br}),info:Ke({},s,{value:ga}),warn:Ke({},s,{value:ba}),error:Ke({},s,{value:$r}),group:Ke({},s,{value:gi}),groupCollapsed:Ke({},s,{value:dn}),groupEnd:Ke({},s,{value:_t})})}Va<0&&I("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}}var bi=Xe.ReactCurrentDispatcher,Yr;function ao(s,h,M){{if(Yr===void 0)try{throw Error()}catch(K){var O=K.stack.trim().match(/\n( *(at )?)/);Yr=O&&O[1]||""}return` `+Yr+s}}var Si=!1,ro;{var ol=typeof WeakMap=="function"?WeakMap:Map;ro=new ol}function Yu(s,h){if(!s||Si)return"";{var M=ro.get(s);if(M!==void 0)return M}var O;Si=!0;var K=Error.prepareStackTrace;Error.prepareStackTrace=void 0;var ke;ke=bi.current,bi.current=null,Ta();try{if(h){var ge=function(){throw Error()};if(Object.defineProperty(ge.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(ge,[])}catch(vn){O=vn}Reflect.construct(s,[],ge)}else{try{ge.call()}catch(vn){O=vn}s.call(ge.prototype)}}else{try{throw Error()}catch(vn){O=vn}s()}}catch(vn){if(vn&&O&&typeof vn.stack=="string"){for(var We=vn.stack.split(` `),ft=O.stack.split(` `),jt=We.length-1,Wt=ft.length-1;jt>=1&&Wt>=0&&We[jt]!==ft[Wt];)Wt--;for(;jt>=1&&Wt>=0;jt--,Wt--)if(We[jt]!==ft[Wt]){if(jt!==1||Wt!==1)do if(jt--,Wt--,Wt<0||We[jt]!==ft[Wt]){var qt=` @@ -28,7 +28,7 @@ Check the render method of \``+s+"`."}return""}function Jn(s){if(s!==void 0){var Check your code at `+h+":"+M+"."}return""}function Ei(s){return s!=null?Jn(s.__source):""}var Ir={};function of(s){var h=sl();if(!h){var M=typeof s=="string"?s:s.displayName||s.name;M&&(h=` -Check the top-level render call using <`+M+">.")}return h}function Mn(s,h){if(!(!s._store||s._store.validated||s.key!=null)){s._store.validated=!0;var M=of(h);if(!Ir[M]){Ir[M]=!0;var O="";s&&s._owner&&s._owner!==et.current&&(O=" It was passed a child from "+me(s._owner.type)+"."),gr(s),I('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.',M,O),gr(null)}}}function tn(s,h){if(typeof s=="object"){if(Xt(s))for(var M=0;M",K=" Did you accidentally export a JSX literal instead of a component?"):ge=typeof s,I("React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",ge,K)}var We=Pe.apply(this,arguments);if(We==null)return We;if(O)for(var ft=2;ft10&&$("Detected a large number of updates inside startTransition. If this is due to a subscription please re-write it to use React provided hooks. Otherwise concurrent mode guarantees are off the table."),O._updatedFibers.clear()}}}var fl=!1,io=null;function uf(s){if(io===null)try{var h=("require"+Math.random()).slice(0,7),M=w&&w[h];io=M.call(w,"timers").setImmediate}catch{io=function(K){fl===!1&&(fl=!0,typeof MessageChannel>"u"&&I("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var ke=new MessageChannel;ke.port1.onmessage=K,ke.port2.postMessage(void 0)}}return io(s)}var Wr=0,Ci=!1;function dl(s){{var h=Wr;Wr++,xe.current===null&&(xe.current=[]);var M=xe.isBatchingLegacy,O;try{if(xe.isBatchingLegacy=!0,O=s(),!M&&xe.didScheduleLegacyUpdate){var K=xe.current;K!==null&&(xe.didScheduleLegacyUpdate=!1,uo(K))}}catch(ot){throw br(h),ot}finally{xe.isBatchingLegacy=M}if(O!==null&&typeof O=="object"&&typeof O.then=="function"){var ke=O,ge=!1,We={then:function(ot,nn){ge=!0,ke.then(function(vn){br(h),Wr===0?oo(vn,ot,nn):ot(vn)},function(vn){br(h),nn(vn)})}};return!Ci&&typeof Promise<"u"&&Promise.resolve().then(function(){}).then(function(){ge||(Ci=!0,I("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),We}else{var ft=O;if(br(h),Wr===0){var jt=xe.current;jt!==null&&(uo(jt),xe.current=null);var Wt={then:function(ot,nn){xe.current===null?(xe.current=[],oo(ft,ot,nn)):ot(ft)}};return Wt}else{var qt={then:function(ot,nn){ot(ft)}};return qt}}}}function br(s){s!==Wr-1&&I("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. "),Wr=s}function oo(s,h,M){{var O=xe.current;if(O!==null)try{uo(O),uf(function(){O.length===0?(xe.current=null,h(s)):oo(s,h,M)})}catch(K){M(K)}else h(s)}}var lo=!1;function uo(s){if(!lo){lo=!0;var h=0;try{for(;h.")}return h}function Mn(s,h){if(!(!s._store||s._store.validated||s.key!=null)){s._store.validated=!0;var M=of(h);if(!Ir[M]){Ir[M]=!0;var O="";s&&s._owner&&s._owner!==et.current&&(O=" It was passed a child from "+me(s._owner.type)+"."),gr(s),I('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.',M,O),gr(null)}}}function tn(s,h){if(typeof s=="object"){if(Xt(s))for(var M=0;M",K=" Did you accidentally export a JSX literal instead of a component?"):ge=typeof s,I("React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",ge,K)}var We=Pe.apply(this,arguments);if(We==null)return We;if(O)for(var ft=2;ft10&&$("Detected a large number of updates inside startTransition. If this is due to a subscription please re-write it to use React provided hooks. Otherwise concurrent mode guarantees are off the table."),O._updatedFibers.clear()}}}var fl=!1,io=null;function uf(s){if(io===null)try{var h=("require"+Math.random()).slice(0,7),M=w&&w[h];io=M.call(w,"timers").setImmediate}catch{io=function(K){fl===!1&&(fl=!0,typeof MessageChannel>"u"&&I("This browser does not have a MessageChannel implementation, so enqueuing tasks via await act(async () => ...) will fail. Please file an issue at https://github.com/facebook/react/issues if you encounter this warning."));var ke=new MessageChannel;ke.port1.onmessage=K,ke.port2.postMessage(void 0)}}return io(s)}var Wr=0,Ci=!1;function dl(s){{var h=Wr;Wr++,xe.current===null&&(xe.current=[]);var M=xe.isBatchingLegacy,O;try{if(xe.isBatchingLegacy=!0,O=s(),!M&&xe.didScheduleLegacyUpdate){var K=xe.current;K!==null&&(xe.didScheduleLegacyUpdate=!1,uo(K))}}catch(ot){throw br(h),ot}finally{xe.isBatchingLegacy=M}if(O!==null&&typeof O=="object"&&typeof O.then=="function"){var ke=O,ge=!1,We={then:function(ot,nn){ge=!0,ke.then(function(vn){br(h),Wr===0?oo(vn,ot,nn):ot(vn)},function(vn){br(h),nn(vn)})}};return!Ci&&typeof Promise<"u"&&Promise.resolve().then(function(){}).then(function(){ge||(Ci=!0,I("You called act(async () => ...) without await. This could lead to unexpected testing behaviour, interleaving multiple act calls and mixing their scopes. You should - await act(async () => ...);"))}),We}else{var ft=O;if(br(h),Wr===0){var jt=xe.current;jt!==null&&(uo(jt),xe.current=null);var Wt={then:function(ot,nn){xe.current===null?(xe.current=[],oo(ft,ot,nn)):ot(ft)}};return Wt}else{var qt={then:function(ot,nn){ot(ft)}};return qt}}}}function br(s){s!==Wr-1&&I("You seem to have overlapping act() calls, this is not supported. Be sure to await previous act() calls before making a new one. "),Wr=s}function oo(s,h,M){{var O=xe.current;if(O!==null)try{uo(O),uf(function(){O.length===0?(xe.current=null,h(s)):oo(s,h,M)})}catch(K){M(K)}else h(s)}}var lo=!1;function uo(s){if(!lo){lo=!0;var h=0;try{for(;h.")}return h}function Mn(s,h){if(!( * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */return function(){var w=Zc(),_=Symbol.for("react.element"),ve=Symbol.for("react.portal"),be=Symbol.for("react.fragment"),pe=Symbol.for("react.strict_mode"),Oe=Symbol.for("react.profiler"),d=Symbol.for("react.provider"),Z=Symbol.for("react.context"),Se=Symbol.for("react.forward_ref"),ne=Symbol.for("react.suspense"),nt=Symbol.for("react.suspense_list"),G=Symbol.for("react.memo"),N=Symbol.for("react.lazy"),ae=Symbol.for("react.offscreen"),Ue=Symbol.iterator,Ft="@@iterator";function xt(c){if(c===null||typeof c!="object")return null;var p=Ue&&c[Ue]||c[Ft];return typeof p=="function"?p:null}var Rt=w.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;function Ge(c){{for(var p=arguments.length,T=new Array(p>1?p-1:0),R=1;R1?p-1:0),R=1;R=1&&it>=0&&ce[Le]!==ut[it];)it--;for(;Le>=1&&it>=0;Le--,it--)if(ce[Le]!==ut[it]){if(Le!==1||it!==1)do if(Le--,it--,it<0||ce[Le]!==ut[it]){var fn=` -`+ce[Le].replace(" at new "," at ");return c.displayName&&fn.includes("")&&(fn=fn.replace("",c.displayName)),typeof c=="function"&&Ie.set(c,fn),fn}while(Le>=1&&it>=0);break}}}finally{rt=!1,$t.current=re,st(),Error.prepareStackTrace=P}var _n=c?c.displayName||c.name:"",en=_n?At(_n):"";return typeof c=="function"&&Ie.set(c,en),en}function Xt(c,p,T){return xn(c,!1)}function cn(c){var p=c.prototype;return!!(p&&p.isReactComponent)}function Yt(c,p,T){if(c==null)return"";if(typeof c=="function")return xn(c,cn(c));if(typeof c=="string")return At(c);switch(c){case ne:return At("Suspense");case nt:return At("SuspenseList")}if(typeof c=="object")switch(c.$$typeof){case Se:return Xt(c.render);case G:return Yt(c.type,p,T);case N:{var R=c,P=R._payload,re=R._init;try{return Yt(re(P),p,T)}catch{}}}return""}var an=Object.prototype.hasOwnProperty,Rn={},U=Rt.ReactDebugCurrentFrame;function W(c){if(c){var p=c._owner,T=Yt(c.type,c._source,p?p.type:null);U.setExtraStackFrame(T)}else U.setExtraStackFrame(null)}function me(c,p,T,R,P){{var re=Function.call.bind(an);for(var z in c)if(re(c,z)){var ce=void 0;try{if(typeof c[z]!="function"){var ut=Error((R||"React class")+": "+T+" type `"+z+"` is invalid; it must be a function, usually from the `prop-types` package, but received `"+typeof c[z]+"`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.");throw ut.name="Invariant Violation",ut}ce=c[z](p,z,R,T,null,"SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED")}catch(Le){ce=Le}ce&&!(ce instanceof Error)&&(W(P),Ge("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).",R||"React class",T,z,typeof ce),W(null)),ce instanceof Error&&!(ce.message in Rn)&&(Rn[ce.message]=!0,W(P),Ge("Failed %s type: %s",T,ce.message),W(null))}}}var le=Array.isArray;function Ee(c){return le(c)}function we(c){{var p=typeof Symbol=="function"&&Symbol.toStringTag,T=p&&c[Symbol.toStringTag]||c.constructor.name||"Object";return T}}function yt(c){try{return _e(c),!1}catch{return!0}}function _e(c){return""+c}function ct(c){if(yt(c))return Ge("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.",we(c)),_e(c)}var wt=Rt.ReactCurrentOwner,un={key:!0,ref:!0,__self:!0,__source:!0},wn,Q;function ye(c){if(an.call(c,"ref")){var p=Object.getOwnPropertyDescriptor(c,"ref").get;if(p&&p.isReactWarning)return!1}return c.ref!==void 0}function Pe(c){if(an.call(c,"key")){var p=Object.getOwnPropertyDescriptor(c,"key").get;if(p&&p.isReactWarning)return!1}return c.key!==void 0}function gt(c,p){typeof c.ref=="string"&&wt.current}function Pt(c,p){{var T=function(){wn||(wn=!0,Ge("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",p))};T.isReactWarning=!0,Object.defineProperty(c,"key",{get:T,configurable:!0})}}function Qt(c,p){{var T=function(){Q||(Q=!0,Ge("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",p))};T.isReactWarning=!0,Object.defineProperty(c,"ref",{get:T,configurable:!0})}}var Kt=function(c,p,T,R,P,re,z){var ce={$$typeof:_,type:c,key:p,ref:T,props:z,_owner:re};return ce._store={},Object.defineProperty(ce._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:!1}),Object.defineProperty(ce,"_self",{configurable:!1,enumerable:!1,writable:!1,value:R}),Object.defineProperty(ce,"_source",{configurable:!1,enumerable:!1,writable:!1,value:P}),Object.freeze&&(Object.freeze(ce.props),Object.freeze(ce)),ce};function Dn(c,p,T,R,P){{var re,z={},ce=null,ut=null;T!==void 0&&(ct(T),ce=""+T),Pe(p)&&(ct(p.key),ce=""+p.key),ye(p)&&(ut=p.ref,gt(p,P));for(re in p)an.call(p,re)&&!un.hasOwnProperty(re)&&(z[re]=p[re]);if(c&&c.defaultProps){var Le=c.defaultProps;for(re in Le)z[re]===void 0&&(z[re]=Le[re])}if(ce||ut){var it=typeof c=="function"?c.displayName||c.name||"Unknown":c;ce&&Pt(z,it),ut&&Qt(z,it)}return Kt(c,ce,ut,P,R,wt.current,z)}}var It=Rt.ReactCurrentOwner,Vt=Rt.ReactDebugCurrentFrame;function bt(c){if(c){var p=c._owner,T=Yt(c.type,c._source,p?p.type:null);Vt.setExtraStackFrame(T)}else Vt.setExtraStackFrame(null)}var ua;ua=!1;function ha(c){return typeof c=="object"&&c!==null&&c.$$typeof===_}function Yn(){{if(It.current){var c=X(It.current.type);if(c)return` +`+ce[Le].replace(" at new "," at ");return c.displayName&&fn.includes("")&&(fn=fn.replace("",c.displayName)),typeof c=="function"&&Ie.set(c,fn),fn}while(Le>=1&&it>=0);break}}}finally{rt=!1,$t.current=re,st(),Error.prepareStackTrace=P}var _n=c?c.displayName||c.name:"",en=_n?At(_n):"";return typeof c=="function"&&Ie.set(c,en),en}function Xt(c,p,T){return xn(c,!1)}function cn(c){var p=c.prototype;return!!(p&&p.isReactComponent)}function Yt(c,p,T){if(c==null)return"";if(typeof c=="function")return xn(c,cn(c));if(typeof c=="string")return At(c);switch(c){case ne:return At("Suspense");case nt:return At("SuspenseList")}if(typeof c=="object")switch(c.$$typeof){case Se:return Xt(c.render);case G:return Yt(c.type,p,T);case N:{var R=c,P=R._payload,re=R._init;try{return Yt(re(P),p,T)}catch{}}}return""}var an=Object.prototype.hasOwnProperty,Rn={},U=Rt.ReactDebugCurrentFrame;function W(c){if(c){var p=c._owner,T=Yt(c.type,c._source,p?p.type:null);U.setExtraStackFrame(T)}else U.setExtraStackFrame(null)}function me(c,p,T,R,P){{var re=Function.call.bind(an);for(var z in c)if(re(c,z)){var ce=void 0;try{if(typeof c[z]!="function"){var ut=Error((R||"React class")+": "+T+" type `"+z+"` is invalid; it must be a function, usually from the `prop-types` package, but received `"+typeof c[z]+"`.This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.");throw ut.name="Invariant Violation",ut}ce=c[z](p,z,R,T,null,"SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED")}catch(Le){ce=Le}ce&&!(ce instanceof Error)&&(W(P),Ge("%s: type specification of %s `%s` is invalid; the type checker function must return `null` or an `Error` but returned a %s. You may have forgotten to pass an argument to the type checker creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and shape all require an argument).",R||"React class",T,z,typeof ce),W(null)),ce instanceof Error&&!(ce.message in Rn)&&(Rn[ce.message]=!0,W(P),Ge("Failed %s type: %s",T,ce.message),W(null))}}}var le=Array.isArray;function Ee(c){return le(c)}function we(c){{var p=typeof Symbol=="function"&&Symbol.toStringTag,T=p&&c[Symbol.toStringTag]||c.constructor.name||"Object";return T}}function yt(c){try{return _e(c),!1}catch{return!0}}function _e(c){return""+c}function ct(c){if(yt(c))return Ge("The provided key is an unsupported type %s. This value must be coerced to a string before before using it here.",we(c)),_e(c)}var wt=Rt.ReactCurrentOwner,un={key:!0,ref:!0,__self:!0,__source:!0},wn,Q;function ye(c){if(an.call(c,"ref")){var p=Object.getOwnPropertyDescriptor(c,"ref").get;if(p&&p.isReactWarning)return!1}return c.ref!==void 0}function Pe(c){if(an.call(c,"key")){var p=Object.getOwnPropertyDescriptor(c,"key").get;if(p&&p.isReactWarning)return!1}return c.key!==void 0}function gt(c,p){typeof c.ref=="string"&&wt.current}function Pt(c,p){{var T=function(){wn||(wn=!0,Ge("%s: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",p))};T.isReactWarning=!0,Object.defineProperty(c,"key",{get:T,configurable:!0})}}function Qt(c,p){{var T=function(){Q||(Q=!0,Ge("%s: `ref` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://reactjs.org/link/special-props)",p))};T.isReactWarning=!0,Object.defineProperty(c,"ref",{get:T,configurable:!0})}}var Kt=function(c,p,T,R,P,re,z){var ce={$$typeof:_,type:c,key:p,ref:T,props:z,_owner:re};return ce._store={},Object.defineProperty(ce._store,"validated",{configurable:!1,enumerable:!1,writable:!0,value:!1}),Object.defineProperty(ce,"_self",{configurable:!1,enumerable:!1,writable:!1,value:R}),Object.defineProperty(ce,"_source",{configurable:!1,enumerable:!1,writable:!1,value:P}),Object.freeze&&(Object.freeze(ce.props),Object.freeze(ce)),ce};function Dn(c,p,T,R,P){{var re,z={},ce=null,ut=null;T!==void 0&&(ct(T),ce=""+T),Pe(p)&&(ct(p.key),ce=""+p.key),ye(p)&&(ut=p.ref,gt(p,P));for(re in p)an.call(p,re)&&!un.hasOwnProperty(re)&&(z[re]=p[re]);if(c&&c.defaultProps){var Le=c.defaultProps;for(re in Le)z[re]===void 0&&(z[re]=Le[re])}if(ce||ut){var it=typeof c=="function"?c.displayName||c.name||"Unknown":c;ce&&Pt(z,it),ut&&Qt(z,it)}return Kt(c,ce,ut,P,R,wt.current,z)}}var It=Rt.ReactCurrentOwner,Ft=Rt.ReactDebugCurrentFrame;function bt(c){if(c){var p=c._owner,T=Yt(c.type,c._source,p?p.type:null);Ft.setExtraStackFrame(T)}else Ft.setExtraStackFrame(null)}var ua;ua=!1;function ha(c){return typeof c=="object"&&c!==null&&c.$$typeof===_}function Yn(){{if(It.current){var c=X(It.current.type);if(c)return` -Check the render method of \``+c+"`."}return""}}function nr(c){return""}var Fr={};function Pr(c){{var p=Yn();if(!p){var T=typeof c=="string"?c:c.displayName||c.name;T&&(p=` +Check the render method of \``+c+"`."}return""}}function nr(c){return""}var Vr={};function Pr(c){{var p=Yn();if(!p){var T=typeof c=="string"?c:c.displayName||c.name;T&&(p=` -Check the top-level render call using <`+T+">.")}return p}}function hr(c,p){{if(!c._store||c._store.validated||c.key!=null)return;c._store.validated=!0;var T=Pr(p);if(Fr[T])return;Fr[T]=!0;var R="";c&&c._owner&&c._owner!==It.current&&(R=" It was passed a child from "+X(c._owner.type)+"."),bt(c),Ge('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.',T,R),bt(null)}}function za(c,p){{if(typeof c!="object")return;if(Ee(c))for(var T=0;T",ce=" Did you accidentally export a JSX literal instead of a component?"):Le=typeof c,Ge("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",Le,ce)}var it=Dn(c,p,T,P,re);if(it==null)return it;if(z){var fn=p.children;if(fn!==void 0)if(R)if(Ee(fn)){for(var _n=0;_n0?"{key: someKey, "+zt.join(": ..., ")+": ...}":"{key: someKey}";if(!Kn[en+De]){var Dt=zt.length>0?"{"+zt.join(": ..., ")+": ...}":"{}";Ge(`A props object containing a "key" prop is being spread into JSX: +Check the top-level render call using <`+T+">.")}return p}}function hr(c,p){{if(!c._store||c._store.validated||c.key!=null)return;c._store.validated=!0;var T=Pr(p);if(Vr[T])return;Vr[T]=!0;var R="";c&&c._owner&&c._owner!==It.current&&(R=" It was passed a child from "+X(c._owner.type)+"."),bt(c),Ge('Each child in a list should have a unique "key" prop.%s%s See https://reactjs.org/link/warning-keys for more information.',T,R),bt(null)}}function za(c,p){{if(typeof c!="object")return;if(Ee(c))for(var T=0;T",ce=" Did you accidentally export a JSX literal instead of a component?"):Le=typeof c,Ge("React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: %s.%s",Le,ce)}var it=Dn(c,p,T,P,re);if(it==null)return it;if(z){var fn=p.children;if(fn!==void 0)if(R)if(Ee(fn)){for(var _n=0;_n0?"{key: someKey, "+zt.join(": ..., ")+": ...}":"{key: someKey}";if(!Kn[en+De]){var Dt=zt.length>0?"{"+zt.join(": ..., ")+": ...}":"{}";Ge(`A props object containing a "key" prop is being spread into JSX: let props = %s; <%s {...props} /> React keys must be passed directly to JSX without using spread: let props = %s; - <%s key={someKey} {...props} />`,De,en,Dt,en),Kn[en+De]=!0}}return c===be?ya(it):Va(it),it}}function F(c,p,T){return g(c,p,T,!0)}function k(c,p,T){return g(c,p,T,!1)}var S=k,x=F;il.Fragment=be,il.jsx=S,il.jsxs=x}(),il}dm.exports=VS();var m=dm.exports,hm={exports:{}},Jc={exports:{}},ef={},ym;function FS(){return ym||(ym=1,function(w){/** + <%s key={someKey} {...props} />`,De,en,Dt,en),Kn[en+De]=!0}}return c===be?ya(it):Fa(it),it}}function V(c,p,T){return g(c,p,T,!0)}function k(c,p,T){return g(c,p,T,!1)}var S=k,x=V;il.Fragment=be,il.jsx=S,il.jsxs=x}(),il}dm.exports=FS();var m=dm.exports,hm={exports:{}},Jc={exports:{}},ef={},ym;function VS(){return ym||(ym=1,function(w){/** * @license React * scheduler.development.js * @@ -57,7 +57,7 @@ React keys must be passed directly to JSX without using spread: * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */(function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var _=!1,ve=5;function be(Q,ye){var Pe=Q.length;Q.push(ye),d(Q,ye,Pe)}function pe(Q){return Q.length===0?null:Q[0]}function Oe(Q){if(Q.length===0)return null;var ye=Q[0],Pe=Q.pop();return Pe!==ye&&(Q[0]=Pe,Z(Q,Pe,0)),ye}function d(Q,ye,Pe){for(var gt=Pe;gt>0;){var Pt=gt-1>>>1,Qt=Q[Pt];if(Se(Qt,ye)>0)Q[Pt]=ye,Q[gt]=Qt,gt=Pt;else return}}function Z(Q,ye,Pe){for(var gt=Pe,Pt=Q.length,Qt=Pt>>>1;gtPe&&(!Q||U()));){var gt=Ze.callback;if(typeof gt=="function"){Ze.callback=null,X=Ze.priorityLevel;var Pt=Ze.expirationTime<=Pe,Qt=gt(Pt);Pe=w.unstable_now(),typeof Qt=="function"?Ze.callback=Qt:Ze===pe(tt)&&Oe(tt),at(Pe)}else Oe(tt);Ze=pe(tt)}if(Ze!==null)return!0;var Kt=pe(He);return Kt!==null&&ct(ht,Kt.startTime-Pe),!1}function Ae(Q,ye){switch(Q){case ne:case nt:case G:case N:case ae:break;default:Q=G}var Pe=X;X=Q;try{return ye()}finally{X=Pe}}function st(Q){var ye;switch(X){case ne:case nt:case G:ye=G;break;default:ye=X;break}var Pe=X;X=ye;try{return Q()}finally{X=Pe}}function $t(Q){var ye=X;return function(){var Pe=X;X=ye;try{return Q.apply(this,arguments)}finally{X=Pe}}}function Ye(Q,ye,Pe){var gt=w.unstable_now(),Pt;if(typeof Pe=="object"&&Pe!==null){var Qt=Pe.delay;typeof Qt=="number"&&Qt>0?Pt=gt+Qt:Pt=gt}else Pt=gt;var Kt;switch(Q){case ne:Kt=mt;break;case nt:Kt=xe;break;case ae:Kt=kt;break;case N:Kt=B;break;case G:default:Kt=et;break}var Dn=Pt+Kt,It={id:J++,callback:ye,priorityLevel:Q,startTime:Pt,expirationTime:Dn,sortIndex:-1};return Pt>gt?(It.sortIndex=Pt,be(He,It),pe(tt)===null&&It===pe(He)&&($?wt():$=!0,ct(ht,Pt-gt))):(It.sortIndex=Dn,be(tt,It),!Xe&&!Ot&&(Xe=!0,_e(Ke))),It}function At(){}function rt(){!Xe&&!Ot&&(Xe=!0,_e(Ke))}function Ie(){return pe(tt)}function Jt(Q){Q.callback=null}function xn(){return X}var Xt=!1,cn=null,Yt=-1,an=ve,Rn=-1;function U(){var Q=w.unstable_now()-Rn;return!(Q125){console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported");return}Q>0?an=Math.floor(1e3/Q):an=ve}var le=function(){if(cn!==null){var Q=w.unstable_now();Rn=Q;var ye=!0,Pe=!0;try{Pe=cn(ye,Q)}finally{Pe?Ee():(Xt=!1,cn=null)}}else Xt=!1},Ee;if(typeof Ve=="function")Ee=function(){Ve(le)};else if(typeof MessageChannel<"u"){var we=new MessageChannel,yt=we.port2;we.port1.onmessage=le,Ee=function(){yt.postMessage(null)}}else Ee=function(){I(le,0)};function _e(Q){cn=Q,Xt||(Xt=!0,Ee())}function ct(Q,ye){Yt=I(function(){Q(w.unstable_now())},ye)}function wt(){ze(Yt),Yt=-1}var un=W,wn=null;w.unstable_IdlePriority=ae,w.unstable_ImmediatePriority=ne,w.unstable_LowPriority=N,w.unstable_NormalPriority=G,w.unstable_Profiling=wn,w.unstable_UserBlockingPriority=nt,w.unstable_cancelCallback=Jt,w.unstable_continueExecution=rt,w.unstable_forceFrameRate=me,w.unstable_getCurrentPriorityLevel=xn,w.unstable_getFirstCallbackNode=Ie,w.unstable_next=st,w.unstable_pauseExecution=At,w.unstable_requestPaint=un,w.unstable_runWithPriority=Ae,w.unstable_scheduleCallback=Ye,w.unstable_shouldYield=U,w.unstable_wrapCallback=$t,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error)})()}(ef)),ef}var gm;function PS(){return gm||(gm=1,Jc.exports=FS()),Jc.exports}var la={},bm;function BS(){if(bm)return la;bm=1;/** + */(function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var _=!1,ve=5;function be(Q,ye){var Pe=Q.length;Q.push(ye),d(Q,ye,Pe)}function pe(Q){return Q.length===0?null:Q[0]}function Oe(Q){if(Q.length===0)return null;var ye=Q[0],Pe=Q.pop();return Pe!==ye&&(Q[0]=Pe,Z(Q,Pe,0)),ye}function d(Q,ye,Pe){for(var gt=Pe;gt>0;){var Pt=gt-1>>>1,Qt=Q[Pt];if(Se(Qt,ye)>0)Q[Pt]=ye,Q[gt]=Qt,gt=Pt;else return}}function Z(Q,ye,Pe){for(var gt=Pe,Pt=Q.length,Qt=Pt>>>1;gtPe&&(!Q||U()));){var gt=Ze.callback;if(typeof gt=="function"){Ze.callback=null,X=Ze.priorityLevel;var Pt=Ze.expirationTime<=Pe,Qt=gt(Pt);Pe=w.unstable_now(),typeof Qt=="function"?Ze.callback=Qt:Ze===pe(tt)&&Oe(tt),at(Pe)}else Oe(tt);Ze=pe(tt)}if(Ze!==null)return!0;var Kt=pe(He);return Kt!==null&&ct(ht,Kt.startTime-Pe),!1}function Ae(Q,ye){switch(Q){case ne:case nt:case G:case N:case ae:break;default:Q=G}var Pe=X;X=Q;try{return ye()}finally{X=Pe}}function st(Q){var ye;switch(X){case ne:case nt:case G:ye=G;break;default:ye=X;break}var Pe=X;X=ye;try{return Q()}finally{X=Pe}}function $t(Q){var ye=X;return function(){var Pe=X;X=ye;try{return Q.apply(this,arguments)}finally{X=Pe}}}function Ye(Q,ye,Pe){var gt=w.unstable_now(),Pt;if(typeof Pe=="object"&&Pe!==null){var Qt=Pe.delay;typeof Qt=="number"&&Qt>0?Pt=gt+Qt:Pt=gt}else Pt=gt;var Kt;switch(Q){case ne:Kt=mt;break;case nt:Kt=xe;break;case ae:Kt=kt;break;case N:Kt=B;break;case G:default:Kt=et;break}var Dn=Pt+Kt,It={id:J++,callback:ye,priorityLevel:Q,startTime:Pt,expirationTime:Dn,sortIndex:-1};return Pt>gt?(It.sortIndex=Pt,be(He,It),pe(tt)===null&&It===pe(He)&&($?wt():$=!0,ct(ht,Pt-gt))):(It.sortIndex=Dn,be(tt,It),!Xe&&!Ot&&(Xe=!0,_e(Ke))),It}function At(){}function rt(){!Xe&&!Ot&&(Xe=!0,_e(Ke))}function Ie(){return pe(tt)}function Jt(Q){Q.callback=null}function xn(){return X}var Xt=!1,cn=null,Yt=-1,an=ve,Rn=-1;function U(){var Q=w.unstable_now()-Rn;return!(Q125){console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported");return}Q>0?an=Math.floor(1e3/Q):an=ve}var le=function(){if(cn!==null){var Q=w.unstable_now();Rn=Q;var ye=!0,Pe=!0;try{Pe=cn(ye,Q)}finally{Pe?Ee():(Xt=!1,cn=null)}}else Xt=!1},Ee;if(typeof Fe=="function")Ee=function(){Fe(le)};else if(typeof MessageChannel<"u"){var we=new MessageChannel,yt=we.port2;we.port1.onmessage=le,Ee=function(){yt.postMessage(null)}}else Ee=function(){I(le,0)};function _e(Q){cn=Q,Xt||(Xt=!0,Ee())}function ct(Q,ye){Yt=I(function(){Q(w.unstable_now())},ye)}function wt(){ze(Yt),Yt=-1}var un=W,wn=null;w.unstable_IdlePriority=ae,w.unstable_ImmediatePriority=ne,w.unstable_LowPriority=N,w.unstable_NormalPriority=G,w.unstable_Profiling=wn,w.unstable_UserBlockingPriority=nt,w.unstable_cancelCallback=Jt,w.unstable_continueExecution=rt,w.unstable_forceFrameRate=me,w.unstable_getCurrentPriorityLevel=xn,w.unstable_getFirstCallbackNode=Ie,w.unstable_next=st,w.unstable_pauseExecution=At,w.unstable_requestPaint=un,w.unstable_runWithPriority=Ae,w.unstable_scheduleCallback=Ye,w.unstable_shouldYield=U,w.unstable_wrapCallback=$t,typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(new Error)})()}(ef)),ef}var gm;function PS(){return gm||(gm=1,Jc.exports=VS()),Jc.exports}var la={},bm;function BS(){if(bm)return la;bm=1;/** * @license React * react-dom.development.js * @@ -65,15 +65,15 @@ React keys must be passed directly to JSX without using spread: * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. - */return function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var w=Zc(),_=PS(),ve=w.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,be=!1;function pe(e){be=e}function Oe(e){if(!be){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a1?t-1:0),a=1;a2&&(e[0]==="o"||e[0]==="O")&&(e[1]==="n"||e[1]==="N")}function Kt(e,t,n,a){if(n!==null&&n.type===Ee)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":{if(a)return!1;if(n!==null)return!n.acceptsBooleans;var r=e.toLowerCase().slice(0,5);return r!=="data-"&&r!=="aria-"}default:return!1}}function Dn(e,t,n,a){if(t===null||typeof t>"u"||Kt(e,t,n,a))return!0;if(a)return!1;if(n!==null)switch(n.type){case _e:return!t;case ct:return t===!1;case wt:return isNaN(t);case un:return isNaN(t)||t<1}return!1}function It(e){return bt.hasOwnProperty(e)?bt[e]:null}function Vt(e,t,n,a,r,i,o){this.acceptsBooleans=t===yt||t===_e||t===ct,this.attributeName=a,this.attributeNamespace=r,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=o}var bt={},ua=["children","dangerouslySetInnerHTML","defaultValue","defaultChecked","innerHTML","suppressContentEditableWarning","suppressHydrationWarning","style"];ua.forEach(function(e){bt[e]=new Vt(e,Ee,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0],n=e[1];bt[t]=new Vt(t,we,!1,n,null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){bt[e]=new Vt(e,yt,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){bt[e]=new Vt(e,yt,!1,e,null,!1,!1)}),["allowFullScreen","async","autoFocus","autoPlay","controls","default","defer","disabled","disablePictureInPicture","disableRemotePlayback","formNoValidate","hidden","loop","noModule","noValidate","open","playsInline","readOnly","required","reversed","scoped","seamless","itemScope"].forEach(function(e){bt[e]=new Vt(e,_e,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){bt[e]=new Vt(e,_e,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){bt[e]=new Vt(e,ct,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){bt[e]=new Vt(e,un,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){bt[e]=new Vt(e,wt,!1,e.toLowerCase(),null,!1,!1)});var ha=/[\-\:]([a-z])/g,Yn=function(e){return e[1].toUpperCase()};["accent-height","alignment-baseline","arabic-form","baseline-shift","cap-height","clip-path","clip-rule","color-interpolation","color-interpolation-filters","color-profile","color-rendering","dominant-baseline","enable-background","fill-opacity","fill-rule","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","glyph-name","glyph-orientation-horizontal","glyph-orientation-vertical","horiz-adv-x","horiz-origin-x","image-rendering","letter-spacing","lighting-color","marker-end","marker-mid","marker-start","overline-position","overline-thickness","paint-order","panose-1","pointer-events","rendering-intent","shape-rendering","stop-color","stop-opacity","strikethrough-position","strikethrough-thickness","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-anchor","text-decoration","text-rendering","underline-position","underline-thickness","unicode-bidi","unicode-range","units-per-em","v-alphabetic","v-hanging","v-ideographic","v-mathematical","vector-effect","vert-adv-y","vert-origin-x","vert-origin-y","word-spacing","writing-mode","xmlns:xlink","x-height"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Vt(t,we,!1,e,null,!1,!1)}),["xlink:actuate","xlink:arcrole","xlink:role","xlink:show","xlink:title","xlink:type"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Vt(t,we,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Vt(t,we,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){bt[e]=new Vt(e,we,!1,e.toLowerCase(),null,!1,!1)});var nr="xlinkHref";bt[nr]=new Vt("xlinkHref",we,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){bt[e]=new Vt(e,we,!1,e.toLowerCase(),null,!0,!0)});var Fr=/^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i,Pr=!1;function hr(e){!Pr&&Fr.test(e)&&(Pr=!0,d("A future version of React will block javascript: URLs as a security precaution. Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead. React was passed %s.",JSON.stringify(e)))}function za(e,t,n,a){if(a.mustUseProperty){var r=a.propertyName;return e[r]}else{an(n,t),a.sanitizeURL&&hr(""+n);var i=a.attributeName,o=null;if(a.type===ct){if(e.hasAttribute(i)){var l=e.getAttribute(i);return l===""?!0:Dn(t,n,a,!1)?l:l===""+n?n:l}}else if(e.hasAttribute(i)){if(Dn(t,n,a,!1))return e.getAttribute(i);if(a.type===_e)return n;o=e.getAttribute(i)}return Dn(t,n,a,!1)?o===null?n:o:o===""+n?n:o}}function Va(e,t,n,a){{if(!Pt(t))return;if(!e.hasAttribute(t))return n===void 0?void 0:null;var r=e.getAttribute(t);return an(n,t),r===""+n?n:r}}function ya(e,t,n,a){var r=It(t);if(!Qt(t,r,a)){if(Dn(t,n,r,a)&&(n=null),a||r===null){if(Pt(t)){var i=t;n===null?e.removeAttribute(i):(an(n,t),e.setAttribute(i,""+n))}return}var o=r.mustUseProperty;if(o){var l=r.propertyName;if(n===null){var u=r.type;e[l]=u===_e?!1:""}else e[l]=n;return}var f=r.attributeName,v=r.attributeNamespace;if(n===null)e.removeAttribute(f);else{var b=r.type,y;b===_e||b===ct&&n===!0?y="":(an(n,f),y=""+n,r.sanitizeURL&&hr(y.toString())),v?e.setAttributeNS(v,f,y):e.setAttribute(f,y)}}}var Kn=Symbol.for("react.element"),g=Symbol.for("react.portal"),F=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),S=Symbol.for("react.profiler"),x=Symbol.for("react.provider"),c=Symbol.for("react.context"),p=Symbol.for("react.forward_ref"),T=Symbol.for("react.suspense"),R=Symbol.for("react.suspense_list"),P=Symbol.for("react.memo"),re=Symbol.for("react.lazy"),z=Symbol.for("react.scope"),ce=Symbol.for("react.debug_trace_mode"),ut=Symbol.for("react.offscreen"),Le=Symbol.for("react.legacy_hidden"),it=Symbol.for("react.cache"),fn=Symbol.for("react.tracing_marker"),_n=Symbol.iterator,en="@@iterator";function zt(e){if(e===null||typeof e!="object")return null;var t=_n&&e[_n]||e[en];return typeof t=="function"?t:null}var De=Object.assign,Dt=0,Zn,yr,Fa,Br,ga,ba,$r;function gi(){}gi.__reactDisabledLog=!0;function dn(){{if(Dt===0){Zn=console.log,yr=console.info,Fa=console.warn,Br=console.error,ga=console.group,ba=console.groupCollapsed,$r=console.groupEnd;var e={configurable:!0,enumerable:!0,value:gi,writable:!0};Object.defineProperties(console,{info:e,log:e,warn:e,error:e,group:e,groupCollapsed:e,groupEnd:e})}Dt++}}function _t(){{if(Dt--,Dt===0){var e={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:De({},e,{value:Zn}),info:De({},e,{value:yr}),warn:De({},e,{value:Fa}),error:De({},e,{value:Br}),group:De({},e,{value:ga}),groupCollapsed:De({},e,{value:ba}),groupEnd:De({},e,{value:$r})})}Dt<0&&d("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}}var Sa=ve.ReactCurrentDispatcher,Ta;function sa(e,t,n){{if(Ta===void 0)try{throw Error()}catch(r){var a=r.stack.trim().match(/\n( *(at )?)/);Ta=a&&a[1]||""}return` + */return function(){typeof __REACT_DEVTOOLS_GLOBAL_HOOK__<"u"&&typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart=="function"&&__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(new Error);var w=Zc(),_=PS(),ve=w.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,be=!1;function pe(e){be=e}function Oe(e){if(!be){for(var t=arguments.length,n=new Array(t>1?t-1:0),a=1;a1?t-1:0),a=1;a2&&(e[0]==="o"||e[0]==="O")&&(e[1]==="n"||e[1]==="N")}function Kt(e,t,n,a){if(n!==null&&n.type===Ee)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":{if(a)return!1;if(n!==null)return!n.acceptsBooleans;var r=e.toLowerCase().slice(0,5);return r!=="data-"&&r!=="aria-"}default:return!1}}function Dn(e,t,n,a){if(t===null||typeof t>"u"||Kt(e,t,n,a))return!0;if(a)return!1;if(n!==null)switch(n.type){case _e:return!t;case ct:return t===!1;case wt:return isNaN(t);case un:return isNaN(t)||t<1}return!1}function It(e){return bt.hasOwnProperty(e)?bt[e]:null}function Ft(e,t,n,a,r,i,o){this.acceptsBooleans=t===yt||t===_e||t===ct,this.attributeName=a,this.attributeNamespace=r,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=o}var bt={},ua=["children","dangerouslySetInnerHTML","defaultValue","defaultChecked","innerHTML","suppressContentEditableWarning","suppressHydrationWarning","style"];ua.forEach(function(e){bt[e]=new Ft(e,Ee,!1,e,null,!1,!1)}),[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0],n=e[1];bt[t]=new Ft(t,we,!1,n,null,!1,!1)}),["contentEditable","draggable","spellCheck","value"].forEach(function(e){bt[e]=new Ft(e,yt,!1,e.toLowerCase(),null,!1,!1)}),["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){bt[e]=new Ft(e,yt,!1,e,null,!1,!1)}),["allowFullScreen","async","autoFocus","autoPlay","controls","default","defer","disabled","disablePictureInPicture","disableRemotePlayback","formNoValidate","hidden","loop","noModule","noValidate","open","playsInline","readOnly","required","reversed","scoped","seamless","itemScope"].forEach(function(e){bt[e]=new Ft(e,_e,!1,e.toLowerCase(),null,!1,!1)}),["checked","multiple","muted","selected"].forEach(function(e){bt[e]=new Ft(e,_e,!0,e,null,!1,!1)}),["capture","download"].forEach(function(e){bt[e]=new Ft(e,ct,!1,e,null,!1,!1)}),["cols","rows","size","span"].forEach(function(e){bt[e]=new Ft(e,un,!1,e,null,!1,!1)}),["rowSpan","start"].forEach(function(e){bt[e]=new Ft(e,wt,!1,e.toLowerCase(),null,!1,!1)});var ha=/[\-\:]([a-z])/g,Yn=function(e){return e[1].toUpperCase()};["accent-height","alignment-baseline","arabic-form","baseline-shift","cap-height","clip-path","clip-rule","color-interpolation","color-interpolation-filters","color-profile","color-rendering","dominant-baseline","enable-background","fill-opacity","fill-rule","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","glyph-name","glyph-orientation-horizontal","glyph-orientation-vertical","horiz-adv-x","horiz-origin-x","image-rendering","letter-spacing","lighting-color","marker-end","marker-mid","marker-start","overline-position","overline-thickness","paint-order","panose-1","pointer-events","rendering-intent","shape-rendering","stop-color","stop-opacity","strikethrough-position","strikethrough-thickness","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke-width","text-anchor","text-decoration","text-rendering","underline-position","underline-thickness","unicode-bidi","unicode-range","units-per-em","v-alphabetic","v-hanging","v-ideographic","v-mathematical","vector-effect","vert-adv-y","vert-origin-x","vert-origin-y","word-spacing","writing-mode","xmlns:xlink","x-height"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Ft(t,we,!1,e,null,!1,!1)}),["xlink:actuate","xlink:arcrole","xlink:role","xlink:show","xlink:title","xlink:type"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Ft(t,we,!1,e,"http://www.w3.org/1999/xlink",!1,!1)}),["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(ha,Yn);bt[t]=new Ft(t,we,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)}),["tabIndex","crossOrigin"].forEach(function(e){bt[e]=new Ft(e,we,!1,e.toLowerCase(),null,!1,!1)});var nr="xlinkHref";bt[nr]=new Ft("xlinkHref",we,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1),["src","href","action","formAction"].forEach(function(e){bt[e]=new Ft(e,we,!1,e.toLowerCase(),null,!0,!0)});var Vr=/^[\u0000-\u001F ]*j[\r\n\t]*a[\r\n\t]*v[\r\n\t]*a[\r\n\t]*s[\r\n\t]*c[\r\n\t]*r[\r\n\t]*i[\r\n\t]*p[\r\n\t]*t[\r\n\t]*\:/i,Pr=!1;function hr(e){!Pr&&Vr.test(e)&&(Pr=!0,d("A future version of React will block javascript: URLs as a security precaution. Use event handlers instead if you can. If you need to generate unsafe HTML try using dangerouslySetInnerHTML instead. React was passed %s.",JSON.stringify(e)))}function za(e,t,n,a){if(a.mustUseProperty){var r=a.propertyName;return e[r]}else{an(n,t),a.sanitizeURL&&hr(""+n);var i=a.attributeName,o=null;if(a.type===ct){if(e.hasAttribute(i)){var l=e.getAttribute(i);return l===""?!0:Dn(t,n,a,!1)?l:l===""+n?n:l}}else if(e.hasAttribute(i)){if(Dn(t,n,a,!1))return e.getAttribute(i);if(a.type===_e)return n;o=e.getAttribute(i)}return Dn(t,n,a,!1)?o===null?n:o:o===""+n?n:o}}function Fa(e,t,n,a){{if(!Pt(t))return;if(!e.hasAttribute(t))return n===void 0?void 0:null;var r=e.getAttribute(t);return an(n,t),r===""+n?n:r}}function ya(e,t,n,a){var r=It(t);if(!Qt(t,r,a)){if(Dn(t,n,r,a)&&(n=null),a||r===null){if(Pt(t)){var i=t;n===null?e.removeAttribute(i):(an(n,t),e.setAttribute(i,""+n))}return}var o=r.mustUseProperty;if(o){var l=r.propertyName;if(n===null){var u=r.type;e[l]=u===_e?!1:""}else e[l]=n;return}var f=r.attributeName,v=r.attributeNamespace;if(n===null)e.removeAttribute(f);else{var b=r.type,y;b===_e||b===ct&&n===!0?y="":(an(n,f),y=""+n,r.sanitizeURL&&hr(y.toString())),v?e.setAttributeNS(v,f,y):e.setAttribute(f,y)}}}var Kn=Symbol.for("react.element"),g=Symbol.for("react.portal"),V=Symbol.for("react.fragment"),k=Symbol.for("react.strict_mode"),S=Symbol.for("react.profiler"),x=Symbol.for("react.provider"),c=Symbol.for("react.context"),p=Symbol.for("react.forward_ref"),T=Symbol.for("react.suspense"),R=Symbol.for("react.suspense_list"),P=Symbol.for("react.memo"),re=Symbol.for("react.lazy"),z=Symbol.for("react.scope"),ce=Symbol.for("react.debug_trace_mode"),ut=Symbol.for("react.offscreen"),Le=Symbol.for("react.legacy_hidden"),it=Symbol.for("react.cache"),fn=Symbol.for("react.tracing_marker"),_n=Symbol.iterator,en="@@iterator";function zt(e){if(e===null||typeof e!="object")return null;var t=_n&&e[_n]||e[en];return typeof t=="function"?t:null}var De=Object.assign,Dt=0,Zn,yr,Va,Br,ga,ba,$r;function gi(){}gi.__reactDisabledLog=!0;function dn(){{if(Dt===0){Zn=console.log,yr=console.info,Va=console.warn,Br=console.error,ga=console.group,ba=console.groupCollapsed,$r=console.groupEnd;var e={configurable:!0,enumerable:!0,value:gi,writable:!0};Object.defineProperties(console,{info:e,log:e,warn:e,error:e,group:e,groupCollapsed:e,groupEnd:e})}Dt++}}function _t(){{if(Dt--,Dt===0){var e={configurable:!0,enumerable:!0,writable:!0};Object.defineProperties(console,{log:De({},e,{value:Zn}),info:De({},e,{value:yr}),warn:De({},e,{value:Va}),error:De({},e,{value:Br}),group:De({},e,{value:ga}),groupCollapsed:De({},e,{value:ba}),groupEnd:De({},e,{value:$r})})}Dt<0&&d("disabledDepth fell below zero. This is a bug in React. Please file an issue.")}}var Sa=ve.ReactCurrentDispatcher,Ta;function sa(e,t,n){{if(Ta===void 0)try{throw Error()}catch(r){var a=r.stack.trim().match(/\n( *(at )?)/);Ta=a&&a[1]||""}return` `+Ta+e}}var bi=!1,Yr;{var ao=typeof WeakMap=="function"?WeakMap:Map;Yr=new ao}function Si(e,t){if(!e||bi)return"";{var n=Yr.get(e);if(n!==void 0)return n}var a;bi=!0;var r=Error.prepareStackTrace;Error.prepareStackTrace=void 0;var i;i=Sa.current,Sa.current=null,dn();try{if(t){var o=function(){throw Error()};if(Object.defineProperty(o.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(o,[])}catch(L){a=L}Reflect.construct(e,[],o)}else{try{o.call()}catch(L){a=L}e.call(o.prototype)}}else{try{throw Error()}catch(L){a=L}e()}}catch(L){if(L&&a&&typeof L.stack=="string"){for(var l=L.stack.split(` `),u=a.stack.split(` `),f=l.length-1,v=u.length-1;f>=1&&v>=0&&l[f]!==u[v];)v--;for(;f>=1&&v>=0;f--,v--)if(l[f]!==u[v]){if(f!==1||v!==1)do if(f--,v--,v<0||l[f]!==u[v]){var b=` `+l[f].replace(" at new "," at ");return e.displayName&&b.includes("")&&(b=b.replace("",e.displayName)),typeof e=="function"&&Yr.set(e,b),b}while(f>=1&&v>=0);break}}}finally{bi=!1,Sa.current=i,_t(),Error.prepareStackTrace=r}var y=e?e.displayName||e.name:"",D=y?sa(y):"";return typeof e=="function"&&Yr.set(e,D),D}function ro(e,t,n){return Si(e,!0)}function ol(e,t,n){return Si(e,!1)}function Yu(e){var t=e.prototype;return!!(t&&t.isReactComponent)}function ll(e,t,n){if(e==null)return"";if(typeof e=="function")return Si(e,Yu(e));if(typeof e=="string")return sa(e);switch(e){case T:return sa("Suspense");case R:return sa("SuspenseList")}if(typeof e=="object")switch(e.$$typeof){case p:return ol(e.render);case P:return ll(e.type,t,n);case re:{var a=e,r=a._payload,i=a._init;try{return ll(i(r),t,n)}catch{}}}return""}function af(e){switch(e._debugOwner&&e._debugOwner.type,e._debugSource,e.tag){case ae:return sa(e.type);case kt:return sa("Lazy");case xe:return sa("Suspense");case J:return sa("SuspenseList");case Se:case nt:case B:return ol(e.type);case Ce:return ol(e.type.render);case ne:return ro(e.type);default:return""}}function Ti(e){try{var t="",n=e;do t+=af(n),n=n.return;while(n);return t}catch(a){return` Error generating stack: `+a.message+` -`+a.stack}}function Iu(e,t,n){var a=e.displayName;if(a)return a;var r=t.displayName||t.name||"";return r!==""?n+"("+r+")":n}function ul(e){return e.displayName||"Context"}function Et(e){if(e==null)return null;if(typeof e.tag=="number"&&d("Received an unexpected object in getComponentNameFromType(). This is likely a bug in React. Please file an issue."),typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case F:return"Fragment";case g:return"Portal";case S:return"Profiler";case k:return"StrictMode";case T:return"Suspense";case R:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case c:var t=e;return ul(t)+".Consumer";case x:var n=e;return ul(n._context)+".Provider";case p:return Iu(e,e.render,"ForwardRef");case P:var a=e.displayName||null;return a!==null?a:Et(e.type)||"Memo";case re:{var r=e,i=r._payload,o=r._init;try{return Et(o(i))}catch{return null}}}return null}function rf(e,t,n){var a=t.displayName||t.name||"";return e.displayName||(a!==""?n+"("+a+")":n)}function gr(e){return e.displayName||"Context"}function Qe(e){var t=e.tag,n=e.type;switch(t){case Xe:return"Cache";case Rt:var a=n;return gr(a)+".Consumer";case Ge:var r=n;return gr(r._context)+".Provider";case He:return"DehydratedFragment";case Ce:return rf(n,n.render,"ForwardRef");case Ft:return"Fragment";case ae:return n;case N:return"Portal";case G:return"Root";case Ue:return"Text";case kt:return Et(n);case xt:return n===k?"StrictMode":"Mode";case X:return"Offscreen";case mt:return"Profiler";case Ze:return"Scope";case xe:return"Suspense";case J:return"SuspenseList";case $:return"TracingMarker";case ne:case Se:case tt:case nt:case et:case B:if(typeof n=="function")return n.displayName||n.name||null;if(typeof n=="string")return n;break}return null}var sl=ve.ReactDebugCurrentFrame,Jn=null,Ei=!1;function Ir(){{if(Jn===null)return null;var e=Jn._debugOwner;if(e!==null&&typeof e<"u")return Qe(e)}return null}function of(){return Jn===null?"":Ti(Jn)}function Mn(){sl.getCurrentStack=null,Jn=null,Ei=!1}function tn(e){sl.getCurrentStack=e===null?null:of,Jn=e,Ei=!1}function Wu(){return Jn}function Ma(e){Ei=e}function ea(e){return""+e}function Pa(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return le(e),e;default:return""}}var lf={button:!0,checkbox:!0,image:!0,hidden:!0,radio:!0,reset:!0,submit:!0};function cl(e,t){lf[t.type]||t.onChange||t.onInput||t.readOnly||t.disabled||t.value==null||d("You provided a `value` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultValue`. Otherwise, set either `onChange` or `readOnly`."),t.onChange||t.readOnly||t.disabled||t.checked==null||d("You provided a `checked` prop to a form field without an `onChange` handler. This will render a read-only field. If the field should be mutable use `defaultChecked`. Otherwise, set either `onChange` or `readOnly`.")}function qu(e){var t=e.type,n=e.nodeName;return n&&n.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function fl(e){return e._valueTracker}function io(e){e._valueTracker=null}function uf(e){var t="";return e&&(qu(e)?t=e.checked?"true":"false":t=e.value),t}function Wr(e){var t=qu(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t);le(e[t]);var a=""+e[t];if(!(e.hasOwnProperty(t)||typeof n>"u"||typeof n.get!="function"||typeof n.set!="function")){var r=n.get,i=n.set;Object.defineProperty(e,t,{configurable:!0,get:function(){return r.call(this)},set:function(l){le(l),a=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable});var o={getValue:function(){return a},setValue:function(l){le(l),a=""+l},stopTracking:function(){io(e),delete e[t]}};return o}}function Ci(e){fl(e)||(e._valueTracker=Wr(e))}function dl(e){if(!e)return!1;var t=fl(e);if(!t)return!0;var n=t.getValue(),a=uf(e);return a!==n?(t.setValue(a),!0):!1}function br(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var oo=!1,lo=!1,uo=!1,Gu=!1;function Xu(e){var t=e.type==="checkbox"||e.type==="radio";return t?e.checked!=null:e.value!=null}function vl(e,t){var n=e,a=t.checked,r=De({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:a??n._wrapperState.initialChecked});return r}function Qu(e,t){cl("input",t),t.checked!==void 0&&t.defaultChecked!==void 0&&!lo&&(d("%s contains an input of type %s with both checked and defaultChecked props. Input elements must be either controlled or uncontrolled (specify either the checked prop, or the defaultChecked prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://reactjs.org/link/controlled-components",Ir()||"A component",t.type),lo=!0),t.value!==void 0&&t.defaultValue!==void 0&&!oo&&(d("%s contains an input of type %s with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://reactjs.org/link/controlled-components",Ir()||"A component",t.type),oo=!0);var n=e,a=t.defaultValue==null?"":t.defaultValue;n._wrapperState={initialChecked:t.checked!=null?t.checked:t.defaultChecked,initialValue:Pa(t.value!=null?t.value:a),controlled:Xu(t)}}function s(e,t){var n=e,a=t.checked;a!=null&&ya(n,"checked",a,!1)}function h(e,t){var n=e;{var a=Xu(t);!n._wrapperState.controlled&&a&&!Gu&&(d("A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components"),Gu=!0),n._wrapperState.controlled&&!a&&!uo&&(d("A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components"),uo=!0)}s(e,t);var r=Pa(t.value),i=t.type;if(r!=null)i==="number"?(r===0&&n.value===""||n.value!=r)&&(n.value=ea(r)):n.value!==ea(r)&&(n.value=ea(r));else if(i==="submit"||i==="reset"){n.removeAttribute("value");return}t.hasOwnProperty("value")?ke(n,t.type,r):t.hasOwnProperty("defaultValue")&&ke(n,t.type,Pa(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(n.defaultChecked=!!t.defaultChecked)}function M(e,t,n){var a=e;if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type,i=r==="submit"||r==="reset";if(i&&(t.value===void 0||t.value===null))return;var o=ea(a._wrapperState.initialValue);n||o!==a.value&&(a.value=o),a.defaultValue=o}var l=a.name;l!==""&&(a.name=""),a.defaultChecked=!a.defaultChecked,a.defaultChecked=!!a._wrapperState.initialChecked,l!==""&&(a.name=l)}function O(e,t){var n=e;h(n,t),K(n,t)}function K(e,t){var n=t.name;if(t.type==="radio"&&n!=null){for(var a=e;a.parentNode;)a=a.parentNode;an(n,"name");for(var r=a.querySelectorAll("input[name="+JSON.stringify(""+n)+'][type="radio"]'),i=0;i.")))}):t.dangerouslySetInnerHTML!=null&&(ft||(ft=!0,d("Pass a `value` prop if you set dangerouslyInnerHTML so React knows which value should be selected.")))),t.selected!=null&&!ge&&(d("Use the `defaultValue` or `value` props on instead of setting `selected` on