Browser extension for SecureBit Chat — a P2P messenger with military-grade cryptography.
43
.gitignore
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Build outputs
|
||||
dist/
|
||||
extension-build/
|
||||
|
||||
# Environment variables
|
||||
.env
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# IDE files
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
249
EXTENSION_INSTALLATION.md
Normal file
@@ -0,0 +1,249 @@
|
||||
# SecureBit Chat Extension - Installation Guide
|
||||
|
||||
Complete step-by-step guide for installing and using the SecureBit Chat browser extension.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [System Requirements](#system-requirements)
|
||||
2. [Download Options](#download-options)
|
||||
3. [Installation Methods](#installation-methods)
|
||||
4. [First Time Setup](#first-time-setup)
|
||||
5. [Usage Guide](#usage-guide)
|
||||
6. [Troubleshooting](#troubleshooting)
|
||||
7. [Uninstallation](#uninstallation)
|
||||
|
||||
## System Requirements
|
||||
|
||||
### Minimum Requirements
|
||||
- **Operating System**: Windows 10/11, macOS 10.14+, or Linux (Ubuntu 18.04+)
|
||||
- **Browser**: Microsoft Edge 88+ (Chromium-based)
|
||||
- **RAM**: 4GB minimum, 8GB recommended
|
||||
- **Storage**: 100MB free space
|
||||
- **Network**: Internet connection for initial setup
|
||||
|
||||
### Recommended Requirements
|
||||
- **RAM**: 8GB or more
|
||||
- **CPU**: Multi-core processor
|
||||
- **Network**: Stable broadband connection
|
||||
- **Camera**: For QR code scanning (optional)
|
||||
|
||||
## Download Options
|
||||
|
||||
### Option 1: Download from GitHub (Recommended)
|
||||
1. Go to [SecureBit Chat Extension Repository](https://github.com/SecureBitChat/SecureBitChatBrowserExtension)
|
||||
2. Click the green "Code" button
|
||||
3. Select "Download ZIP"
|
||||
4. Extract the ZIP file to your desired location
|
||||
|
||||
### Option 2: Clone with Git
|
||||
```bash
|
||||
git clone https://github.com/SecureBitChat/SecureBitChatBrowserExtension.git
|
||||
cd SecureBitChatBrowserExtension
|
||||
```
|
||||
|
||||
### Option 3: Build from Source
|
||||
1. Download the source code
|
||||
2. Run the build script:
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File build-extension.ps1
|
||||
```
|
||||
|
||||
## Installation Methods
|
||||
|
||||
### Method 1: Developer Mode Installation (Recommended)
|
||||
|
||||
#### Step 1: Enable Developer Mode
|
||||
1. Open Microsoft Edge
|
||||
2. Navigate to `edge://extensions/`
|
||||
3. Find "Developer mode" toggle in the left sidebar
|
||||
4. Turn ON the "Developer mode" toggle
|
||||
5. You should see new buttons appear: "Load unpacked", "Pack extension", "Update"
|
||||
|
||||
#### Step 2: Load the Extension
|
||||
1. Click the "Load unpacked" button
|
||||
2. Navigate to the downloaded extension folder
|
||||
3. Select the `extension-build` folder (not the root folder)
|
||||
4. Click "Select Folder"
|
||||
5. The extension should now appear in your extensions list
|
||||
|
||||
#### Step 3: Verify Installation
|
||||
1. Look for "SecureBit Chat Extension" in the extensions list
|
||||
2. Ensure it's enabled (toggle should be ON)
|
||||
3. Check that the version shows "1.2.14"
|
||||
4. You should see the SecureBit icon in the browser toolbar
|
||||
|
||||
### Method 2: Manual Installation
|
||||
|
||||
#### Step 1: Prepare Extension Files
|
||||
1. Ensure you have the `extension-build` folder with all required files:
|
||||
- `manifest.json`
|
||||
- `background.js`
|
||||
- `content.js`
|
||||
- `popup.html`
|
||||
- `popup.js`
|
||||
- `assets/` folder
|
||||
- `dist/` folder
|
||||
- `libs/` folder
|
||||
- `logo/` folder
|
||||
|
||||
#### Step 2: Load Extension
|
||||
1. Follow the same steps as Method 1, Step 1-2
|
||||
2. Make sure to select the correct folder containing `manifest.json`
|
||||
|
||||
## First Time Setup
|
||||
|
||||
### Initial Configuration
|
||||
1. **Pin the Extension**: Right-click the SecureBit icon in the toolbar and select "Pin"
|
||||
2. **Grant Permissions**: The extension may request permissions for:
|
||||
- Storage access
|
||||
- Active tab access
|
||||
- Notifications
|
||||
- Background processing
|
||||
|
||||
### Security Setup
|
||||
1. **Generate Keys**: The extension will automatically generate cryptographic keys
|
||||
2. **Verify Installation**: Test the popup interface
|
||||
3. **Test Widget**: Use `Ctrl + Shift + S` on any webpage to test the widget
|
||||
|
||||
## Usage Guide
|
||||
|
||||
### Main Interface (Popup)
|
||||
1. **Open Extension**: Click the SecureBit icon in the toolbar
|
||||
2. **Create Channel**: Click "Create Channel" to start a new chat
|
||||
3. **Join Channel**: Click "Join Channel" and scan a QR code
|
||||
4. **Send Messages**: Type and send encrypted messages
|
||||
|
||||
### Widget on Web Pages
|
||||
1. **Activate Widget**: Press `Ctrl + Shift + S` on any webpage
|
||||
2. **Widget Controls**:
|
||||
- **Minimize**: Click the "−" button
|
||||
- **Close**: Click the "×" button
|
||||
- **Resize**: Drag the bottom-right corner
|
||||
|
||||
### Keyboard Shortcuts
|
||||
- `Ctrl + Shift + S`: Toggle widget on current page
|
||||
- `Enter`: Send message (when input is focused)
|
||||
- `Escape`: Close popup or widget
|
||||
|
||||
### Security Features
|
||||
- **End-to-End Encryption**: All messages are encrypted
|
||||
- **P2P Connection**: Direct peer-to-peer communication
|
||||
- **QR Code Sharing**: Secure channel sharing via QR codes
|
||||
- **Key Verification**: SAS (Short Authentication String) verification
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues and Solutions
|
||||
|
||||
#### Extension Won't Load
|
||||
**Problem**: Extension fails to load or shows errors
|
||||
**Solutions**:
|
||||
1. Check that Developer mode is enabled
|
||||
2. Verify all files are in the `extension-build` folder
|
||||
3. Ensure `manifest.json` is valid
|
||||
4. Try reloading the extension
|
||||
|
||||
#### Widget Doesn't Appear
|
||||
**Problem**: Widget doesn't show when using `Ctrl + Shift + S`
|
||||
**Solutions**:
|
||||
1. Check browser console for errors (F12)
|
||||
2. Ensure content script is loaded
|
||||
3. Try refreshing the page
|
||||
4. Check if another extension is interfering
|
||||
|
||||
#### QR Codes Not Working
|
||||
**Problem**: QR code scanning fails
|
||||
**Solutions**:
|
||||
1. Grant camera permissions to the browser
|
||||
2. Ensure good lighting conditions
|
||||
3. Try generating a new QR code
|
||||
4. Check if camera is being used by another application
|
||||
|
||||
#### Connection Issues
|
||||
**Problem**: Can't establish P2P connection
|
||||
**Solutions**:
|
||||
1. Check firewall settings
|
||||
2. Ensure both parties have the extension installed
|
||||
3. Try using a different network
|
||||
4. Check if NAT traversal is working
|
||||
|
||||
#### Performance Issues
|
||||
**Problem**: Extension is slow or unresponsive
|
||||
**Solutions**:
|
||||
1. Close unnecessary browser tabs
|
||||
2. Restart the browser
|
||||
3. Check system resources
|
||||
4. Update to the latest version
|
||||
|
||||
### Error Messages
|
||||
|
||||
#### "Failed to load resource"
|
||||
- Check that all files are present in the extension folder
|
||||
- Verify file paths in `manifest.json`
|
||||
- Try rebuilding the extension
|
||||
|
||||
#### "Permission denied"
|
||||
- Grant necessary permissions in browser settings
|
||||
- Check if the extension is blocked by security software
|
||||
- Try running browser as administrator (Windows)
|
||||
|
||||
#### "Content script failed"
|
||||
- Refresh the webpage
|
||||
- Check browser console for detailed errors
|
||||
- Try disabling other extensions temporarily
|
||||
|
||||
## Uninstallation
|
||||
|
||||
### Remove Extension
|
||||
1. Go to `edge://extensions/`
|
||||
2. Find "SecureBit Chat Extension"
|
||||
3. Click the "Remove" button
|
||||
4. Confirm removal
|
||||
|
||||
### Clean Up Data
|
||||
1. Clear extension data (optional):
|
||||
- Go to `edge://settings/clearBrowserData`
|
||||
- Select "Extensions" data
|
||||
- Click "Clear data"
|
||||
|
||||
### Remove Files
|
||||
1. Delete the extension folder from your computer
|
||||
2. Remove any shortcuts or pinned icons
|
||||
|
||||
## Support and Updates
|
||||
|
||||
### Getting Help
|
||||
- **GitHub Issues**: Report bugs or request features
|
||||
- **Documentation**: Check README files for detailed information
|
||||
- **Community**: Join discussions in the repository
|
||||
|
||||
### Updating the Extension
|
||||
1. Download the latest version from GitHub
|
||||
2. Remove the old extension
|
||||
3. Install the new version following the installation guide
|
||||
4. Your settings and data will be preserved
|
||||
|
||||
### Version History
|
||||
- **v1.2.14**: Fixed content script errors, added keyboard shortcuts
|
||||
- **v1.2.13**: Improved build process and error handling
|
||||
- **v1.2.12**: Initial release with full functionality
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Best Practices
|
||||
1. **Keep Updated**: Always use the latest version
|
||||
2. **Verify Sources**: Only download from official repositories
|
||||
3. **Check Permissions**: Review extension permissions regularly
|
||||
4. **Secure Networks**: Use trusted networks for P2P connections
|
||||
|
||||
### Privacy Protection
|
||||
- All communication is end-to-end encrypted
|
||||
- No data is stored on external servers
|
||||
- Keys are generated locally
|
||||
- Messages are not logged
|
||||
|
||||
## Conclusion
|
||||
|
||||
The SecureBit Chat Extension provides secure, private communication directly in your browser. Follow this guide carefully for the best installation and usage experience.
|
||||
|
||||
For additional support or questions, please refer to the main README file or create an issue in the GitHub repository.
|
||||
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 SecureBitChat
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
84
README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
# SecureBit Chat Browser Extension
|
||||
|
||||
Browser extension for SecureBit Chat - P2P messenger with military-grade cryptography.
|
||||
|
||||
## Features
|
||||
|
||||
- 🔐 **Military-grade cryptography**: ECDH + DTLS + SAS
|
||||
- 🌐 **P2P communication**: Direct connection without servers
|
||||
- 📱 **QR codes**: Quick connection via QR scanning
|
||||
- ⚡ **High performance**: Optimized for speed
|
||||
- 🎯 **Non-intrusive**: Widget appears only on demand
|
||||
|
||||
## Installation
|
||||
|
||||
1. Download or clone this repository
|
||||
2. Open Microsoft Edge browser
|
||||
3. Navigate to `edge://extensions/`
|
||||
4. Enable "Developer mode" toggle
|
||||
5. Click "Load unpacked" button
|
||||
6. Select the `extension-build` folder
|
||||
|
||||
## Usage
|
||||
|
||||
### Main Interface
|
||||
- Click the extension icon in the toolbar
|
||||
- Use all chat features as in the web version
|
||||
|
||||
### Widget on Web Pages
|
||||
The widget does **NOT** appear automatically on all pages.
|
||||
|
||||
**Ways to activate the widget:**
|
||||
|
||||
1. **Keyboard shortcut**: `Ctrl + Shift + S` on any web page
|
||||
2. **From popup**: "Show widget" button (if added)
|
||||
|
||||
**Widget controls:**
|
||||
- `Ctrl + Shift + S` - show/hide widget
|
||||
- "−" button - minimize widget
|
||||
- "×" button - close widget
|
||||
|
||||
## Building
|
||||
|
||||
To build the extension, use the PowerShell script:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File build-extension.ps1
|
||||
```
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
├── extension-build/ # Built extension
|
||||
├── extension-manifest.json # Extension manifest
|
||||
├── extension-background.js # Background script
|
||||
├── extension-content.js # Content script
|
||||
├── extension-popup.html # Popup HTML
|
||||
├── extension-popup.js # Popup script
|
||||
├── build-extension.ps1 # Build script
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Security Features
|
||||
|
||||
- **ECDH Key Exchange**: Elliptic Curve Diffie-Hellman for secure key generation
|
||||
- **DTLS Encryption**: Datagram Transport Layer Security for data protection
|
||||
- **SAS Verification**: Short Authentication String for identity verification
|
||||
- **P2P Architecture**: No central servers, direct peer-to-peer communication
|
||||
- **Military-grade**: Enterprise-level security standards
|
||||
|
||||
## Version
|
||||
|
||||
Current version: **1.2.14**
|
||||
|
||||
## License
|
||||
|
||||
MIT License
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues, create an issue in the repository.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Installation Guide](INSTALLATION_GUIDE_EN.md) - Detailed installation instructions
|
||||
9
assets/fontawesome/css/all.min.css
vendored
Normal file
BIN
assets/fontawesome/webfonts/fa-brands-400.woff2
Normal file
BIN
assets/fontawesome/webfonts/fa-regular-400.woff2
Normal file
BIN
assets/fontawesome/webfonts/fa-solid-900.woff2
Normal file
36
assets/fonts/inter/inter.css
Normal file
@@ -0,0 +1,36 @@
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v19/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuOKfMZg.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v19/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuLyfMZg.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v19/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuI6fMZg.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v19/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuGKYMZg.ttf) format('truetype');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Inter';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url(https://fonts.gstatic.com/s/inter/v19/UcCO3FwrK3iLTeHuS_nVMrMxCp50SjIw2boKoduKmMEVuFuYMZg.ttf) format('truetype');
|
||||
}
|
||||
|
||||
1
assets/tailwind.css
Normal file
17
browserconfig.xml
Normal file
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/logo/ms-icon-70x70.png"/>
|
||||
<square150x150logo src="/logo/ms-icon-150x150.png"/>
|
||||
<square310x310logo src="/logo/ms-icon-310x310.png"/>
|
||||
<wide310x150logo src="/logo/ms-icon-310x150.png"/>
|
||||
<TileColor>#ff6b35</TileColor>
|
||||
</tile>
|
||||
<notification>
|
||||
<polling-uri src="/api/notifications/polling"/>
|
||||
<frequency>30</frequency>
|
||||
<cycle>1</cycle>
|
||||
</notification>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
101
build-extension.ps1
Normal file
@@ -0,0 +1,101 @@
|
||||
# Build script for SecureBit Chat Extension
|
||||
# This script builds the extension for Edge browser
|
||||
|
||||
Write-Host "Building SecureBit Chat Extension..." -ForegroundColor Green
|
||||
|
||||
# Create extension directory
|
||||
$extensionDir = "extension-build"
|
||||
if (Test-Path $extensionDir) {
|
||||
Remove-Item $extensionDir -Recurse -Force
|
||||
}
|
||||
New-Item -ItemType Directory -Path $extensionDir
|
||||
|
||||
# Copy manifest
|
||||
Copy-Item "extension-manifest.json" "$extensionDir/manifest.json"
|
||||
|
||||
# Copy background script
|
||||
Copy-Item "extension-background.js" "$extensionDir/background.js"
|
||||
|
||||
# Copy popup files
|
||||
Copy-Item "extension-popup.html" "$extensionDir/popup.html"
|
||||
Copy-Item "extension-popup.js" "$extensionDir/popup.js"
|
||||
|
||||
# Copy content scripts
|
||||
Copy-Item "extension-content.js" "$extensionDir/content.js"
|
||||
Copy-Item "extension-content.css" "$extensionDir/content.css"
|
||||
|
||||
# Copy assets
|
||||
Write-Host "Copying assets..." -ForegroundColor Yellow
|
||||
Copy-Item "assets" "$extensionDir/assets" -Recurse
|
||||
Copy-Item "libs" "$extensionDir/libs" -Recurse
|
||||
Copy-Item "logo" "$extensionDir/logo" -Recurse
|
||||
Copy-Item "src" "$extensionDir/src" -Recurse
|
||||
|
||||
# Copy built files
|
||||
if (Test-Path "dist") {
|
||||
Copy-Item "dist" "$extensionDir/dist" -Recurse
|
||||
}
|
||||
|
||||
# Copy node_modules for QR dependencies
|
||||
if (Test-Path "node_modules") {
|
||||
Copy-Item "node_modules" "$extensionDir/node_modules" -Recurse
|
||||
}
|
||||
|
||||
# Copy styles
|
||||
Copy-Item "src/styles" "$extensionDir/src/styles" -Recurse
|
||||
|
||||
# Create necessary icon sizes if they don't exist
|
||||
$iconSizes = @(16, 32, 48, 128, 256, 512)
|
||||
foreach ($size in $iconSizes) {
|
||||
$iconPath = "$extensionDir/logo/icon-${size}x${size}.png"
|
||||
if (-not (Test-Path $iconPath)) {
|
||||
# Use existing 72x72 icon as fallback for smaller sizes
|
||||
$sourceIcon = "$extensionDir/logo/icon-72x72.png"
|
||||
if (Test-Path $sourceIcon) {
|
||||
Copy-Item $sourceIcon $iconPath
|
||||
Write-Host "Using 72x72 icon for ${size}x${size}..." -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Build the main app for extension
|
||||
Write-Host "Building main app..." -ForegroundColor Yellow
|
||||
npm run build
|
||||
|
||||
# Copy built app files
|
||||
Copy-Item "dist/app.js" "$extensionDir/dist/app.js"
|
||||
Copy-Item "dist/app-boot.js" "$extensionDir/dist/app-boot.js"
|
||||
Copy-Item "dist/qr-local.js" "$extensionDir/dist/qr-local.js"
|
||||
|
||||
# Create extension info file
|
||||
$extensionInfo = @"
|
||||
SecureBit Chat Extension
|
||||
Version: 1.0.0
|
||||
Build Date: $(Get-Date -Format "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
Installation Instructions:
|
||||
1. Open Microsoft Edge
|
||||
2. Go to edge://extensions/
|
||||
3. Enable "Developer mode"
|
||||
4. Click "Load unpacked"
|
||||
5. Select the extension-build folder
|
||||
|
||||
Features:
|
||||
- P2P secure messaging
|
||||
- Military-grade encryption
|
||||
- WebRTC communication
|
||||
- QR code scanning
|
||||
- Browser integration
|
||||
"@
|
||||
|
||||
$extensionInfo | Out-File "$extensionDir/README.txt" -Encoding UTF8
|
||||
|
||||
Write-Host "Extension built successfully!" -ForegroundColor Green
|
||||
Write-Host "Extension directory: $extensionDir" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host "To install the extension:" -ForegroundColor Yellow
|
||||
Write-Host "1. Open Microsoft Edge" -ForegroundColor White
|
||||
Write-Host "2. Go to edge://extensions/" -ForegroundColor White
|
||||
Write-Host "3. Enable 'Developer mode'" -ForegroundColor White
|
||||
Write-Host "4. Click 'Load unpacked'" -ForegroundColor White
|
||||
Write-Host "5. Select the '$extensionDir' folder" -ForegroundColor White
|
||||
83
build.ps1
Normal file
@@ -0,0 +1,83 @@
|
||||
# SecureBit.chat Build Script
|
||||
# PowerShell script for building the application
|
||||
|
||||
Write-Host "🔨 Building SecureBit.chat..." -ForegroundColor Green
|
||||
|
||||
# Check if Node.js is installed
|
||||
if (!(Get-Command node -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "❌ Node.js is not installed. Please install Node.js first." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check if npm is installed
|
||||
if (!(Get-Command npm -ErrorAction SilentlyContinue)) {
|
||||
Write-Host "❌ npm is not installed. Please install npm first." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Install dependencies if needed
|
||||
if (!(Test-Path "node_modules")) {
|
||||
Write-Host "📦 Installing dependencies..." -ForegroundColor Yellow
|
||||
npm install
|
||||
}
|
||||
|
||||
# Install build tools if needed
|
||||
Write-Host "🛠️ Installing build tools..." -ForegroundColor Yellow
|
||||
npm install -D tailwindcss esbuild
|
||||
npm install qrcode
|
||||
|
||||
# Create directories if they don't exist
|
||||
if (!(Test-Path "dist")) { New-Item -ItemType Directory -Path "dist" }
|
||||
if (!(Test-Path "assets")) { New-Item -ItemType Directory -Path "assets" }
|
||||
|
||||
# Build CSS
|
||||
Write-Host "🎨 Building Tailwind CSS..." -ForegroundColor Cyan
|
||||
try {
|
||||
npx tailwindcss -i src/styles/tw-input.css -o assets/tailwind.css --minify --content "./index.html,./src/**/*.jsx,./src/**/*.js"
|
||||
Write-Host "✅ CSS build completed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ CSS build failed: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build JavaScript files
|
||||
Write-Host "⚡ Building JavaScript files..." -ForegroundColor Cyan
|
||||
|
||||
# Build main app
|
||||
try {
|
||||
npx esbuild src/app.jsx --bundle --format=esm --outfile=dist/app.js --sourcemap
|
||||
Write-Host "✅ Main app build completed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ Main app build failed: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build app bootstrap
|
||||
try {
|
||||
npx esbuild src/scripts/app-boot.js --bundle --format=esm --outfile=dist/app-boot.js --sourcemap
|
||||
Write-Host "✅ App bootstrap build completed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ App bootstrap build failed: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build QR generator
|
||||
try {
|
||||
npx esbuild src/scripts/qr-local.js --bundle --format=esm --outfile=dist/qr-local.js --sourcemap
|
||||
Write-Host "✅ QR generator build completed" -ForegroundColor Green
|
||||
} catch {
|
||||
Write-Host "❌ QR generator build failed: $_" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Host "🎉 Build completed successfully!" -ForegroundColor Green
|
||||
Write-Host "📁 Output files:" -ForegroundColor Yellow
|
||||
Write-Host " - assets/tailwind.css" -ForegroundColor White
|
||||
Write-Host " - dist/app.js" -ForegroundColor White
|
||||
Write-Host " - dist/app-boot.js" -ForegroundColor White
|
||||
Write-Host " - dist/qr-local.js" -ForegroundColor White
|
||||
|
||||
Write-Host "`n🚀 You can now serve the application with:" -ForegroundColor Cyan
|
||||
Write-Host " python -m http.server 8000" -ForegroundColor White
|
||||
Write-Host " or" -ForegroundColor White
|
||||
Write-Host " npx http-server" -ForegroundColor White
|
||||
303
extension-app.js
Normal file
@@ -0,0 +1,303 @@
|
||||
// Adapted SecureBit Chat App for Browser Extension
|
||||
// This is a simplified version of the main app adapted for extension use
|
||||
|
||||
class SecureBitExtensionApp {
|
||||
constructor() {
|
||||
this.isExtension = true;
|
||||
this.cryptoUtils = null;
|
||||
this.webrtcManager = null;
|
||||
this.currentChannel = null;
|
||||
this.isConnected = false;
|
||||
this.initializeApp();
|
||||
}
|
||||
|
||||
async initializeApp() {
|
||||
try {
|
||||
// Initialize crypto utilities
|
||||
await this.initializeCrypto();
|
||||
|
||||
// Initialize WebRTC manager
|
||||
await this.initializeWebRTC();
|
||||
|
||||
// Set up extension-specific event listeners
|
||||
this.setupExtensionListeners();
|
||||
|
||||
console.log('SecureBit Extension App initialized');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize SecureBit Extension App:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async initializeCrypto() {
|
||||
// Load and initialize crypto utilities
|
||||
try {
|
||||
// Import the crypto utilities (you'll need to adapt the import for extension)
|
||||
if (typeof EnhancedSecureCryptoUtils !== 'undefined') {
|
||||
this.cryptoUtils = EnhancedSecureCryptoUtils;
|
||||
} else {
|
||||
// Fallback crypto implementation for extension
|
||||
this.cryptoUtils = new ExtensionCryptoUtils();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Crypto initialization error:', error);
|
||||
this.cryptoUtils = new ExtensionCryptoUtils();
|
||||
}
|
||||
}
|
||||
|
||||
async initializeWebRTC() {
|
||||
// Initialize WebRTC manager for extension
|
||||
try {
|
||||
if (typeof EnhancedSecureWebRTCManager !== 'undefined') {
|
||||
this.webrtcManager = new EnhancedSecureWebRTCManager();
|
||||
} else {
|
||||
this.webrtcManager = new ExtensionWebRTCManager();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('WebRTC initialization error:', error);
|
||||
this.webrtcManager = new ExtensionWebRTCManager();
|
||||
}
|
||||
}
|
||||
|
||||
setupExtensionListeners() {
|
||||
// Listen for messages from popup and content scripts
|
||||
if (typeof chrome !== 'undefined' && chrome.runtime) {
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
this.handleExtensionMessage(request, sender, sendResponse);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async handleExtensionMessage(request, sender, sendResponse) {
|
||||
try {
|
||||
switch (request.action) {
|
||||
case 'createChannel':
|
||||
const channelId = await this.createChannel();
|
||||
sendResponse({ success: true, data: { channelId } });
|
||||
break;
|
||||
|
||||
case 'joinChannel':
|
||||
const result = await this.joinChannel(request.data.channelId);
|
||||
sendResponse({ success: true, data: result });
|
||||
break;
|
||||
|
||||
case 'sendMessage':
|
||||
await this.sendMessage(request.data.message);
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'getConnectionStatus':
|
||||
sendResponse({ success: true, data: { connected: this.isConnected } });
|
||||
break;
|
||||
|
||||
case 'disconnect':
|
||||
await this.disconnect();
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
default:
|
||||
sendResponse({ success: false, error: 'Unknown action' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Extension message handling error:', error);
|
||||
sendResponse({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async createChannel() {
|
||||
try {
|
||||
// Generate a new channel ID
|
||||
const channelId = this.generateChannelId();
|
||||
|
||||
// Initialize WebRTC connection
|
||||
await this.webrtcManager.createOffer();
|
||||
|
||||
this.currentChannel = channelId;
|
||||
this.isConnected = true;
|
||||
|
||||
// Notify all connected components
|
||||
this.notifyComponents('channelCreated', { channelId });
|
||||
|
||||
return channelId;
|
||||
|
||||
} catch (error) {
|
||||
console.error('Create channel error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async joinChannel(channelId) {
|
||||
try {
|
||||
// Join existing channel
|
||||
await this.webrtcManager.joinChannel(channelId);
|
||||
|
||||
this.currentChannel = channelId;
|
||||
this.isConnected = true;
|
||||
|
||||
// Notify all connected components
|
||||
this.notifyComponents('channelJoined', { channelId });
|
||||
|
||||
return { success: true, channelId };
|
||||
|
||||
} catch (error) {
|
||||
console.error('Join channel error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async sendMessage(message) {
|
||||
try {
|
||||
if (!this.isConnected) {
|
||||
throw new Error('Not connected to any channel');
|
||||
}
|
||||
|
||||
// Encrypt the message
|
||||
const encryptedMessage = await this.cryptoUtils.encryptMessage(message);
|
||||
|
||||
// Send via WebRTC
|
||||
await this.webrtcManager.sendMessage(encryptedMessage);
|
||||
|
||||
// Notify components
|
||||
this.notifyComponents('messageSent', { message, encrypted: true });
|
||||
|
||||
} catch (error) {
|
||||
console.error('Send message error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
try {
|
||||
if (this.webrtcManager) {
|
||||
await this.webrtcManager.disconnect();
|
||||
}
|
||||
|
||||
this.isConnected = false;
|
||||
this.currentChannel = null;
|
||||
|
||||
// Notify components
|
||||
this.notifyComponents('disconnected', {});
|
||||
|
||||
} catch (error) {
|
||||
console.error('Disconnect error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
notifyComponents(event, data) {
|
||||
// Send notifications to popup and content scripts
|
||||
if (typeof chrome !== 'undefined' && chrome.runtime) {
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'notifyComponents',
|
||||
event: event,
|
||||
data: data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
generateChannelId() {
|
||||
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
}
|
||||
}
|
||||
|
||||
// Extension-specific crypto utilities
|
||||
class ExtensionCryptoUtils {
|
||||
async encryptMessage(message) {
|
||||
// Simplified encryption for extension
|
||||
// In a real implementation, you'd use the full crypto suite
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(message);
|
||||
const key = await crypto.subtle.generateKey(
|
||||
{ name: 'AES-GCM', length: 256 },
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
);
|
||||
const iv = crypto.getRandomValues(new Uint8Array(12));
|
||||
const encrypted = await crypto.subtle.encrypt(
|
||||
{ name: 'AES-GCM', iv: iv },
|
||||
key,
|
||||
data
|
||||
);
|
||||
return {
|
||||
encrypted: Array.from(new Uint8Array(encrypted)),
|
||||
iv: Array.from(iv),
|
||||
keyId: 'temp'
|
||||
};
|
||||
}
|
||||
|
||||
async decryptMessage(encryptedData) {
|
||||
// Simplified decryption for extension
|
||||
const key = await crypto.subtle.generateKey(
|
||||
{ name: 'AES-GCM', length: 256 },
|
||||
true,
|
||||
['encrypt', 'decrypt']
|
||||
);
|
||||
const decrypted = await crypto.subtle.decrypt(
|
||||
{ name: 'AES-GCM', iv: new Uint8Array(encryptedData.iv) },
|
||||
key,
|
||||
new Uint8Array(encryptedData.encrypted)
|
||||
);
|
||||
const decoder = new TextDecoder();
|
||||
return decoder.decode(decrypted);
|
||||
}
|
||||
}
|
||||
|
||||
// Extension-specific WebRTC manager
|
||||
class ExtensionWebRTCManager {
|
||||
constructor() {
|
||||
this.peerConnection = null;
|
||||
this.dataChannel = null;
|
||||
}
|
||||
|
||||
async createOffer() {
|
||||
// Simplified WebRTC implementation for extension
|
||||
this.peerConnection = new RTCPeerConnection({
|
||||
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
|
||||
});
|
||||
|
||||
this.dataChannel = this.peerConnection.createDataChannel('securebit');
|
||||
this.dataChannel.onopen = () => {
|
||||
console.log('Data channel opened');
|
||||
};
|
||||
this.dataChannel.onmessage = (event) => {
|
||||
this.handleMessage(event.data);
|
||||
};
|
||||
}
|
||||
|
||||
async joinChannel(channelId) {
|
||||
// Simplified channel joining for extension
|
||||
console.log('Joining channel:', channelId);
|
||||
}
|
||||
|
||||
async sendMessage(message) {
|
||||
if (this.dataChannel && this.dataChannel.readyState === 'open') {
|
||||
this.dataChannel.send(JSON.stringify(message));
|
||||
} else {
|
||||
throw new Error('Data channel not ready');
|
||||
}
|
||||
}
|
||||
|
||||
handleMessage(data) {
|
||||
try {
|
||||
const message = JSON.parse(data);
|
||||
// Notify the app about received message
|
||||
if (typeof window !== 'undefined' && window.secureBitApp) {
|
||||
window.secureBitApp.handleReceivedMessage(message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Message handling error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async disconnect() {
|
||||
if (this.dataChannel) {
|
||||
this.dataChannel.close();
|
||||
}
|
||||
if (this.peerConnection) {
|
||||
this.peerConnection.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the extension app
|
||||
window.secureBitApp = new SecureBitExtensionApp();
|
||||
162
extension-background.js
Normal file
@@ -0,0 +1,162 @@
|
||||
// Background script for SecureBit Chat Extension
|
||||
// Handles extension lifecycle, notifications, and communication
|
||||
|
||||
class SecureBitBackground {
|
||||
constructor() {
|
||||
this.initializeExtension();
|
||||
}
|
||||
|
||||
initializeExtension() {
|
||||
// Handle extension installation
|
||||
chrome.runtime.onInstalled.addListener((details) => {
|
||||
console.log('SecureBit Chat Extension installed:', details);
|
||||
this.setupDefaultSettings();
|
||||
});
|
||||
|
||||
// Handle extension startup
|
||||
chrome.runtime.onStartup.addListener(() => {
|
||||
console.log('SecureBit Chat Extension started');
|
||||
});
|
||||
|
||||
// Handle messages from content scripts and popup
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
this.handleMessage(request, sender, sendResponse);
|
||||
return true; // Keep message channel open for async responses
|
||||
});
|
||||
|
||||
// Handle tab updates for content script injection
|
||||
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
|
||||
if (changeInfo.status === 'complete' && tab.url) {
|
||||
this.injectContentScriptIfNeeded(tabId, tab.url);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
setupDefaultSettings() {
|
||||
// Set default extension settings
|
||||
chrome.storage.local.set({
|
||||
'securebit_settings': {
|
||||
autoConnect: true,
|
||||
notifications: true,
|
||||
theme: 'dark',
|
||||
language: 'en',
|
||||
encryptionLevel: 'military',
|
||||
lastActive: Date.now()
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async handleMessage(request, sender, sendResponse) {
|
||||
try {
|
||||
switch (request.action) {
|
||||
case 'getSettings':
|
||||
const settings = await this.getSettings();
|
||||
sendResponse({ success: true, data: settings });
|
||||
break;
|
||||
|
||||
case 'updateSettings':
|
||||
await this.updateSettings(request.data);
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'showNotification':
|
||||
await this.showNotification(request.data);
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'getActiveTab':
|
||||
const tab = await this.getActiveTab();
|
||||
sendResponse({ success: true, data: tab });
|
||||
break;
|
||||
|
||||
case 'executeScript':
|
||||
const result = await this.executeScript(request.script, request.tabId);
|
||||
sendResponse({ success: true, data: result });
|
||||
break;
|
||||
|
||||
case 'getStorageData':
|
||||
const data = await this.getStorageData(request.key);
|
||||
sendResponse({ success: true, data: data });
|
||||
break;
|
||||
|
||||
case 'setStorageData':
|
||||
await this.setStorageData(request.key, request.value);
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
default:
|
||||
sendResponse({ success: false, error: 'Unknown action' });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Background script error:', error);
|
||||
sendResponse({ success: false, error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async getSettings() {
|
||||
const result = await chrome.storage.local.get(['securebit_settings']);
|
||||
return result.securebit_settings || {};
|
||||
}
|
||||
|
||||
async updateSettings(newSettings) {
|
||||
const currentSettings = await this.getSettings();
|
||||
const updatedSettings = { ...currentSettings, ...newSettings };
|
||||
await chrome.storage.local.set({ 'securebit_settings': updatedSettings });
|
||||
}
|
||||
|
||||
async showNotification(data) {
|
||||
if (data.title && data.message) {
|
||||
await chrome.notifications.create({
|
||||
type: 'basic',
|
||||
iconUrl: 'logo/icon-128x128.png',
|
||||
title: data.title,
|
||||
message: data.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async getActiveTab() {
|
||||
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
|
||||
return tabs[0] || null;
|
||||
}
|
||||
|
||||
async executeScript(script, tabId) {
|
||||
try {
|
||||
const results = await chrome.scripting.executeScript({
|
||||
target: { tabId: tabId || (await this.getActiveTab()).id },
|
||||
func: new Function(script)
|
||||
});
|
||||
return results[0]?.result;
|
||||
} catch (error) {
|
||||
console.error('Script execution error:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async getStorageData(key) {
|
||||
const result = await chrome.storage.local.get([key]);
|
||||
return result[key];
|
||||
}
|
||||
|
||||
async setStorageData(key, value) {
|
||||
await chrome.storage.local.set({ [key]: value });
|
||||
}
|
||||
|
||||
async injectContentScriptIfNeeded(tabId, url) {
|
||||
// Only inject on http/https pages
|
||||
if (url.startsWith('http://') || url.startsWith('https://')) {
|
||||
try {
|
||||
await chrome.scripting.executeScript({
|
||||
target: { tabId: tabId },
|
||||
files: ['content.js']
|
||||
});
|
||||
} catch (error) {
|
||||
// Content script might already be injected
|
||||
console.log('Content script injection skipped:', error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the background script
|
||||
new SecureBitBackground();
|
||||
237
extension-content.css
Normal file
@@ -0,0 +1,237 @@
|
||||
/* Content script styles for SecureBit Chat Extension */
|
||||
|
||||
.securebit-widget {
|
||||
position: fixed !important;
|
||||
bottom: 20px !important;
|
||||
right: 20px !important;
|
||||
width: 300px !important;
|
||||
height: 400px !important;
|
||||
background: #1a1a1a !important;
|
||||
border: 1px solid #333 !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
|
||||
z-index: 2147483647 !important; /* Maximum z-index */
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||||
color: white !important;
|
||||
overflow: hidden !important;
|
||||
transition: all 0.3s ease !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.securebit-widget.minimized {
|
||||
height: 60px !important;
|
||||
}
|
||||
|
||||
.securebit-widget * {
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
.securebit-container {
|
||||
height: 100% !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
}
|
||||
|
||||
.securebit-header {
|
||||
display: flex !important;
|
||||
justify-content: space-between !important;
|
||||
align-items: center !important;
|
||||
padding: 12px 16px !important;
|
||||
background: #2a2a2a !important;
|
||||
border-bottom: 1px solid #333 !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.securebit-logo {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
font-weight: 600 !important;
|
||||
font-size: 14px !important;
|
||||
}
|
||||
|
||||
.securebit-logo img {
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
margin-right: 8px !important;
|
||||
}
|
||||
|
||||
.securebit-controls {
|
||||
display: flex !important;
|
||||
gap: 4px !important;
|
||||
}
|
||||
|
||||
.securebit-btn {
|
||||
background: none !important;
|
||||
border: none !important;
|
||||
color: #999 !important;
|
||||
cursor: pointer !important;
|
||||
padding: 4px !important;
|
||||
border-radius: 4px !important;
|
||||
transition: all 0.2s !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.securebit-btn:hover {
|
||||
background: #333 !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.securebit-content {
|
||||
flex: 1 !important;
|
||||
padding: 16px !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
.securebit-status {
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
margin-bottom: 16px !important;
|
||||
font-size: 12px !important;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 8px !important;
|
||||
height: 8px !important;
|
||||
border-radius: 50% !important;
|
||||
background: #4ade80 !important;
|
||||
margin-right: 8px !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.status-indicator.disconnected {
|
||||
background: #ef4444 !important;
|
||||
}
|
||||
|
||||
.securebit-actions {
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
gap: 8px !important;
|
||||
margin-bottom: 16px !important;
|
||||
}
|
||||
|
||||
.securebit-action-btn {
|
||||
background: #ff6b35 !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
padding: 10px 16px !important;
|
||||
border-radius: 6px !important;
|
||||
cursor: pointer !important;
|
||||
font-size: 13px !important;
|
||||
font-weight: 500 !important;
|
||||
transition: all 0.2s !important;
|
||||
display: flex !important;
|
||||
align-items: center !important;
|
||||
justify-content: center !important;
|
||||
gap: 8px !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.securebit-action-btn:hover {
|
||||
background: #e55a2b !important;
|
||||
}
|
||||
|
||||
.securebit-action-btn:active {
|
||||
transform: translateY(1px) !important;
|
||||
}
|
||||
|
||||
.securebit-chat {
|
||||
flex: 1 !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
min-height: 0 !important;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1 !important;
|
||||
overflow-y: auto !important;
|
||||
padding: 8px !important;
|
||||
background: #0f0f0f !important;
|
||||
border-radius: 6px !important;
|
||||
margin-bottom: 8px !important;
|
||||
max-height: 200px !important;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
display: flex !important;
|
||||
gap: 8px !important;
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
flex: 1 !important;
|
||||
background: #2a2a2a !important;
|
||||
border: 1px solid #333 !important;
|
||||
color: white !important;
|
||||
padding: 8px 12px !important;
|
||||
border-radius: 6px !important;
|
||||
font-size: 13px !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
border-color: #ff6b35 !important;
|
||||
}
|
||||
|
||||
.chat-input button {
|
||||
background: #ff6b35 !important;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
padding: 8px 16px !important;
|
||||
border-radius: 6px !important;
|
||||
cursor: pointer !important;
|
||||
font-size: 13px !important;
|
||||
white-space: nowrap !important;
|
||||
}
|
||||
|
||||
.chat-input button:hover {
|
||||
background: #e55a2b !important;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 8px !important;
|
||||
padding: 6px 8px !important;
|
||||
border-radius: 4px !important;
|
||||
font-size: 12px !important;
|
||||
word-wrap: break-word !important;
|
||||
}
|
||||
|
||||
.message.sent {
|
||||
background: #ff6b35 !important;
|
||||
margin-left: 20px !important;
|
||||
}
|
||||
|
||||
.message.received {
|
||||
background: #333 !important;
|
||||
margin-right: 20px !important;
|
||||
}
|
||||
|
||||
/* Ensure the widget doesn't interfere with page styles */
|
||||
.securebit-widget,
|
||||
.securebit-widget * {
|
||||
all: unset !important;
|
||||
display: revert !important;
|
||||
box-sizing: border-box !important;
|
||||
}
|
||||
|
||||
/* Reset specific properties that might be inherited */
|
||||
.securebit-widget {
|
||||
position: fixed !important;
|
||||
bottom: 20px !important;
|
||||
right: 20px !important;
|
||||
width: 300px !important;
|
||||
height: 400px !important;
|
||||
background: #1a1a1a !important;
|
||||
border: 1px solid #333 !important;
|
||||
border-radius: 12px !important;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3) !important;
|
||||
z-index: 2147483647 !important;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
|
||||
color: white !important;
|
||||
overflow: hidden !important;
|
||||
transition: all 0.3s ease !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
500
extension-content.js
Normal file
@@ -0,0 +1,500 @@
|
||||
// Content script for SecureBit Chat Extension
|
||||
// Injects SecureBit functionality into web pages
|
||||
|
||||
class SecureBitContentScript {
|
||||
constructor() {
|
||||
this.isInjected = false;
|
||||
this.secureBitWidget = null;
|
||||
this.initializeContentScript();
|
||||
}
|
||||
|
||||
initializeContentScript() {
|
||||
// Check if already injected
|
||||
if (document.getElementById('securebit-widget')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't auto-inject widget, wait for user action
|
||||
this.setupKeyboardShortcut();
|
||||
|
||||
// Listen for messages from background script
|
||||
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
|
||||
this.handleMessage(request, sender, sendResponse);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
injectSecureBit() {
|
||||
if (this.isInjected) return;
|
||||
|
||||
try {
|
||||
// Create the SecureBit widget
|
||||
this.createSecureBitWidget();
|
||||
|
||||
// Inject the widget into the page
|
||||
document.body.appendChild(this.secureBitWidget);
|
||||
|
||||
this.isInjected = true;
|
||||
console.log('SecureBit Chat widget injected');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Failed to inject SecureBit widget:', error);
|
||||
}
|
||||
}
|
||||
|
||||
createSecureBitWidget() {
|
||||
// Create the main widget container
|
||||
this.secureBitWidget = document.createElement('div');
|
||||
this.secureBitWidget.id = 'securebit-widget';
|
||||
this.secureBitWidget.className = 'securebit-widget';
|
||||
|
||||
// Add styles
|
||||
this.addWidgetStyles();
|
||||
|
||||
// Create widget content
|
||||
this.secureBitWidget.innerHTML = `
|
||||
<div class="securebit-container">
|
||||
<div class="securebit-header">
|
||||
<div class="securebit-logo">
|
||||
<img src="${chrome.runtime.getURL('logo/icon-32x32.png')}" alt="SecureBit">
|
||||
<span>SecureBit Chat</span>
|
||||
</div>
|
||||
<div class="securebit-controls">
|
||||
<button id="securebit-minimize" class="securebit-control-btn" title="Minimize">
|
||||
<i class="fas fa-minus"></i>
|
||||
</button>
|
||||
<button id="securebit-close" class="securebit-control-btn" title="Close">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="securebit-content">
|
||||
<div class="securebit-status">
|
||||
<div class="status-indicator"></div>
|
||||
<span class="status-text">Ready</span>
|
||||
</div>
|
||||
|
||||
<div class="securebit-actions">
|
||||
<button id="securebit-create" class="securebit-action-btn">
|
||||
<i class="fas fa-plus"></i>
|
||||
Create Channel
|
||||
</button>
|
||||
<button id="securebit-join" class="securebit-action-btn">
|
||||
<i class="fas fa-qrcode"></i>
|
||||
Join Channel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="securebit-chat" id="securebit-chat-area" style="display: none;">
|
||||
<div class="chat-messages" id="securebit-messages"></div>
|
||||
<div class="chat-input">
|
||||
<input type="text" id="securebit-input" placeholder="Type a message...">
|
||||
<button id="securebit-send">Send</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Add event listeners
|
||||
this.setupWidgetEventListeners();
|
||||
}
|
||||
|
||||
addWidgetStyles() {
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.securebit-widget {
|
||||
position: fixed;
|
||||
bottom: 20px;
|
||||
right: 20px;
|
||||
width: 300px;
|
||||
height: 400px;
|
||||
background: #1a1a1a;
|
||||
border: 1px solid #333;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
|
||||
z-index: 10000;
|
||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||
color: white;
|
||||
overflow: hidden;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.securebit-widget.minimized {
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
.securebit-container {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.securebit-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
background: #2a2a2a;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.securebit-logo {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.securebit-logo img {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.securebit-controls {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.securebit-control-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ccc;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 3px;
|
||||
transition: all 0.2s;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.securebit-control-btn:hover {
|
||||
background: #444;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.securebit-btn {
|
||||
background: none;
|
||||
border: none;
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
border-radius: 4px;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
|
||||
.securebit-btn:hover {
|
||||
background: #333;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.securebit-content {
|
||||
flex: 1;
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.securebit-status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.status-indicator {
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
border-radius: 50%;
|
||||
background: #4ade80;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.status-indicator.disconnected {
|
||||
background: #ef4444;
|
||||
}
|
||||
|
||||
.securebit-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.securebit-action-btn {
|
||||
background: #ff6b35;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 10px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.securebit-action-btn:hover {
|
||||
background: #e55a2b;
|
||||
}
|
||||
|
||||
.securebit-action-btn:active {
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.securebit-chat {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.chat-messages {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
padding: 8px;
|
||||
background: #0f0f0f;
|
||||
border-radius: 6px;
|
||||
margin-bottom: 8px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
.chat-input {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.chat-input input {
|
||||
flex: 1;
|
||||
background: #2a2a2a;
|
||||
border: 1px solid #333;
|
||||
color: white;
|
||||
padding: 8px 12px;
|
||||
border-radius: 6px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.chat-input input:focus {
|
||||
outline: none;
|
||||
border-color: #ff6b35;
|
||||
}
|
||||
|
||||
.chat-input button {
|
||||
background: #ff6b35;
|
||||
border: none;
|
||||
color: white;
|
||||
padding: 8px 16px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.chat-input button:hover {
|
||||
background: #e55a2b;
|
||||
}
|
||||
|
||||
.message {
|
||||
margin-bottom: 8px;
|
||||
padding: 6px 8px;
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.message.sent {
|
||||
background: #ff6b35;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.message.received {
|
||||
background: #333;
|
||||
margin-right: 20px;
|
||||
}
|
||||
`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
setupWidgetEventListeners() {
|
||||
// Minimize button
|
||||
const minimizeBtn = document.getElementById('securebit-minimize');
|
||||
if (minimizeBtn) {
|
||||
minimizeBtn.addEventListener('click', () => {
|
||||
this.secureBitWidget.classList.toggle('minimized');
|
||||
});
|
||||
}
|
||||
|
||||
// Close button
|
||||
const closeBtn = document.getElementById('securebit-close');
|
||||
if (closeBtn) {
|
||||
closeBtn.addEventListener('click', () => {
|
||||
this.secureBitWidget.remove();
|
||||
this.isInjected = false;
|
||||
});
|
||||
}
|
||||
|
||||
// Create channel button
|
||||
const createBtn = document.getElementById('securebit-create');
|
||||
if (createBtn) {
|
||||
createBtn.addEventListener('click', () => {
|
||||
this.createChannel();
|
||||
});
|
||||
}
|
||||
|
||||
// Join channel button
|
||||
const joinBtn = document.getElementById('securebit-join');
|
||||
if (joinBtn) {
|
||||
joinBtn.addEventListener('click', () => {
|
||||
this.joinChannel();
|
||||
});
|
||||
}
|
||||
|
||||
// Send message button
|
||||
const sendBtn = document.getElementById('securebit-send');
|
||||
if (sendBtn) {
|
||||
sendBtn.addEventListener('click', () => {
|
||||
this.sendMessage();
|
||||
});
|
||||
}
|
||||
|
||||
// Enter key in input
|
||||
const inputField = document.getElementById('securebit-input');
|
||||
if (inputField) {
|
||||
inputField.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
this.sendMessage();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setupKeyboardShortcut() {
|
||||
// Add keyboard shortcut to toggle widget (Ctrl+Shift+S)
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.ctrlKey && e.shiftKey && e.key === 'S') {
|
||||
e.preventDefault();
|
||||
this.toggleWidget();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
toggleWidget() {
|
||||
if (this.isInjected) {
|
||||
// Hide widget
|
||||
this.secureBitWidget.style.display = 'none';
|
||||
this.isInjected = false;
|
||||
} else {
|
||||
// Show widget
|
||||
this.injectSecureBit();
|
||||
}
|
||||
}
|
||||
|
||||
async createChannel() {
|
||||
try {
|
||||
// Generate channel ID
|
||||
const channelId = this.generateChannelId();
|
||||
|
||||
// Update status
|
||||
this.updateStatus('Connected', true);
|
||||
|
||||
// Show chat area
|
||||
document.getElementById('securebit-chat-area').style.display = 'flex';
|
||||
|
||||
// Notify background script
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'channelCreated',
|
||||
data: { channelId }
|
||||
});
|
||||
|
||||
console.log('Channel created:', channelId);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Create channel error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async joinChannel() {
|
||||
// This would open a QR scanner or input field
|
||||
const channelId = prompt('Enter channel ID:');
|
||||
if (channelId) {
|
||||
this.updateStatus('Connected', true);
|
||||
document.getElementById('securebit-chat-area').style.display = 'flex';
|
||||
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'channelJoined',
|
||||
data: { channelId }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendMessage() {
|
||||
const input = document.getElementById('securebit-input');
|
||||
const message = input.value.trim();
|
||||
|
||||
if (message) {
|
||||
this.addMessage(message, 'sent');
|
||||
input.value = '';
|
||||
|
||||
// Send to background script
|
||||
chrome.runtime.sendMessage({
|
||||
action: 'sendMessage',
|
||||
data: { message }
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addMessage(text, type) {
|
||||
const messagesContainer = document.getElementById('securebit-messages');
|
||||
const messageElement = document.createElement('div');
|
||||
messageElement.className = `message ${type}`;
|
||||
messageElement.textContent = text;
|
||||
messagesContainer.appendChild(messageElement);
|
||||
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
||||
}
|
||||
|
||||
updateStatus(text, connected) {
|
||||
const statusText = document.querySelector('.status-text');
|
||||
const statusIndicator = document.querySelector('.status-indicator');
|
||||
|
||||
statusText.textContent = text;
|
||||
statusIndicator.classList.toggle('disconnected', !connected);
|
||||
}
|
||||
|
||||
generateChannelId() {
|
||||
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
}
|
||||
|
||||
handleMessage(request, sender, sendResponse) {
|
||||
switch (request.action) {
|
||||
case 'injectWidget':
|
||||
this.injectSecureBit();
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'removeWidget':
|
||||
if (this.secureBitWidget) {
|
||||
this.secureBitWidget.remove();
|
||||
this.isInjected = false;
|
||||
}
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'toggleWidget':
|
||||
this.toggleWidget();
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
case 'updateStatus':
|
||||
this.updateStatus(request.data.text, request.data.connected);
|
||||
sendResponse({ success: true });
|
||||
break;
|
||||
|
||||
default:
|
||||
sendResponse({ success: false, error: 'Unknown action' });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize content script
|
||||
new SecureBitContentScript();
|
||||
60
extension-manifest.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "SecureBit Chat Extension",
|
||||
"version": "1.2.14",
|
||||
"description": "P2P messenger with ECDH + DTLS + SAS security, military-grade cryptography",
|
||||
"permissions": [
|
||||
"storage",
|
||||
"activeTab",
|
||||
"tabs",
|
||||
"notifications",
|
||||
"background"
|
||||
],
|
||||
"host_permissions": [
|
||||
"https://*/*",
|
||||
"http://*/*"
|
||||
],
|
||||
"background": {
|
||||
"service_worker": "background.js"
|
||||
},
|
||||
"action": {
|
||||
"default_popup": "popup.html",
|
||||
"default_title": "SecureBit Chat",
|
||||
"default_icon": {
|
||||
"16": "logo/icon-16x16.png",
|
||||
"32": "logo/icon-32x32.png",
|
||||
"48": "logo/icon-48x48.png",
|
||||
"128": "logo/icon-128x128.png"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"16": "logo/icon-16x16.png",
|
||||
"32": "logo/icon-32x32.png",
|
||||
"48": "logo/icon-48x48.png",
|
||||
"128": "logo/icon-128x128.png",
|
||||
"256": "logo/icon-256x256.png",
|
||||
"512": "logo/icon-512x512.png"
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": ["<all_urls>"],
|
||||
"js": ["content.js"],
|
||||
"css": ["content.css"],
|
||||
"run_at": "document_end"
|
||||
}
|
||||
],
|
||||
"web_accessible_resources": [
|
||||
{
|
||||
"resources": [
|
||||
"assets/*",
|
||||
"dist/*",
|
||||
"libs/*",
|
||||
"logo/*"
|
||||
],
|
||||
"matches": ["<all_urls>"]
|
||||
}
|
||||
],
|
||||
"content_security_policy": {
|
||||
"extension_pages": "script-src 'self'; object-src 'self';"
|
||||
}
|
||||
}
|
||||
53
extension-popup.html
Normal file
@@ -0,0 +1,53 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SecureBit Chat</title>
|
||||
<link rel="stylesheet" href="assets/tailwind.css">
|
||||
<link rel="stylesheet" href="assets/fontawesome/css/all.min.css">
|
||||
<link rel="stylesheet" href="src/styles/main.css">
|
||||
<link rel="stylesheet" href="src/styles/animations.css">
|
||||
<link rel="stylesheet" href="src/styles/components.css">
|
||||
<style>
|
||||
body {
|
||||
width: 400px;
|
||||
height: 600px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.popup-container {
|
||||
height: 100vh;
|
||||
overflow-y: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root" class="popup-container bg-gray-900 text-white">
|
||||
<!-- Loading state -->
|
||||
<div id="loading" class="flex items-center justify-center h-full">
|
||||
<div class="text-center">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-orange-500 mx-auto mb-4"></div>
|
||||
<p class="text-gray-400">Loading SecureBit...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Main app content will be rendered here -->
|
||||
<div id="app-content" class="hidden">
|
||||
<!-- This will be populated by the popup script -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Scripts -->
|
||||
<script src="libs/react/react.production.min.js"></script>
|
||||
<script src="libs/react-dom/react-dom.production.min.js"></script>
|
||||
<script src="src/scripts/fa-check.js"></script>
|
||||
<script type="module" src="src/crypto/EnhancedSecureCryptoUtils.js"></script>
|
||||
<script type="module" src="src/network/EnhancedSecureWebRTCManager.js"></script>
|
||||
<script type="module" src="dist/qr-local.js"></script>
|
||||
<script type="module" src="dist/app.js"></script>
|
||||
<script type="module" src="dist/app-boot.js"></script>
|
||||
<script type="module" src="popup.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
331
extension-popup.js
Normal file
@@ -0,0 +1,331 @@
|
||||
// Popup script for SecureBit Chat Extension
|
||||
// Handles the popup UI and communication with background script
|
||||
|
||||
class SecureBitPopup {
|
||||
constructor() {
|
||||
this.isConnected = false;
|
||||
this.currentChannel = null;
|
||||
this.settings = {};
|
||||
this.initializePopup();
|
||||
}
|
||||
|
||||
async initializePopup() {
|
||||
try {
|
||||
// Hide loading and show content
|
||||
document.getElementById('loading').classList.add('hidden');
|
||||
document.getElementById('app-content').classList.remove('hidden');
|
||||
|
||||
// Load settings
|
||||
await this.loadSettings();
|
||||
|
||||
// Initialize the popup UI
|
||||
this.renderPopup();
|
||||
|
||||
// Set up event listeners
|
||||
this.setupEventListeners();
|
||||
|
||||
// Check connection status
|
||||
await this.checkConnectionStatus();
|
||||
|
||||
} catch (error) {
|
||||
console.error('Popup initialization error:', error);
|
||||
this.showError('Failed to initialize SecureBit Chat');
|
||||
}
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
try {
|
||||
const response = await this.sendMessage({ action: 'getSettings' });
|
||||
this.settings = response.data || {};
|
||||
} catch (error) {
|
||||
console.error('Failed to load settings:', error);
|
||||
this.settings = {};
|
||||
}
|
||||
}
|
||||
|
||||
renderPopup() {
|
||||
const appContent = document.getElementById('app-content');
|
||||
|
||||
appContent.innerHTML = `
|
||||
<div class="p-4 space-y-4">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<div class="flex items-center">
|
||||
<img src="logo/icon-32x32.png" alt="SecureBit" class="w-8 h-8 mr-3">
|
||||
<h1 class="text-lg font-bold text-orange-500">SecureBit Chat</h1>
|
||||
</div>
|
||||
<button id="settings-btn" class="text-gray-400 hover:text-white">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Connection Status -->
|
||||
<div id="connection-status" class="p-3 rounded-lg border border-gray-700">
|
||||
<div class="flex items-center">
|
||||
<div id="status-indicator" class="w-3 h-3 rounded-full bg-red-500 mr-3"></div>
|
||||
<span id="status-text" class="text-sm">Disconnected</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Quick Actions -->
|
||||
<div class="space-y-2">
|
||||
<button id="create-channel-btn" class="w-full bg-orange-500 hover:bg-orange-600 text-white py-2 px-4 rounded-lg transition-colors">
|
||||
<i class="fas fa-plus mr-2"></i>Create Channel
|
||||
</button>
|
||||
<button id="join-channel-btn" class="w-full bg-blue-500 hover:bg-blue-600 text-white py-2 px-4 rounded-lg transition-colors">
|
||||
<i class="fas fa-qrcode mr-2"></i>Join Channel
|
||||
</button>
|
||||
<button id="scan-qr-btn" class="w-full bg-green-500 hover:bg-green-600 text-white py-2 px-4 rounded-lg transition-colors">
|
||||
<i class="fas fa-camera mr-2"></i>Scan QR Code
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Recent Channels -->
|
||||
<div id="recent-channels" class="space-y-2">
|
||||
<h3 class="text-sm font-medium text-gray-400 mb-2">Recent Channels</h3>
|
||||
<div id="channels-list" class="space-y-1">
|
||||
<!-- Channels will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Settings Panel -->
|
||||
<div id="settings-panel" class="hidden space-y-3">
|
||||
<h3 class="text-sm font-medium text-gray-400">Settings</h3>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" id="auto-connect" class="mr-2">
|
||||
<span class="text-sm">Auto-connect</span>
|
||||
</label>
|
||||
<label class="flex items-center">
|
||||
<input type="checkbox" id="notifications" class="mr-2">
|
||||
<span class="text-sm">Notifications</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="space-y-2">
|
||||
<label class="block text-sm text-gray-400">Theme</label>
|
||||
<select id="theme-select" class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm">
|
||||
<option value="dark">Dark</option>
|
||||
<option value="light">Light</option>
|
||||
<option value="auto">Auto</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<button id="save-settings-btn" class="w-full bg-gray-700 hover:bg-gray-600 text-white py-2 px-4 rounded-lg transition-colors">
|
||||
Save Settings
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- QR Scanner Modal -->
|
||||
<div id="qr-scanner-modal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
|
||||
<div class="bg-gray-800 rounded-lg p-4 w-80">
|
||||
<div class="flex justify-between items-center mb-4">
|
||||
<h3 class="text-lg font-medium">Scan QR Code</h3>
|
||||
<button id="close-qr-scanner" class="text-gray-400 hover:text-white">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="qr-scanner-container" class="w-full h-64 bg-gray-900 rounded-lg flex items-center justify-center">
|
||||
<div class="text-center">
|
||||
<i class="fas fa-camera text-4xl text-gray-600 mb-2"></i>
|
||||
<p class="text-gray-400">Camera access required</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
// Settings toggle
|
||||
document.getElementById('settings-btn').addEventListener('click', () => {
|
||||
const settingsPanel = document.getElementById('settings-panel');
|
||||
settingsPanel.classList.toggle('hidden');
|
||||
});
|
||||
|
||||
// Create channel
|
||||
document.getElementById('create-channel-btn').addEventListener('click', () => {
|
||||
this.createChannel();
|
||||
});
|
||||
|
||||
// Join channel
|
||||
document.getElementById('join-channel-btn').addEventListener('click', () => {
|
||||
this.joinChannel();
|
||||
});
|
||||
|
||||
// Scan QR
|
||||
document.getElementById('scan-qr-btn').addEventListener('click', () => {
|
||||
this.showQRScanner();
|
||||
});
|
||||
|
||||
// Close QR scanner
|
||||
document.getElementById('close-qr-scanner').addEventListener('click', () => {
|
||||
this.hideQRScanner();
|
||||
});
|
||||
|
||||
// Save settings
|
||||
document.getElementById('save-settings-btn').addEventListener('click', () => {
|
||||
this.saveSettings();
|
||||
});
|
||||
|
||||
// Load saved settings into form
|
||||
this.loadSettingsIntoForm();
|
||||
}
|
||||
|
||||
async checkConnectionStatus() {
|
||||
try {
|
||||
// This would check if there's an active WebRTC connection
|
||||
// For now, we'll simulate the status
|
||||
this.updateConnectionStatus(false);
|
||||
} catch (error) {
|
||||
console.error('Connection check error:', error);
|
||||
this.updateConnectionStatus(false);
|
||||
}
|
||||
}
|
||||
|
||||
updateConnectionStatus(connected) {
|
||||
this.isConnected = connected;
|
||||
const indicator = document.getElementById('status-indicator');
|
||||
const text = document.getElementById('status-text');
|
||||
|
||||
if (connected) {
|
||||
indicator.className = 'w-3 h-3 rounded-full bg-green-500 mr-3';
|
||||
text.textContent = 'Connected';
|
||||
} else {
|
||||
indicator.className = 'w-3 h-3 rounded-full bg-red-500 mr-3';
|
||||
text.textContent = 'Disconnected';
|
||||
}
|
||||
}
|
||||
|
||||
async createChannel() {
|
||||
try {
|
||||
// Generate a new channel ID
|
||||
const channelId = this.generateChannelId();
|
||||
|
||||
// Show notification
|
||||
await this.sendMessage({
|
||||
action: 'showNotification',
|
||||
data: {
|
||||
title: 'Channel Created',
|
||||
message: `Channel ID: ${channelId}`
|
||||
}
|
||||
});
|
||||
|
||||
// Update UI
|
||||
this.updateConnectionStatus(true);
|
||||
this.currentChannel = channelId;
|
||||
|
||||
// Add to recent channels
|
||||
this.addToRecentChannels(channelId, 'New Channel');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Create channel error:', error);
|
||||
this.showError('Failed to create channel');
|
||||
}
|
||||
}
|
||||
|
||||
async joinChannel() {
|
||||
// This would open a QR scanner or input field
|
||||
this.showQRScanner();
|
||||
}
|
||||
|
||||
showQRScanner() {
|
||||
document.getElementById('qr-scanner-modal').classList.remove('hidden');
|
||||
// Here you would initialize the QR scanner
|
||||
this.initializeQRScanner();
|
||||
}
|
||||
|
||||
hideQRScanner() {
|
||||
document.getElementById('qr-scanner-modal').classList.add('hidden');
|
||||
}
|
||||
|
||||
initializeQRScanner() {
|
||||
// Initialize QR scanner functionality
|
||||
// This would integrate with your existing QR scanner component
|
||||
console.log('QR Scanner initialized');
|
||||
}
|
||||
|
||||
addToRecentChannels(channelId, name) {
|
||||
const channelsList = document.getElementById('channels-list');
|
||||
const channelElement = document.createElement('div');
|
||||
channelElement.className = 'flex items-center justify-between p-2 bg-gray-800 rounded-lg hover:bg-gray-700 cursor-pointer';
|
||||
channelElement.innerHTML = `
|
||||
<div>
|
||||
<div class="text-sm font-medium">${name}</div>
|
||||
<div class="text-xs text-gray-400">${channelId}</div>
|
||||
</div>
|
||||
<div class="flex space-x-2">
|
||||
<button class="text-blue-400 hover:text-blue-300">
|
||||
<i class="fas fa-external-link-alt"></i>
|
||||
</button>
|
||||
<button class="text-red-400 hover:text-red-300">
|
||||
<i class="fas fa-trash"></i>
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
channelsList.appendChild(channelElement);
|
||||
}
|
||||
|
||||
loadSettingsIntoForm() {
|
||||
document.getElementById('auto-connect').checked = this.settings.autoConnect || false;
|
||||
document.getElementById('notifications').checked = this.settings.notifications || false;
|
||||
document.getElementById('theme-select').value = this.settings.theme || 'dark';
|
||||
}
|
||||
|
||||
async saveSettings() {
|
||||
try {
|
||||
const newSettings = {
|
||||
autoConnect: document.getElementById('auto-connect').checked,
|
||||
notifications: document.getElementById('notifications').checked,
|
||||
theme: document.getElementById('theme-select').value
|
||||
};
|
||||
|
||||
await this.sendMessage({
|
||||
action: 'updateSettings',
|
||||
data: newSettings
|
||||
});
|
||||
|
||||
this.settings = { ...this.settings, ...newSettings };
|
||||
this.showSuccess('Settings saved');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Save settings error:', error);
|
||||
this.showError('Failed to save settings');
|
||||
}
|
||||
}
|
||||
|
||||
generateChannelId() {
|
||||
return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
|
||||
}
|
||||
|
||||
async sendMessage(message) {
|
||||
return new Promise((resolve, reject) => {
|
||||
chrome.runtime.sendMessage(message, (response) => {
|
||||
if (chrome.runtime.lastError) {
|
||||
reject(new Error(chrome.runtime.lastError.message));
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
// Simple error notification
|
||||
console.error(message);
|
||||
// You could implement a toast notification here
|
||||
}
|
||||
|
||||
showSuccess(message) {
|
||||
// Simple success notification
|
||||
console.log(message);
|
||||
// You could implement a toast notification here
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize popup when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new SecureBitPopup();
|
||||
});
|
||||
BIN
favicon.ico
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
1
ico.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path fill="#fb923c" d="M320 64C324.6 64 329.2 65 333.4 66.9L521.8 146.8C543.8 156.1 560.2 177.8 560.1 204C559.6 303.2 518.8 484.7 346.5 567.2C329.8 575.2 310.4 575.2 293.7 567.2C121.3 484.7 80.6 303.2 80.1 204C80 177.8 96.4 156.1 118.4 146.8L306.7 66.9C310.9 65 315.4 64 320 64zM320 130.8L320 508.9C458 442.1 495.1 294.1 496 205.5L320 130.9L320 130.9z"/></svg>
|
||||
|
After Width: | Height: | Size: 575 B |
65
index.html
Normal file
@@ -0,0 +1,65 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Security-Policy"
|
||||
content="default-src 'self';
|
||||
script-src 'self' ;
|
||||
style-src 'self';
|
||||
font-src 'self' ;
|
||||
connect-src 'self' https: ;
|
||||
img-src 'self' data:;
|
||||
object-src 'none';
|
||||
frame-ancestors 'none';
|
||||
form-action 'self';
|
||||
upgrade-insecure-requests;">
|
||||
<meta http-equiv="X-Content-Type-Options" content="nosniff">
|
||||
<meta http-equiv="X-XSS-Protection" content="1; mode=block">
|
||||
<meta http-equiv="Referrer-Policy" content="strict-origin-when-cross-origin">
|
||||
|
||||
<!-- Basic Meta Tags -->
|
||||
<link rel="icon" type="image/x-icon" href="./logo/favicon.ico">
|
||||
<meta name="theme-color" content="#ff6b35">
|
||||
|
||||
<!-- GitHub Pages SEO -->
|
||||
<meta name="description" content="SecureBit.chat v4.3.120 — P2P messenger with ECDH + DTLS + SAS security and 18-layer military-grade cryptography">
|
||||
<meta name="keywords" content="P2P messenger, ECDH, DTLS, SAS, encryption, WebRTC, privacy, ASN.1 validation, military-grade security, 18-layer defense, MITM protection, PFS">
|
||||
<meta name="author" content="Volodymyr">
|
||||
<link rel="canonical" href="https://github.com/SecureBitChat/securebit-chat/">
|
||||
|
||||
<!-- Open Graph -->
|
||||
<meta property="og:title" content="SecureBit.chat - Enhanced Security Edition">
|
||||
<meta property="og:description" content="The most secure P2P messenger with military-grade cryptography">
|
||||
<meta property="og:url" content="https://github.com/SecureBitChat/securebit-chat/">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:image" content="https://github.com/SecureBitChat/securebit-chat/favicon.ico">
|
||||
|
||||
<!-- Twitter Card -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:title" content="SecureBit.chat - Enhanced Security Edition">
|
||||
<meta name="twitter:description" content="P2P messenger with military-grade cryptography">
|
||||
|
||||
<title>SecureBit.chat - Enhanced Security Edition</title>
|
||||
<script src="libs/react/react.production.min.js"></script>
|
||||
<script src="libs/react-dom/react-dom.production.min.js"></script>
|
||||
<link rel="stylesheet" href="assets/tailwind.css">
|
||||
<link rel="icon" type="image/x-icon" href="/logo/favicon.ico">
|
||||
<link rel="stylesheet" href="/assets/fontawesome/css/all.min.css">
|
||||
<link rel="preload" href="/assets/fontawesome/webfonts/fa-solid-900.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/assets/fontawesome/webfonts/fa-regular-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="/assets/fontawesome/webfonts/fa-brands-400.woff2" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="stylesheet" href="/assets/fonts/inter/inter.css">
|
||||
<link rel="stylesheet" href="src/styles/main.css">
|
||||
<link rel="stylesheet" href="src/styles/animations.css">
|
||||
<link rel="stylesheet" href="src/styles/components.css">
|
||||
<script src="src/scripts/fa-check.js"></script>
|
||||
<script type="module" src="dist/qr-local.js?v=1757383302"></script>
|
||||
<script type="module" src="src/components/QRScanner.js?v=3"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="dist/app.js?v=1757383304"></script>
|
||||
<script type="module" src="dist/app-boot.js?v=1757383304"></script>
|
||||
</body>
|
||||
</html>
|
||||
4
libs/babel/babel.min.js
vendored
Normal file
267
libs/react-dom/react-dom.production.min.js
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
(function(){/*
|
||||
Modernizr 3.0.0pre (Custom Build) | MIT
|
||||
*/
|
||||
'use strict';(function(Q,zb){"object"===typeof exports&&"undefined"!==typeof module?zb(exports,require("react")):"function"===typeof define&&define.amd?define(["exports","react"],zb):(Q=Q||self,zb(Q.ReactDOM={},Q.React))})(this,function(Q,zb){function m(a){for(var b="https://reactjs.org/docs/error-decoder.html?invariant="+a,c=1;c<arguments.length;c++)b+="&args[]="+encodeURIComponent(arguments[c]);return"Minified React error #"+a+"; visit "+b+" for the full message or use the non-minified dev environment for full errors and additional helpful warnings."}
|
||||
function mb(a,b){Ab(a,b);Ab(a+"Capture",b)}function Ab(a,b){$b[a]=b;for(a=0;a<b.length;a++)cg.add(b[a])}function bj(a){if(Zd.call(dg,a))return!0;if(Zd.call(eg,a))return!1;if(cj.test(a))return dg[a]=!0;eg[a]=!0;return!1}function dj(a,b,c,d){if(null!==c&&0===c.type)return!1;switch(typeof b){case "function":case "symbol":return!0;case "boolean":if(d)return!1;if(null!==c)return!c.acceptsBooleans;a=a.toLowerCase().slice(0,5);return"data-"!==a&&"aria-"!==a;default:return!1}}function ej(a,b,c,d){if(null===
|
||||
b||"undefined"===typeof b||dj(a,b,c,d))return!0;if(d)return!1;if(null!==c)switch(c.type){case 3:return!b;case 4:return!1===b;case 5:return isNaN(b);case 6:return isNaN(b)||1>b}return!1}function Y(a,b,c,d,e,f,g){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b;this.sanitizeURL=f;this.removeEmptyString=g}function $d(a,b,c,d){var e=R.hasOwnProperty(b)?R[b]:null;if(null!==e?0!==e.type:d||!(2<b.length)||"o"!==
|
||||
b[0]&&"O"!==b[0]||"n"!==b[1]&&"N"!==b[1])ej(b,c,e,d)&&(c=null),d||null===e?bj(b)&&(null===c?a.removeAttribute(b):a.setAttribute(b,""+c)):e.mustUseProperty?a[e.propertyName]=null===c?3===e.type?!1:"":c:(b=e.attributeName,d=e.attributeNamespace,null===c?a.removeAttribute(b):(e=e.type,c=3===e||4===e&&!0===c?"":""+c,d?a.setAttributeNS(d,b,c):a.setAttribute(b,c)))}function ac(a){if(null===a||"object"!==typeof a)return null;a=fg&&a[fg]||a["@@iterator"];return"function"===typeof a?a:null}function bc(a,b,
|
||||
c){if(void 0===ae)try{throw Error();}catch(d){ae=(b=d.stack.trim().match(/\n( *(at )?)/))&&b[1]||""}return"\n"+ae+a}function be(a,b){if(!a||ce)return"";ce=!0;var c=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{if(b)if(b=function(){throw Error();},Object.defineProperty(b.prototype,"props",{set:function(){throw Error();}}),"object"===typeof Reflect&&Reflect.construct){try{Reflect.construct(b,[])}catch(n){var d=n}Reflect.construct(a,[],b)}else{try{b.call()}catch(n){d=n}a.call(b.prototype)}else{try{throw Error();
|
||||
}catch(n){d=n}a()}}catch(n){if(n&&d&&"string"===typeof n.stack){for(var e=n.stack.split("\n"),f=d.stack.split("\n"),g=e.length-1,h=f.length-1;1<=g&&0<=h&&e[g]!==f[h];)h--;for(;1<=g&&0<=h;g--,h--)if(e[g]!==f[h]){if(1!==g||1!==h){do if(g--,h--,0>h||e[g]!==f[h]){var k="\n"+e[g].replace(" at new "," at ");a.displayName&&k.includes("<anonymous>")&&(k=k.replace("<anonymous>",a.displayName));return k}while(1<=g&&0<=h)}break}}}finally{ce=!1,Error.prepareStackTrace=c}return(a=a?a.displayName||a.name:"")?bc(a):
|
||||
""}function fj(a){switch(a.tag){case 5:return bc(a.type);case 16:return bc("Lazy");case 13:return bc("Suspense");case 19:return bc("SuspenseList");case 0:case 2:case 15:return a=be(a.type,!1),a;case 11:return a=be(a.type.render,!1),a;case 1:return a=be(a.type,!0),a;default:return""}}function de(a){if(null==a)return null;if("function"===typeof a)return a.displayName||a.name||null;if("string"===typeof a)return a;switch(a){case Bb:return"Fragment";case Cb:return"Portal";case ee:return"Profiler";case fe:return"StrictMode";
|
||||
case ge:return"Suspense";case he:return"SuspenseList"}if("object"===typeof a)switch(a.$$typeof){case gg:return(a.displayName||"Context")+".Consumer";case hg:return(a._context.displayName||"Context")+".Provider";case ie:var b=a.render;a=a.displayName;a||(a=b.displayName||b.name||"",a=""!==a?"ForwardRef("+a+")":"ForwardRef");return a;case je:return b=a.displayName||null,null!==b?b:de(a.type)||"Memo";case Ta:b=a._payload;a=a._init;try{return de(a(b))}catch(c){}}return null}function gj(a){var b=a.type;
|
||||
switch(a.tag){case 24:return"Cache";case 9:return(b.displayName||"Context")+".Consumer";case 10:return(b._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return a=b.render,a=a.displayName||a.name||"",b.displayName||(""!==a?"ForwardRef("+a+")":"ForwardRef");case 7:return"Fragment";case 5:return b;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return de(b);case 8:return b===fe?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";
|
||||
case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if("function"===typeof b)return b.displayName||b.name||null;if("string"===typeof b)return b}return null}function Ua(a){switch(typeof a){case "boolean":case "number":case "string":case "undefined":return a;case "object":return a;default:return""}}function ig(a){var b=a.type;return(a=a.nodeName)&&"input"===a.toLowerCase()&&("checkbox"===b||"radio"===
|
||||
b)}function hj(a){var b=ig(a)?"checked":"value",c=Object.getOwnPropertyDescriptor(a.constructor.prototype,b),d=""+a[b];if(!a.hasOwnProperty(b)&&"undefined"!==typeof c&&"function"===typeof c.get&&"function"===typeof c.set){var e=c.get,f=c.set;Object.defineProperty(a,b,{configurable:!0,get:function(){return e.call(this)},set:function(a){d=""+a;f.call(this,a)}});Object.defineProperty(a,b,{enumerable:c.enumerable});return{getValue:function(){return d},setValue:function(a){d=""+a},stopTracking:function(){a._valueTracker=
|
||||
null;delete a[b]}}}}function Pc(a){a._valueTracker||(a._valueTracker=hj(a))}function jg(a){if(!a)return!1;var b=a._valueTracker;if(!b)return!0;var c=b.getValue();var d="";a&&(d=ig(a)?a.checked?"true":"false":a.value);a=d;return a!==c?(b.setValue(a),!0):!1}function Qc(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}}function ke(a,b){var c=b.checked;return E({},b,{defaultChecked:void 0,defaultValue:void 0,
|
||||
value:void 0,checked:null!=c?c:a._wrapperState.initialChecked})}function kg(a,b){var c=null==b.defaultValue?"":b.defaultValue,d=null!=b.checked?b.checked:b.defaultChecked;c=Ua(null!=b.value?b.value:c);a._wrapperState={initialChecked:d,initialValue:c,controlled:"checkbox"===b.type||"radio"===b.type?null!=b.checked:null!=b.value}}function lg(a,b){b=b.checked;null!=b&&$d(a,"checked",b,!1)}function le(a,b){lg(a,b);var c=Ua(b.value),d=b.type;if(null!=c)if("number"===d){if(0===c&&""===a.value||a.value!=
|
||||
c)a.value=""+c}else a.value!==""+c&&(a.value=""+c);else if("submit"===d||"reset"===d){a.removeAttribute("value");return}b.hasOwnProperty("value")?me(a,b.type,c):b.hasOwnProperty("defaultValue")&&me(a,b.type,Ua(b.defaultValue));null==b.checked&&null!=b.defaultChecked&&(a.defaultChecked=!!b.defaultChecked)}function mg(a,b,c){if(b.hasOwnProperty("value")||b.hasOwnProperty("defaultValue")){var d=b.type;if(!("submit"!==d&&"reset"!==d||void 0!==b.value&&null!==b.value))return;b=""+a._wrapperState.initialValue;
|
||||
c||b===a.value||(a.value=b);a.defaultValue=b}c=a.name;""!==c&&(a.name="");a.defaultChecked=!!a._wrapperState.initialChecked;""!==c&&(a.name=c)}function me(a,b,c){if("number"!==b||Qc(a.ownerDocument)!==a)null==c?a.defaultValue=""+a._wrapperState.initialValue:a.defaultValue!==""+c&&(a.defaultValue=""+c)}function Db(a,b,c,d){a=a.options;if(b){b={};for(var e=0;e<c.length;e++)b["$"+c[e]]=!0;for(c=0;c<a.length;c++)e=b.hasOwnProperty("$"+a[c].value),a[c].selected!==e&&(a[c].selected=e),e&&d&&(a[c].defaultSelected=
|
||||
!0)}else{c=""+Ua(c);b=null;for(e=0;e<a.length;e++){if(a[e].value===c){a[e].selected=!0;d&&(a[e].defaultSelected=!0);return}null!==b||a[e].disabled||(b=a[e])}null!==b&&(b.selected=!0)}}function ne(a,b){if(null!=b.dangerouslySetInnerHTML)throw Error(m(91));return E({},b,{value:void 0,defaultValue:void 0,children:""+a._wrapperState.initialValue})}function ng(a,b){var c=b.value;if(null==c){c=b.children;b=b.defaultValue;if(null!=c){if(null!=b)throw Error(m(92));if(cc(c)){if(1<c.length)throw Error(m(93));
|
||||
c=c[0]}b=c}null==b&&(b="");c=b}a._wrapperState={initialValue:Ua(c)}}function og(a,b){var c=Ua(b.value),d=Ua(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function pg(a,b){b=a.textContent;b===a._wrapperState.initialValue&&""!==b&&null!==b&&(a.value=b)}function qg(a){switch(a){case "svg":return"http://www.w3.org/2000/svg";case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}
|
||||
function oe(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?qg(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function rg(a,b,c){return null==b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||dc.hasOwnProperty(a)&&dc[a]?(""+b).trim():b+"px"}function sg(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=rg(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function pe(a,b){if(b){if(ij[a]&&
|
||||
(null!=b.children||null!=b.dangerouslySetInnerHTML))throw Error(m(137,a));if(null!=b.dangerouslySetInnerHTML){if(null!=b.children)throw Error(m(60));if("object"!==typeof b.dangerouslySetInnerHTML||!("__html"in b.dangerouslySetInnerHTML))throw Error(m(61));}if(null!=b.style&&"object"!==typeof b.style)throw Error(m(62));}}function qe(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;
|
||||
default:return!0}}function re(a){a=a.target||a.srcElement||window;a.correspondingUseElement&&(a=a.correspondingUseElement);return 3===a.nodeType?a.parentNode:a}function tg(a){if(a=ec(a)){if("function"!==typeof se)throw Error(m(280));var b=a.stateNode;b&&(b=Rc(b),se(a.stateNode,a.type,b))}}function ug(a){Eb?Fb?Fb.push(a):Fb=[a]:Eb=a}function vg(){if(Eb){var a=Eb,b=Fb;Fb=Eb=null;tg(a);if(b)for(a=0;a<b.length;a++)tg(b[a])}}function wg(a,b,c){if(te)return a(b,c);te=!0;try{return xg(a,b,c)}finally{if(te=
|
||||
!1,null!==Eb||null!==Fb)yg(),vg()}}function fc(a,b){var c=a.stateNode;if(null===c)return null;var d=Rc(c);if(null===d)return null;c=d[b];a:switch(b){case "onClick":case "onClickCapture":case "onDoubleClick":case "onDoubleClickCapture":case "onMouseDown":case "onMouseDownCapture":case "onMouseMove":case "onMouseMoveCapture":case "onMouseUp":case "onMouseUpCapture":case "onMouseEnter":(d=!d.disabled)||(a=a.type,d=!("button"===a||"input"===a||"select"===a||"textarea"===a));a=!d;break a;default:a=!1}if(a)return null;
|
||||
if(c&&"function"!==typeof c)throw Error(m(231,b,typeof c));return c}function jj(a,b,c,d,e,f,g,h,k){gc=!1;Sc=null;kj.apply(lj,arguments)}function mj(a,b,c,d,e,f,g,h,k){jj.apply(this,arguments);if(gc){if(gc){var n=Sc;gc=!1;Sc=null}else throw Error(m(198));Tc||(Tc=!0,ue=n)}}function nb(a){var b=a,c=a;if(a.alternate)for(;b.return;)b=b.return;else{a=b;do b=a,0!==(b.flags&4098)&&(c=b.return),a=b.return;while(a)}return 3===b.tag?c:null}function zg(a){if(13===a.tag){var b=a.memoizedState;null===b&&(a=a.alternate,
|
||||
null!==a&&(b=a.memoizedState));if(null!==b)return b.dehydrated}return null}function Ag(a){if(nb(a)!==a)throw Error(m(188));}function nj(a){var b=a.alternate;if(!b){b=nb(a);if(null===b)throw Error(m(188));return b!==a?null:a}for(var c=a,d=b;;){var e=c.return;if(null===e)break;var f=e.alternate;if(null===f){d=e.return;if(null!==d){c=d;continue}break}if(e.child===f.child){for(f=e.child;f;){if(f===c)return Ag(e),a;if(f===d)return Ag(e),b;f=f.sibling}throw Error(m(188));}if(c.return!==d.return)c=e,d=f;
|
||||
else{for(var g=!1,h=e.child;h;){if(h===c){g=!0;c=e;d=f;break}if(h===d){g=!0;d=e;c=f;break}h=h.sibling}if(!g){for(h=f.child;h;){if(h===c){g=!0;c=f;d=e;break}if(h===d){g=!0;d=f;c=e;break}h=h.sibling}if(!g)throw Error(m(189));}}if(c.alternate!==d)throw Error(m(190));}if(3!==c.tag)throw Error(m(188));return c.stateNode.current===c?a:b}function Bg(a){a=nj(a);return null!==a?Cg(a):null}function Cg(a){if(5===a.tag||6===a.tag)return a;for(a=a.child;null!==a;){var b=Cg(a);if(null!==b)return b;a=a.sibling}return null}
|
||||
function oj(a,b){if(Ca&&"function"===typeof Ca.onCommitFiberRoot)try{Ca.onCommitFiberRoot(Uc,a,void 0,128===(a.current.flags&128))}catch(c){}}function pj(a){a>>>=0;return 0===a?32:31-(qj(a)/rj|0)|0}function hc(a){switch(a&-a){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return a&
|
||||
4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return a&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return a}}function Vc(a,b){var c=a.pendingLanes;if(0===c)return 0;var d=0,e=a.suspendedLanes,f=a.pingedLanes,g=c&268435455;if(0!==g){var h=g&~e;0!==h?d=hc(h):(f&=g,0!==f&&(d=hc(f)))}else g=c&~e,0!==g?d=hc(g):0!==f&&(d=hc(f));if(0===d)return 0;if(0!==b&&b!==d&&0===(b&e)&&
|
||||
(e=d&-d,f=b&-b,e>=f||16===e&&0!==(f&4194240)))return b;0!==(d&4)&&(d|=c&16);b=a.entangledLanes;if(0!==b)for(a=a.entanglements,b&=d;0<b;)c=31-ta(b),e=1<<c,d|=a[c],b&=~e;return d}function sj(a,b){switch(a){case 1:case 2:case 4:return b+250;case 8:case 16:case 32:case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return b+5E3;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return-1;
|
||||
case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function tj(a,b){for(var c=a.suspendedLanes,d=a.pingedLanes,e=a.expirationTimes,f=a.pendingLanes;0<f;){var g=31-ta(f),h=1<<g,k=e[g];if(-1===k){if(0===(h&c)||0!==(h&d))e[g]=sj(h,b)}else k<=b&&(a.expiredLanes|=h);f&=~h}}function ve(a){a=a.pendingLanes&-1073741825;return 0!==a?a:a&1073741824?1073741824:0}function Dg(){var a=Wc;Wc<<=1;0===(Wc&4194240)&&(Wc=64);return a}function we(a){for(var b=[],c=0;31>c;c++)b.push(a);
|
||||
return b}function ic(a,b,c){a.pendingLanes|=b;536870912!==b&&(a.suspendedLanes=0,a.pingedLanes=0);a=a.eventTimes;b=31-ta(b);a[b]=c}function uj(a,b){var c=a.pendingLanes&~b;a.pendingLanes=b;a.suspendedLanes=0;a.pingedLanes=0;a.expiredLanes&=b;a.mutableReadLanes&=b;a.entangledLanes&=b;b=a.entanglements;var d=a.eventTimes;for(a=a.expirationTimes;0<c;){var e=31-ta(c),f=1<<e;b[e]=0;d[e]=-1;a[e]=-1;c&=~f}}function xe(a,b){var c=a.entangledLanes|=b;for(a=a.entanglements;c;){var d=31-ta(c),e=1<<d;e&b|a[d]&
|
||||
b&&(a[d]|=b);c&=~e}}function Eg(a){a&=-a;return 1<a?4<a?0!==(a&268435455)?16:536870912:4:1}function Fg(a,b){switch(a){case "focusin":case "focusout":Va=null;break;case "dragenter":case "dragleave":Wa=null;break;case "mouseover":case "mouseout":Xa=null;break;case "pointerover":case "pointerout":jc.delete(b.pointerId);break;case "gotpointercapture":case "lostpointercapture":kc.delete(b.pointerId)}}function lc(a,b,c,d,e,f){if(null===a||a.nativeEvent!==f)return a={blockedOn:b,domEventName:c,eventSystemFlags:d,
|
||||
nativeEvent:f,targetContainers:[e]},null!==b&&(b=ec(b),null!==b&&Gg(b)),a;a.eventSystemFlags|=d;b=a.targetContainers;null!==e&&-1===b.indexOf(e)&&b.push(e);return a}function vj(a,b,c,d,e){switch(b){case "focusin":return Va=lc(Va,a,b,c,d,e),!0;case "dragenter":return Wa=lc(Wa,a,b,c,d,e),!0;case "mouseover":return Xa=lc(Xa,a,b,c,d,e),!0;case "pointerover":var f=e.pointerId;jc.set(f,lc(jc.get(f)||null,a,b,c,d,e));return!0;case "gotpointercapture":return f=e.pointerId,kc.set(f,lc(kc.get(f)||null,a,b,
|
||||
c,d,e)),!0}return!1}function Hg(a){var b=ob(a.target);if(null!==b){var c=nb(b);if(null!==c)if(b=c.tag,13===b){if(b=zg(c),null!==b){a.blockedOn=b;wj(a.priority,function(){xj(c)});return}}else if(3===b&&c.stateNode.current.memoizedState.isDehydrated){a.blockedOn=3===c.tag?c.stateNode.containerInfo:null;return}}a.blockedOn=null}function Xc(a){if(null!==a.blockedOn)return!1;for(var b=a.targetContainers;0<b.length;){var c=ye(a.domEventName,a.eventSystemFlags,b[0],a.nativeEvent);if(null===c){c=a.nativeEvent;
|
||||
var d=new c.constructor(c.type,c);ze=d;c.target.dispatchEvent(d);ze=null}else return b=ec(c),null!==b&&Gg(b),a.blockedOn=c,!1;b.shift()}return!0}function Ig(a,b,c){Xc(a)&&c.delete(b)}function yj(){Ae=!1;null!==Va&&Xc(Va)&&(Va=null);null!==Wa&&Xc(Wa)&&(Wa=null);null!==Xa&&Xc(Xa)&&(Xa=null);jc.forEach(Ig);kc.forEach(Ig)}function mc(a,b){a.blockedOn===b&&(a.blockedOn=null,Ae||(Ae=!0,Jg(Kg,yj)))}function nc(a){if(0<Yc.length){mc(Yc[0],a);for(var b=1;b<Yc.length;b++){var c=Yc[b];c.blockedOn===a&&(c.blockedOn=
|
||||
null)}}null!==Va&&mc(Va,a);null!==Wa&&mc(Wa,a);null!==Xa&&mc(Xa,a);b=function(b){return mc(b,a)};jc.forEach(b);kc.forEach(b);for(b=0;b<Ya.length;b++)c=Ya[b],c.blockedOn===a&&(c.blockedOn=null);for(;0<Ya.length&&(b=Ya[0],null===b.blockedOn);)Hg(b),null===b.blockedOn&&Ya.shift()}function zj(a,b,c,d){var e=z,f=Gb.transition;Gb.transition=null;try{z=1,Be(a,b,c,d)}finally{z=e,Gb.transition=f}}function Aj(a,b,c,d){var e=z,f=Gb.transition;Gb.transition=null;try{z=4,Be(a,b,c,d)}finally{z=e,Gb.transition=
|
||||
f}}function Be(a,b,c,d){if(Zc){var e=ye(a,b,c,d);if(null===e)Ce(a,b,d,$c,c),Fg(a,d);else if(vj(e,a,b,c,d))d.stopPropagation();else if(Fg(a,d),b&4&&-1<Bj.indexOf(a)){for(;null!==e;){var f=ec(e);null!==f&&Cj(f);f=ye(a,b,c,d);null===f&&Ce(a,b,d,$c,c);if(f===e)break;e=f}null!==e&&d.stopPropagation()}else Ce(a,b,d,null,c)}}function ye(a,b,c,d){$c=null;a=re(d);a=ob(a);if(null!==a)if(b=nb(a),null===b)a=null;else if(c=b.tag,13===c){a=zg(b);if(null!==a)return a;a=null}else if(3===c){if(b.stateNode.current.memoizedState.isDehydrated)return 3===
|
||||
b.tag?b.stateNode.containerInfo:null;a=null}else b!==a&&(a=null);$c=a;return null}function Lg(a){switch(a){case "cancel":case "click":case "close":case "contextmenu":case "copy":case "cut":case "auxclick":case "dblclick":case "dragend":case "dragstart":case "drop":case "focusin":case "focusout":case "input":case "invalid":case "keydown":case "keypress":case "keyup":case "mousedown":case "mouseup":case "paste":case "pause":case "play":case "pointercancel":case "pointerdown":case "pointerup":case "ratechange":case "reset":case "resize":case "seeked":case "submit":case "touchcancel":case "touchend":case "touchstart":case "volumechange":case "change":case "selectionchange":case "textInput":case "compositionstart":case "compositionend":case "compositionupdate":case "beforeblur":case "afterblur":case "beforeinput":case "blur":case "fullscreenchange":case "focus":case "hashchange":case "popstate":case "select":case "selectstart":return 1;
|
||||
case "drag":case "dragenter":case "dragexit":case "dragleave":case "dragover":case "mousemove":case "mouseout":case "mouseover":case "pointermove":case "pointerout":case "pointerover":case "scroll":case "toggle":case "touchmove":case "wheel":case "mouseenter":case "mouseleave":case "pointerenter":case "pointerleave":return 4;case "message":switch(Dj()){case De:return 1;case Mg:return 4;case ad:case Ej:return 16;case Ng:return 536870912;default:return 16}default:return 16}}function Og(){if(bd)return bd;
|
||||
var a,b=Ee,c=b.length,d,e="value"in Za?Za.value:Za.textContent,f=e.length;for(a=0;a<c&&b[a]===e[a];a++);var g=c-a;for(d=1;d<=g&&b[c-d]===e[f-d];d++);return bd=e.slice(a,1<d?1-d:void 0)}function cd(a){var b=a.keyCode;"charCode"in a?(a=a.charCode,0===a&&13===b&&(a=13)):a=b;10===a&&(a=13);return 32<=a||13===a?a:0}function dd(){return!0}function Pg(){return!1}function ka(a){function b(b,d,e,f,g){this._reactName=b;this._targetInst=e;this.type=d;this.nativeEvent=f;this.target=g;this.currentTarget=null;
|
||||
for(var c in a)a.hasOwnProperty(c)&&(b=a[c],this[c]=b?b(f):f[c]);this.isDefaultPrevented=(null!=f.defaultPrevented?f.defaultPrevented:!1===f.returnValue)?dd:Pg;this.isPropagationStopped=Pg;return this}E(b.prototype,{preventDefault:function(){this.defaultPrevented=!0;var a=this.nativeEvent;a&&(a.preventDefault?a.preventDefault():"unknown"!==typeof a.returnValue&&(a.returnValue=!1),this.isDefaultPrevented=dd)},stopPropagation:function(){var a=this.nativeEvent;a&&(a.stopPropagation?a.stopPropagation():
|
||||
"unknown"!==typeof a.cancelBubble&&(a.cancelBubble=!0),this.isPropagationStopped=dd)},persist:function(){},isPersistent:dd});return b}function Fj(a){var b=this.nativeEvent;return b.getModifierState?b.getModifierState(a):(a=Gj[a])?!!b[a]:!1}function Fe(a){return Fj}function Qg(a,b){switch(a){case "keyup":return-1!==Hj.indexOf(b.keyCode);case "keydown":return 229!==b.keyCode;case "keypress":case "mousedown":case "focusout":return!0;default:return!1}}function Rg(a){a=a.detail;return"object"===typeof a&&
|
||||
"data"in a?a.data:null}function Ij(a,b){switch(a){case "compositionend":return Rg(b);case "keypress":if(32!==b.which)return null;Sg=!0;return Tg;case "textInput":return a=b.data,a===Tg&&Sg?null:a;default:return null}}function Jj(a,b){if(Hb)return"compositionend"===a||!Ge&&Qg(a,b)?(a=Og(),bd=Ee=Za=null,Hb=!1,a):null;switch(a){case "paste":return null;case "keypress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1<b.char.length)return b.char;if(b.which)return String.fromCharCode(b.which)}return null;
|
||||
case "compositionend":return Ug&&"ko"!==b.locale?null:b.data;default:return null}}function Vg(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return"input"===b?!!Kj[a.type]:"textarea"===b?!0:!1}function Lj(a){if(!Ia)return!1;a="on"+a;var b=a in document;b||(b=document.createElement("div"),b.setAttribute(a,"return;"),b="function"===typeof b[a]);return b}function Wg(a,b,c,d){ug(d);b=ed(b,"onChange");0<b.length&&(c=new He("onChange","change",null,c,d),a.push({event:c,listeners:b}))}function Mj(a){Xg(a,
|
||||
0)}function fd(a){var b=Ib(a);if(jg(b))return a}function Nj(a,b){if("change"===a)return b}function Yg(){oc&&(oc.detachEvent("onpropertychange",Zg),pc=oc=null)}function Zg(a){if("value"===a.propertyName&&fd(pc)){var b=[];Wg(b,pc,a,re(a));wg(Mj,b)}}function Oj(a,b,c){"focusin"===a?(Yg(),oc=b,pc=c,oc.attachEvent("onpropertychange",Zg)):"focusout"===a&&Yg()}function Pj(a,b){if("selectionchange"===a||"keyup"===a||"keydown"===a)return fd(pc)}function Qj(a,b){if("click"===a)return fd(b)}function Rj(a,b){if("input"===
|
||||
a||"change"===a)return fd(b)}function Sj(a,b){return a===b&&(0!==a||1/a===1/b)||a!==a&&b!==b}function qc(a,b){if(ua(a,b))return!0;if("object"!==typeof a||null===a||"object"!==typeof b||null===b)return!1;var c=Object.keys(a),d=Object.keys(b);if(c.length!==d.length)return!1;for(d=0;d<c.length;d++){var e=c[d];if(!Zd.call(b,e)||!ua(a[e],b[e]))return!1}return!0}function $g(a){for(;a&&a.firstChild;)a=a.firstChild;return a}function ah(a,b){var c=$g(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;
|
||||
if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=$g(c)}}function bh(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?bh(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function ch(){for(var a=window,b=Qc();b instanceof a.HTMLIFrameElement;){try{var c="string"===typeof b.contentWindow.location.href}catch(d){c=!1}if(c)a=b.contentWindow;else break;
|
||||
b=Qc(a.document)}return b}function Ie(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function Tj(a){var b=ch(),c=a.focusedElem,d=a.selectionRange;if(b!==c&&c&&c.ownerDocument&&bh(c.ownerDocument.documentElement,c)){if(null!==d&&Ie(c))if(b=d.start,a=d.end,void 0===a&&(a=b),"selectionStart"in c)c.selectionStart=b,c.selectionEnd=Math.min(a,c.value.length);
|
||||
else if(a=(b=c.ownerDocument||document)&&b.defaultView||window,a.getSelection){a=a.getSelection();var e=c.textContent.length,f=Math.min(d.start,e);d=void 0===d.end?f:Math.min(d.end,e);!a.extend&&f>d&&(e=d,d=f,f=e);e=ah(c,f);var g=ah(c,d);e&&g&&(1!==a.rangeCount||a.anchorNode!==e.node||a.anchorOffset!==e.offset||a.focusNode!==g.node||a.focusOffset!==g.offset)&&(b=b.createRange(),b.setStart(e.node,e.offset),a.removeAllRanges(),f>d?(a.addRange(b),a.extend(g.node,g.offset)):(b.setEnd(g.node,g.offset),
|
||||
a.addRange(b)))}b=[];for(a=c;a=a.parentNode;)1===a.nodeType&&b.push({element:a,left:a.scrollLeft,top:a.scrollTop});"function"===typeof c.focus&&c.focus();for(c=0;c<b.length;c++)a=b[c],a.element.scrollLeft=a.left,a.element.scrollTop=a.top}}function dh(a,b,c){var d=c.window===c?c.document:9===c.nodeType?c:c.ownerDocument;Je||null==Jb||Jb!==Qc(d)||(d=Jb,"selectionStart"in d&&Ie(d)?d={start:d.selectionStart,end:d.selectionEnd}:(d=(d.ownerDocument&&d.ownerDocument.defaultView||window).getSelection(),d=
|
||||
{anchorNode:d.anchorNode,anchorOffset:d.anchorOffset,focusNode:d.focusNode,focusOffset:d.focusOffset}),rc&&qc(rc,d)||(rc=d,d=ed(Ke,"onSelect"),0<d.length&&(b=new He("onSelect","select",null,b,c),a.push({event:b,listeners:d}),b.target=Jb)))}function gd(a,b){var c={};c[a.toLowerCase()]=b.toLowerCase();c["Webkit"+a]="webkit"+b;c["Moz"+a]="moz"+b;return c}function hd(a){if(Le[a])return Le[a];if(!Kb[a])return a;var b=Kb[a],c;for(c in b)if(b.hasOwnProperty(c)&&c in eh)return Le[a]=b[c];return a}function $a(a,
|
||||
b){fh.set(a,b);mb(b,[a])}function gh(a,b,c){var d=a.type||"unknown-event";a.currentTarget=c;mj(d,b,void 0,a);a.currentTarget=null}function Xg(a,b){b=0!==(b&4);for(var c=0;c<a.length;c++){var d=a[c],e=d.event;d=d.listeners;a:{var f=void 0;if(b)for(var g=d.length-1;0<=g;g--){var h=d[g],k=h.instance,n=h.currentTarget;h=h.listener;if(k!==f&&e.isPropagationStopped())break a;gh(e,h,n);f=k}else for(g=0;g<d.length;g++){h=d[g];k=h.instance;n=h.currentTarget;h=h.listener;if(k!==f&&e.isPropagationStopped())break a;
|
||||
gh(e,h,n);f=k}}}if(Tc)throw a=ue,Tc=!1,ue=null,a;}function B(a,b){var c=b[Me];void 0===c&&(c=b[Me]=new Set);var d=a+"__bubble";c.has(d)||(hh(b,a,2,!1),c.add(d))}function Ne(a,b,c){var d=0;b&&(d|=4);hh(c,a,d,b)}function sc(a){if(!a[id]){a[id]=!0;cg.forEach(function(b){"selectionchange"!==b&&(Uj.has(b)||Ne(b,!1,a),Ne(b,!0,a))});var b=9===a.nodeType?a:a.ownerDocument;null===b||b[id]||(b[id]=!0,Ne("selectionchange",!1,b))}}function hh(a,b,c,d,e){switch(Lg(b)){case 1:e=zj;break;case 4:e=Aj;break;default:e=
|
||||
Be}c=e.bind(null,b,c,a);e=void 0;!Oe||"touchstart"!==b&&"touchmove"!==b&&"wheel"!==b||(e=!0);d?void 0!==e?a.addEventListener(b,c,{capture:!0,passive:e}):a.addEventListener(b,c,!0):void 0!==e?a.addEventListener(b,c,{passive:e}):a.addEventListener(b,c,!1)}function Ce(a,b,c,d,e){var f=d;if(0===(b&1)&&0===(b&2)&&null!==d)a:for(;;){if(null===d)return;var g=d.tag;if(3===g||4===g){var h=d.stateNode.containerInfo;if(h===e||8===h.nodeType&&h.parentNode===e)break;if(4===g)for(g=d.return;null!==g;){var k=g.tag;
|
||||
if(3===k||4===k)if(k=g.stateNode.containerInfo,k===e||8===k.nodeType&&k.parentNode===e)return;g=g.return}for(;null!==h;){g=ob(h);if(null===g)return;k=g.tag;if(5===k||6===k){d=f=g;continue a}h=h.parentNode}}d=d.return}wg(function(){var d=f,e=re(c),g=[];a:{var h=fh.get(a);if(void 0!==h){var k=He,m=a;switch(a){case "keypress":if(0===cd(c))break a;case "keydown":case "keyup":k=Vj;break;case "focusin":m="focus";k=Pe;break;case "focusout":m="blur";k=Pe;break;case "beforeblur":case "afterblur":k=Pe;break;
|
||||
case "click":if(2===c.button)break a;case "auxclick":case "dblclick":case "mousedown":case "mousemove":case "mouseup":case "mouseout":case "mouseover":case "contextmenu":k=ih;break;case "drag":case "dragend":case "dragenter":case "dragexit":case "dragleave":case "dragover":case "dragstart":case "drop":k=Wj;break;case "touchcancel":case "touchend":case "touchmove":case "touchstart":k=Xj;break;case jh:case kh:case lh:k=Yj;break;case mh:k=Zj;break;case "scroll":k=ak;break;case "wheel":k=bk;break;case "copy":case "cut":case "paste":k=
|
||||
ck;break;case "gotpointercapture":case "lostpointercapture":case "pointercancel":case "pointerdown":case "pointermove":case "pointerout":case "pointerover":case "pointerup":k=nh}var l=0!==(b&4),p=!l&&"scroll"===a,w=l?null!==h?h+"Capture":null:h;l=[];for(var A=d,t;null!==A;){t=A;var M=t.stateNode;5===t.tag&&null!==M&&(t=M,null!==w&&(M=fc(A,w),null!=M&&l.push(tc(A,M,t))));if(p)break;A=A.return}0<l.length&&(h=new k(h,m,null,c,e),g.push({event:h,listeners:l}))}}if(0===(b&7)){a:{h="mouseover"===a||"pointerover"===
|
||||
a;k="mouseout"===a||"pointerout"===a;if(h&&c!==ze&&(m=c.relatedTarget||c.fromElement)&&(ob(m)||m[Ja]))break a;if(k||h){h=e.window===e?e:(h=e.ownerDocument)?h.defaultView||h.parentWindow:window;if(k){if(m=c.relatedTarget||c.toElement,k=d,m=m?ob(m):null,null!==m&&(p=nb(m),m!==p||5!==m.tag&&6!==m.tag))m=null}else k=null,m=d;if(k!==m){l=ih;M="onMouseLeave";w="onMouseEnter";A="mouse";if("pointerout"===a||"pointerover"===a)l=nh,M="onPointerLeave",w="onPointerEnter",A="pointer";p=null==k?h:Ib(k);t=null==
|
||||
m?h:Ib(m);h=new l(M,A+"leave",k,c,e);h.target=p;h.relatedTarget=t;M=null;ob(e)===d&&(l=new l(w,A+"enter",m,c,e),l.target=t,l.relatedTarget=p,M=l);p=M;if(k&&m)b:{l=k;w=m;A=0;for(t=l;t;t=Lb(t))A++;t=0;for(M=w;M;M=Lb(M))t++;for(;0<A-t;)l=Lb(l),A--;for(;0<t-A;)w=Lb(w),t--;for(;A--;){if(l===w||null!==w&&l===w.alternate)break b;l=Lb(l);w=Lb(w)}l=null}else l=null;null!==k&&oh(g,h,k,l,!1);null!==m&&null!==p&&oh(g,p,m,l,!0)}}}a:{h=d?Ib(d):window;k=h.nodeName&&h.nodeName.toLowerCase();if("select"===k||"input"===
|
||||
k&&"file"===h.type)var ma=Nj;else if(Vg(h))if(ph)ma=Rj;else{ma=Pj;var va=Oj}else(k=h.nodeName)&&"input"===k.toLowerCase()&&("checkbox"===h.type||"radio"===h.type)&&(ma=Qj);if(ma&&(ma=ma(a,d))){Wg(g,ma,c,e);break a}va&&va(a,h,d);"focusout"===a&&(va=h._wrapperState)&&va.controlled&&"number"===h.type&&me(h,"number",h.value)}va=d?Ib(d):window;switch(a){case "focusin":if(Vg(va)||"true"===va.contentEditable)Jb=va,Ke=d,rc=null;break;case "focusout":rc=Ke=Jb=null;break;case "mousedown":Je=!0;break;case "contextmenu":case "mouseup":case "dragend":Je=
|
||||
!1;dh(g,c,e);break;case "selectionchange":if(dk)break;case "keydown":case "keyup":dh(g,c,e)}var ab;if(Ge)b:{switch(a){case "compositionstart":var da="onCompositionStart";break b;case "compositionend":da="onCompositionEnd";break b;case "compositionupdate":da="onCompositionUpdate";break b}da=void 0}else Hb?Qg(a,c)&&(da="onCompositionEnd"):"keydown"===a&&229===c.keyCode&&(da="onCompositionStart");da&&(Ug&&"ko"!==c.locale&&(Hb||"onCompositionStart"!==da?"onCompositionEnd"===da&&Hb&&(ab=Og()):(Za=e,Ee=
|
||||
"value"in Za?Za.value:Za.textContent,Hb=!0)),va=ed(d,da),0<va.length&&(da=new qh(da,a,null,c,e),g.push({event:da,listeners:va}),ab?da.data=ab:(ab=Rg(c),null!==ab&&(da.data=ab))));if(ab=ek?Ij(a,c):Jj(a,c))d=ed(d,"onBeforeInput"),0<d.length&&(e=new fk("onBeforeInput","beforeinput",null,c,e),g.push({event:e,listeners:d}),e.data=ab)}Xg(g,b)})}function tc(a,b,c){return{instance:a,listener:b,currentTarget:c}}function ed(a,b){for(var c=b+"Capture",d=[];null!==a;){var e=a,f=e.stateNode;5===e.tag&&null!==
|
||||
f&&(e=f,f=fc(a,c),null!=f&&d.unshift(tc(a,f,e)),f=fc(a,b),null!=f&&d.push(tc(a,f,e)));a=a.return}return d}function Lb(a){if(null===a)return null;do a=a.return;while(a&&5!==a.tag);return a?a:null}function oh(a,b,c,d,e){for(var f=b._reactName,g=[];null!==c&&c!==d;){var h=c,k=h.alternate,n=h.stateNode;if(null!==k&&k===d)break;5===h.tag&&null!==n&&(h=n,e?(k=fc(c,f),null!=k&&g.unshift(tc(c,k,h))):e||(k=fc(c,f),null!=k&&g.push(tc(c,k,h))));c=c.return}0!==g.length&&a.push({event:b,listeners:g})}function rh(a){return("string"===
|
||||
typeof a?a:""+a).replace(gk,"\n").replace(hk,"")}function jd(a,b,c,d){b=rh(b);if(rh(a)!==b&&c)throw Error(m(425));}function kd(){}function Qe(a,b){return"textarea"===a||"noscript"===a||"string"===typeof b.children||"number"===typeof b.children||"object"===typeof b.dangerouslySetInnerHTML&&null!==b.dangerouslySetInnerHTML&&null!=b.dangerouslySetInnerHTML.__html}function ik(a){setTimeout(function(){throw a;})}function Re(a,b){var c=b,d=0;do{var e=c.nextSibling;a.removeChild(c);if(e&&8===e.nodeType)if(c=
|
||||
e.data,"/$"===c){if(0===d){a.removeChild(e);nc(b);return}d--}else"$"!==c&&"$?"!==c&&"$!"!==c||d++;c=e}while(c);nc(b)}function Ka(a){for(;null!=a;a=a.nextSibling){var b=a.nodeType;if(1===b||3===b)break;if(8===b){b=a.data;if("$"===b||"$!"===b||"$?"===b)break;if("/$"===b)return null}}return a}function sh(a){a=a.previousSibling;for(var b=0;a;){if(8===a.nodeType){var c=a.data;if("$"===c||"$!"===c||"$?"===c){if(0===b)return a;b--}else"/$"===c&&b++}a=a.previousSibling}return null}function ob(a){var b=a[Da];
|
||||
if(b)return b;for(var c=a.parentNode;c;){if(b=c[Ja]||c[Da]){c=b.alternate;if(null!==b.child||null!==c&&null!==c.child)for(a=sh(a);null!==a;){if(c=a[Da])return c;a=sh(a)}return b}a=c;c=a.parentNode}return null}function ec(a){a=a[Da]||a[Ja];return!a||5!==a.tag&&6!==a.tag&&13!==a.tag&&3!==a.tag?null:a}function Ib(a){if(5===a.tag||6===a.tag)return a.stateNode;throw Error(m(33));}function Rc(a){return a[uc]||null}function bb(a){return{current:a}}function v(a,b){0>Mb||(a.current=Se[Mb],Se[Mb]=null,Mb--)}
|
||||
function y(a,b,c){Mb++;Se[Mb]=a.current;a.current=b}function Nb(a,b){var c=a.type.contextTypes;if(!c)return cb;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext===b)return d.__reactInternalMemoizedMaskedChildContext;var e={},f;for(f in c)e[f]=b[f];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function ea(a){a=a.childContextTypes;return null!==a&&void 0!==a}function th(a,b,c){if(J.current!==cb)throw Error(m(168));
|
||||
y(J,b);y(S,c)}function uh(a,b,c){var d=a.stateNode;b=b.childContextTypes;if("function"!==typeof d.getChildContext)return c;d=d.getChildContext();for(var e in d)if(!(e in b))throw Error(m(108,gj(a)||"Unknown",e));return E({},c,d)}function ld(a){a=(a=a.stateNode)&&a.__reactInternalMemoizedMergedChildContext||cb;pb=J.current;y(J,a);y(S,S.current);return!0}function vh(a,b,c){var d=a.stateNode;if(!d)throw Error(m(169));c?(a=uh(a,b,pb),d.__reactInternalMemoizedMergedChildContext=a,v(S),v(J),y(J,a)):v(S);
|
||||
y(S,c)}function wh(a){null===La?La=[a]:La.push(a)}function jk(a){md=!0;wh(a)}function db(){if(!Te&&null!==La){Te=!0;var a=0,b=z;try{var c=La;for(z=1;a<c.length;a++){var d=c[a];do d=d(!0);while(null!==d)}La=null;md=!1}catch(e){throw null!==La&&(La=La.slice(a+1)),xh(De,db),e;}finally{z=b,Te=!1}}return null}function qb(a,b){Ob[Pb++]=nd;Ob[Pb++]=od;od=a;nd=b}function yh(a,b,c){na[oa++]=Ma;na[oa++]=Na;na[oa++]=rb;rb=a;var d=Ma;a=Na;var e=32-ta(d)-1;d&=~(1<<e);c+=1;var f=32-ta(b)+e;if(30<f){var g=e-e%5;
|
||||
f=(d&(1<<g)-1).toString(32);d>>=g;e-=g;Ma=1<<32-ta(b)+e|c<<e|d;Na=f+a}else Ma=1<<f|c<<e|d,Na=a}function Ue(a){null!==a.return&&(qb(a,1),yh(a,1,0))}function Ve(a){for(;a===od;)od=Ob[--Pb],Ob[Pb]=null,nd=Ob[--Pb],Ob[Pb]=null;for(;a===rb;)rb=na[--oa],na[oa]=null,Na=na[--oa],na[oa]=null,Ma=na[--oa],na[oa]=null}function zh(a,b){var c=pa(5,null,null,0);c.elementType="DELETED";c.stateNode=b;c.return=a;b=a.deletions;null===b?(a.deletions=[c],a.flags|=16):b.push(c)}function Ah(a,b){switch(a.tag){case 5:var c=
|
||||
a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,la=a,fa=Ka(b.firstChild),!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,la=a,fa=null,!0):!1;case 13:return b=8!==b.nodeType?null:b,null!==b?(c=null!==rb?{id:Ma,overflow:Na}:null,a.memoizedState={dehydrated:b,treeContext:c,retryLane:1073741824},c=pa(18,null,null,0),c.stateNode=b,c.return=a,a.child=c,la=a,fa=null,!0):!1;default:return!1}}function We(a){return 0!==
|
||||
(a.mode&1)&&0===(a.flags&128)}function Xe(a){if(D){var b=fa;if(b){var c=b;if(!Ah(a,b)){if(We(a))throw Error(m(418));b=Ka(c.nextSibling);var d=la;b&&Ah(a,b)?zh(d,c):(a.flags=a.flags&-4097|2,D=!1,la=a)}}else{if(We(a))throw Error(m(418));a.flags=a.flags&-4097|2;D=!1;la=a}}}function Bh(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag&&13!==a.tag;)a=a.return;la=a}function pd(a){if(a!==la)return!1;if(!D)return Bh(a),D=!0,!1;var b;(b=3!==a.tag)&&!(b=5!==a.tag)&&(b=a.type,b="head"!==b&&"body"!==b&&!Qe(a.type,
|
||||
a.memoizedProps));if(b&&(b=fa)){if(We(a)){for(a=fa;a;)a=Ka(a.nextSibling);throw Error(m(418));}for(;b;)zh(a,b),b=Ka(b.nextSibling)}Bh(a);if(13===a.tag){a=a.memoizedState;a=null!==a?a.dehydrated:null;if(!a)throw Error(m(317));a:{a=a.nextSibling;for(b=0;a;){if(8===a.nodeType){var c=a.data;if("/$"===c){if(0===b){fa=Ka(a.nextSibling);break a}b--}else"$"!==c&&"$!"!==c&&"$?"!==c||b++}a=a.nextSibling}fa=null}}else fa=la?Ka(a.stateNode.nextSibling):null;return!0}function Qb(){fa=la=null;D=!1}function Ye(a){null===
|
||||
wa?wa=[a]:wa.push(a)}function vc(a,b,c){a=c.ref;if(null!==a&&"function"!==typeof a&&"object"!==typeof a){if(c._owner){c=c._owner;if(c){if(1!==c.tag)throw Error(m(309));var d=c.stateNode}if(!d)throw Error(m(147,a));var e=d,f=""+a;if(null!==b&&null!==b.ref&&"function"===typeof b.ref&&b.ref._stringRef===f)return b.ref;b=function(a){var b=e.refs;null===a?delete b[f]:b[f]=a};b._stringRef=f;return b}if("string"!==typeof a)throw Error(m(284));if(!c._owner)throw Error(m(290,a));}return a}function qd(a,b){a=
|
||||
Object.prototype.toString.call(b);throw Error(m(31,"[object Object]"===a?"object with keys {"+Object.keys(b).join(", ")+"}":a));}function Ch(a){var b=a._init;return b(a._payload)}function Dh(a){function b(b,c){if(a){var d=b.deletions;null===d?(b.deletions=[c],b.flags|=16):d.push(c)}}function c(c,d){if(!a)return null;for(;null!==d;)b(c,d),d=d.sibling;return null}function d(a,b){for(a=new Map;null!==b;)null!==b.key?a.set(b.key,b):a.set(b.index,b),b=b.sibling;return a}function e(a,b){a=eb(a,b);a.index=
|
||||
0;a.sibling=null;return a}function f(b,c,d){b.index=d;if(!a)return b.flags|=1048576,c;d=b.alternate;if(null!==d)return d=d.index,d<c?(b.flags|=2,c):d;b.flags|=2;return c}function g(b){a&&null===b.alternate&&(b.flags|=2);return b}function h(a,b,c,d){if(null===b||6!==b.tag)return b=Ze(c,a.mode,d),b.return=a,b;b=e(b,c);b.return=a;return b}function k(a,b,c,d){var f=c.type;if(f===Bb)return l(a,b,c.props.children,d,c.key);if(null!==b&&(b.elementType===f||"object"===typeof f&&null!==f&&f.$$typeof===Ta&&
|
||||
Ch(f)===b.type))return d=e(b,c.props),d.ref=vc(a,b,c),d.return=a,d;d=rd(c.type,c.key,c.props,null,a.mode,d);d.ref=vc(a,b,c);d.return=a;return d}function n(a,b,c,d){if(null===b||4!==b.tag||b.stateNode.containerInfo!==c.containerInfo||b.stateNode.implementation!==c.implementation)return b=$e(c,a.mode,d),b.return=a,b;b=e(b,c.children||[]);b.return=a;return b}function l(a,b,c,d,f){if(null===b||7!==b.tag)return b=sb(c,a.mode,d,f),b.return=a,b;b=e(b,c);b.return=a;return b}function u(a,b,c){if("string"===
|
||||
typeof b&&""!==b||"number"===typeof b)return b=Ze(""+b,a.mode,c),b.return=a,b;if("object"===typeof b&&null!==b){switch(b.$$typeof){case sd:return c=rd(b.type,b.key,b.props,null,a.mode,c),c.ref=vc(a,null,b),c.return=a,c;case Cb:return b=$e(b,a.mode,c),b.return=a,b;case Ta:var d=b._init;return u(a,d(b._payload),c)}if(cc(b)||ac(b))return b=sb(b,a.mode,c,null),b.return=a,b;qd(a,b)}return null}function r(a,b,c,d){var e=null!==b?b.key:null;if("string"===typeof c&&""!==c||"number"===typeof c)return null!==
|
||||
e?null:h(a,b,""+c,d);if("object"===typeof c&&null!==c){switch(c.$$typeof){case sd:return c.key===e?k(a,b,c,d):null;case Cb:return c.key===e?n(a,b,c,d):null;case Ta:return e=c._init,r(a,b,e(c._payload),d)}if(cc(c)||ac(c))return null!==e?null:l(a,b,c,d,null);qd(a,c)}return null}function p(a,b,c,d,e){if("string"===typeof d&&""!==d||"number"===typeof d)return a=a.get(c)||null,h(b,a,""+d,e);if("object"===typeof d&&null!==d){switch(d.$$typeof){case sd:return a=a.get(null===d.key?c:d.key)||null,k(b,a,d,
|
||||
e);case Cb:return a=a.get(null===d.key?c:d.key)||null,n(b,a,d,e);case Ta:var f=d._init;return p(a,b,c,f(d._payload),e)}if(cc(d)||ac(d))return a=a.get(c)||null,l(b,a,d,e,null);qd(b,d)}return null}function x(e,g,h,k){for(var n=null,m=null,l=g,t=g=0,q=null;null!==l&&t<h.length;t++){l.index>t?(q=l,l=null):q=l.sibling;var A=r(e,l,h[t],k);if(null===A){null===l&&(l=q);break}a&&l&&null===A.alternate&&b(e,l);g=f(A,g,t);null===m?n=A:m.sibling=A;m=A;l=q}if(t===h.length)return c(e,l),D&&qb(e,t),n;if(null===l){for(;t<
|
||||
h.length;t++)l=u(e,h[t],k),null!==l&&(g=f(l,g,t),null===m?n=l:m.sibling=l,m=l);D&&qb(e,t);return n}for(l=d(e,l);t<h.length;t++)q=p(l,e,t,h[t],k),null!==q&&(a&&null!==q.alternate&&l.delete(null===q.key?t:q.key),g=f(q,g,t),null===m?n=q:m.sibling=q,m=q);a&&l.forEach(function(a){return b(e,a)});D&&qb(e,t);return n}function I(e,g,h,k){var n=ac(h);if("function"!==typeof n)throw Error(m(150));h=n.call(h);if(null==h)throw Error(m(151));for(var l=n=null,q=g,t=g=0,A=null,w=h.next();null!==q&&!w.done;t++,w=
|
||||
h.next()){q.index>t?(A=q,q=null):A=q.sibling;var x=r(e,q,w.value,k);if(null===x){null===q&&(q=A);break}a&&q&&null===x.alternate&&b(e,q);g=f(x,g,t);null===l?n=x:l.sibling=x;l=x;q=A}if(w.done)return c(e,q),D&&qb(e,t),n;if(null===q){for(;!w.done;t++,w=h.next())w=u(e,w.value,k),null!==w&&(g=f(w,g,t),null===l?n=w:l.sibling=w,l=w);D&&qb(e,t);return n}for(q=d(e,q);!w.done;t++,w=h.next())w=p(q,e,t,w.value,k),null!==w&&(a&&null!==w.alternate&&q.delete(null===w.key?t:w.key),g=f(w,g,t),null===l?n=w:l.sibling=
|
||||
w,l=w);a&&q.forEach(function(a){return b(e,a)});D&&qb(e,t);return n}function v(a,d,f,h){"object"===typeof f&&null!==f&&f.type===Bb&&null===f.key&&(f=f.props.children);if("object"===typeof f&&null!==f){switch(f.$$typeof){case sd:a:{for(var k=f.key,n=d;null!==n;){if(n.key===k){k=f.type;if(k===Bb){if(7===n.tag){c(a,n.sibling);d=e(n,f.props.children);d.return=a;a=d;break a}}else if(n.elementType===k||"object"===typeof k&&null!==k&&k.$$typeof===Ta&&Ch(k)===n.type){c(a,n.sibling);d=e(n,f.props);d.ref=vc(a,
|
||||
n,f);d.return=a;a=d;break a}c(a,n);break}else b(a,n);n=n.sibling}f.type===Bb?(d=sb(f.props.children,a.mode,h,f.key),d.return=a,a=d):(h=rd(f.type,f.key,f.props,null,a.mode,h),h.ref=vc(a,d,f),h.return=a,a=h)}return g(a);case Cb:a:{for(n=f.key;null!==d;){if(d.key===n)if(4===d.tag&&d.stateNode.containerInfo===f.containerInfo&&d.stateNode.implementation===f.implementation){c(a,d.sibling);d=e(d,f.children||[]);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=$e(f,a.mode,h);d.return=a;
|
||||
a=d}return g(a);case Ta:return n=f._init,v(a,d,n(f._payload),h)}if(cc(f))return x(a,d,f,h);if(ac(f))return I(a,d,f,h);qd(a,f)}return"string"===typeof f&&""!==f||"number"===typeof f?(f=""+f,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,f),d.return=a,a=d):(c(a,d),d=Ze(f,a.mode,h),d.return=a,a=d),g(a)):c(a,d)}return v}function af(){bf=Rb=td=null}function cf(a,b){b=ud.current;v(ud);a._currentValue=b}function df(a,b,c){for(;null!==a;){var d=a.alternate;(a.childLanes&b)!==b?(a.childLanes|=b,null!==d&&(d.childLanes|=
|
||||
b)):null!==d&&(d.childLanes&b)!==b&&(d.childLanes|=b);if(a===c)break;a=a.return}}function Sb(a,b){td=a;bf=Rb=null;a=a.dependencies;null!==a&&null!==a.firstContext&&(0!==(a.lanes&b)&&(ha=!0),a.firstContext=null)}function qa(a){var b=a._currentValue;if(bf!==a)if(a={context:a,memoizedValue:b,next:null},null===Rb){if(null===td)throw Error(m(308));Rb=a;td.dependencies={lanes:0,firstContext:a}}else Rb=Rb.next=a;return b}function ef(a){null===tb?tb=[a]:tb.push(a)}function Eh(a,b,c,d){var e=b.interleaved;
|
||||
null===e?(c.next=c,ef(b)):(c.next=e.next,e.next=c);b.interleaved=c;return Oa(a,d)}function Oa(a,b){a.lanes|=b;var c=a.alternate;null!==c&&(c.lanes|=b);c=a;for(a=a.return;null!==a;)a.childLanes|=b,c=a.alternate,null!==c&&(c.childLanes|=b),c=a,a=a.return;return 3===c.tag?c.stateNode:null}function ff(a){a.updateQueue={baseState:a.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Fh(a,b){a=a.updateQueue;b.updateQueue===a&&(b.updateQueue=
|
||||
{baseState:a.baseState,firstBaseUpdate:a.firstBaseUpdate,lastBaseUpdate:a.lastBaseUpdate,shared:a.shared,effects:a.effects})}function Pa(a,b){return{eventTime:a,lane:b,tag:0,payload:null,callback:null,next:null}}function fb(a,b,c){var d=a.updateQueue;if(null===d)return null;d=d.shared;if(0!==(p&2)){var e=d.pending;null===e?b.next=b:(b.next=e.next,e.next=b);d.pending=b;return kk(a,c)}e=d.interleaved;null===e?(b.next=b,ef(d)):(b.next=e.next,e.next=b);d.interleaved=b;return Oa(a,c)}function vd(a,b,c){b=
|
||||
b.updateQueue;if(null!==b&&(b=b.shared,0!==(c&4194240))){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function Gh(a,b){var c=a.updateQueue,d=a.alternate;if(null!==d&&(d=d.updateQueue,c===d)){var e=null,f=null;c=c.firstBaseUpdate;if(null!==c){do{var g={eventTime:c.eventTime,lane:c.lane,tag:c.tag,payload:c.payload,callback:c.callback,next:null};null===f?e=f=g:f=f.next=g;c=c.next}while(null!==c);null===f?e=f=b:f=f.next=b}else e=f=b;c={baseState:d.baseState,firstBaseUpdate:e,lastBaseUpdate:f,
|
||||
shared:d.shared,effects:d.effects};a.updateQueue=c;return}a=c.lastBaseUpdate;null===a?c.firstBaseUpdate=b:a.next=b;c.lastBaseUpdate=b}function wd(a,b,c,d){var e=a.updateQueue;gb=!1;var f=e.firstBaseUpdate,g=e.lastBaseUpdate,h=e.shared.pending;if(null!==h){e.shared.pending=null;var k=h,n=k.next;k.next=null;null===g?f=n:g.next=n;g=k;var l=a.alternate;null!==l&&(l=l.updateQueue,h=l.lastBaseUpdate,h!==g&&(null===h?l.firstBaseUpdate=n:h.next=n,l.lastBaseUpdate=k))}if(null!==f){var m=e.baseState;g=0;l=
|
||||
n=k=null;h=f;do{var r=h.lane,p=h.eventTime;if((d&r)===r){null!==l&&(l=l.next={eventTime:p,lane:0,tag:h.tag,payload:h.payload,callback:h.callback,next:null});a:{var x=a,v=h;r=b;p=c;switch(v.tag){case 1:x=v.payload;if("function"===typeof x){m=x.call(p,m,r);break a}m=x;break a;case 3:x.flags=x.flags&-65537|128;case 0:x=v.payload;r="function"===typeof x?x.call(p,m,r):x;if(null===r||void 0===r)break a;m=E({},m,r);break a;case 2:gb=!0}}null!==h.callback&&0!==h.lane&&(a.flags|=64,r=e.effects,null===r?e.effects=
|
||||
[h]:r.push(h))}else p={eventTime:p,lane:r,tag:h.tag,payload:h.payload,callback:h.callback,next:null},null===l?(n=l=p,k=m):l=l.next=p,g|=r;h=h.next;if(null===h)if(h=e.shared.pending,null===h)break;else r=h,h=r.next,r.next=null,e.lastBaseUpdate=r,e.shared.pending=null}while(1);null===l&&(k=m);e.baseState=k;e.firstBaseUpdate=n;e.lastBaseUpdate=l;b=e.shared.interleaved;if(null!==b){e=b;do g|=e.lane,e=e.next;while(e!==b)}else null===f&&(e.shared.lanes=0);ra|=g;a.lanes=g;a.memoizedState=m}}function Hh(a,
|
||||
b,c){a=b.effects;b.effects=null;if(null!==a)for(b=0;b<a.length;b++){var d=a[b],e=d.callback;if(null!==e){d.callback=null;d=c;if("function"!==typeof e)throw Error(m(191,e));e.call(d)}}}function ub(a){if(a===wc)throw Error(m(174));return a}function gf(a,b){y(xc,b);y(yc,a);y(Ea,wc);a=b.nodeType;switch(a){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:oe(null,"");break;default:a=8===a?b.parentNode:b,b=a.namespaceURI||null,a=a.tagName,b=oe(b,a)}v(Ea);y(Ea,b)}function Tb(a){v(Ea);v(yc);v(xc)}function Ih(a){ub(xc.current);
|
||||
var b=ub(Ea.current);var c=oe(b,a.type);b!==c&&(y(yc,a),y(Ea,c))}function hf(a){yc.current===a&&(v(Ea),v(yc))}function xd(a){for(var b=a;null!==b;){if(13===b.tag){var c=b.memoizedState;if(null!==c&&(c=c.dehydrated,null===c||"$?"===c.data||"$!"===c.data))return b}else if(19===b.tag&&void 0!==b.memoizedProps.revealOrder){if(0!==(b.flags&128))return b}else if(null!==b.child){b.child.return=b;b=b.child;continue}if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return null;b=b.return}b.sibling.return=
|
||||
b.return;b=b.sibling}return null}function jf(){for(var a=0;a<kf.length;a++)kf[a]._workInProgressVersionPrimary=null;kf.length=0}function V(){throw Error(m(321));}function lf(a,b){if(null===b)return!1;for(var c=0;c<b.length&&c<a.length;c++)if(!ua(a[c],b[c]))return!1;return!0}function mf(a,b,c,d,e,f){vb=f;C=b;b.memoizedState=null;b.updateQueue=null;b.lanes=0;yd.current=null===a||null===a.memoizedState?lk:mk;a=c(d,e);if(zc){f=0;do{zc=!1;Ac=0;if(25<=f)throw Error(m(301));f+=1;N=K=null;b.updateQueue=null;
|
||||
yd.current=nk;a=c(d,e)}while(zc)}yd.current=zd;b=null!==K&&null!==K.next;vb=0;N=K=C=null;Ad=!1;if(b)throw Error(m(300));return a}function nf(){var a=0!==Ac;Ac=0;return a}function Fa(){var a={memoizedState:null,baseState:null,baseQueue:null,queue:null,next:null};null===N?C.memoizedState=N=a:N=N.next=a;return N}function sa(){if(null===K){var a=C.alternate;a=null!==a?a.memoizedState:null}else a=K.next;var b=null===N?C.memoizedState:N.next;if(null!==b)N=b,K=a;else{if(null===a)throw Error(m(310));K=a;
|
||||
a={memoizedState:K.memoizedState,baseState:K.baseState,baseQueue:K.baseQueue,queue:K.queue,next:null};null===N?C.memoizedState=N=a:N=N.next=a}return N}function Bc(a,b){return"function"===typeof b?b(a):b}function of(a,b,c){b=sa();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=K,e=d.baseQueue,f=c.pending;if(null!==f){if(null!==e){var g=e.next;e.next=f.next;f.next=g}d.baseQueue=e=f;c.pending=null}if(null!==e){f=e.next;d=d.baseState;var h=g=null,k=null,n=f;do{var l=n.lane;if((vb&
|
||||
l)===l)null!==k&&(k=k.next={lane:0,action:n.action,hasEagerState:n.hasEagerState,eagerState:n.eagerState,next:null}),d=n.hasEagerState?n.eagerState:a(d,n.action);else{var u={lane:l,action:n.action,hasEagerState:n.hasEagerState,eagerState:n.eagerState,next:null};null===k?(h=k=u,g=d):k=k.next=u;C.lanes|=l;ra|=l}n=n.next}while(null!==n&&n!==f);null===k?g=d:k.next=h;ua(d,b.memoizedState)||(ha=!0);b.memoizedState=d;b.baseState=g;b.baseQueue=k;c.lastRenderedState=d}a=c.interleaved;if(null!==a){e=a;do f=
|
||||
e.lane,C.lanes|=f,ra|=f,e=e.next;while(e!==a)}else null===e&&(c.lanes=0);return[b.memoizedState,c.dispatch]}function pf(a,b,c){b=sa();c=b.queue;if(null===c)throw Error(m(311));c.lastRenderedReducer=a;var d=c.dispatch,e=c.pending,f=b.memoizedState;if(null!==e){c.pending=null;var g=e=e.next;do f=a(f,g.action),g=g.next;while(g!==e);ua(f,b.memoizedState)||(ha=!0);b.memoizedState=f;null===b.baseQueue&&(b.baseState=f);c.lastRenderedState=f}return[f,d]}function Jh(a,b,c){}function Kh(a,b,c){c=C;var d=sa(),
|
||||
e=b(),f=!ua(d.memoizedState,e);f&&(d.memoizedState=e,ha=!0);d=d.queue;qf(Lh.bind(null,c,d,a),[a]);if(d.getSnapshot!==b||f||null!==N&&N.memoizedState.tag&1){c.flags|=2048;Cc(9,Mh.bind(null,c,d,e,b),void 0,null);if(null===O)throw Error(m(349));0!==(vb&30)||Nh(c,b,e)}return e}function Nh(a,b,c){a.flags|=16384;a={getSnapshot:b,value:c};b=C.updateQueue;null===b?(b={lastEffect:null,stores:null},C.updateQueue=b,b.stores=[a]):(c=b.stores,null===c?b.stores=[a]:c.push(a))}function Mh(a,b,c,d){b.value=c;b.getSnapshot=
|
||||
d;Oh(b)&&Ph(a)}function Lh(a,b,c){return c(function(){Oh(b)&&Ph(a)})}function Oh(a){var b=a.getSnapshot;a=a.value;try{var c=b();return!ua(a,c)}catch(d){return!0}}function Ph(a){var b=Oa(a,1);null!==b&&xa(b,a,1,-1)}function Qh(a){var b=Fa();"function"===typeof a&&(a=a());b.memoizedState=b.baseState=a;a={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:Bc,lastRenderedState:a};b.queue=a;a=a.dispatch=ok.bind(null,C,a);return[b.memoizedState,a]}function Cc(a,b,c,d){a={tag:a,create:b,
|
||||
destroy:c,deps:d,next:null};b=C.updateQueue;null===b?(b={lastEffect:null,stores:null},C.updateQueue=b,b.lastEffect=a.next=a):(c=b.lastEffect,null===c?b.lastEffect=a.next=a:(d=c.next,c.next=a,a.next=d,b.lastEffect=a));return a}function Rh(a){return sa().memoizedState}function Bd(a,b,c,d){var e=Fa();C.flags|=a;e.memoizedState=Cc(1|b,c,void 0,void 0===d?null:d)}function Cd(a,b,c,d){var e=sa();d=void 0===d?null:d;var f=void 0;if(null!==K){var g=K.memoizedState;f=g.destroy;if(null!==d&&lf(d,g.deps)){e.memoizedState=
|
||||
Cc(b,c,f,d);return}}C.flags|=a;e.memoizedState=Cc(1|b,c,f,d)}function Sh(a,b){return Bd(8390656,8,a,b)}function qf(a,b){return Cd(2048,8,a,b)}function Th(a,b){return Cd(4,2,a,b)}function Uh(a,b){return Cd(4,4,a,b)}function Vh(a,b){if("function"===typeof b)return a=a(),b(a),function(){b(null)};if(null!==b&&void 0!==b)return a=a(),b.current=a,function(){b.current=null}}function Wh(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return Cd(4,4,Vh.bind(null,b,a),c)}function rf(a,b){}function Xh(a,b){var c=
|
||||
sa();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&lf(b,d[1]))return d[0];c.memoizedState=[a,b];return a}function Yh(a,b){var c=sa();b=void 0===b?null:b;var d=c.memoizedState;if(null!==d&&null!==b&&lf(b,d[1]))return d[0];a=a();c.memoizedState=[a,b];return a}function Zh(a,b,c){if(0===(vb&21))return a.baseState&&(a.baseState=!1,ha=!0),a.memoizedState=c;ua(c,b)||(c=Dg(),C.lanes|=c,ra|=c,a.baseState=!0);return b}function pk(a,b,c){c=z;z=0!==c&&4>c?c:4;a(!0);var d=sf.transition;sf.transition=
|
||||
{};try{a(!1),b()}finally{z=c,sf.transition=d}}function $h(){return sa().memoizedState}function qk(a,b,c){var d=hb(a);c={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,c);else if(c=Eh(a,b,c,d),null!==c){var e=Z();xa(c,a,d,e);ci(c,b,d)}}function ok(a,b,c){var d=hb(a),e={lane:d,action:c,hasEagerState:!1,eagerState:null,next:null};if(ai(a))bi(b,e);else{var f=a.alternate;if(0===a.lanes&&(null===f||0===f.lanes)&&(f=b.lastRenderedReducer,null!==f))try{var g=b.lastRenderedState,
|
||||
h=f(g,c);e.hasEagerState=!0;e.eagerState=h;if(ua(h,g)){var k=b.interleaved;null===k?(e.next=e,ef(b)):(e.next=k.next,k.next=e);b.interleaved=e;return}}catch(n){}finally{}c=Eh(a,b,e,d);null!==c&&(e=Z(),xa(c,a,d,e),ci(c,b,d))}}function ai(a){var b=a.alternate;return a===C||null!==b&&b===C}function bi(a,b){zc=Ad=!0;var c=a.pending;null===c?b.next=b:(b.next=c.next,c.next=b);a.pending=b}function ci(a,b,c){if(0!==(c&4194240)){var d=b.lanes;d&=a.pendingLanes;c|=d;b.lanes=c;xe(a,c)}}function ya(a,b){if(a&&
|
||||
a.defaultProps){b=E({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c]);return b}return b}function tf(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:E({},b,c);a.memoizedState=c;0===a.lanes&&(a.updateQueue.baseState=c)}function di(a,b,c,d,e,f,g){a=a.stateNode;return"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,f,g):b.prototype&&b.prototype.isPureReactComponent?!qc(c,d)||!qc(e,f):!0}function ei(a,b,c){var d=!1,e=cb;var f=b.contextType;"object"===typeof f&&
|
||||
null!==f?f=qa(f):(e=ea(b)?pb:J.current,d=b.contextTypes,f=(d=null!==d&&void 0!==d)?Nb(a,e):cb);b=new b(c,f);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=Dd;a.stateNode=b;b._reactInternals=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=e,a.__reactInternalMemoizedMaskedChildContext=f);return b}function fi(a,b,c,d){a=b.state;"function"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);"function"===typeof b.UNSAFE_componentWillReceiveProps&&
|
||||
b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&Dd.enqueueReplaceState(b,b.state,null)}function uf(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs={};ff(a);var f=b.contextType;"object"===typeof f&&null!==f?e.context=qa(f):(f=ea(b)?pb:J.current,e.context=Nb(a,f));e.state=a.memoizedState;f=b.getDerivedStateFromProps;"function"===typeof f&&(tf(a,b,f,c),e.state=a.memoizedState);"function"===typeof b.getDerivedStateFromProps||"function"===typeof e.getSnapshotBeforeUpdate||"function"!==
|
||||
typeof e.UNSAFE_componentWillMount&&"function"!==typeof e.componentWillMount||(b=e.state,"function"===typeof e.componentWillMount&&e.componentWillMount(),"function"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(),b!==e.state&&Dd.enqueueReplaceState(e,e.state,null),wd(a,c,e,d),e.state=a.memoizedState);"function"===typeof e.componentDidMount&&(a.flags|=4194308)}function Ub(a,b){try{var c="",d=b;do c+=fj(d),d=d.return;while(d);var e=c}catch(f){e="\nError generating stack: "+f.message+
|
||||
"\n"+f.stack}return{value:a,source:b,stack:e,digest:null}}function vf(a,b,c){return{value:a,source:null,stack:null!=c?c:null,digest:null!=b?b:null}}function wf(a,b){try{console.error(b.value)}catch(c){setTimeout(function(){throw c;})}}function gi(a,b,c){c=Pa(-1,c);c.tag=3;c.payload={element:null};var d=b.value;c.callback=function(){Ed||(Ed=!0,xf=d);wf(a,b)};return c}function hi(a,b,c){c=Pa(-1,c);c.tag=3;var d=a.type.getDerivedStateFromError;if("function"===typeof d){var e=b.value;c.payload=function(){return d(e)};
|
||||
c.callback=function(){wf(a,b)}}var f=a.stateNode;null!==f&&"function"===typeof f.componentDidCatch&&(c.callback=function(){wf(a,b);"function"!==typeof d&&(null===ib?ib=new Set([this]):ib.add(this));var c=b.stack;this.componentDidCatch(b.value,{componentStack:null!==c?c:""})});return c}function ii(a,b,c){var d=a.pingCache;if(null===d){d=a.pingCache=new rk;var e=new Set;d.set(b,e)}else e=d.get(b),void 0===e&&(e=new Set,d.set(b,e));e.has(c)||(e.add(c),a=sk.bind(null,a,b,c),b.then(a,a))}function ji(a){do{var b;
|
||||
if(b=13===a.tag)b=a.memoizedState,b=null!==b?null!==b.dehydrated?!0:!1:!0;if(b)return a;a=a.return}while(null!==a);return null}function ki(a,b,c,d,e){if(0===(a.mode&1))return a===b?a.flags|=65536:(a.flags|=128,c.flags|=131072,c.flags&=-52805,1===c.tag&&(null===c.alternate?c.tag=17:(b=Pa(-1,1),b.tag=2,fb(c,b,1))),c.lanes|=1),a;a.flags|=65536;a.lanes=e;return a}function aa(a,b,c,d){b.child=null===a?li(b,null,c,d):Vb(b,a.child,c,d)}function mi(a,b,c,d,e){c=c.render;var f=b.ref;Sb(b,e);d=mf(a,b,c,d,f,
|
||||
e);c=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&c&&Ue(b);b.flags|=1;aa(a,b,d,e);return b.child}function ni(a,b,c,d,e){if(null===a){var f=c.type;if("function"===typeof f&&!yf(f)&&void 0===f.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=f,oi(a,b,f,d,e);a=rd(c.type,null,d,b,b.mode,e);a.ref=b.ref;a.return=b;return b.child=a}f=a.child;if(0===(a.lanes&e)){var g=f.memoizedProps;c=c.compare;c=null!==c?c:qc;if(c(g,d)&&a.ref===
|
||||
b.ref)return Qa(a,b,e)}b.flags|=1;a=eb(f,d);a.ref=b.ref;a.return=b;return b.child=a}function oi(a,b,c,d,e){if(null!==a){var f=a.memoizedProps;if(qc(f,d)&&a.ref===b.ref)if(ha=!1,b.pendingProps=d=f,0!==(a.lanes&e))0!==(a.flags&131072)&&(ha=!0);else return b.lanes=a.lanes,Qa(a,b,e)}return zf(a,b,c,d,e)}function pi(a,b,c){var d=b.pendingProps,e=d.children,f=null!==a?a.memoizedState:null;if("hidden"===d.mode)if(0===(b.mode&1))b.memoizedState={baseLanes:0,cachePool:null,transitions:null},y(Ga,ba),ba|=c;
|
||||
else{if(0===(c&1073741824))return a=null!==f?f.baseLanes|c:c,b.lanes=b.childLanes=1073741824,b.memoizedState={baseLanes:a,cachePool:null,transitions:null},b.updateQueue=null,y(Ga,ba),ba|=a,null;b.memoizedState={baseLanes:0,cachePool:null,transitions:null};d=null!==f?f.baseLanes:c;y(Ga,ba);ba|=d}else null!==f?(d=f.baseLanes|c,b.memoizedState=null):d=c,y(Ga,ba),ba|=d;aa(a,b,e,c);return b.child}function qi(a,b){var c=b.ref;if(null===a&&null!==c||null!==a&&a.ref!==c)b.flags|=512,b.flags|=2097152}function zf(a,
|
||||
b,c,d,e){var f=ea(c)?pb:J.current;f=Nb(b,f);Sb(b,e);c=mf(a,b,c,d,f,e);d=nf();if(null!==a&&!ha)return b.updateQueue=a.updateQueue,b.flags&=-2053,a.lanes&=~e,Qa(a,b,e);D&&d&&Ue(b);b.flags|=1;aa(a,b,c,e);return b.child}function ri(a,b,c,d,e){if(ea(c)){var f=!0;ld(b)}else f=!1;Sb(b,e);if(null===b.stateNode)Fd(a,b),ei(b,c,d),uf(b,c,d,e),d=!0;else if(null===a){var g=b.stateNode,h=b.memoizedProps;g.props=h;var k=g.context,n=c.contextType;"object"===typeof n&&null!==n?n=qa(n):(n=ea(c)?pb:J.current,n=Nb(b,
|
||||
n));var l=c.getDerivedStateFromProps,m="function"===typeof l||"function"===typeof g.getSnapshotBeforeUpdate;m||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==d||k!==n)&&fi(b,g,d,n);gb=!1;var r=b.memoizedState;g.state=r;wd(b,d,g,e);k=b.memoizedState;h!==d||r!==k||S.current||gb?("function"===typeof l&&(tf(b,c,l,d),k=b.memoizedState),(h=gb||di(b,c,h,d,r,k,n))?(m||"function"!==typeof g.UNSAFE_componentWillMount&&"function"!==typeof g.componentWillMount||
|
||||
("function"===typeof g.componentWillMount&&g.componentWillMount(),"function"===typeof g.UNSAFE_componentWillMount&&g.UNSAFE_componentWillMount()),"function"===typeof g.componentDidMount&&(b.flags|=4194308)):("function"===typeof g.componentDidMount&&(b.flags|=4194308),b.memoizedProps=d,b.memoizedState=k),g.props=d,g.state=k,g.context=n,d=h):("function"===typeof g.componentDidMount&&(b.flags|=4194308),d=!1)}else{g=b.stateNode;Fh(a,b);h=b.memoizedProps;n=b.type===b.elementType?h:ya(b.type,h);g.props=
|
||||
n;m=b.pendingProps;r=g.context;k=c.contextType;"object"===typeof k&&null!==k?k=qa(k):(k=ea(c)?pb:J.current,k=Nb(b,k));var p=c.getDerivedStateFromProps;(l="function"===typeof p||"function"===typeof g.getSnapshotBeforeUpdate)||"function"!==typeof g.UNSAFE_componentWillReceiveProps&&"function"!==typeof g.componentWillReceiveProps||(h!==m||r!==k)&&fi(b,g,d,k);gb=!1;r=b.memoizedState;g.state=r;wd(b,d,g,e);var x=b.memoizedState;h!==m||r!==x||S.current||gb?("function"===typeof p&&(tf(b,c,p,d),x=b.memoizedState),
|
||||
(n=gb||di(b,c,n,d,r,x,k)||!1)?(l||"function"!==typeof g.UNSAFE_componentWillUpdate&&"function"!==typeof g.componentWillUpdate||("function"===typeof g.componentWillUpdate&&g.componentWillUpdate(d,x,k),"function"===typeof g.UNSAFE_componentWillUpdate&&g.UNSAFE_componentWillUpdate(d,x,k)),"function"===typeof g.componentDidUpdate&&(b.flags|=4),"function"===typeof g.getSnapshotBeforeUpdate&&(b.flags|=1024)):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=
|
||||
4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),b.memoizedProps=d,b.memoizedState=x),g.props=d,g.state=x,g.context=k,d=n):("function"!==typeof g.componentDidUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=4),"function"!==typeof g.getSnapshotBeforeUpdate||h===a.memoizedProps&&r===a.memoizedState||(b.flags|=1024),d=!1)}return Af(a,b,c,d,f,e)}function Af(a,b,c,d,e,f){qi(a,b);var g=0!==(b.flags&128);if(!d&&!g)return e&&vh(b,c,!1),
|
||||
Qa(a,b,f);d=b.stateNode;tk.current=b;var h=g&&"function"!==typeof c.getDerivedStateFromError?null:d.render();b.flags|=1;null!==a&&g?(b.child=Vb(b,a.child,null,f),b.child=Vb(b,null,h,f)):aa(a,b,h,f);b.memoizedState=d.state;e&&vh(b,c,!0);return b.child}function si(a){var b=a.stateNode;b.pendingContext?th(a,b.pendingContext,b.pendingContext!==b.context):b.context&&th(a,b.context,!1);gf(a,b.containerInfo)}function ti(a,b,c,d,e){Qb();Ye(e);b.flags|=256;aa(a,b,c,d);return b.child}function Bf(a){return{baseLanes:a,
|
||||
cachePool:null,transitions:null}}function ui(a,b,c){var d=b.pendingProps,e=F.current,f=!1,g=0!==(b.flags&128),h;(h=g)||(h=null!==a&&null===a.memoizedState?!1:0!==(e&2));if(h)f=!0,b.flags&=-129;else if(null===a||null!==a.memoizedState)e|=1;y(F,e&1);if(null===a){Xe(b);a=b.memoizedState;if(null!==a&&(a=a.dehydrated,null!==a))return 0===(b.mode&1)?b.lanes=1:"$!"===a.data?b.lanes=8:b.lanes=1073741824,null;g=d.children;a=d.fallback;return f?(d=b.mode,f=b.child,g={mode:"hidden",children:g},0===(d&1)&&null!==
|
||||
f?(f.childLanes=0,f.pendingProps=g):f=Gd(g,d,0,null),a=sb(a,d,c,null),f.return=b,a.return=b,f.sibling=a,b.child=f,b.child.memoizedState=Bf(c),b.memoizedState=Cf,a):Df(b,g)}e=a.memoizedState;if(null!==e&&(h=e.dehydrated,null!==h))return uk(a,b,g,d,h,e,c);if(f){f=d.fallback;g=b.mode;e=a.child;h=e.sibling;var k={mode:"hidden",children:d.children};0===(g&1)&&b.child!==e?(d=b.child,d.childLanes=0,d.pendingProps=k,b.deletions=null):(d=eb(e,k),d.subtreeFlags=e.subtreeFlags&14680064);null!==h?f=eb(h,f):(f=
|
||||
sb(f,g,c,null),f.flags|=2);f.return=b;d.return=b;d.sibling=f;b.child=d;d=f;f=b.child;g=a.child.memoizedState;g=null===g?Bf(c):{baseLanes:g.baseLanes|c,cachePool:null,transitions:g.transitions};f.memoizedState=g;f.childLanes=a.childLanes&~c;b.memoizedState=Cf;return d}f=a.child;a=f.sibling;d=eb(f,{mode:"visible",children:d.children});0===(b.mode&1)&&(d.lanes=c);d.return=b;d.sibling=null;null!==a&&(c=b.deletions,null===c?(b.deletions=[a],b.flags|=16):c.push(a));b.child=d;b.memoizedState=null;return d}
|
||||
function Df(a,b,c){b=Gd({mode:"visible",children:b},a.mode,0,null);b.return=a;return a.child=b}function Hd(a,b,c,d){null!==d&&Ye(d);Vb(b,a.child,null,c);a=Df(b,b.pendingProps.children);a.flags|=2;b.memoizedState=null;return a}function uk(a,b,c,d,e,f,g){if(c){if(b.flags&256)return b.flags&=-257,d=vf(Error(m(422))),Hd(a,b,g,d);if(null!==b.memoizedState)return b.child=a.child,b.flags|=128,null;f=d.fallback;e=b.mode;d=Gd({mode:"visible",children:d.children},e,0,null);f=sb(f,e,g,null);f.flags|=2;d.return=
|
||||
b;f.return=b;d.sibling=f;b.child=d;0!==(b.mode&1)&&Vb(b,a.child,null,g);b.child.memoizedState=Bf(g);b.memoizedState=Cf;return f}if(0===(b.mode&1))return Hd(a,b,g,null);if("$!"===e.data){d=e.nextSibling&&e.nextSibling.dataset;if(d)var h=d.dgst;d=h;f=Error(m(419));d=vf(f,d,void 0);return Hd(a,b,g,d)}h=0!==(g&a.childLanes);if(ha||h){d=O;if(null!==d){switch(g&-g){case 4:e=2;break;case 16:e=8;break;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:e=
|
||||
32;break;case 536870912:e=268435456;break;default:e=0}e=0!==(e&(d.suspendedLanes|g))?0:e;0!==e&&e!==f.retryLane&&(f.retryLane=e,Oa(a,e),xa(d,a,e,-1))}Ef();d=vf(Error(m(421)));return Hd(a,b,g,d)}if("$?"===e.data)return b.flags|=128,b.child=a.child,b=vk.bind(null,a),e._reactRetry=b,null;a=f.treeContext;fa=Ka(e.nextSibling);la=b;D=!0;wa=null;null!==a&&(na[oa++]=Ma,na[oa++]=Na,na[oa++]=rb,Ma=a.id,Na=a.overflow,rb=b);b=Df(b,d.children);b.flags|=4096;return b}function vi(a,b,c){a.lanes|=b;var d=a.alternate;
|
||||
null!==d&&(d.lanes|=b);df(a.return,b,c)}function Ff(a,b,c,d,e){var f=a.memoizedState;null===f?a.memoizedState={isBackwards:b,rendering:null,renderingStartTime:0,last:d,tail:c,tailMode:e}:(f.isBackwards=b,f.rendering=null,f.renderingStartTime=0,f.last=d,f.tail=c,f.tailMode=e)}function wi(a,b,c){var d=b.pendingProps,e=d.revealOrder,f=d.tail;aa(a,b,d.children,c);d=F.current;if(0!==(d&2))d=d&1|2,b.flags|=128;else{if(null!==a&&0!==(a.flags&128))a:for(a=b.child;null!==a;){if(13===a.tag)null!==a.memoizedState&&
|
||||
vi(a,c,b);else if(19===a.tag)vi(a,c,b);else if(null!==a.child){a.child.return=a;a=a.child;continue}if(a===b)break a;for(;null===a.sibling;){if(null===a.return||a.return===b)break a;a=a.return}a.sibling.return=a.return;a=a.sibling}d&=1}y(F,d);if(0===(b.mode&1))b.memoizedState=null;else switch(e){case "forwards":c=b.child;for(e=null;null!==c;)a=c.alternate,null!==a&&null===xd(a)&&(e=c),c=c.sibling;c=e;null===c?(e=b.child,b.child=null):(e=c.sibling,c.sibling=null);Ff(b,!1,e,c,f);break;case "backwards":c=
|
||||
null;e=b.child;for(b.child=null;null!==e;){a=e.alternate;if(null!==a&&null===xd(a)){b.child=e;break}a=e.sibling;e.sibling=c;c=e;e=a}Ff(b,!0,c,null,f);break;case "together":Ff(b,!1,null,null,void 0);break;default:b.memoizedState=null}return b.child}function Fd(a,b){0===(b.mode&1)&&null!==a&&(a.alternate=null,b.alternate=null,b.flags|=2)}function Qa(a,b,c){null!==a&&(b.dependencies=a.dependencies);ra|=b.lanes;if(0===(c&b.childLanes))return null;if(null!==a&&b.child!==a.child)throw Error(m(153));if(null!==
|
||||
b.child){a=b.child;c=eb(a,a.pendingProps);b.child=c;for(c.return=b;null!==a.sibling;)a=a.sibling,c=c.sibling=eb(a,a.pendingProps),c.return=b;c.sibling=null}return b.child}function wk(a,b,c){switch(b.tag){case 3:si(b);Qb();break;case 5:Ih(b);break;case 1:ea(b.type)&&ld(b);break;case 4:gf(b,b.stateNode.containerInfo);break;case 10:var d=b.type._context,e=b.memoizedProps.value;y(ud,d._currentValue);d._currentValue=e;break;case 13:d=b.memoizedState;if(null!==d){if(null!==d.dehydrated)return y(F,F.current&
|
||||
1),b.flags|=128,null;if(0!==(c&b.child.childLanes))return ui(a,b,c);y(F,F.current&1);a=Qa(a,b,c);return null!==a?a.sibling:null}y(F,F.current&1);break;case 19:d=0!==(c&b.childLanes);if(0!==(a.flags&128)){if(d)return wi(a,b,c);b.flags|=128}e=b.memoizedState;null!==e&&(e.rendering=null,e.tail=null,e.lastEffect=null);y(F,F.current);if(d)break;else return null;case 22:case 23:return b.lanes=0,pi(a,b,c)}return Qa(a,b,c)}function Dc(a,b){if(!D)switch(a.tailMode){case "hidden":b=a.tail;for(var c=null;null!==
|
||||
b;)null!==b.alternate&&(c=b),b=b.sibling;null===c?a.tail=null:c.sibling=null;break;case "collapsed":c=a.tail;for(var d=null;null!==c;)null!==c.alternate&&(d=c),c=c.sibling;null===d?b||null===a.tail?a.tail=null:a.tail.sibling=null:d.sibling=null}}function W(a){var b=null!==a.alternate&&a.alternate.child===a.child,c=0,d=0;if(b)for(var e=a.child;null!==e;)c|=e.lanes|e.childLanes,d|=e.subtreeFlags&14680064,d|=e.flags&14680064,e.return=a,e=e.sibling;else for(e=a.child;null!==e;)c|=e.lanes|e.childLanes,
|
||||
d|=e.subtreeFlags,d|=e.flags,e.return=a,e=e.sibling;a.subtreeFlags|=d;a.childLanes=c;return b}function xk(a,b,c){var d=b.pendingProps;Ve(b);switch(b.tag){case 2:case 16:case 15:case 0:case 11:case 7:case 8:case 12:case 9:case 14:return W(b),null;case 1:return ea(b.type)&&(v(S),v(J)),W(b),null;case 3:d=b.stateNode;Tb();v(S);v(J);jf();d.pendingContext&&(d.context=d.pendingContext,d.pendingContext=null);if(null===a||null===a.child)pd(b)?b.flags|=4:null===a||a.memoizedState.isDehydrated&&0===(b.flags&
|
||||
256)||(b.flags|=1024,null!==wa&&(Gf(wa),wa=null));xi(a,b);W(b);return null;case 5:hf(b);var e=ub(xc.current);c=b.type;if(null!==a&&null!=b.stateNode)yk(a,b,c,d,e),a.ref!==b.ref&&(b.flags|=512,b.flags|=2097152);else{if(!d){if(null===b.stateNode)throw Error(m(166));W(b);return null}a=ub(Ea.current);if(pd(b)){d=b.stateNode;c=b.type;var f=b.memoizedProps;d[Da]=b;d[uc]=f;a=0!==(b.mode&1);switch(c){case "dialog":B("cancel",d);B("close",d);break;case "iframe":case "object":case "embed":B("load",d);break;
|
||||
case "video":case "audio":for(e=0;e<Ec.length;e++)B(Ec[e],d);break;case "source":B("error",d);break;case "img":case "image":case "link":B("error",d);B("load",d);break;case "details":B("toggle",d);break;case "input":kg(d,f);B("invalid",d);break;case "select":d._wrapperState={wasMultiple:!!f.multiple};B("invalid",d);break;case "textarea":ng(d,f),B("invalid",d)}pe(c,f);e=null;for(var g in f)if(f.hasOwnProperty(g)){var h=f[g];"children"===g?"string"===typeof h?d.textContent!==h&&(!0!==f.suppressHydrationWarning&&
|
||||
jd(d.textContent,h,a),e=["children",h]):"number"===typeof h&&d.textContent!==""+h&&(!0!==f.suppressHydrationWarning&&jd(d.textContent,h,a),e=["children",""+h]):$b.hasOwnProperty(g)&&null!=h&&"onScroll"===g&&B("scroll",d)}switch(c){case "input":Pc(d);mg(d,f,!0);break;case "textarea":Pc(d);pg(d);break;case "select":case "option":break;default:"function"===typeof f.onClick&&(d.onclick=kd)}d=e;b.updateQueue=d;null!==d&&(b.flags|=4)}else{g=9===e.nodeType?e:e.ownerDocument;"http://www.w3.org/1999/xhtml"===
|
||||
a&&(a=qg(c));"http://www.w3.org/1999/xhtml"===a?"script"===c?(a=g.createElement("div"),a.innerHTML="<script>\x3c/script>",a=a.removeChild(a.firstChild)):"string"===typeof d.is?a=g.createElement(c,{is:d.is}):(a=g.createElement(c),"select"===c&&(g=a,d.multiple?g.multiple=!0:d.size&&(g.size=d.size))):a=g.createElementNS(a,c);a[Da]=b;a[uc]=d;zk(a,b,!1,!1);b.stateNode=a;a:{g=qe(c,d);switch(c){case "dialog":B("cancel",a);B("close",a);e=d;break;case "iframe":case "object":case "embed":B("load",a);e=d;break;
|
||||
case "video":case "audio":for(e=0;e<Ec.length;e++)B(Ec[e],a);e=d;break;case "source":B("error",a);e=d;break;case "img":case "image":case "link":B("error",a);B("load",a);e=d;break;case "details":B("toggle",a);e=d;break;case "input":kg(a,d);e=ke(a,d);B("invalid",a);break;case "option":e=d;break;case "select":a._wrapperState={wasMultiple:!!d.multiple};e=E({},d,{value:void 0});B("invalid",a);break;case "textarea":ng(a,d);e=ne(a,d);B("invalid",a);break;default:e=d}pe(c,e);h=e;for(f in h)if(h.hasOwnProperty(f)){var k=
|
||||
h[f];"style"===f?sg(a,k):"dangerouslySetInnerHTML"===f?(k=k?k.__html:void 0,null!=k&&yi(a,k)):"children"===f?"string"===typeof k?("textarea"!==c||""!==k)&&Fc(a,k):"number"===typeof k&&Fc(a,""+k):"suppressContentEditableWarning"!==f&&"suppressHydrationWarning"!==f&&"autoFocus"!==f&&($b.hasOwnProperty(f)?null!=k&&"onScroll"===f&&B("scroll",a):null!=k&&$d(a,f,k,g))}switch(c){case "input":Pc(a);mg(a,d,!1);break;case "textarea":Pc(a);pg(a);break;case "option":null!=d.value&&a.setAttribute("value",""+Ua(d.value));
|
||||
break;case "select":a.multiple=!!d.multiple;f=d.value;null!=f?Db(a,!!d.multiple,f,!1):null!=d.defaultValue&&Db(a,!!d.multiple,d.defaultValue,!0);break;default:"function"===typeof e.onClick&&(a.onclick=kd)}switch(c){case "button":case "input":case "select":case "textarea":d=!!d.autoFocus;break a;case "img":d=!0;break a;default:d=!1}}d&&(b.flags|=4)}null!==b.ref&&(b.flags|=512,b.flags|=2097152)}W(b);return null;case 6:if(a&&null!=b.stateNode)Ak(a,b,a.memoizedProps,d);else{if("string"!==typeof d&&null===
|
||||
b.stateNode)throw Error(m(166));c=ub(xc.current);ub(Ea.current);if(pd(b)){d=b.stateNode;c=b.memoizedProps;d[Da]=b;if(f=d.nodeValue!==c)if(a=la,null!==a)switch(a.tag){case 3:jd(d.nodeValue,c,0!==(a.mode&1));break;case 5:!0!==a.memoizedProps.suppressHydrationWarning&&jd(d.nodeValue,c,0!==(a.mode&1))}f&&(b.flags|=4)}else d=(9===c.nodeType?c:c.ownerDocument).createTextNode(d),d[Da]=b,b.stateNode=d}W(b);return null;case 13:v(F);d=b.memoizedState;if(null===a||null!==a.memoizedState&&null!==a.memoizedState.dehydrated){if(D&&
|
||||
null!==fa&&0!==(b.mode&1)&&0===(b.flags&128)){for(f=fa;f;)f=Ka(f.nextSibling);Qb();b.flags|=98560;f=!1}else if(f=pd(b),null!==d&&null!==d.dehydrated){if(null===a){if(!f)throw Error(m(318));f=b.memoizedState;f=null!==f?f.dehydrated:null;if(!f)throw Error(m(317));f[Da]=b}else Qb(),0===(b.flags&128)&&(b.memoizedState=null),b.flags|=4;W(b);f=!1}else null!==wa&&(Gf(wa),wa=null),f=!0;if(!f)return b.flags&65536?b:null}if(0!==(b.flags&128))return b.lanes=c,b;d=null!==d;d!==(null!==a&&null!==a.memoizedState)&&
|
||||
d&&(b.child.flags|=8192,0!==(b.mode&1)&&(null===a||0!==(F.current&1)?0===L&&(L=3):Ef()));null!==b.updateQueue&&(b.flags|=4);W(b);return null;case 4:return Tb(),xi(a,b),null===a&&sc(b.stateNode.containerInfo),W(b),null;case 10:return cf(b.type._context),W(b),null;case 17:return ea(b.type)&&(v(S),v(J)),W(b),null;case 19:v(F);f=b.memoizedState;if(null===f)return W(b),null;d=0!==(b.flags&128);g=f.rendering;if(null===g)if(d)Dc(f,!1);else{if(0!==L||null!==a&&0!==(a.flags&128))for(a=b.child;null!==a;){g=
|
||||
xd(a);if(null!==g){b.flags|=128;Dc(f,!1);d=g.updateQueue;null!==d&&(b.updateQueue=d,b.flags|=4);b.subtreeFlags=0;d=c;for(c=b.child;null!==c;)f=c,a=d,f.flags&=14680066,g=f.alternate,null===g?(f.childLanes=0,f.lanes=a,f.child=null,f.subtreeFlags=0,f.memoizedProps=null,f.memoizedState=null,f.updateQueue=null,f.dependencies=null,f.stateNode=null):(f.childLanes=g.childLanes,f.lanes=g.lanes,f.child=g.child,f.subtreeFlags=0,f.deletions=null,f.memoizedProps=g.memoizedProps,f.memoizedState=g.memoizedState,
|
||||
f.updateQueue=g.updateQueue,f.type=g.type,a=g.dependencies,f.dependencies=null===a?null:{lanes:a.lanes,firstContext:a.firstContext}),c=c.sibling;y(F,F.current&1|2);return b.child}a=a.sibling}null!==f.tail&&P()>Hf&&(b.flags|=128,d=!0,Dc(f,!1),b.lanes=4194304)}else{if(!d)if(a=xd(g),null!==a){if(b.flags|=128,d=!0,c=a.updateQueue,null!==c&&(b.updateQueue=c,b.flags|=4),Dc(f,!0),null===f.tail&&"hidden"===f.tailMode&&!g.alternate&&!D)return W(b),null}else 2*P()-f.renderingStartTime>Hf&&1073741824!==c&&(b.flags|=
|
||||
128,d=!0,Dc(f,!1),b.lanes=4194304);f.isBackwards?(g.sibling=b.child,b.child=g):(c=f.last,null!==c?c.sibling=g:b.child=g,f.last=g)}if(null!==f.tail)return b=f.tail,f.rendering=b,f.tail=b.sibling,f.renderingStartTime=P(),b.sibling=null,c=F.current,y(F,d?c&1|2:c&1),b;W(b);return null;case 22:case 23:return ba=Ga.current,v(Ga),d=null!==b.memoizedState,null!==a&&null!==a.memoizedState!==d&&(b.flags|=8192),d&&0!==(b.mode&1)?0!==(ba&1073741824)&&(W(b),b.subtreeFlags&6&&(b.flags|=8192)):W(b),null;case 24:return null;
|
||||
case 25:return null}throw Error(m(156,b.tag));}function Bk(a,b,c){Ve(b);switch(b.tag){case 1:return ea(b.type)&&(v(S),v(J)),a=b.flags,a&65536?(b.flags=a&-65537|128,b):null;case 3:return Tb(),v(S),v(J),jf(),a=b.flags,0!==(a&65536)&&0===(a&128)?(b.flags=a&-65537|128,b):null;case 5:return hf(b),null;case 13:v(F);a=b.memoizedState;if(null!==a&&null!==a.dehydrated){if(null===b.alternate)throw Error(m(340));Qb()}a=b.flags;return a&65536?(b.flags=a&-65537|128,b):null;case 19:return v(F),null;case 4:return Tb(),
|
||||
null;case 10:return cf(b.type._context),null;case 22:case 23:return ba=Ga.current,v(Ga),null;case 24:return null;default:return null}}function Wb(a,b){var c=a.ref;if(null!==c)if("function"===typeof c)try{c(null)}catch(d){G(a,b,d)}else c.current=null}function If(a,b,c){try{c()}catch(d){G(a,b,d)}}function Ck(a,b){Jf=Zc;a=ch();if(Ie(a)){if("selectionStart"in a)var c={start:a.selectionStart,end:a.selectionEnd};else a:{c=(c=a.ownerDocument)&&c.defaultView||window;var d=c.getSelection&&c.getSelection();
|
||||
if(d&&0!==d.rangeCount){c=d.anchorNode;var e=d.anchorOffset,f=d.focusNode;d=d.focusOffset;try{c.nodeType,f.nodeType}catch(M){c=null;break a}var g=0,h=-1,k=-1,n=0,q=0,u=a,r=null;b:for(;;){for(var p;;){u!==c||0!==e&&3!==u.nodeType||(h=g+e);u!==f||0!==d&&3!==u.nodeType||(k=g+d);3===u.nodeType&&(g+=u.nodeValue.length);if(null===(p=u.firstChild))break;r=u;u=p}for(;;){if(u===a)break b;r===c&&++n===e&&(h=g);r===f&&++q===d&&(k=g);if(null!==(p=u.nextSibling))break;u=r;r=u.parentNode}u=p}c=-1===h||-1===k?null:
|
||||
{start:h,end:k}}else c=null}c=c||{start:0,end:0}}else c=null;Kf={focusedElem:a,selectionRange:c};Zc=!1;for(l=b;null!==l;)if(b=l,a=b.child,0!==(b.subtreeFlags&1028)&&null!==a)a.return=b,l=a;else for(;null!==l;){b=l;try{var x=b.alternate;if(0!==(b.flags&1024))switch(b.tag){case 0:case 11:case 15:break;case 1:if(null!==x){var v=x.memoizedProps,z=x.memoizedState,w=b.stateNode,A=w.getSnapshotBeforeUpdate(b.elementType===b.type?v:ya(b.type,v),z);w.__reactInternalSnapshotBeforeUpdate=A}break;case 3:var t=
|
||||
b.stateNode.containerInfo;1===t.nodeType?t.textContent="":9===t.nodeType&&t.documentElement&&t.removeChild(t.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(m(163));}}catch(M){G(b,b.return,M)}a=b.sibling;if(null!==a){a.return=b.return;l=a;break}l=b.return}x=zi;zi=!1;return x}function Gc(a,b,c){var d=b.updateQueue;d=null!==d?d.lastEffect:null;if(null!==d){var e=d=d.next;do{if((e.tag&a)===a){var f=e.destroy;e.destroy=void 0;void 0!==f&&If(b,c,f)}e=e.next}while(e!==d)}}
|
||||
function Id(a,b){b=b.updateQueue;b=null!==b?b.lastEffect:null;if(null!==b){var c=b=b.next;do{if((c.tag&a)===a){var d=c.create;c.destroy=d()}c=c.next}while(c!==b)}}function Lf(a){var b=a.ref;if(null!==b){var c=a.stateNode;switch(a.tag){case 5:a=c;break;default:a=c}"function"===typeof b?b(a):b.current=a}}function Ai(a){var b=a.alternate;null!==b&&(a.alternate=null,Ai(b));a.child=null;a.deletions=null;a.sibling=null;5===a.tag&&(b=a.stateNode,null!==b&&(delete b[Da],delete b[uc],delete b[Me],delete b[Dk],
|
||||
delete b[Ek]));a.stateNode=null;a.return=null;a.dependencies=null;a.memoizedProps=null;a.memoizedState=null;a.pendingProps=null;a.stateNode=null;a.updateQueue=null}function Bi(a){return 5===a.tag||3===a.tag||4===a.tag}function Ci(a){a:for(;;){for(;null===a.sibling;){if(null===a.return||Bi(a.return))return null;a=a.return}a.sibling.return=a.return;for(a=a.sibling;5!==a.tag&&6!==a.tag&&18!==a.tag;){if(a.flags&2)continue a;if(null===a.child||4===a.tag)continue a;else a.child.return=a,a=a.child}if(!(a.flags&
|
||||
2))return a.stateNode}}function Mf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?8===c.nodeType?c.parentNode.insertBefore(a,b):c.insertBefore(a,b):(8===c.nodeType?(b=c.parentNode,b.insertBefore(a,c)):(b=c,b.appendChild(a)),c=c._reactRootContainer,null!==c&&void 0!==c||null!==b.onclick||(b.onclick=kd));else if(4!==d&&(a=a.child,null!==a))for(Mf(a,b,c),a=a.sibling;null!==a;)Mf(a,b,c),a=a.sibling}function Nf(a,b,c){var d=a.tag;if(5===d||6===d)a=a.stateNode,b?c.insertBefore(a,b):c.appendChild(a);
|
||||
else if(4!==d&&(a=a.child,null!==a))for(Nf(a,b,c),a=a.sibling;null!==a;)Nf(a,b,c),a=a.sibling}function jb(a,b,c){for(c=c.child;null!==c;)Di(a,b,c),c=c.sibling}function Di(a,b,c){if(Ca&&"function"===typeof Ca.onCommitFiberUnmount)try{Ca.onCommitFiberUnmount(Uc,c)}catch(h){}switch(c.tag){case 5:X||Wb(c,b);case 6:var d=T,e=za;T=null;jb(a,b,c);T=d;za=e;null!==T&&(za?(a=T,c=c.stateNode,8===a.nodeType?a.parentNode.removeChild(c):a.removeChild(c)):T.removeChild(c.stateNode));break;case 18:null!==T&&(za?
|
||||
(a=T,c=c.stateNode,8===a.nodeType?Re(a.parentNode,c):1===a.nodeType&&Re(a,c),nc(a)):Re(T,c.stateNode));break;case 4:d=T;e=za;T=c.stateNode.containerInfo;za=!0;jb(a,b,c);T=d;za=e;break;case 0:case 11:case 14:case 15:if(!X&&(d=c.updateQueue,null!==d&&(d=d.lastEffect,null!==d))){e=d=d.next;do{var f=e,g=f.destroy;f=f.tag;void 0!==g&&(0!==(f&2)?If(c,b,g):0!==(f&4)&&If(c,b,g));e=e.next}while(e!==d)}jb(a,b,c);break;case 1:if(!X&&(Wb(c,b),d=c.stateNode,"function"===typeof d.componentWillUnmount))try{d.props=
|
||||
c.memoizedProps,d.state=c.memoizedState,d.componentWillUnmount()}catch(h){G(c,b,h)}jb(a,b,c);break;case 21:jb(a,b,c);break;case 22:c.mode&1?(X=(d=X)||null!==c.memoizedState,jb(a,b,c),X=d):jb(a,b,c);break;default:jb(a,b,c)}}function Ei(a){var b=a.updateQueue;if(null!==b){a.updateQueue=null;var c=a.stateNode;null===c&&(c=a.stateNode=new Fk);b.forEach(function(b){var d=Gk.bind(null,a,b);c.has(b)||(c.add(b),b.then(d,d))})}}function Aa(a,b,c){c=b.deletions;if(null!==c)for(var d=0;d<c.length;d++){var e=
|
||||
c[d];try{var f=a,g=b,h=g;a:for(;null!==h;){switch(h.tag){case 5:T=h.stateNode;za=!1;break a;case 3:T=h.stateNode.containerInfo;za=!0;break a;case 4:T=h.stateNode.containerInfo;za=!0;break a}h=h.return}if(null===T)throw Error(m(160));Di(f,g,e);T=null;za=!1;var k=e.alternate;null!==k&&(k.return=null);e.return=null}catch(n){G(e,b,n)}}if(b.subtreeFlags&12854)for(b=b.child;null!==b;)Fi(b,a),b=b.sibling}function Fi(a,b,c){var d=a.alternate;c=a.flags;switch(a.tag){case 0:case 11:case 14:case 15:Aa(b,a);
|
||||
Ha(a);if(c&4){try{Gc(3,a,a.return),Id(3,a)}catch(I){G(a,a.return,I)}try{Gc(5,a,a.return)}catch(I){G(a,a.return,I)}}break;case 1:Aa(b,a);Ha(a);c&512&&null!==d&&Wb(d,d.return);break;case 5:Aa(b,a);Ha(a);c&512&&null!==d&&Wb(d,d.return);if(a.flags&32){var e=a.stateNode;try{Fc(e,"")}catch(I){G(a,a.return,I)}}if(c&4&&(e=a.stateNode,null!=e)){var f=a.memoizedProps,g=null!==d?d.memoizedProps:f,h=a.type,k=a.updateQueue;a.updateQueue=null;if(null!==k)try{"input"===h&&"radio"===f.type&&null!=f.name&&lg(e,f);
|
||||
qe(h,g);var n=qe(h,f);for(g=0;g<k.length;g+=2){var q=k[g],u=k[g+1];"style"===q?sg(e,u):"dangerouslySetInnerHTML"===q?yi(e,u):"children"===q?Fc(e,u):$d(e,q,u,n)}switch(h){case "input":le(e,f);break;case "textarea":og(e,f);break;case "select":var r=e._wrapperState.wasMultiple;e._wrapperState.wasMultiple=!!f.multiple;var p=f.value;null!=p?Db(e,!!f.multiple,p,!1):r!==!!f.multiple&&(null!=f.defaultValue?Db(e,!!f.multiple,f.defaultValue,!0):Db(e,!!f.multiple,f.multiple?[]:"",!1))}e[uc]=f}catch(I){G(a,a.return,
|
||||
I)}}break;case 6:Aa(b,a);Ha(a);if(c&4){if(null===a.stateNode)throw Error(m(162));e=a.stateNode;f=a.memoizedProps;try{e.nodeValue=f}catch(I){G(a,a.return,I)}}break;case 3:Aa(b,a);Ha(a);if(c&4&&null!==d&&d.memoizedState.isDehydrated)try{nc(b.containerInfo)}catch(I){G(a,a.return,I)}break;case 4:Aa(b,a);Ha(a);break;case 13:Aa(b,a);Ha(a);e=a.child;e.flags&8192&&(f=null!==e.memoizedState,e.stateNode.isHidden=f,!f||null!==e.alternate&&null!==e.alternate.memoizedState||(Of=P()));c&4&&Ei(a);break;case 22:q=
|
||||
null!==d&&null!==d.memoizedState;a.mode&1?(X=(n=X)||q,Aa(b,a),X=n):Aa(b,a);Ha(a);if(c&8192){n=null!==a.memoizedState;if((a.stateNode.isHidden=n)&&!q&&0!==(a.mode&1))for(l=a,q=a.child;null!==q;){for(u=l=q;null!==l;){r=l;p=r.child;switch(r.tag){case 0:case 11:case 14:case 15:Gc(4,r,r.return);break;case 1:Wb(r,r.return);var x=r.stateNode;if("function"===typeof x.componentWillUnmount){c=r;b=r.return;try{d=c,x.props=d.memoizedProps,x.state=d.memoizedState,x.componentWillUnmount()}catch(I){G(c,b,I)}}break;
|
||||
case 5:Wb(r,r.return);break;case 22:if(null!==r.memoizedState){Gi(u);continue}}null!==p?(p.return=r,l=p):Gi(u)}q=q.sibling}a:for(q=null,u=a;;){if(5===u.tag){if(null===q){q=u;try{e=u.stateNode,n?(f=e.style,"function"===typeof f.setProperty?f.setProperty("display","none","important"):f.display="none"):(h=u.stateNode,k=u.memoizedProps.style,g=void 0!==k&&null!==k&&k.hasOwnProperty("display")?k.display:null,h.style.display=rg("display",g))}catch(I){G(a,a.return,I)}}}else if(6===u.tag){if(null===q)try{u.stateNode.nodeValue=
|
||||
n?"":u.memoizedProps}catch(I){G(a,a.return,I)}}else if((22!==u.tag&&23!==u.tag||null===u.memoizedState||u===a)&&null!==u.child){u.child.return=u;u=u.child;continue}if(u===a)break a;for(;null===u.sibling;){if(null===u.return||u.return===a)break a;q===u&&(q=null);u=u.return}q===u&&(q=null);u.sibling.return=u.return;u=u.sibling}}break;case 19:Aa(b,a);Ha(a);c&4&&Ei(a);break;case 21:break;default:Aa(b,a),Ha(a)}}function Ha(a){var b=a.flags;if(b&2){try{a:{for(var c=a.return;null!==c;){if(Bi(c)){var d=c;
|
||||
break a}c=c.return}throw Error(m(160));}switch(d.tag){case 5:var e=d.stateNode;d.flags&32&&(Fc(e,""),d.flags&=-33);var f=Ci(a);Nf(a,f,e);break;case 3:case 4:var g=d.stateNode.containerInfo,h=Ci(a);Mf(a,h,g);break;default:throw Error(m(161));}}catch(k){G(a,a.return,k)}a.flags&=-3}b&4096&&(a.flags&=-4097)}function Hk(a,b,c){l=a;Hi(a,b,c)}function Hi(a,b,c){for(var d=0!==(a.mode&1);null!==l;){var e=l,f=e.child;if(22===e.tag&&d){var g=null!==e.memoizedState||Jd;if(!g){var h=e.alternate,k=null!==h&&null!==
|
||||
h.memoizedState||X;h=Jd;var n=X;Jd=g;if((X=k)&&!n)for(l=e;null!==l;)g=l,k=g.child,22===g.tag&&null!==g.memoizedState?Ii(e):null!==k?(k.return=g,l=k):Ii(e);for(;null!==f;)l=f,Hi(f,b,c),f=f.sibling;l=e;Jd=h;X=n}Ji(a,b,c)}else 0!==(e.subtreeFlags&8772)&&null!==f?(f.return=e,l=f):Ji(a,b,c)}}function Ji(a,b,c){for(;null!==l;){b=l;if(0!==(b.flags&8772)){c=b.alternate;try{if(0!==(b.flags&8772))switch(b.tag){case 0:case 11:case 15:X||Id(5,b);break;case 1:var d=b.stateNode;if(b.flags&4&&!X)if(null===c)d.componentDidMount();
|
||||
else{var e=b.elementType===b.type?c.memoizedProps:ya(b.type,c.memoizedProps);d.componentDidUpdate(e,c.memoizedState,d.__reactInternalSnapshotBeforeUpdate)}var f=b.updateQueue;null!==f&&Hh(b,f,d);break;case 3:var g=b.updateQueue;if(null!==g){c=null;if(null!==b.child)switch(b.child.tag){case 5:c=b.child.stateNode;break;case 1:c=b.child.stateNode}Hh(b,g,c)}break;case 5:var h=b.stateNode;if(null===c&&b.flags&4){c=h;var k=b.memoizedProps;switch(b.type){case "button":case "input":case "select":case "textarea":k.autoFocus&&
|
||||
c.focus();break;case "img":k.src&&(c.src=k.src)}}break;case 6:break;case 4:break;case 12:break;case 13:if(null===b.memoizedState){var n=b.alternate;if(null!==n){var q=n.memoizedState;if(null!==q){var p=q.dehydrated;null!==p&&nc(p)}}}break;case 19:case 17:case 21:case 22:case 23:case 25:break;default:throw Error(m(163));}X||b.flags&512&&Lf(b)}catch(r){G(b,b.return,r)}}if(b===a){l=null;break}c=b.sibling;if(null!==c){c.return=b.return;l=c;break}l=b.return}}function Gi(a){for(;null!==l;){var b=l;if(b===
|
||||
a){l=null;break}var c=b.sibling;if(null!==c){c.return=b.return;l=c;break}l=b.return}}function Ii(a){for(;null!==l;){var b=l;try{switch(b.tag){case 0:case 11:case 15:var c=b.return;try{Id(4,b)}catch(k){G(b,c,k)}break;case 1:var d=b.stateNode;if("function"===typeof d.componentDidMount){var e=b.return;try{d.componentDidMount()}catch(k){G(b,e,k)}}var f=b.return;try{Lf(b)}catch(k){G(b,f,k)}break;case 5:var g=b.return;try{Lf(b)}catch(k){G(b,g,k)}}}catch(k){G(b,b.return,k)}if(b===a){l=null;break}var h=b.sibling;
|
||||
if(null!==h){h.return=b.return;l=h;break}l=b.return}}function Hc(){Hf=P()+500}function Z(){return 0!==(p&6)?P():-1!==Kd?Kd:Kd=P()}function hb(a){if(0===(a.mode&1))return 1;if(0!==(p&2)&&0!==U)return U&-U;if(null!==Ik.transition)return 0===Ld&&(Ld=Dg()),Ld;a=z;if(0!==a)return a;a=window.event;a=void 0===a?16:Lg(a.type);return a}function xa(a,b,c,d){if(50<Ic)throw Ic=0,Pf=null,Error(m(185));ic(a,c,d);if(0===(p&2)||a!==O)a===O&&(0===(p&2)&&(Md|=c),4===L&&kb(a,U)),ia(a,d),1===c&&0===p&&0===(b.mode&1)&&
|
||||
(Hc(),md&&db())}function ia(a,b){var c=a.callbackNode;tj(a,b);var d=Vc(a,a===O?U:0);if(0===d)null!==c&&Ki(c),a.callbackNode=null,a.callbackPriority=0;else if(b=d&-d,a.callbackPriority!==b){null!=c&&Ki(c);if(1===b)0===a.tag?jk(Li.bind(null,a)):wh(Li.bind(null,a)),Jk(function(){0===(p&6)&&db()}),c=null;else{switch(Eg(d)){case 1:c=De;break;case 4:c=Mg;break;case 16:c=ad;break;case 536870912:c=Ng;break;default:c=ad}c=Mi(c,Ni.bind(null,a))}a.callbackPriority=b;a.callbackNode=c}}function Ni(a,b){Kd=-1;
|
||||
Ld=0;if(0!==(p&6))throw Error(m(327));var c=a.callbackNode;if(Xb()&&a.callbackNode!==c)return null;var d=Vc(a,a===O?U:0);if(0===d)return null;if(0!==(d&30)||0!==(d&a.expiredLanes)||b)b=Nd(a,d);else{b=d;var e=p;p|=2;var f=Oi();if(O!==a||U!==b)Ra=null,Hc(),wb(a,b);do try{Kk();break}catch(h){Pi(a,h)}while(1);af();Od.current=f;p=e;null!==H?b=0:(O=null,U=0,b=L)}if(0!==b){2===b&&(e=ve(a),0!==e&&(d=e,b=Qf(a,e)));if(1===b)throw c=Jc,wb(a,0),kb(a,d),ia(a,P()),c;if(6===b)kb(a,d);else{e=a.current.alternate;
|
||||
if(0===(d&30)&&!Lk(e)&&(b=Nd(a,d),2===b&&(f=ve(a),0!==f&&(d=f,b=Qf(a,f))),1===b))throw c=Jc,wb(a,0),kb(a,d),ia(a,P()),c;a.finishedWork=e;a.finishedLanes=d;switch(b){case 0:case 1:throw Error(m(345));case 2:xb(a,ja,Ra);break;case 3:kb(a,d);if((d&130023424)===d&&(b=Of+500-P(),10<b)){if(0!==Vc(a,0))break;e=a.suspendedLanes;if((e&d)!==d){Z();a.pingedLanes|=a.suspendedLanes&e;break}a.timeoutHandle=Rf(xb.bind(null,a,ja,Ra),b);break}xb(a,ja,Ra);break;case 4:kb(a,d);if((d&4194240)===d)break;b=a.eventTimes;
|
||||
for(e=-1;0<d;){var g=31-ta(d);f=1<<g;g=b[g];g>e&&(e=g);d&=~f}d=e;d=P()-d;d=(120>d?120:480>d?480:1080>d?1080:1920>d?1920:3E3>d?3E3:4320>d?4320:1960*Mk(d/1960))-d;if(10<d){a.timeoutHandle=Rf(xb.bind(null,a,ja,Ra),d);break}xb(a,ja,Ra);break;case 5:xb(a,ja,Ra);break;default:throw Error(m(329));}}}ia(a,P());return a.callbackNode===c?Ni.bind(null,a):null}function Qf(a,b){var c=Kc;a.current.memoizedState.isDehydrated&&(wb(a,b).flags|=256);a=Nd(a,b);2!==a&&(b=ja,ja=c,null!==b&&Gf(b));return a}function Gf(a){null===
|
||||
ja?ja=a:ja.push.apply(ja,a)}function Lk(a){for(var b=a;;){if(b.flags&16384){var c=b.updateQueue;if(null!==c&&(c=c.stores,null!==c))for(var d=0;d<c.length;d++){var e=c[d],f=e.getSnapshot;e=e.value;try{if(!ua(f(),e))return!1}catch(g){return!1}}}c=b.child;if(b.subtreeFlags&16384&&null!==c)c.return=b,b=c;else{if(b===a)break;for(;null===b.sibling;){if(null===b.return||b.return===a)return!0;b=b.return}b.sibling.return=b.return;b=b.sibling}}return!0}function kb(a,b){b&=~Sf;b&=~Md;a.suspendedLanes|=b;a.pingedLanes&=
|
||||
~b;for(a=a.expirationTimes;0<b;){var c=31-ta(b),d=1<<c;a[c]=-1;b&=~d}}function Li(a){if(0!==(p&6))throw Error(m(327));Xb();var b=Vc(a,0);if(0===(b&1))return ia(a,P()),null;var c=Nd(a,b);if(0!==a.tag&&2===c){var d=ve(a);0!==d&&(b=d,c=Qf(a,d))}if(1===c)throw c=Jc,wb(a,0),kb(a,b),ia(a,P()),c;if(6===c)throw Error(m(345));a.finishedWork=a.current.alternate;a.finishedLanes=b;xb(a,ja,Ra);ia(a,P());return null}function Tf(a,b){var c=p;p|=1;try{return a(b)}finally{p=c,0===p&&(Hc(),md&&db())}}function yb(a){null!==
|
||||
lb&&0===lb.tag&&0===(p&6)&&Xb();var b=p;p|=1;var c=ca.transition,d=z;try{if(ca.transition=null,z=1,a)return a()}finally{z=d,ca.transition=c,p=b,0===(p&6)&&db()}}function wb(a,b){a.finishedWork=null;a.finishedLanes=0;var c=a.timeoutHandle;-1!==c&&(a.timeoutHandle=-1,Nk(c));if(null!==H)for(c=H.return;null!==c;){var d=c;Ve(d);switch(d.tag){case 1:d=d.type.childContextTypes;null!==d&&void 0!==d&&(v(S),v(J));break;case 3:Tb();v(S);v(J);jf();break;case 5:hf(d);break;case 4:Tb();break;case 13:v(F);break;
|
||||
case 19:v(F);break;case 10:cf(d.type._context);break;case 22:case 23:ba=Ga.current,v(Ga)}c=c.return}O=a;H=a=eb(a.current,null);U=ba=b;L=0;Jc=null;Sf=Md=ra=0;ja=Kc=null;if(null!==tb){for(b=0;b<tb.length;b++)if(c=tb[b],d=c.interleaved,null!==d){c.interleaved=null;var e=d.next,f=c.pending;if(null!==f){var g=f.next;f.next=e;d.next=g}c.pending=d}tb=null}return a}function Pi(a,b){do{var c=H;try{af();yd.current=zd;if(Ad){for(var d=C.memoizedState;null!==d;){var e=d.queue;null!==e&&(e.pending=null);d=d.next}Ad=
|
||||
!1}vb=0;N=K=C=null;zc=!1;Ac=0;Uf.current=null;if(null===c||null===c.return){L=1;Jc=b;H=null;break}a:{var f=a,g=c.return,h=c,k=b;b=U;h.flags|=32768;if(null!==k&&"object"===typeof k&&"function"===typeof k.then){var n=k,l=h,p=l.tag;if(0===(l.mode&1)&&(0===p||11===p||15===p)){var r=l.alternate;r?(l.updateQueue=r.updateQueue,l.memoizedState=r.memoizedState,l.lanes=r.lanes):(l.updateQueue=null,l.memoizedState=null)}var v=ji(g);if(null!==v){v.flags&=-257;ki(v,g,h,f,b);v.mode&1&&ii(f,n,b);b=v;k=n;var x=b.updateQueue;
|
||||
if(null===x){var z=new Set;z.add(k);b.updateQueue=z}else x.add(k);break a}else{if(0===(b&1)){ii(f,n,b);Ef();break a}k=Error(m(426))}}else if(D&&h.mode&1){var y=ji(g);if(null!==y){0===(y.flags&65536)&&(y.flags|=256);ki(y,g,h,f,b);Ye(Ub(k,h));break a}}f=k=Ub(k,h);4!==L&&(L=2);null===Kc?Kc=[f]:Kc.push(f);f=g;do{switch(f.tag){case 3:f.flags|=65536;b&=-b;f.lanes|=b;var w=gi(f,k,b);Gh(f,w);break a;case 1:h=k;var A=f.type,t=f.stateNode;if(0===(f.flags&128)&&("function"===typeof A.getDerivedStateFromError||
|
||||
null!==t&&"function"===typeof t.componentDidCatch&&(null===ib||!ib.has(t)))){f.flags|=65536;b&=-b;f.lanes|=b;var B=hi(f,h,b);Gh(f,B);break a}}f=f.return}while(null!==f)}Qi(c)}catch(ma){b=ma;H===c&&null!==c&&(H=c=c.return);continue}break}while(1)}function Oi(){var a=Od.current;Od.current=zd;return null===a?zd:a}function Ef(){if(0===L||3===L||2===L)L=4;null===O||0===(ra&268435455)&&0===(Md&268435455)||kb(O,U)}function Nd(a,b){var c=p;p|=2;var d=Oi();if(O!==a||U!==b)Ra=null,wb(a,b);do try{Ok();break}catch(e){Pi(a,
|
||||
e)}while(1);af();p=c;Od.current=d;if(null!==H)throw Error(m(261));O=null;U=0;return L}function Ok(){for(;null!==H;)Ri(H)}function Kk(){for(;null!==H&&!Pk();)Ri(H)}function Ri(a){var b=Qk(a.alternate,a,ba);a.memoizedProps=a.pendingProps;null===b?Qi(a):H=b;Uf.current=null}function Qi(a){var b=a;do{var c=b.alternate;a=b.return;if(0===(b.flags&32768)){if(c=xk(c,b,ba),null!==c){H=c;return}}else{c=Bk(c,b);if(null!==c){c.flags&=32767;H=c;return}if(null!==a)a.flags|=32768,a.subtreeFlags=0,a.deletions=null;
|
||||
else{L=6;H=null;return}}b=b.sibling;if(null!==b){H=b;return}H=b=a}while(null!==b);0===L&&(L=5)}function xb(a,b,c){var d=z,e=ca.transition;try{ca.transition=null,z=1,Rk(a,b,c,d)}finally{ca.transition=e,z=d}return null}function Rk(a,b,c,d){do Xb();while(null!==lb);if(0!==(p&6))throw Error(m(327));c=a.finishedWork;var e=a.finishedLanes;if(null===c)return null;a.finishedWork=null;a.finishedLanes=0;if(c===a.current)throw Error(m(177));a.callbackNode=null;a.callbackPriority=0;var f=c.lanes|c.childLanes;
|
||||
uj(a,f);a===O&&(H=O=null,U=0);0===(c.subtreeFlags&2064)&&0===(c.flags&2064)||Pd||(Pd=!0,Mi(ad,function(){Xb();return null}));f=0!==(c.flags&15990);if(0!==(c.subtreeFlags&15990)||f){f=ca.transition;ca.transition=null;var g=z;z=1;var h=p;p|=4;Uf.current=null;Ck(a,c);Fi(c,a);Tj(Kf);Zc=!!Jf;Kf=Jf=null;a.current=c;Hk(c,a,e);Sk();p=h;z=g;ca.transition=f}else a.current=c;Pd&&(Pd=!1,lb=a,Qd=e);f=a.pendingLanes;0===f&&(ib=null);oj(c.stateNode,d);ia(a,P());if(null!==b)for(d=a.onRecoverableError,c=0;c<b.length;c++)e=
|
||||
b[c],d(e.value,{componentStack:e.stack,digest:e.digest});if(Ed)throw Ed=!1,a=xf,xf=null,a;0!==(Qd&1)&&0!==a.tag&&Xb();f=a.pendingLanes;0!==(f&1)?a===Pf?Ic++:(Ic=0,Pf=a):Ic=0;db();return null}function Xb(){if(null!==lb){var a=Eg(Qd),b=ca.transition,c=z;try{ca.transition=null;z=16>a?16:a;if(null===lb)var d=!1;else{a=lb;lb=null;Qd=0;if(0!==(p&6))throw Error(m(331));var e=p;p|=4;for(l=a.current;null!==l;){var f=l,g=f.child;if(0!==(l.flags&16)){var h=f.deletions;if(null!==h){for(var k=0;k<h.length;k++){var n=
|
||||
h[k];for(l=n;null!==l;){var q=l;switch(q.tag){case 0:case 11:case 15:Gc(8,q,f)}var u=q.child;if(null!==u)u.return=q,l=u;else for(;null!==l;){q=l;var r=q.sibling,v=q.return;Ai(q);if(q===n){l=null;break}if(null!==r){r.return=v;l=r;break}l=v}}}var x=f.alternate;if(null!==x){var y=x.child;if(null!==y){x.child=null;do{var C=y.sibling;y.sibling=null;y=C}while(null!==y)}}l=f}}if(0!==(f.subtreeFlags&2064)&&null!==g)g.return=f,l=g;else b:for(;null!==l;){f=l;if(0!==(f.flags&2048))switch(f.tag){case 0:case 11:case 15:Gc(9,
|
||||
f,f.return)}var w=f.sibling;if(null!==w){w.return=f.return;l=w;break b}l=f.return}}var A=a.current;for(l=A;null!==l;){g=l;var t=g.child;if(0!==(g.subtreeFlags&2064)&&null!==t)t.return=g,l=t;else b:for(g=A;null!==l;){h=l;if(0!==(h.flags&2048))try{switch(h.tag){case 0:case 11:case 15:Id(9,h)}}catch(ma){G(h,h.return,ma)}if(h===g){l=null;break b}var B=h.sibling;if(null!==B){B.return=h.return;l=B;break b}l=h.return}}p=e;db();if(Ca&&"function"===typeof Ca.onPostCommitFiberRoot)try{Ca.onPostCommitFiberRoot(Uc,
|
||||
a)}catch(ma){}d=!0}return d}finally{z=c,ca.transition=b}}return!1}function Si(a,b,c){b=Ub(c,b);b=gi(a,b,1);a=fb(a,b,1);b=Z();null!==a&&(ic(a,1,b),ia(a,b))}function G(a,b,c){if(3===a.tag)Si(a,a,c);else for(;null!==b;){if(3===b.tag){Si(b,a,c);break}else if(1===b.tag){var d=b.stateNode;if("function"===typeof b.type.getDerivedStateFromError||"function"===typeof d.componentDidCatch&&(null===ib||!ib.has(d))){a=Ub(c,a);a=hi(b,a,1);b=fb(b,a,1);a=Z();null!==b&&(ic(b,1,a),ia(b,a));break}}b=b.return}}function sk(a,
|
||||
b,c){var d=a.pingCache;null!==d&&d.delete(b);b=Z();a.pingedLanes|=a.suspendedLanes&c;O===a&&(U&c)===c&&(4===L||3===L&&(U&130023424)===U&&500>P()-Of?wb(a,0):Sf|=c);ia(a,b)}function Ti(a,b){0===b&&(0===(a.mode&1)?b=1:(b=Rd,Rd<<=1,0===(Rd&130023424)&&(Rd=4194304)));var c=Z();a=Oa(a,b);null!==a&&(ic(a,b,c),ia(a,c))}function vk(a){var b=a.memoizedState,c=0;null!==b&&(c=b.retryLane);Ti(a,c)}function Gk(a,b){var c=0;switch(a.tag){case 13:var d=a.stateNode;var e=a.memoizedState;null!==e&&(c=e.retryLane);
|
||||
break;case 19:d=a.stateNode;break;default:throw Error(m(314));}null!==d&&d.delete(b);Ti(a,c)}function Mi(a,b){return xh(a,b)}function Tk(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.subtreeFlags=this.flags=0;this.deletions=null;this.childLanes=this.lanes=0;this.alternate=null}function yf(a){a=
|
||||
a.prototype;return!(!a||!a.isReactComponent)}function Uk(a){if("function"===typeof a)return yf(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===ie)return 11;if(a===je)return 14}return 2}function eb(a,b){var c=a.alternate;null===c?(c=pa(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode,c.alternate=a,a.alternate=c):(c.pendingProps=b,c.type=a.type,c.flags=0,c.subtreeFlags=0,c.deletions=null);c.flags=a.flags&14680064;c.childLanes=a.childLanes;c.lanes=a.lanes;c.child=
|
||||
a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;b=a.dependencies;c.dependencies=null===b?null:{lanes:b.lanes,firstContext:b.firstContext};c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function rd(a,b,c,d,e,f){var g=2;d=a;if("function"===typeof a)yf(a)&&(g=1);else if("string"===typeof a)g=5;else a:switch(a){case Bb:return sb(c.children,e,f,b);case fe:g=8;e|=8;break;case ee:return a=pa(12,c,b,e|2),a.elementType=ee,a.lanes=f,a;case ge:return a=
|
||||
pa(13,c,b,e),a.elementType=ge,a.lanes=f,a;case he:return a=pa(19,c,b,e),a.elementType=he,a.lanes=f,a;case Ui:return Gd(c,e,f,b);default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case hg:g=10;break a;case gg:g=9;break a;case ie:g=11;break a;case je:g=14;break a;case Ta:g=16;d=null;break a}throw Error(m(130,null==a?a:typeof a,""));}b=pa(g,c,b,e);b.elementType=a;b.type=d;b.lanes=f;return b}function sb(a,b,c,d){a=pa(7,a,d,b);a.lanes=c;return a}function Gd(a,b,c,d){a=pa(22,a,d,b);a.elementType=
|
||||
Ui;a.lanes=c;a.stateNode={isHidden:!1};return a}function Ze(a,b,c){a=pa(6,a,null,b);a.lanes=c;return a}function $e(a,b,c){b=pa(4,null!==a.children?a.children:[],a.key,b);b.lanes=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function Vk(a,b,c,d,e){this.tag=b;this.containerInfo=a;this.finishedWork=this.pingCache=this.current=this.pendingChildren=null;this.timeoutHandle=-1;this.callbackNode=this.pendingContext=this.context=null;this.callbackPriority=
|
||||
0;this.eventTimes=we(0);this.expirationTimes=we(-1);this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0;this.entanglements=we(0);this.identifierPrefix=d;this.onRecoverableError=e;this.mutableSourceEagerHydrationData=null}function Vf(a,b,c,d,e,f,g,h,k,l){a=new Vk(a,b,c,h,k);1===b?(b=1,!0===f&&(b|=8)):b=0;f=pa(3,null,null,b);a.current=f;f.stateNode=a;f.memoizedState={element:d,isDehydrated:c,cache:null,transitions:null,
|
||||
pendingSuspenseBoundaries:null};ff(f);return a}function Wk(a,b,c){var d=3<arguments.length&&void 0!==arguments[3]?arguments[3]:null;return{$$typeof:Cb,key:null==d?null:""+d,children:a,containerInfo:b,implementation:c}}function Vi(a){if(!a)return cb;a=a._reactInternals;a:{if(nb(a)!==a||1!==a.tag)throw Error(m(170));var b=a;do{switch(b.tag){case 3:b=b.stateNode.context;break a;case 1:if(ea(b.type)){b=b.stateNode.__reactInternalMemoizedMergedChildContext;break a}}b=b.return}while(null!==b);throw Error(m(171));
|
||||
}if(1===a.tag){var c=a.type;if(ea(c))return uh(a,c,b)}return b}function Wi(a,b,c,d,e,f,g,h,k,l){a=Vf(c,d,!0,a,e,f,g,h,k);a.context=Vi(null);c=a.current;d=Z();e=hb(c);f=Pa(d,e);f.callback=void 0!==b&&null!==b?b:null;fb(c,f,e);a.current.lanes=e;ic(a,e,d);ia(a,d);return a}function Sd(a,b,c,d){var e=b.current,f=Z(),g=hb(e);c=Vi(c);null===b.context?b.context=c:b.pendingContext=c;b=Pa(f,g);b.payload={element:a};d=void 0===d?null:d;null!==d&&(b.callback=d);a=fb(e,b,g);null!==a&&(xa(a,e,g,f),vd(a,e,g));return g}
|
||||
function Td(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function Xi(a,b){a=a.memoizedState;if(null!==a&&null!==a.dehydrated){var c=a.retryLane;a.retryLane=0!==c&&c<b?c:b}}function Wf(a,b){Xi(a,b);(a=a.alternate)&&Xi(a,b)}function Xk(a){a=Bg(a);return null===a?null:a.stateNode}function Yk(a){return null}function Xf(a){this._internalRoot=a}function Ud(a){this._internalRoot=a}function Yf(a){return!(!a||1!==a.nodeType&&9!==
|
||||
a.nodeType&&11!==a.nodeType)}function Vd(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||" react-mount-point-unstable "!==a.nodeValue))}function Yi(){}function Zk(a,b,c,d,e){if(e){if("function"===typeof d){var f=d;d=function(){var a=Td(g);f.call(a)}}var g=Wi(b,d,a,0,null,!1,!1,"",Yi);a._reactRootContainer=g;a[Ja]=g.current;sc(8===a.nodeType?a.parentNode:a);yb();return g}for(;e=a.lastChild;)a.removeChild(e);if("function"===typeof d){var h=d;d=function(){var a=Td(k);
|
||||
h.call(a)}}var k=Vf(a,0,!1,null,null,!1,!1,"",Yi);a._reactRootContainer=k;a[Ja]=k.current;sc(8===a.nodeType?a.parentNode:a);yb(function(){Sd(b,k,c,d)});return k}function Wd(a,b,c,d,e){var f=c._reactRootContainer;if(f){var g=f;if("function"===typeof e){var h=e;e=function(){var a=Td(g);h.call(a)}}Sd(b,g,a,e)}else g=Zk(c,b,a,e,d);return Td(g)}var cg=new Set,$b={},Ia=!("undefined"===typeof window||"undefined"===typeof window.document||"undefined"===typeof window.document.createElement),Zd=Object.prototype.hasOwnProperty,
|
||||
cj=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,eg={},dg={},R={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){R[a]=
|
||||
new Y(a,0,!1,a,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var b=a[0];R[b]=new Y(b,1,!1,a[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(a){R[a]=new Y(a,2,!1,a.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){R[a]=new Y(a,2,!1,a,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".split(" ").forEach(function(a){R[a]=
|
||||
new Y(a,3,!1,a.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(a){R[a]=new Y(a,3,!0,a,null,!1,!1)});["capture","download"].forEach(function(a){R[a]=new Y(a,4,!1,a,null,!1,!1)});["cols","rows","size","span"].forEach(function(a){R[a]=new Y(a,6,!1,a,null,!1,!1)});["rowSpan","start"].forEach(function(a){R[a]=new Y(a,5,!1,a.toLowerCase(),null,!1,!1)});var Zf=/[\-:]([a-z])/g,$f=function(a){return a[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".split(" ").forEach(function(a){var b=
|
||||
a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var b=a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(a){var b=a.replace(Zf,$f);R[b]=new Y(b,1,!1,a,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(a){R[a]=new Y(a,1,!1,a.toLowerCase(),null,!1,!1)});R.xlinkHref=new Y("xlinkHref",
|
||||
1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(a){R[a]=new Y(a,1,!1,a.toLowerCase(),null,!0,!0)});var Sa=zb.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED,sd=Symbol.for("react.element"),Cb=Symbol.for("react.portal"),Bb=Symbol.for("react.fragment"),fe=Symbol.for("react.strict_mode"),ee=Symbol.for("react.profiler"),hg=Symbol.for("react.provider"),gg=Symbol.for("react.context"),ie=Symbol.for("react.forward_ref"),ge=Symbol.for("react.suspense"),
|
||||
he=Symbol.for("react.suspense_list"),je=Symbol.for("react.memo"),Ta=Symbol.for("react.lazy");Symbol.for("react.scope");Symbol.for("react.debug_trace_mode");var Ui=Symbol.for("react.offscreen");Symbol.for("react.legacy_hidden");Symbol.for("react.cache");Symbol.for("react.tracing_marker");var fg=Symbol.iterator,E=Object.assign,ae,ce=!1,cc=Array.isArray,Xd,yi=function(a){return"undefined"!==typeof MSApp&&MSApp.execUnsafeLocalFunction?function(b,c,d,e){MSApp.execUnsafeLocalFunction(function(){return a(b,
|
||||
c,d,e)})}:a}(function(a,b){if("http://www.w3.org/2000/svg"!==a.namespaceURI||"innerHTML"in a)a.innerHTML=b;else{Xd=Xd||document.createElement("div");Xd.innerHTML="<svg>"+b.valueOf().toString()+"</svg>";for(b=Xd.firstChild;a.firstChild;)a.removeChild(a.firstChild);for(;b.firstChild;)a.appendChild(b.firstChild)}}),Fc=function(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b},dc={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,
|
||||
borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,
|
||||
strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},$k=["Webkit","ms","Moz","O"];Object.keys(dc).forEach(function(a){$k.forEach(function(b){b=b+a.charAt(0).toUpperCase()+a.substring(1);dc[b]=dc[a]})});var ij=E({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0}),ze=null,se=null,Eb=null,Fb=null,xg=function(a,b){return a(b)},yg=function(){},te=!1,Oe=!1;if(Ia)try{var Lc={};Object.defineProperty(Lc,
|
||||
"passive",{get:function(){Oe=!0}});window.addEventListener("test",Lc,Lc);window.removeEventListener("test",Lc,Lc)}catch(a){Oe=!1}var kj=function(a,b,c,d,e,f,g,h,k){var l=Array.prototype.slice.call(arguments,3);try{b.apply(c,l)}catch(q){this.onError(q)}},gc=!1,Sc=null,Tc=!1,ue=null,lj={onError:function(a){gc=!0;Sc=a}},Ba=zb.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.Scheduler,Jg=Ba.unstable_scheduleCallback,Kg=Ba.unstable_NormalPriority,xh=Jg,Ki=Ba.unstable_cancelCallback,Pk=Ba.unstable_shouldYield,
|
||||
Sk=Ba.unstable_requestPaint,P=Ba.unstable_now,Dj=Ba.unstable_getCurrentPriorityLevel,De=Ba.unstable_ImmediatePriority,Mg=Ba.unstable_UserBlockingPriority,ad=Kg,Ej=Ba.unstable_LowPriority,Ng=Ba.unstable_IdlePriority,Uc=null,Ca=null,ta=Math.clz32?Math.clz32:pj,qj=Math.log,rj=Math.LN2,Wc=64,Rd=4194304,z=0,Ae=!1,Yc=[],Va=null,Wa=null,Xa=null,jc=new Map,kc=new Map,Ya=[],Bj="mousedown mouseup touchcancel touchend touchstart auxclick dblclick pointercancel pointerdown pointerup dragend dragstart drop compositionend compositionstart keydown keypress keyup input textInput copy cut paste click change contextmenu reset submit".split(" "),
|
||||
Gb=Sa.ReactCurrentBatchConfig,Zc=!0,$c=null,Za=null,Ee=null,bd=null,Yb={eventPhase:0,bubbles:0,cancelable:0,timeStamp:function(a){return a.timeStamp||Date.now()},defaultPrevented:0,isTrusted:0},He=ka(Yb),Mc=E({},Yb,{view:0,detail:0}),ak=ka(Mc),ag,bg,Nc,Yd=E({},Mc,{screenX:0,screenY:0,clientX:0,clientY:0,pageX:0,pageY:0,ctrlKey:0,shiftKey:0,altKey:0,metaKey:0,getModifierState:Fe,button:0,buttons:0,relatedTarget:function(a){return void 0===a.relatedTarget?a.fromElement===a.srcElement?a.toElement:a.fromElement:
|
||||
a.relatedTarget},movementX:function(a){if("movementX"in a)return a.movementX;a!==Nc&&(Nc&&"mousemove"===a.type?(ag=a.screenX-Nc.screenX,bg=a.screenY-Nc.screenY):bg=ag=0,Nc=a);return ag},movementY:function(a){return"movementY"in a?a.movementY:bg}}),ih=ka(Yd),al=E({},Yd,{dataTransfer:0}),Wj=ka(al),bl=E({},Mc,{relatedTarget:0}),Pe=ka(bl),cl=E({},Yb,{animationName:0,elapsedTime:0,pseudoElement:0}),Yj=ka(cl),dl=E({},Yb,{clipboardData:function(a){return"clipboardData"in a?a.clipboardData:window.clipboardData}}),
|
||||
ck=ka(dl),el=E({},Yb,{data:0}),qh=ka(el),fk=qh,fl={Esc:"Escape",Spacebar:" ",Left:"ArrowLeft",Up:"ArrowUp",Right:"ArrowRight",Down:"ArrowDown",Del:"Delete",Win:"OS",Menu:"ContextMenu",Apps:"ContextMenu",Scroll:"ScrollLock",MozPrintableKey:"Unidentified"},gl={8:"Backspace",9:"Tab",12:"Clear",13:"Enter",16:"Shift",17:"Control",18:"Alt",19:"Pause",20:"CapsLock",27:"Escape",32:" ",33:"PageUp",34:"PageDown",35:"End",36:"Home",37:"ArrowLeft",38:"ArrowUp",39:"ArrowRight",40:"ArrowDown",45:"Insert",46:"Delete",
|
||||
112:"F1",113:"F2",114:"F3",115:"F4",116:"F5",117:"F6",118:"F7",119:"F8",120:"F9",121:"F10",122:"F11",123:"F12",144:"NumLock",145:"ScrollLock",224:"Meta"},Gj={Alt:"altKey",Control:"ctrlKey",Meta:"metaKey",Shift:"shiftKey"},hl=E({},Mc,{key:function(a){if(a.key){var b=fl[a.key]||a.key;if("Unidentified"!==b)return b}return"keypress"===a.type?(a=cd(a),13===a?"Enter":String.fromCharCode(a)):"keydown"===a.type||"keyup"===a.type?gl[a.keyCode]||"Unidentified":""},code:0,location:0,ctrlKey:0,shiftKey:0,altKey:0,
|
||||
metaKey:0,repeat:0,locale:0,getModifierState:Fe,charCode:function(a){return"keypress"===a.type?cd(a):0},keyCode:function(a){return"keydown"===a.type||"keyup"===a.type?a.keyCode:0},which:function(a){return"keypress"===a.type?cd(a):"keydown"===a.type||"keyup"===a.type?a.keyCode:0}}),Vj=ka(hl),il=E({},Yd,{pointerId:0,width:0,height:0,pressure:0,tangentialPressure:0,tiltX:0,tiltY:0,twist:0,pointerType:0,isPrimary:0}),nh=ka(il),jl=E({},Mc,{touches:0,targetTouches:0,changedTouches:0,altKey:0,metaKey:0,
|
||||
ctrlKey:0,shiftKey:0,getModifierState:Fe}),Xj=ka(jl),kl=E({},Yb,{propertyName:0,elapsedTime:0,pseudoElement:0}),Zj=ka(kl),ll=E({},Yd,{deltaX:function(a){return"deltaX"in a?a.deltaX:"wheelDeltaX"in a?-a.wheelDeltaX:0},deltaY:function(a){return"deltaY"in a?a.deltaY:"wheelDeltaY"in a?-a.wheelDeltaY:"wheelDelta"in a?-a.wheelDelta:0},deltaZ:0,deltaMode:0}),bk=ka(ll),Hj=[9,13,27,32],Ge=Ia&&"CompositionEvent"in window,Oc=null;Ia&&"documentMode"in document&&(Oc=document.documentMode);var ek=Ia&&"TextEvent"in
|
||||
window&&!Oc,Ug=Ia&&(!Ge||Oc&&8<Oc&&11>=Oc),Tg=String.fromCharCode(32),Sg=!1,Hb=!1,Kj={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},oc=null,pc=null,ph=!1;Ia&&(ph=Lj("input")&&(!document.documentMode||9<document.documentMode));var ua="function"===typeof Object.is?Object.is:Sj,dk=Ia&&"documentMode"in document&&11>=document.documentMode,Jb=null,Ke=null,rc=null,Je=!1,Kb={animationend:gd("Animation","AnimationEnd"),
|
||||
animationiteration:gd("Animation","AnimationIteration"),animationstart:gd("Animation","AnimationStart"),transitionend:gd("Transition","TransitionEnd")},Le={},eh={};Ia&&(eh=document.createElement("div").style,"AnimationEvent"in window||(delete Kb.animationend.animation,delete Kb.animationiteration.animation,delete Kb.animationstart.animation),"TransitionEvent"in window||delete Kb.transitionend.transition);var jh=hd("animationend"),kh=hd("animationiteration"),lh=hd("animationstart"),mh=hd("transitionend"),
|
||||
fh=new Map,Zi="abort auxClick cancel canPlay canPlayThrough click close contextMenu copy cut drag dragEnd dragEnter dragExit dragLeave dragOver dragStart drop durationChange emptied encrypted ended error gotPointerCapture input invalid keyDown keyPress keyUp load loadedData loadedMetadata loadStart lostPointerCapture mouseDown mouseMove mouseOut mouseOver mouseUp paste pause play playing pointerCancel pointerDown pointerMove pointerOut pointerOver pointerUp progress rateChange reset resize seeked seeking stalled submit suspend timeUpdate touchCancel touchEnd touchStart volumeChange scroll toggle touchMove waiting wheel".split(" ");
|
||||
(function(){for(var a=0;a<Zi.length;a++){var b=Zi[a],c=b.toLowerCase();b=b[0].toUpperCase()+b.slice(1);$a(c,"on"+b)}$a(jh,"onAnimationEnd");$a(kh,"onAnimationIteration");$a(lh,"onAnimationStart");$a("dblclick","onDoubleClick");$a("focusin","onFocus");$a("focusout","onBlur");$a(mh,"onTransitionEnd")})();Ab("onMouseEnter",["mouseout","mouseover"]);Ab("onMouseLeave",["mouseout","mouseover"]);Ab("onPointerEnter",["pointerout","pointerover"]);Ab("onPointerLeave",["pointerout","pointerover"]);mb("onChange",
|
||||
"change click focusin focusout input keydown keyup selectionchange".split(" "));mb("onSelect","focusout contextmenu dragend focusin keydown keyup mousedown mouseup selectionchange".split(" "));mb("onBeforeInput",["compositionend","keypress","textInput","paste"]);mb("onCompositionEnd","compositionend focusout keydown keypress keyup mousedown".split(" "));mb("onCompositionStart","compositionstart focusout keydown keypress keyup mousedown".split(" "));mb("onCompositionUpdate","compositionupdate focusout keydown keypress keyup mousedown".split(" "));
|
||||
var Ec="abort canplay canplaythrough durationchange emptied encrypted ended error loadeddata loadedmetadata loadstart pause play playing progress ratechange resize seeked seeking stalled suspend timeupdate volumechange waiting".split(" "),Uj=new Set("cancel close invalid load scroll toggle".split(" ").concat(Ec)),id="_reactListening"+Math.random().toString(36).slice(2),gk=/\r\n?/g,hk=/\u0000|\uFFFD/g,Jf=null,Kf=null,Rf="function"===typeof setTimeout?setTimeout:void 0,Nk="function"===typeof clearTimeout?
|
||||
clearTimeout:void 0,$i="function"===typeof Promise?Promise:void 0,Jk="function"===typeof queueMicrotask?queueMicrotask:"undefined"!==typeof $i?function(a){return $i.resolve(null).then(a).catch(ik)}:Rf,Zb=Math.random().toString(36).slice(2),Da="__reactFiber$"+Zb,uc="__reactProps$"+Zb,Ja="__reactContainer$"+Zb,Me="__reactEvents$"+Zb,Dk="__reactListeners$"+Zb,Ek="__reactHandles$"+Zb,Se=[],Mb=-1,cb={},J=bb(cb),S=bb(!1),pb=cb,La=null,md=!1,Te=!1,Ob=[],Pb=0,od=null,nd=0,na=[],oa=0,rb=null,Ma=1,Na="",la=
|
||||
null,fa=null,D=!1,wa=null,Ik=Sa.ReactCurrentBatchConfig,Vb=Dh(!0),li=Dh(!1),ud=bb(null),td=null,Rb=null,bf=null,tb=null,kk=Oa,gb=!1,wc={},Ea=bb(wc),yc=bb(wc),xc=bb(wc),F=bb(0),kf=[],yd=Sa.ReactCurrentDispatcher,sf=Sa.ReactCurrentBatchConfig,vb=0,C=null,K=null,N=null,Ad=!1,zc=!1,Ac=0,ml=0,zd={readContext:qa,useCallback:V,useContext:V,useEffect:V,useImperativeHandle:V,useInsertionEffect:V,useLayoutEffect:V,useMemo:V,useReducer:V,useRef:V,useState:V,useDebugValue:V,useDeferredValue:V,useTransition:V,
|
||||
useMutableSource:V,useSyncExternalStore:V,useId:V,unstable_isNewReconciler:!1},lk={readContext:qa,useCallback:function(a,b){Fa().memoizedState=[a,void 0===b?null:b];return a},useContext:qa,useEffect:Sh,useImperativeHandle:function(a,b,c){c=null!==c&&void 0!==c?c.concat([a]):null;return Bd(4194308,4,Vh.bind(null,b,a),c)},useLayoutEffect:function(a,b){return Bd(4194308,4,a,b)},useInsertionEffect:function(a,b){return Bd(4,2,a,b)},useMemo:function(a,b){var c=Fa();b=void 0===b?null:b;a=a();c.memoizedState=
|
||||
[a,b];return a},useReducer:function(a,b,c){var d=Fa();b=void 0!==c?c(b):b;d.memoizedState=d.baseState=b;a={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:a,lastRenderedState:b};d.queue=a;a=a.dispatch=qk.bind(null,C,a);return[d.memoizedState,a]},useRef:function(a){var b=Fa();a={current:a};return b.memoizedState=a},useState:Qh,useDebugValue:rf,useDeferredValue:function(a){return Fa().memoizedState=a},useTransition:function(){var a=Qh(!1),b=a[0];a=pk.bind(null,a[1]);Fa().memoizedState=
|
||||
a;return[b,a]},useMutableSource:function(a,b,c){},useSyncExternalStore:function(a,b,c){var d=C,e=Fa();if(D){if(void 0===c)throw Error(m(407));c=c()}else{c=b();if(null===O)throw Error(m(349));0!==(vb&30)||Nh(d,b,c)}e.memoizedState=c;var f={value:c,getSnapshot:b};e.queue=f;Sh(Lh.bind(null,d,f,a),[a]);d.flags|=2048;Cc(9,Mh.bind(null,d,f,c,b),void 0,null);return c},useId:function(){var a=Fa(),b=O.identifierPrefix;if(D){var c=Na;var d=Ma;c=(d&~(1<<32-ta(d)-1)).toString(32)+c;b=":"+b+"R"+c;c=Ac++;0<c&&
|
||||
(b+="H"+c.toString(32));b+=":"}else c=ml++,b=":"+b+"r"+c.toString(32)+":";return a.memoizedState=b},unstable_isNewReconciler:!1},mk={readContext:qa,useCallback:Xh,useContext:qa,useEffect:qf,useImperativeHandle:Wh,useInsertionEffect:Th,useLayoutEffect:Uh,useMemo:Yh,useReducer:of,useRef:Rh,useState:function(a){return of(Bc)},useDebugValue:rf,useDeferredValue:function(a){var b=sa();return Zh(b,K.memoizedState,a)},useTransition:function(){var a=of(Bc)[0],b=sa().memoizedState;return[a,b]},useMutableSource:Jh,
|
||||
useSyncExternalStore:Kh,useId:$h,unstable_isNewReconciler:!1},nk={readContext:qa,useCallback:Xh,useContext:qa,useEffect:qf,useImperativeHandle:Wh,useInsertionEffect:Th,useLayoutEffect:Uh,useMemo:Yh,useReducer:pf,useRef:Rh,useState:function(a){return pf(Bc)},useDebugValue:rf,useDeferredValue:function(a){var b=sa();return null===K?b.memoizedState=a:Zh(b,K.memoizedState,a)},useTransition:function(){var a=pf(Bc)[0],b=sa().memoizedState;return[a,b]},useMutableSource:Jh,useSyncExternalStore:Kh,useId:$h,
|
||||
unstable_isNewReconciler:!1},Dd={isMounted:function(a){return(a=a._reactInternals)?nb(a)===a:!1},enqueueSetState:function(a,b,c){a=a._reactInternals;var d=Z(),e=hb(a),f=Pa(d,e);f.payload=b;void 0!==c&&null!==c&&(f.callback=c);b=fb(a,f,e);null!==b&&(xa(b,a,e,d),vd(b,a,e))},enqueueReplaceState:function(a,b,c){a=a._reactInternals;var d=Z(),e=hb(a),f=Pa(d,e);f.tag=1;f.payload=b;void 0!==c&&null!==c&&(f.callback=c);b=fb(a,f,e);null!==b&&(xa(b,a,e,d),vd(b,a,e))},enqueueForceUpdate:function(a,b){a=a._reactInternals;
|
||||
var c=Z(),d=hb(a),e=Pa(c,d);e.tag=2;void 0!==b&&null!==b&&(e.callback=b);b=fb(a,e,d);null!==b&&(xa(b,a,d,c),vd(b,a,d))}},rk="function"===typeof WeakMap?WeakMap:Map,tk=Sa.ReactCurrentOwner,ha=!1,Cf={dehydrated:null,treeContext:null,retryLane:0};var zk=function(a,b,c,d){for(c=b.child;null!==c;){if(5===c.tag||6===c.tag)a.appendChild(c.stateNode);else if(4!==c.tag&&null!==c.child){c.child.return=c;c=c.child;continue}if(c===b)break;for(;null===c.sibling;){if(null===c.return||c.return===b)return;c=c.return}c.sibling.return=
|
||||
c.return;c=c.sibling}};var xi=function(a,b){};var yk=function(a,b,c,d,e){var f=a.memoizedProps;if(f!==d){a=b.stateNode;ub(Ea.current);e=null;switch(c){case "input":f=ke(a,f);d=ke(a,d);e=[];break;case "select":f=E({},f,{value:void 0});d=E({},d,{value:void 0});e=[];break;case "textarea":f=ne(a,f);d=ne(a,d);e=[];break;default:"function"!==typeof f.onClick&&"function"===typeof d.onClick&&(a.onclick=kd)}pe(c,d);var g;c=null;for(l in f)if(!d.hasOwnProperty(l)&&f.hasOwnProperty(l)&&null!=f[l])if("style"===
|
||||
l){var h=f[l];for(g in h)h.hasOwnProperty(g)&&(c||(c={}),c[g]="")}else"dangerouslySetInnerHTML"!==l&&"children"!==l&&"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&"autoFocus"!==l&&($b.hasOwnProperty(l)?e||(e=[]):(e=e||[]).push(l,null));for(l in d){var k=d[l];h=null!=f?f[l]:void 0;if(d.hasOwnProperty(l)&&k!==h&&(null!=k||null!=h))if("style"===l)if(h){for(g in h)!h.hasOwnProperty(g)||k&&k.hasOwnProperty(g)||(c||(c={}),c[g]="");for(g in k)k.hasOwnProperty(g)&&h[g]!==k[g]&&(c||
|
||||
(c={}),c[g]=k[g])}else c||(e||(e=[]),e.push(l,c)),c=k;else"dangerouslySetInnerHTML"===l?(k=k?k.__html:void 0,h=h?h.__html:void 0,null!=k&&h!==k&&(e=e||[]).push(l,k)):"children"===l?"string"!==typeof k&&"number"!==typeof k||(e=e||[]).push(l,""+k):"suppressContentEditableWarning"!==l&&"suppressHydrationWarning"!==l&&($b.hasOwnProperty(l)?(null!=k&&"onScroll"===l&&B("scroll",a),e||h===k||(e=[])):(e=e||[]).push(l,k))}c&&(e=e||[]).push("style",c);var l=e;if(b.updateQueue=l)b.flags|=4}};var Ak=function(a,
|
||||
b,c,d){c!==d&&(b.flags|=4)};var Jd=!1,X=!1,Fk="function"===typeof WeakSet?WeakSet:Set,l=null,zi=!1,T=null,za=!1,Mk=Math.ceil,Od=Sa.ReactCurrentDispatcher,Uf=Sa.ReactCurrentOwner,ca=Sa.ReactCurrentBatchConfig,p=0,O=null,H=null,U=0,ba=0,Ga=bb(0),L=0,Jc=null,ra=0,Md=0,Sf=0,Kc=null,ja=null,Of=0,Hf=Infinity,Ra=null,Ed=!1,xf=null,ib=null,Pd=!1,lb=null,Qd=0,Ic=0,Pf=null,Kd=-1,Ld=0;var Qk=function(a,b,c){if(null!==a)if(a.memoizedProps!==b.pendingProps||S.current)ha=!0;else{if(0===(a.lanes&c)&&0===(b.flags&
|
||||
128))return ha=!1,wk(a,b,c);ha=0!==(a.flags&131072)?!0:!1}else ha=!1,D&&0!==(b.flags&1048576)&&yh(b,nd,b.index);b.lanes=0;switch(b.tag){case 2:var d=b.type;Fd(a,b);a=b.pendingProps;var e=Nb(b,J.current);Sb(b,c);e=mf(null,b,d,a,e,c);var f=nf();b.flags|=1;"object"===typeof e&&null!==e&&"function"===typeof e.render&&void 0===e.$$typeof?(b.tag=1,b.memoizedState=null,b.updateQueue=null,ea(d)?(f=!0,ld(b)):f=!1,b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null,ff(b),e.updater=Dd,b.stateNode=
|
||||
e,e._reactInternals=b,uf(b,d,a,c),b=Af(null,b,d,!0,f,c)):(b.tag=0,D&&f&&Ue(b),aa(null,b,e,c),b=b.child);return b;case 16:d=b.elementType;a:{Fd(a,b);a=b.pendingProps;e=d._init;d=e(d._payload);b.type=d;e=b.tag=Uk(d);a=ya(d,a);switch(e){case 0:b=zf(null,b,d,a,c);break a;case 1:b=ri(null,b,d,a,c);break a;case 11:b=mi(null,b,d,a,c);break a;case 14:b=ni(null,b,d,ya(d.type,a),c);break a}throw Error(m(306,d,""));}return b;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),zf(a,b,d,e,c);
|
||||
case 1:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),ri(a,b,d,e,c);case 3:a:{si(b);if(null===a)throw Error(m(387));d=b.pendingProps;f=b.memoizedState;e=f.element;Fh(a,b);wd(b,d,null,c);var g=b.memoizedState;d=g.element;if(f.isDehydrated)if(f={element:d,isDehydrated:!1,cache:g.cache,pendingSuspenseBoundaries:g.pendingSuspenseBoundaries,transitions:g.transitions},b.updateQueue.baseState=f,b.memoizedState=f,b.flags&256){e=Ub(Error(m(423)),b);b=ti(a,b,d,c,e);break a}else if(d!==e){e=
|
||||
Ub(Error(m(424)),b);b=ti(a,b,d,c,e);break a}else for(fa=Ka(b.stateNode.containerInfo.firstChild),la=b,D=!0,wa=null,c=li(b,null,d,c),b.child=c;c;)c.flags=c.flags&-3|4096,c=c.sibling;else{Qb();if(d===e){b=Qa(a,b,c);break a}aa(a,b,d,c)}b=b.child}return b;case 5:return Ih(b),null===a&&Xe(b),d=b.type,e=b.pendingProps,f=null!==a?a.memoizedProps:null,g=e.children,Qe(d,e)?g=null:null!==f&&Qe(d,f)&&(b.flags|=32),qi(a,b),aa(a,b,g,c),b.child;case 6:return null===a&&Xe(b),null;case 13:return ui(a,b,c);case 4:return gf(b,
|
||||
b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=Vb(b,null,d,c):aa(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),mi(a,b,d,e,c);case 7:return aa(a,b,b.pendingProps,c),b.child;case 8:return aa(a,b,b.pendingProps.children,c),b.child;case 12:return aa(a,b,b.pendingProps.children,c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;f=b.memoizedProps;g=e.value;y(ud,d._currentValue);d._currentValue=g;if(null!==f)if(ua(f.value,g)){if(f.children===
|
||||
e.children&&!S.current){b=Qa(a,b,c);break a}}else for(f=b.child,null!==f&&(f.return=b);null!==f;){var h=f.dependencies;if(null!==h){g=f.child;for(var k=h.firstContext;null!==k;){if(k.context===d){if(1===f.tag){k=Pa(-1,c&-c);k.tag=2;var l=f.updateQueue;if(null!==l){l=l.shared;var p=l.pending;null===p?k.next=k:(k.next=p.next,p.next=k);l.pending=k}}f.lanes|=c;k=f.alternate;null!==k&&(k.lanes|=c);df(f.return,c,b);h.lanes|=c;break}k=k.next}}else if(10===f.tag)g=f.type===b.type?null:f.child;else if(18===
|
||||
f.tag){g=f.return;if(null===g)throw Error(m(341));g.lanes|=c;h=g.alternate;null!==h&&(h.lanes|=c);df(g,c,b);g=f.sibling}else g=f.child;if(null!==g)g.return=f;else for(g=f;null!==g;){if(g===b){g=null;break}f=g.sibling;if(null!==f){f.return=g.return;g=f;break}g=g.return}f=g}aa(a,b,e.children,c);b=b.child}return b;case 9:return e=b.type,d=b.pendingProps.children,Sb(b,c),e=qa(e),d=d(e),b.flags|=1,aa(a,b,d,c),b.child;case 14:return d=b.type,e=ya(d,b.pendingProps),e=ya(d.type,e),ni(a,b,d,e,c);case 15:return oi(a,
|
||||
b,b.type,b.pendingProps,c);case 17:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:ya(d,e),Fd(a,b),b.tag=1,ea(d)?(a=!0,ld(b)):a=!1,Sb(b,c),ei(b,d,e),uf(b,d,e,c),Af(null,b,d,!0,a,c);case 19:return wi(a,b,c);case 22:return pi(a,b,c)}throw Error(m(156,b.tag));};var pa=function(a,b,c,d){return new Tk(a,b,c,d)},aj="function"===typeof reportError?reportError:function(a){console.error(a)};Ud.prototype.render=Xf.prototype.render=function(a){var b=this._internalRoot;if(null===b)throw Error(m(409));
|
||||
Sd(a,b,null,null)};Ud.prototype.unmount=Xf.prototype.unmount=function(){var a=this._internalRoot;if(null!==a){this._internalRoot=null;var b=a.containerInfo;yb(function(){Sd(null,a,null,null)});b[Ja]=null}};Ud.prototype.unstable_scheduleHydration=function(a){if(a){var b=nl();a={blockedOn:null,target:a,priority:b};for(var c=0;c<Ya.length&&0!==b&&b<Ya[c].priority;c++);Ya.splice(c,0,a);0===c&&Hg(a)}};var Cj=function(a){switch(a.tag){case 3:var b=a.stateNode;if(b.current.memoizedState.isDehydrated){var c=
|
||||
hc(b.pendingLanes);0!==c&&(xe(b,c|1),ia(b,P()),0===(p&6)&&(Hc(),db()))}break;case 13:yb(function(){var b=Oa(a,1);if(null!==b){var c=Z();xa(b,a,1,c)}}),Wf(a,1)}};var Gg=function(a){if(13===a.tag){var b=Oa(a,134217728);if(null!==b){var c=Z();xa(b,a,134217728,c)}Wf(a,134217728)}};var xj=function(a){if(13===a.tag){var b=hb(a),c=Oa(a,b);if(null!==c){var d=Z();xa(c,a,b,d)}Wf(a,b)}};var nl=function(){return z};var wj=function(a,b){var c=z;try{return z=a,b()}finally{z=c}};se=function(a,b,c){switch(b){case "input":le(a,
|
||||
c);b=c.name;if("radio"===c.type&&null!=b){for(c=a;c.parentNode;)c=c.parentNode;c=c.querySelectorAll("input[name="+JSON.stringify(""+b)+'][type="radio"]');for(b=0;b<c.length;b++){var d=c[b];if(d!==a&&d.form===a.form){var e=Rc(d);if(!e)throw Error(m(90));jg(d);le(d,e)}}}break;case "textarea":og(a,c);break;case "select":b=c.value,null!=b&&Db(a,!!c.multiple,b,!1)}};(function(a,b,c){xg=a;yg=c})(Tf,function(a,b,c,d,e){var f=z,g=ca.transition;try{return ca.transition=null,z=1,a(b,c,d,e)}finally{z=f,ca.transition=
|
||||
g,0===p&&Hc()}},yb);var ol={usingClientEntryPoint:!1,Events:[ec,Ib,Rc,ug,vg,Tf]};(function(a){a={bundleType:a.bundleType,version:a.version,rendererPackageName:a.rendererPackageName,rendererConfig:a.rendererConfig,overrideHookState:null,overrideHookStateDeletePath:null,overrideHookStateRenamePath:null,overrideProps:null,overridePropsDeletePath:null,overridePropsRenamePath:null,setErrorHandler:null,setSuspenseHandler:null,scheduleUpdate:null,currentDispatcherRef:Sa.ReactCurrentDispatcher,findHostInstanceByFiber:Xk,
|
||||
findFiberByHostInstance:a.findFiberByHostInstance||Yk,findHostInstancesForRefresh:null,scheduleRefresh:null,scheduleRoot:null,setRefreshHandler:null,getCurrentFiber:null,reconcilerVersion:"18.3.1"};if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)a=!1;else{var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)a=!0;else{try{Uc=b.inject(a),Ca=b}catch(c){}a=b.checkDCE?!0:!1}}return a})({findFiberByHostInstance:ob,bundleType:0,version:"18.3.1-next-f1338f8080-20240426",
|
||||
rendererPackageName:"react-dom"});Q.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=ol;Q.createPortal=function(a,b){var c=2<arguments.length&&void 0!==arguments[2]?arguments[2]:null;if(!Yf(b))throw Error(m(200));return Wk(a,b,null,c)};Q.createRoot=function(a,b){if(!Yf(a))throw Error(m(299));var c=!1,d="",e=aj;null!==b&&void 0!==b&&(!0===b.unstable_strictMode&&(c=!0),void 0!==b.identifierPrefix&&(d=b.identifierPrefix),void 0!==b.onRecoverableError&&(e=b.onRecoverableError));b=Vf(a,1,!1,null,null,
|
||||
c,!1,d,e);a[Ja]=b.current;sc(8===a.nodeType?a.parentNode:a);return new Xf(b)};Q.findDOMNode=function(a){if(null==a)return null;if(1===a.nodeType)return a;var b=a._reactInternals;if(void 0===b){if("function"===typeof a.render)throw Error(m(188));a=Object.keys(a).join(",");throw Error(m(268,a));}a=Bg(b);a=null===a?null:a.stateNode;return a};Q.flushSync=function(a){return yb(a)};Q.hydrate=function(a,b,c){if(!Vd(b))throw Error(m(200));return Wd(null,a,b,!0,c)};Q.hydrateRoot=function(a,b,c){if(!Yf(a))throw Error(m(405));
|
||||
var d=null!=c&&c.hydratedSources||null,e=!1,f="",g=aj;null!==c&&void 0!==c&&(!0===c.unstable_strictMode&&(e=!0),void 0!==c.identifierPrefix&&(f=c.identifierPrefix),void 0!==c.onRecoverableError&&(g=c.onRecoverableError));b=Wi(b,null,a,1,null!=c?c:null,e,!1,f,g);a[Ja]=b.current;sc(a);if(d)for(a=0;a<d.length;a++)c=d[a],e=c._getVersion,e=e(c._source),null==b.mutableSourceEagerHydrationData?b.mutableSourceEagerHydrationData=[c,e]:b.mutableSourceEagerHydrationData.push(c,e);return new Ud(b)};Q.render=
|
||||
function(a,b,c){if(!Vd(b))throw Error(m(200));return Wd(null,a,b,!1,c)};Q.unmountComponentAtNode=function(a){if(!Vd(a))throw Error(m(40));return a._reactRootContainer?(yb(function(){Wd(null,null,a,!1,function(){a._reactRootContainer=null;a[Ja]=null})}),!0):!1};Q.unstable_batchedUpdates=Tf;Q.unstable_renderSubtreeIntoContainer=function(a,b,c,d){if(!Vd(c))throw Error(m(200));if(null==a||void 0===a._reactInternals)throw Error(m(38));return Wd(a,b,c,!1,d)};Q.version="18.3.1-next-f1338f8080-20240426"});
|
||||
})();
|
||||
31
libs/react/react.production.min.js
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
(function(){'use strict';(function(c,x){"object"===typeof exports&&"undefined"!==typeof module?x(exports):"function"===typeof define&&define.amd?define(["exports"],x):(c=c||self,x(c.React={}))})(this,function(c){function x(a){if(null===a||"object"!==typeof a)return null;a=V&&a[V]||a["@@iterator"];return"function"===typeof a?a:null}function w(a,b,e){this.props=a;this.context=b;this.refs=W;this.updater=e||X}function Y(){}function K(a,b,e){this.props=a;this.context=b;this.refs=W;this.updater=e||X}function Z(a,b,
|
||||
e){var m,d={},c=null,h=null;if(null!=b)for(m in void 0!==b.ref&&(h=b.ref),void 0!==b.key&&(c=""+b.key),b)aa.call(b,m)&&!ba.hasOwnProperty(m)&&(d[m]=b[m]);var l=arguments.length-2;if(1===l)d.children=e;else if(1<l){for(var f=Array(l),k=0;k<l;k++)f[k]=arguments[k+2];d.children=f}if(a&&a.defaultProps)for(m in l=a.defaultProps,l)void 0===d[m]&&(d[m]=l[m]);return{$$typeof:y,type:a,key:c,ref:h,props:d,_owner:L.current}}function oa(a,b){return{$$typeof:y,type:a.type,key:b,ref:a.ref,props:a.props,_owner:a._owner}}
|
||||
function M(a){return"object"===typeof a&&null!==a&&a.$$typeof===y}function pa(a){var b={"=":"=0",":":"=2"};return"$"+a.replace(/[=:]/g,function(a){return b[a]})}function N(a,b){return"object"===typeof a&&null!==a&&null!=a.key?pa(""+a.key):b.toString(36)}function B(a,b,e,m,d){var c=typeof a;if("undefined"===c||"boolean"===c)a=null;var h=!1;if(null===a)h=!0;else switch(c){case "string":case "number":h=!0;break;case "object":switch(a.$$typeof){case y:case qa:h=!0}}if(h)return h=a,d=d(h),a=""===m?"."+
|
||||
N(h,0):m,ca(d)?(e="",null!=a&&(e=a.replace(da,"$&/")+"/"),B(d,b,e,"",function(a){return a})):null!=d&&(M(d)&&(d=oa(d,e+(!d.key||h&&h.key===d.key?"":(""+d.key).replace(da,"$&/")+"/")+a)),b.push(d)),1;h=0;m=""===m?".":m+":";if(ca(a))for(var l=0;l<a.length;l++){c=a[l];var f=m+N(c,l);h+=B(c,b,e,f,d)}else if(f=x(a),"function"===typeof f)for(a=f.call(a),l=0;!(c=a.next()).done;)c=c.value,f=m+N(c,l++),h+=B(c,b,e,f,d);else if("object"===c)throw b=String(a),Error("Objects are not valid as a React child (found: "+
|
||||
("[object Object]"===b?"object with keys {"+Object.keys(a).join(", ")+"}":b)+"). If you meant to render a collection of children, use an array instead.");return h}function C(a,b,e){if(null==a)return a;var c=[],d=0;B(a,c,"","",function(a){return b.call(e,a,d++)});return c}function ra(a){if(-1===a._status){var b=a._result;b=b();b.then(function(b){if(0===a._status||-1===a._status)a._status=1,a._result=b},function(b){if(0===a._status||-1===a._status)a._status=2,a._result=b});-1===a._status&&(a._status=
|
||||
0,a._result=b)}if(1===a._status)return a._result.default;throw a._result;}function O(a,b){var e=a.length;a.push(b);a:for(;0<e;){var c=e-1>>>1,d=a[c];if(0<D(d,b))a[c]=b,a[e]=d,e=c;else break a}}function p(a){return 0===a.length?null:a[0]}function E(a){if(0===a.length)return null;var b=a[0],e=a.pop();if(e!==b){a[0]=e;a:for(var c=0,d=a.length,k=d>>>1;c<k;){var h=2*(c+1)-1,l=a[h],f=h+1,g=a[f];if(0>D(l,e))f<d&&0>D(g,l)?(a[c]=g,a[f]=e,c=f):(a[c]=l,a[h]=e,c=h);else if(f<d&&0>D(g,e))a[c]=g,a[f]=e,c=f;else break a}}return b}
|
||||
function D(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}function P(a){for(var b=p(r);null!==b;){if(null===b.callback)E(r);else if(b.startTime<=a)E(r),b.sortIndex=b.expirationTime,O(q,b);else break;b=p(r)}}function Q(a){z=!1;P(a);if(!u)if(null!==p(q))u=!0,R(S);else{var b=p(r);null!==b&&T(Q,b.startTime-a)}}function S(a,b){u=!1;z&&(z=!1,ea(A),A=-1);F=!0;var c=k;try{P(b);for(n=p(q);null!==n&&(!(n.expirationTime>b)||a&&!fa());){var m=n.callback;if("function"===typeof m){n.callback=null;
|
||||
k=n.priorityLevel;var d=m(n.expirationTime<=b);b=v();"function"===typeof d?n.callback=d:n===p(q)&&E(q);P(b)}else E(q);n=p(q)}if(null!==n)var g=!0;else{var h=p(r);null!==h&&T(Q,h.startTime-b);g=!1}return g}finally{n=null,k=c,F=!1}}function fa(){return v()-ha<ia?!1:!0}function R(a){G=a;H||(H=!0,I())}function T(a,b){A=ja(function(){a(v())},b)}function ka(a){throw Error("act(...) is not supported in production builds of React.");}var y=Symbol.for("react.element"),qa=Symbol.for("react.portal"),sa=Symbol.for("react.fragment"),
|
||||
ta=Symbol.for("react.strict_mode"),ua=Symbol.for("react.profiler"),va=Symbol.for("react.provider"),wa=Symbol.for("react.context"),xa=Symbol.for("react.forward_ref"),ya=Symbol.for("react.suspense"),za=Symbol.for("react.memo"),Aa=Symbol.for("react.lazy"),V=Symbol.iterator,X={isMounted:function(a){return!1},enqueueForceUpdate:function(a,b,c){},enqueueReplaceState:function(a,b,c,m){},enqueueSetState:function(a,b,c,m){}},la=Object.assign,W={};w.prototype.isReactComponent={};w.prototype.setState=function(a,
|
||||
b){if("object"!==typeof a&&"function"!==typeof a&&null!=a)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,a,b,"setState")};w.prototype.forceUpdate=function(a){this.updater.enqueueForceUpdate(this,a,"forceUpdate")};Y.prototype=w.prototype;var t=K.prototype=new Y;t.constructor=K;la(t,w.prototype);t.isPureReactComponent=!0;var ca=Array.isArray,aa=Object.prototype.hasOwnProperty,L={current:null},
|
||||
ba={key:!0,ref:!0,__self:!0,__source:!0},da=/\/+/g,g={current:null},J={transition:null};if("object"===typeof performance&&"function"===typeof performance.now){var Ba=performance;var v=function(){return Ba.now()}}else{var ma=Date,Ca=ma.now();v=function(){return ma.now()-Ca}}var q=[],r=[],Da=1,n=null,k=3,F=!1,u=!1,z=!1,ja="function"===typeof setTimeout?setTimeout:null,ea="function"===typeof clearTimeout?clearTimeout:null,na="undefined"!==typeof setImmediate?setImmediate:null;"undefined"!==typeof navigator&&
|
||||
void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);var H=!1,G=null,A=-1,ia=5,ha=-1,U=function(){if(null!==G){var a=v();ha=a;var b=!0;try{b=G(!0,a)}finally{b?I():(H=!1,G=null)}}else H=!1};if("function"===typeof na)var I=function(){na(U)};else if("undefined"!==typeof MessageChannel){t=new MessageChannel;var Ea=t.port2;t.port1.onmessage=U;I=function(){Ea.postMessage(null)}}else I=function(){ja(U,0)};t={ReactCurrentDispatcher:g,
|
||||
ReactCurrentOwner:L,ReactCurrentBatchConfig:J,Scheduler:{__proto__:null,unstable_ImmediatePriority:1,unstable_UserBlockingPriority:2,unstable_NormalPriority:3,unstable_IdlePriority:5,unstable_LowPriority:4,unstable_runWithPriority:function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3}var c=k;k=a;try{return b()}finally{k=c}},unstable_next:function(a){switch(k){case 1:case 2:case 3:var b=3;break;default:b=k}var c=k;k=b;try{return a()}finally{k=c}},unstable_scheduleCallback:function(a,
|
||||
b,c){var e=v();"object"===typeof c&&null!==c?(c=c.delay,c="number"===typeof c&&0<c?e+c:e):c=e;switch(a){case 1:var d=-1;break;case 2:d=250;break;case 5:d=1073741823;break;case 4:d=1E4;break;default:d=5E3}d=c+d;a={id:Da++,callback:b,priorityLevel:a,startTime:c,expirationTime:d,sortIndex:-1};c>e?(a.sortIndex=c,O(r,a),null===p(q)&&a===p(r)&&(z?(ea(A),A=-1):z=!0,T(Q,c-e))):(a.sortIndex=d,O(q,a),u||F||(u=!0,R(S)));return a},unstable_cancelCallback:function(a){a.callback=null},unstable_wrapCallback:function(a){var b=
|
||||
k;return function(){var c=k;k=b;try{return a.apply(this,arguments)}finally{k=c}}},unstable_getCurrentPriorityLevel:function(){return k},unstable_shouldYield:fa,unstable_requestPaint:function(){},unstable_continueExecution:function(){u||F||(u=!0,R(S))},unstable_pauseExecution:function(){},unstable_getFirstCallbackNode:function(){return p(q)},get unstable_now(){return v},unstable_forceFrameRate:function(a){0>a||125<a?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):
|
||||
ia=0<a?Math.floor(1E3/a):5},unstable_Profiling:null}};c.Children={map:C,forEach:function(a,b,c){C(a,function(){b.apply(this,arguments)},c)},count:function(a){var b=0;C(a,function(){b++});return b},toArray:function(a){return C(a,function(a){return a})||[]},only:function(a){if(!M(a))throw Error("React.Children.only expected to receive a single React element child.");return a}};c.Component=w;c.Fragment=sa;c.Profiler=ua;c.PureComponent=K;c.StrictMode=ta;c.Suspense=ya;c.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=
|
||||
t;c.act=ka;c.cloneElement=function(a,b,c){if(null===a||void 0===a)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+a+".");var e=la({},a.props),d=a.key,k=a.ref,h=a._owner;if(null!=b){void 0!==b.ref&&(k=b.ref,h=L.current);void 0!==b.key&&(d=""+b.key);if(a.type&&a.type.defaultProps)var l=a.type.defaultProps;for(f in b)aa.call(b,f)&&!ba.hasOwnProperty(f)&&(e[f]=void 0===b[f]&&void 0!==l?l[f]:b[f])}var f=arguments.length-2;if(1===f)e.children=c;else if(1<f){l=
|
||||
Array(f);for(var g=0;g<f;g++)l[g]=arguments[g+2];e.children=l}return{$$typeof:y,type:a.type,key:d,ref:k,props:e,_owner:h}};c.createContext=function(a){a={$$typeof:wa,_currentValue:a,_currentValue2:a,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null};a.Provider={$$typeof:va,_context:a};return a.Consumer=a};c.createElement=Z;c.createFactory=function(a){var b=Z.bind(null,a);b.type=a;return b};c.createRef=function(){return{current:null}};c.forwardRef=function(a){return{$$typeof:xa,
|
||||
render:a}};c.isValidElement=M;c.lazy=function(a){return{$$typeof:Aa,_payload:{_status:-1,_result:a},_init:ra}};c.memo=function(a,b){return{$$typeof:za,type:a,compare:void 0===b?null:b}};c.startTransition=function(a,b){b=J.transition;J.transition={};try{a()}finally{J.transition=b}};c.unstable_act=ka;c.useCallback=function(a,b){return g.current.useCallback(a,b)};c.useContext=function(a){return g.current.useContext(a)};c.useDebugValue=function(a,b){};c.useDeferredValue=function(a){return g.current.useDeferredValue(a)};
|
||||
c.useEffect=function(a,b){return g.current.useEffect(a,b)};c.useId=function(){return g.current.useId()};c.useImperativeHandle=function(a,b,c){return g.current.useImperativeHandle(a,b,c)};c.useInsertionEffect=function(a,b){return g.current.useInsertionEffect(a,b)};c.useLayoutEffect=function(a,b){return g.current.useLayoutEffect(a,b)};c.useMemo=function(a,b){return g.current.useMemo(a,b)};c.useReducer=function(a,b,c){return g.current.useReducer(a,b,c)};c.useRef=function(a){return g.current.useRef(a)};
|
||||
c.useState=function(a){return g.current.useState(a)};c.useSyncExternalStore=function(a,b,c){return g.current.useSyncExternalStore(a,b,c)};c.useTransition=function(){return g.current.useTransition()};c.version="18.3.1"});
|
||||
})();
|
||||
83
libs/tailwind/tailwind.js
Normal file
BIN
logo/favicon.ico
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
logo/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
logo/icon-144x144.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
logo/icon-152x152.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
logo/icon-16x16.png
Normal file
|
After Width: | Height: | Size: 810 B |
BIN
logo/icon-180x180.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
logo/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 4.5 KiB |
BIN
logo/icon-256x256.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
logo/icon-384x384.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
logo/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
logo/icon-72x72.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
logo/icon-96x96.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
2203
package-lock.json
generated
Normal file
37
package.json
Normal file
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "securebit-chat",
|
||||
"version": "1.2.14",
|
||||
"description": "Secure P2P Communication Application with End-to-End Encryption",
|
||||
"main": "index.html",
|
||||
"scripts": {
|
||||
"build": "npm run build:css && npm run build:js",
|
||||
"build:css": "npx tailwindcss -i src/styles/tw-input.css -o assets/tailwind.css --minify --content \"./index.html,./src/**/*.jsx,./src/**/*.js\"",
|
||||
"build:js": "npx esbuild src/app.jsx --bundle --format=esm --outfile=dist/app.js --sourcemap && npx esbuild src/scripts/app-boot.js --bundle --format=esm --outfile=dist/app-boot.js --sourcemap && npx esbuild src/scripts/qr-local.js --bundle --format=esm --outfile=dist/qr-local.js --sourcemap",
|
||||
"dev": "npm run build && python -m http.server 8000",
|
||||
"watch": "npx tailwindcss -i src/styles/tw-input.css -o assets/tailwind.css --watch",
|
||||
"serve": "npx http-server -p 8000",
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [
|
||||
"p2p",
|
||||
"chat",
|
||||
"encryption",
|
||||
"webrtc",
|
||||
"privacy",
|
||||
"security"
|
||||
],
|
||||
"author": "SecureBit Team",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.25.9",
|
||||
"tailwindcss": "^3.4.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"base64-js": "^1.5.1",
|
||||
"cbor-js": "^0.1.0",
|
||||
"html5-qrcode": "^2.3.8",
|
||||
"pako": "^2.1.0",
|
||||
"qr-scanner": "^1.4.2",
|
||||
"qrcode": "^1.5.4"
|
||||
}
|
||||
}
|
||||
3636
src/app.jsx
Normal file
492
src/components/QRScanner.js
Normal file
@@ -0,0 +1,492 @@
|
||||
// Simple QR Scanner Component using only Html5Qrcode
|
||||
const QRScanner = ({ onScan, onClose, isVisible, continuous = false }) => {
|
||||
const videoRef = React.useRef(null);
|
||||
const qrScannerRef = React.useRef(null);
|
||||
const [error, setError] = React.useState(null);
|
||||
const [isScanning, setIsScanning] = React.useState(false);
|
||||
const [progress, setProgress] = React.useState({ id: null, seq: 0, total: 0 });
|
||||
const [showFocusHint, setShowFocusHint] = React.useState(false);
|
||||
const [manualMode, setManualMode] = React.useState(false);
|
||||
const [scannedParts, setScannedParts] = React.useState(new Set());
|
||||
const [currentQRId, setCurrentQRId] = React.useState(null);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (isVisible) {
|
||||
startScanner();
|
||||
} else {
|
||||
stopScanner();
|
||||
}
|
||||
|
||||
return () => {
|
||||
stopScanner();
|
||||
};
|
||||
}, [isVisible]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const onProgress = (e) => {
|
||||
const { id, seq, total } = e.detail || {};
|
||||
if (!id || !total) return;
|
||||
setProgress({ id, seq, total });
|
||||
|
||||
// Обновляем ID текущего QR кода
|
||||
if (id !== currentQRId) {
|
||||
setCurrentQRId(id);
|
||||
setScannedParts(new Set()); // Сбрасываем сканированные части для нового ID
|
||||
}
|
||||
|
||||
// Добавляем отсканированную часть
|
||||
setScannedParts(prev => new Set([...prev, seq]));
|
||||
};
|
||||
const onComplete = () => {
|
||||
// Close scanner once app signals completion
|
||||
if (!continuous) return;
|
||||
try { stopScanner(); } catch {}
|
||||
};
|
||||
document.addEventListener('qr-scan-progress', onProgress, { passive: true });
|
||||
document.addEventListener('qr-scan-complete', onComplete, { passive: true });
|
||||
return () => {
|
||||
document.removeEventListener('qr-scan-progress', onProgress, { passive: true });
|
||||
document.removeEventListener('qr-scan-complete', onComplete, { passive: true });
|
||||
};
|
||||
}, [currentQRId]);
|
||||
|
||||
// Функция для tap-to-focus
|
||||
const handleTapToFocus = (event, html5Qrcode) => {
|
||||
try {
|
||||
// Показываем подсказку о фокусировке
|
||||
setShowFocusHint(true);
|
||||
setTimeout(() => setShowFocusHint(false), 2000);
|
||||
|
||||
// Получаем координаты клика относительно видео элемента
|
||||
const rect = event.target.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left;
|
||||
const y = event.clientY - rect.top;
|
||||
|
||||
// Нормализуем координаты (0-1)
|
||||
const normalizedX = x / rect.width;
|
||||
const normalizedY = y / rect.height;
|
||||
|
||||
console.log('Tap to focus at:', { x, y, normalizedX, normalizedY });
|
||||
|
||||
// Попытка программной фокусировки (если поддерживается браузером)
|
||||
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
// Это может не работать во всех браузерах, но попробуем
|
||||
console.log('Attempting programmatic focus...');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.warn('Tap to focus error:', error);
|
||||
}
|
||||
};
|
||||
|
||||
// Функции для ручного управления
|
||||
const toggleManualMode = () => {
|
||||
setManualMode(!manualMode);
|
||||
if (!manualMode) {
|
||||
// При включении ручного режима останавливаем автопрокрутку
|
||||
console.log('Manual mode enabled - auto-scroll disabled');
|
||||
} else {
|
||||
// При выключении ручного режима возобновляем автопрокрутку
|
||||
console.log('Manual mode disabled - auto-scroll enabled');
|
||||
}
|
||||
};
|
||||
|
||||
const resetProgress = () => {
|
||||
setScannedParts(new Set());
|
||||
setCurrentQRId(null);
|
||||
setProgress({ id: null, seq: 0, total: 0 });
|
||||
};
|
||||
|
||||
const startScanner = async () => {
|
||||
try {
|
||||
console.log('Starting QR scanner...');
|
||||
setError(null);
|
||||
setIsScanning(true);
|
||||
|
||||
// Allow camera on HTTP as well; rely on browser permission prompts
|
||||
|
||||
// Check if Html5Qrcode is available
|
||||
if (!window.Html5Qrcode) {
|
||||
setError('QR scanner library not loaded');
|
||||
setIsScanning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get available cameras first
|
||||
console.log('Getting available cameras...');
|
||||
const cameras = await window.Html5Qrcode.getCameras();
|
||||
console.log('Available cameras:', cameras);
|
||||
|
||||
if (!cameras || cameras.length === 0) {
|
||||
setError('No cameras found on this device');
|
||||
setIsScanning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear any existing scanner
|
||||
if (qrScannerRef.current) {
|
||||
try {
|
||||
qrScannerRef.current.stop();
|
||||
} catch (e) {
|
||||
console.log('Stopping previous scanner:', e.message);
|
||||
}
|
||||
}
|
||||
|
||||
// Create video element if it doesn't exist
|
||||
if (!videoRef.current) {
|
||||
console.log('Video element not found');
|
||||
setError('Video element not found');
|
||||
setIsScanning(false);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log('Video element found:', videoRef.current);
|
||||
console.log('Video element ID:', videoRef.current.id);
|
||||
|
||||
// Create Html5Qrcode instance
|
||||
console.log('Creating Html5Qrcode instance...');
|
||||
const html5Qrcode = new window.Html5Qrcode(videoRef.current.id || 'qr-reader');
|
||||
|
||||
// Find back camera (environment facing)
|
||||
let cameraId = cameras[0].id; // Default to first camera
|
||||
let selectedCamera = cameras[0];
|
||||
|
||||
// Look for back camera
|
||||
for (const camera of cameras) {
|
||||
if (camera.label.toLowerCase().includes('back') ||
|
||||
camera.label.toLowerCase().includes('rear') ||
|
||||
camera.label.toLowerCase().includes('environment')) {
|
||||
cameraId = camera.id;
|
||||
selectedCamera = camera;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Available cameras:');
|
||||
cameras.forEach((cam, index) => {
|
||||
console.log(`${index + 1}. ${cam.label} (${cam.id})`);
|
||||
});
|
||||
console.log('Selected camera:', selectedCamera.label, 'ID:', cameraId);
|
||||
|
||||
// Start camera
|
||||
console.log('Starting camera with Html5Qrcode...');
|
||||
const isDesktop = (typeof window !== 'undefined') && ((window.innerWidth || 0) >= 1024);
|
||||
const qrboxSize = isDesktop ? 560 : 360;
|
||||
await html5Qrcode.start(
|
||||
cameraId, // Use specific camera ID
|
||||
{
|
||||
fps: /iPhone|iPad|iPod/i.test(navigator.userAgent) ? 2 : 3,
|
||||
qrbox: { width: qrboxSize, height: qrboxSize },
|
||||
// Улучшенные настройки для мобильных устройств
|
||||
aspectRatio: 1.0,
|
||||
videoConstraints: {
|
||||
focusMode: "continuous", // Непрерывная автофокусировка
|
||||
exposureMode: "continuous", // Непрерывная экспозиция
|
||||
whiteBalanceMode: "continuous", // Непрерывный баланс белого
|
||||
torch: false, // Вспышка выключена по умолчанию
|
||||
facingMode: "environment" // Используем заднюю камеру
|
||||
}
|
||||
},
|
||||
(decodedText, decodedResult) => {
|
||||
console.log('QR Code detected:', decodedText);
|
||||
try {
|
||||
const res = onScan(decodedText);
|
||||
const handleResult = (val) => {
|
||||
const shouldClose = val === true || !continuous;
|
||||
if (shouldClose) {
|
||||
stopScanner();
|
||||
}
|
||||
};
|
||||
if (res && typeof res.then === 'function') {
|
||||
res.then(handleResult).catch((e) => {
|
||||
console.warn('onScan async handler error:', e);
|
||||
if (!continuous) stopScanner();
|
||||
});
|
||||
} else {
|
||||
handleResult(res);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('onScan handler threw:', e);
|
||||
if (!continuous) {
|
||||
stopScanner();
|
||||
}
|
||||
}
|
||||
},
|
||||
(error) => {
|
||||
// Ignore decode errors, they're normal during scanning
|
||||
console.log('QR decode error:', error);
|
||||
}
|
||||
);
|
||||
|
||||
// Store scanner reference
|
||||
qrScannerRef.current = html5Qrcode;
|
||||
console.log('QR scanner started successfully');
|
||||
|
||||
// Добавляем обработчик tap-to-focus для мобильных устройств
|
||||
if (videoRef.current) {
|
||||
videoRef.current.addEventListener('click', (event) => {
|
||||
handleTapToFocus(event, html5Qrcode);
|
||||
});
|
||||
}
|
||||
|
||||
} catch (err) {
|
||||
console.error('Error starting QR scanner:', err);
|
||||
let errorMessage = 'Failed to start camera';
|
||||
|
||||
if (err.name === 'NotAllowedError') {
|
||||
errorMessage = 'Camera access denied. Please allow camera access and try again.';
|
||||
} else if (err.name === 'NotFoundError') {
|
||||
errorMessage = 'No camera found on this device.';
|
||||
} else if (err.name === 'NotSupportedError') {
|
||||
errorMessage = 'Camera not supported on this device.';
|
||||
} else if (err.name === 'NotReadableError') {
|
||||
errorMessage = 'Camera is already in use by another application.';
|
||||
} else if (err.message) {
|
||||
errorMessage = err.message;
|
||||
}
|
||||
|
||||
setError(errorMessage);
|
||||
setIsScanning(false);
|
||||
}
|
||||
};
|
||||
|
||||
const stopScanner = () => {
|
||||
if (qrScannerRef.current) {
|
||||
try {
|
||||
qrScannerRef.current.stop().then(() => {
|
||||
console.log('QR scanner stopped');
|
||||
}).catch((err) => {
|
||||
console.log('Error stopping scanner:', err);
|
||||
});
|
||||
} catch (err) {
|
||||
console.log('Error stopping scanner:', err);
|
||||
}
|
||||
qrScannerRef.current = null;
|
||||
}
|
||||
setIsScanning(false);
|
||||
try {
|
||||
// iOS Safari workaround: small delay before closing modal to release camera
|
||||
if (/iPhone|iPad|iPod/i.test(navigator.userAgent)) {
|
||||
setTimeout(() => {
|
||||
// no-op; allow camera to settle
|
||||
}, 150);
|
||||
}
|
||||
} catch {}
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
stopScanner();
|
||||
onClose();
|
||||
};
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return React.createElement('div', {
|
||||
className: "fixed inset-0 bg-black/80 flex items-center justify-center z-50"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'scanner-modal',
|
||||
className: "bg-gray-800 rounded-lg p-6 w-full mx-4 max-w-2xl"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'scanner-header',
|
||||
className: "flex items-center justify-between mb-4"
|
||||
}, [
|
||||
React.createElement('h3', {
|
||||
key: 'title',
|
||||
className: "text-lg font-medium text-white"
|
||||
}, 'Scan QR Code'),
|
||||
React.createElement('button', {
|
||||
key: 'close-btn',
|
||||
onClick: handleClose,
|
||||
className: "text-gray-400 hover:text-white transition-colors"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-times text-xl'
|
||||
})
|
||||
])
|
||||
]),
|
||||
|
||||
// Индикатор прогресса сканирования
|
||||
progress.total > 1 && React.createElement('div', {
|
||||
key: 'progress-indicator',
|
||||
className: "mb-4 p-3 bg-gray-800/50 border border-gray-600/30 rounded-lg"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'progress-header',
|
||||
className: "flex items-center justify-between mb-2"
|
||||
}, [
|
||||
React.createElement('span', {
|
||||
key: 'progress-title',
|
||||
className: "text-sm text-gray-300"
|
||||
}, `QR ID: ${currentQRId ? currentQRId.substring(0, 8) + '...' : 'N/A'}`),
|
||||
React.createElement('span', {
|
||||
key: 'progress-count',
|
||||
className: "text-sm text-blue-400"
|
||||
}, `${scannedParts.size}/${progress.total} scanned`)
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'progress-numbers',
|
||||
className: "flex flex-wrap gap-1"
|
||||
}, Array.from({ length: progress.total }, (_, i) => {
|
||||
const partNumber = i + 1;
|
||||
const isScanned = scannedParts.has(partNumber);
|
||||
return React.createElement('div', {
|
||||
key: `part-${partNumber}`,
|
||||
className: `w-8 h-8 rounded-full flex items-center justify-center text-xs font-medium transition-colors ${
|
||||
isScanned
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-gray-600 text-gray-300'
|
||||
}`
|
||||
}, partNumber);
|
||||
}))
|
||||
]),
|
||||
|
||||
// Панель управления
|
||||
progress.total > 1 && React.createElement('div', {
|
||||
key: 'control-panel',
|
||||
className: "mb-4 flex gap-2"
|
||||
}, [
|
||||
React.createElement('button', {
|
||||
key: 'manual-toggle',
|
||||
onClick: toggleManualMode,
|
||||
className: `px-3 py-1 rounded text-xs font-medium transition-colors ${
|
||||
manualMode
|
||||
? 'bg-blue-500 text-white'
|
||||
: 'bg-gray-600 text-gray-300 hover:bg-gray-500'
|
||||
}`
|
||||
}, manualMode ? 'Manual Mode' : 'Auto Mode'),
|
||||
React.createElement('button', {
|
||||
key: 'reset-progress',
|
||||
onClick: resetProgress,
|
||||
className: "px-3 py-1 bg-red-500/20 text-red-400 border border-red-500/20 rounded text-xs font-medium hover:bg-red-500/30"
|
||||
}, 'Reset'),
|
||||
React.createElement('span', {
|
||||
key: 'mode-hint',
|
||||
className: "text-xs text-gray-400 self-center"
|
||||
}, manualMode ? 'Tap to focus, scan manually' : 'Auto-scrolling enabled')
|
||||
]),
|
||||
|
||||
React.createElement('div', {
|
||||
key: 'scanner-content',
|
||||
className: "relative"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'video-container',
|
||||
id: 'qr-reader',
|
||||
ref: videoRef,
|
||||
className: "w-full h-80 md:h-[32rem] bg-gray-700 rounded-lg"
|
||||
}),
|
||||
|
||||
error && React.createElement('div', {
|
||||
key: 'error',
|
||||
className: "absolute inset-0 flex items-center justify-center bg-red-900/50 rounded-lg"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'error-content',
|
||||
className: "text-center text-white p-4"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'error-icon',
|
||||
className: 'fas fa-exclamation-triangle text-2xl mb-2'
|
||||
}),
|
||||
React.createElement('p', {
|
||||
key: 'error-text',
|
||||
className: "text-sm"
|
||||
}, error)
|
||||
])
|
||||
]),
|
||||
|
||||
!error && !isScanning && React.createElement('div', {
|
||||
key: 'loading',
|
||||
className: "absolute inset-0 flex items-center justify-center bg-gray-700/50 rounded-lg"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'loading-content',
|
||||
className: "text-center text-white"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'loading-icon',
|
||||
className: 'fas fa-spinner fa-spin text-2xl mb-2'
|
||||
}),
|
||||
React.createElement('p', {
|
||||
key: 'loading-text',
|
||||
className: "text-sm"
|
||||
}, 'Starting camera...')
|
||||
])
|
||||
]),
|
||||
|
||||
!error && isScanning && React.createElement('div', {
|
||||
key: 'scanning-overlay',
|
||||
className: "absolute inset-0 flex items-center justify-center"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'scanning-content',
|
||||
className: "text-center text-white bg-black/50 rounded-lg px-4 py-2"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'scanning-icon',
|
||||
className: 'fas fa-qrcode text-xl mb-1'
|
||||
}),
|
||||
React.createElement('p', {
|
||||
key: 'scanning-text',
|
||||
className: "text-xs"
|
||||
}, progress && progress.total > 1 ? `Frames: ${Math.min(progress.seq, progress.total)}/${progress.total}` : 'Point camera at QR code'),
|
||||
React.createElement('p', {
|
||||
key: 'tap-hint',
|
||||
className: "text-xs text-blue-300 mt-1"
|
||||
}, 'Tap screen to focus')
|
||||
])
|
||||
]),
|
||||
|
||||
// Подсказка о фокусировке
|
||||
showFocusHint && React.createElement('div', {
|
||||
key: 'focus-hint',
|
||||
className: "absolute top-4 left-1/2 transform -translate-x-1/2 bg-green-500/90 text-white px-3 py-1 rounded-full text-xs font-medium z-10"
|
||||
}, 'Focusing...'),
|
||||
// Bottom overlay kept simple on mobile
|
||||
]),
|
||||
|
||||
// Дополнительные подсказки для улучшения сканирования
|
||||
React.createElement('div', {
|
||||
key: 'scanning-tips',
|
||||
className: "mt-4 p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg"
|
||||
}, [
|
||||
React.createElement('h4', {
|
||||
key: 'tips-title',
|
||||
className: "text-blue-400 text-sm font-medium mb-2 flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'tips-icon',
|
||||
className: 'fas fa-lightbulb mr-2'
|
||||
}),
|
||||
'Tips for better scanning:'
|
||||
]),
|
||||
React.createElement('ul', {
|
||||
key: 'tips-list',
|
||||
className: "text-xs text-blue-300 space-y-1"
|
||||
}, [
|
||||
React.createElement('li', {
|
||||
key: 'tip-1'
|
||||
}, '• Ensure good lighting'),
|
||||
React.createElement('li', {
|
||||
key: 'tip-2'
|
||||
}, '• Hold phone steady'),
|
||||
React.createElement('li', {
|
||||
key: 'tip-3'
|
||||
}, '• Tap screen to focus'),
|
||||
React.createElement('li', {
|
||||
key: 'tip-4'
|
||||
}, '• Keep QR code in frame')
|
||||
])
|
||||
])
|
||||
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
// Export for use in other files
|
||||
window.QRScanner = QRScanner;
|
||||
console.log('QRScanner component loaded and available on window.QRScanner');
|
||||
1
src/components/QRScanner.jsx
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
320
src/components/ui/ComparisonTable.jsx
Normal file
@@ -0,0 +1,320 @@
|
||||
|
||||
|
||||
|
||||
const ComparisonTable = () => {
|
||||
const [selectedFeature, setSelectedFeature] = React.useState(null);
|
||||
|
||||
const messengers = [
|
||||
{
|
||||
name: "SecureBit.chat",
|
||||
logo: <div className="w-8 h-8 bg-orange-500/10 border border-orange-500/20 rounded-lg flex items-center justify-center">
|
||||
<i className="fas fa-shield-halved text-orange-400" />
|
||||
</div>,
|
||||
type: "P2P WebRTC",
|
||||
version: "Latest",
|
||||
color: "orange",
|
||||
},
|
||||
{
|
||||
name: "Signal",
|
||||
logo: (
|
||||
<svg className="w-8 h-8" viewBox="0 0 122.88 122.31" xmlns="http://www.w3.org/2000/svg">
|
||||
<path className="fill-blue-500" d="M27.75,0H95.13a27.83,27.83,0,0,1,27.75,27.75V94.57a27.83,27.83,0,0,1-27.75,27.74H27.75A27.83,27.83,0,0,1,0,94.57V27.75A27.83,27.83,0,0,1,27.75,0Z" />
|
||||
<path className="fill-white" d="M61.44,25.39A35.76,35.76,0,0,0,31.18,80.18L27.74,94.86l14.67-3.44a35.77,35.77,0,1,0,19-66Z" />
|
||||
</svg>
|
||||
),
|
||||
type: "Centralized",
|
||||
version: "Latest",
|
||||
color: "blue",
|
||||
},
|
||||
{
|
||||
name: "Threema",
|
||||
logo: (
|
||||
<svg className="w-8 h-8" viewBox="0 0 122.88 122.88" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="122.88" height="122.88" rx="18.43" fill="#474747" />
|
||||
<path fill="#FFFFFF" d="M44.26,78.48l-19.44,4.8l4.08-16.56c-4.08-5.28-6.48-12-6.48-18.96c0-18.96,17.52-34.32,39.12-34.32c21.6,0,39.12,15.36,39.12,34.32c0,18.96-17.52,34.32-39.12,34.32c-6,0-12-1.2-17.04-3.36L44.26,78.48z M50.26,44.64h-0.48c-0.96,0-1.68,0.72-1.44,1.68v15.6c0,0.96,0.72,1.68,1.68,1.68l23.04,0c0.96,0,1.68-0.72,1.68-1.68v-15.6c0-0.96-0.72-1.68-1.68-1.68h-0.48v-4.32c0-6-5.04-11.04-11.04-11.04S50.5,34.32,50.5,40.32v4.32H50.26z M68.02,44.64h-13.2v-4.32c0-3.6,2.88-6.72,6.72-6.72c3.6,0,6.72,2.88,6.72,6.72v4.32H68.02z" />
|
||||
<circle cx="37.44" cy="97.44" r="6.72" fill="#3fe669" />
|
||||
<circle cx="61.44" cy="97.44" r="6.72" fill="#3fe669" />
|
||||
<circle cx="85.44" cy="97.44" r="6.72" fill="#3fe669" />
|
||||
</svg>
|
||||
),
|
||||
type: "Centralized",
|
||||
version: "Latest",
|
||||
color: "green",
|
||||
},
|
||||
{
|
||||
name: "Session",
|
||||
logo: (
|
||||
<svg className="w-8 h-8" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="1024" height="1024" fill="#333132" />
|
||||
<path fill="#00f782" d="M431 574.8c-.8-7.4-6.7-8.2-10.8-10.6-13.6-7.9-27.5-15.4-41.3-23l-22.5-12.3c-8.5-4.7-17.1-9.2-25.6-14.1-10.5-6-21-11.9-31.1-18.6-18.9-12.5-33.8-29.1-46.3-48.1-8.3-12.6-14.8-26.1-19.2-40.4-6.7-21.7-10.8-44.1-7.8-66.8 1.8-14 4.6-28 9.7-41.6 7.8-20.8 19.3-38.8 34.2-54.8 9.8-10.6 21.2-19.1 33.4-26.8 14.7-9.3 30.7-15.4 47.4-19 13.8-3 28.1-4.3 42.2-4.4 89.9-.4 179.7-.3 269.6 0 12.6 0 25.5 1 37.7 4.1 24.3 6.2 45.7 18.2 63 37 11.2 12.2 20.4 25.8 25.8 41.2 7.3 20.7 12.3 42.1 6.7 64.4-2.1 8.5-2.7 17.5-6.1 25.4-4.7 10.9-10.8 21.2-17.2 31.2-8.7 13.5-20.5 24.3-34.4 32.2-10.1 5.7-21 10.2-32 14.3-18.1 6.7-37.2 5-56.1 5.2-17.2.2-34.5 0-51.7.1-1.7 0-3.4 1.2-5.1 1.9 1.3 1.8 2.1 4.3 3.9 5.3 13.5 7.8 27.2 15.4 40.8 22.9 11 6 22.3 11.7 33.2 17.9 15.2 8.5 30.2 17.4 45.3 26.1 19.3 11.1 34.8 26.4 47.8 44.3 9.7 13.3 17.2 27.9 23 43.5 6.1 16.6 9.2 33.8 10.4 51.3.6 9.1-.7 18.5-1.9 27.6-1.2 9.1-2.7 18.4-5.6 27.1-3.3 10.2-7.4 20.2-12.4 29.6-8.4 15.7-19.6 29.4-32.8 41.4-12.7 11.5-26.8 20.6-42.4 27.6-22.9 10.3-46.9 14.4-71.6 14.5-89.7.3-179.4.2-269.1-.1-12.6 0-25.5-1-37.7-3.9-24.5-5.7-45.8-18-63.3-36.4-11.6-12.3-20.2-26.5-26.6-41.9-2.7-6.4-4.1-13.5-5.4-20.4-1.5-8.1-2.8-16.3-3.1-24.5-.6-15.7 2.8-30.9 8.2-45.4 8.2-22 21.7-40.6 40.2-55.2 10-7.9 21.3-13.7 33.1-18.8 16.6-7.2 34-8.1 51.4-8.5 21.9-.5 43.9-.1 65.9-.1 1.9-.1 3.9-.3 6.2-.4zm96.3-342.4c0 .1 0 .1 0 0-48.3.1-96.6-.6-144.9.5-13.5.3-27.4 3.9-40.1 8.7-14.9 5.6-28.1 14.6-39.9 25.8-20.2 19-32.2 42.2-37.2 68.9-3.6 19-1.4 38.1 4.1 56.5 4.1 13.7 10.5 26.4 18.5 38.4 14.8 22.2 35.7 36.7 58.4 49.2 11 6.1 22.2 11.9 33.2 18 13.5 7.5 26.9 15.1 40.4 22.6 13.1 7.3 26.2 14.5 39.2 21.7 9.7 5.3 19.4 10.7 29.1 16.1 2.9 1.6 4.1.2 4.5-2.4.3-2 .3-4 .3-6.1v-58.8c0-19.9.1-39.9 0-59.8 0-6.6 1.7-12.8 7.6-16.1 3.5-2 8.2-2.8 12.4-2.8 50.3-.2 100.7-.2 151-.1 19.8 0 38.3-4.4 55.1-15.1 23.1-14.8 36.3-36.3 40.6-62.9 3.4-20.8-1-40.9-12.4-58.5-17.8-27.5-43.6-43-76.5-43.6-47.8-.8-95.6-.2-143.4-.2zm-30.6 559.7c45.1 0 90.2-.2 135.3.1 18.9.1 36.6-3.9 53.9-11.1 18.4-7.7 33.6-19.8 46.3-34.9 9.1-10.8 16.2-22.9 20.8-36.5 4.2-12.4 7.4-24.7 7.3-37.9-.1-10.3.2-20.5-3.4-30.5-2.6-7.2-3.4-15.2-6.4-22.1-3.9-8.9-8.9-17.3-14-25.5-12.9-20.8-31.9-34.7-52.8-46.4-10.6-5.9-21.2-11.6-31.8-17.5-10.3-5.7-20.4-11.7-30.7-17.4-11.2-6.1-22.5-11.9-33.7-18-16.6-9.1-33.1-18.4-49.8-27.5-4.9-2.7-6.1-1.9-6.4 3.9-.1 2-.1 4.1-.1 6.1v114.5c0 14.8-5.6 20.4-20.4 20.4-47.6.1-95.3-.1-142.9.2-10.5.1-21.1 1.4-31.6 2.8-16.5 2.2-30.5 9.9-42.8 21-17 15.5-27 34.7-29.4 57.5-1.1 10.9-.4 21.7 2.9 32.5 3.7 12.3 9.2 23.4 17.5 33 19.2 22.1 43.4 33.3 72.7 33.3 46.6.1 93 0 139.5 0z" />
|
||||
</svg>
|
||||
),
|
||||
type: "Onion Network",
|
||||
version: "Latest",
|
||||
color: "cyan",
|
||||
},
|
||||
];
|
||||
|
||||
const features = [
|
||||
{
|
||||
name: "Security Architecture",
|
||||
lockbit: { status: "trophy", detail: "18-layer military-grade defense system with complete ASN.1 validation" },
|
||||
signal: { status: "check", detail: "Signal Protocol with double ratchet" },
|
||||
threema: { status: "check", detail: "Standard security implementation" },
|
||||
session: { status: "check", detail: "Modified Signal Protocol + Onion routing" },
|
||||
},
|
||||
{
|
||||
name: "Cryptography",
|
||||
lockbit: { status: "trophy", detail: "ECDH P-384 + AES-GCM 256 + ECDSA P-384" },
|
||||
signal: { status: "check", detail: "Signal Protocol + Double Ratchet" },
|
||||
threema: { status: "check", detail: "NaCl + XSalsa20 + Poly1305" },
|
||||
session: { status: "check", detail: "Modified Signal Protocol" },
|
||||
},
|
||||
{
|
||||
name: "Perfect Forward Secrecy",
|
||||
lockbit: { status: "trophy", detail: "Auto rotation every 5 minutes or 100 messages" },
|
||||
signal: { status: "check", detail: "Double Ratchet algorithm" },
|
||||
threema: { status: "warning", detail: "Partial (group chats)" },
|
||||
session: { status: "check", detail: "Session Ratchet algorithm" },
|
||||
},
|
||||
{
|
||||
name: "Architecture",
|
||||
lockbit: { status: "trophy", detail: "Pure P2P WebRTC without servers" },
|
||||
signal: { status: "times", detail: "Centralized Signal servers" },
|
||||
threema: { status: "times", detail: "Threema servers in Switzerland" },
|
||||
session: { status: "warning", detail: "Onion routing via network nodes" },
|
||||
},
|
||||
{
|
||||
name: "Registration Anonymity",
|
||||
lockbit: { status: "trophy", detail: "No registration required, instant anonymous channels" },
|
||||
signal: { status: "times", detail: "Phone number required" },
|
||||
threema: { status: "check", detail: "ID generated locally" },
|
||||
session: { status: "check", detail: "Random session ID" },
|
||||
},
|
||||
{
|
||||
name: "Payment Integration",
|
||||
lockbit: { status: "trophy", detail: "Lightning Network satoshis per session + WebLN" },
|
||||
signal: { status: "times", detail: "No payment system" },
|
||||
threema: { status: "times", detail: "No payment system" },
|
||||
session: { status: "times", detail: "No payment system" },
|
||||
},
|
||||
{
|
||||
name: "Metadata Protection",
|
||||
lockbit: { status: "trophy", detail: "Full metadata encryption + traffic obfuscation" },
|
||||
signal: { status: "warning", detail: "Sealed Sender (partial)" },
|
||||
threema: { status: "warning", detail: "Minimal metadata" },
|
||||
session: { status: "check", detail: "Onion routing hides metadata" },
|
||||
},
|
||||
{
|
||||
name: "Traffic Obfuscation",
|
||||
lockbit: { status: "trophy", detail: "Fake traffic + pattern masking + packet padding" },
|
||||
signal: { status: "times", detail: "No traffic obfuscation" },
|
||||
threema: { status: "times", detail: "No traffic obfuscation" },
|
||||
session: { status: "check", detail: "Onion routing provides obfuscation" },
|
||||
},
|
||||
{
|
||||
name: "Open Source",
|
||||
lockbit: { status: "trophy", detail: "100% open + auditable + MIT license" },
|
||||
signal: { status: "check", detail: "Fully open" },
|
||||
threema: { status: "warning", detail: "Only clients open" },
|
||||
session: { status: "check", detail: "Fully open" },
|
||||
},
|
||||
{
|
||||
name: "MITM Protection",
|
||||
lockbit: { status: "trophy", detail: "Out-of-band verification + mutual auth + ECDSA" },
|
||||
signal: { status: "check", detail: "Safety numbers verification" },
|
||||
threema: { status: "check", detail: "QR code scanning" },
|
||||
session: { status: "warning", detail: "Basic key verification" },
|
||||
},
|
||||
{
|
||||
name: "Economic Model",
|
||||
lockbit: { status: "trophy", detail: "Sustainable pay-per-session model" },
|
||||
signal: { status: "warning", detail: "Donations and grants dependency" },
|
||||
threema: { status: "check", detail: "One-time app purchase" },
|
||||
session: { status: "warning", detail: "Donations dependency" },
|
||||
},
|
||||
{
|
||||
name: "Censorship Resistance",
|
||||
lockbit: { status: "trophy", detail: "Impossible to block P2P + no servers to target" },
|
||||
signal: { status: "warning", detail: "Blocked in authoritarian countries" },
|
||||
threema: { status: "warning", detail: "May be blocked" },
|
||||
session: { status: "check", detail: "Onion routing bypasses blocks" },
|
||||
},
|
||||
{
|
||||
name: "Data Storage",
|
||||
lockbit: { status: "trophy", detail: "Zero data storage - only in browser memory" },
|
||||
signal: { status: "warning", detail: "Local database storage" },
|
||||
threema: { status: "warning", detail: "Local + optional backup" },
|
||||
session: { status: "warning", detail: "Local database storage" },
|
||||
},
|
||||
{
|
||||
name: "Key Security",
|
||||
lockbit: { status: "trophy", detail: "Non-extractable keys + hardware protection" },
|
||||
signal: { status: "check", detail: "Secure key storage" },
|
||||
threema: { status: "check", detail: "Local key storage" },
|
||||
session: { status: "check", detail: "Secure key storage" },
|
||||
},
|
||||
{
|
||||
name: "Post-Quantum Roadmap",
|
||||
lockbit: { status: "check", detail: "Planned v5.0 - CRYSTALS-Kyber/Dilithium" },
|
||||
signal: { status: "warning", detail: "PQXDH in development" },
|
||||
threema: { status: "times", detail: "Not announced" },
|
||||
session: { status: "times", detail: "Not announced" },
|
||||
},
|
||||
];
|
||||
|
||||
const getStatusIcon = (status) => {
|
||||
const statusMap = {
|
||||
"trophy": { icon: "fa-trophy", color: "accent-orange" },
|
||||
"check": { icon: "fa-check", color: "text-green-300" },
|
||||
"warning": { icon: "fa-exclamation-triangle", color: "text-yellow-300" },
|
||||
"times": { icon: "fa-times", color: "text-red-300" },
|
||||
};
|
||||
return statusMap[status] || { icon: "fa-question", color: "text-gray-400" };
|
||||
};
|
||||
|
||||
const toggleFeatureDetail = (index) => {
|
||||
setSelectedFeature(selectedFeature === index ? null : index);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="mt-16">
|
||||
{/* Title */}
|
||||
<div className="text-center mb-8">
|
||||
<h3 className="text-3xl font-bold text-white mb-3">
|
||||
Enhanced Security Edition Comparison
|
||||
</h3>
|
||||
<p className="text-gray-400 max-w-2xl mx-auto mb-4">
|
||||
Enhanced Security Edition vs leading secure messengers
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Table container */}
|
||||
<div className="max-w-7xl mx-auto">
|
||||
{/* Mobile Alert */}
|
||||
<div className="md:hidden p-4 bg-yellow-500/10 border border-yellow-500/20 rounded-lg mb-4">
|
||||
<p className="text-yellow-400 text-sm text-center">
|
||||
<i className="fas fa-lightbulb mr-2"></i>
|
||||
Rotate your device horizontally for better viewing
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Table */}
|
||||
<div className="overflow-x-auto">
|
||||
<table
|
||||
className="w-full border-collapse rounded-xl overflow-hidden shadow-2xl"
|
||||
style={{ backgroundColor: "rgba(42, 43, 42, 0.9)" }}
|
||||
>
|
||||
{/* Table Header */}
|
||||
<thead>
|
||||
<tr className="bg-black-table">
|
||||
<th className="text-left p-4 border-b border-gray-600 text-white font-bold min-w-[240px]">
|
||||
Security Criterion
|
||||
</th>
|
||||
{messengers.map((messenger, index) => (
|
||||
<th key={`messenger-${index}`} className="text-center p-4 border-b border-gray-600 min-w-[160px]">
|
||||
<div className="flex flex-col items-center">
|
||||
<div className="mb-2">{messenger.logo}</div>
|
||||
<div className={`text-sm font-bold ${
|
||||
messenger.color === 'orange' ? 'text-orange-400' :
|
||||
messenger.color === 'blue' ? 'text-blue-400' :
|
||||
messenger.color === 'green' ? 'text-green-400' :
|
||||
'text-cyan-400'
|
||||
}`}>
|
||||
{messenger.name}
|
||||
</div>
|
||||
<div className="text-xs text-gray-400">{messenger.type}</div>
|
||||
<div className="text-xs text-gray-500 mt-1">{messenger.version}</div>
|
||||
</div>
|
||||
</th>
|
||||
))}
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
{/* Table body */}
|
||||
<tbody>
|
||||
{features.map((feature, featureIndex) => (
|
||||
<React.Fragment key={`feature-${featureIndex}`}>
|
||||
<tr
|
||||
className={`border-b border-gray-700/30 transition-all duration-200 cursor-pointer hover:bg-[rgb(20_20_20_/30%)] ${
|
||||
selectedFeature === featureIndex ? 'bg-[rgb(20_20_20_/50%)]' : ''
|
||||
}`}
|
||||
onClick={() => toggleFeatureDetail(featureIndex)}
|
||||
>
|
||||
<td className="p-4 text-white font-semibold">
|
||||
<div className="flex items-center justify-between">
|
||||
<span>{feature.name}</span>
|
||||
<i className={`fas fa-chevron-${selectedFeature === featureIndex ? 'up' : 'down'} text-xs text-gray-400 opacity-60 transition-all duration-200`} />
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<i className={`fas ${getStatusIcon(feature.lockbit.status).icon} ${getStatusIcon(feature.lockbit.status).color} text-2xl`} />
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<i className={`fas ${getStatusIcon(feature.signal.status).icon} ${getStatusIcon(feature.signal.status).color} text-2xl`} />
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<i className={`fas ${getStatusIcon(feature.threema.status).icon} ${getStatusIcon(feature.threema.status).color} text-2xl`} />
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<i className={`fas ${getStatusIcon(feature.session.status).icon} ${getStatusIcon(feature.session.status).color} text-2xl`} />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
{/* Details */}
|
||||
{selectedFeature === featureIndex && (
|
||||
<tr className="border-b border-gray-700/30 bg-gradient-to-r from-gray-800/20 to-gray-900/20">
|
||||
<td className="p-4 text-xs text-gray-400 font-medium">Technical Details:</td>
|
||||
<td className="p-4 text-center">
|
||||
<div className="text-xs text-orange-300 font-medium leading-relaxed">
|
||||
{feature.lockbit.detail}
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<div className="text-xs text-blue-300 leading-relaxed">
|
||||
{feature.signal.detail}
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<div className="text-xs text-green-300 leading-relaxed">
|
||||
{feature.threema.detail}
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-4 text-center">
|
||||
<div className="text-xs text-cyan-300 leading-relaxed">
|
||||
{feature.session.detail}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
)}
|
||||
</React.Fragment>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="mt-8 grid grid-cols-2 md:grid-cols-4 gap-4 max-w-5xl mx-auto">
|
||||
<div className="flex items-center justify-center p-4 bg-orange-500/10 rounded-xl hover:bg-orange-500/40 transition-colors">
|
||||
<i className="fas fa-trophy text-orange-400 mr-2 text-xl"></i>
|
||||
<span className="text-orange-300 text-sm font-bold">Category Leader</span>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-center p-4 bg-green-500/10 rounded-xl hover:bg-green-600/40 transition-colors">
|
||||
<i className="fas fa-check text-green-300 mr-2 text-xl"></i>
|
||||
<span className="text-green-200 text-sm font-bold">Excellent</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center p-4 bg-yellow-500/10 rounded-xl hover:bg-yellow-600/40 transition-colors">
|
||||
<i className="fas fa-exclamation-triangle text-yellow-300 mr-2 text-xl"></i>
|
||||
<span className="text-yellow-200 text-sm font-bold">Partial/Limited</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-center p-4 bg-red-500/10 rounded-xl hover:bg-red-600/40 transition-colors">
|
||||
<i className="fas fa-times text-red-300 mr-2 text-xl"></i>
|
||||
<span className="text-red-200 text-sm font-bold">Not Available</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
window.ComparisonTable = ComparisonTable;
|
||||
86
src/components/ui/DownloadApps.jsx
Normal file
@@ -0,0 +1,86 @@
|
||||
const DownloadApps = () => {
|
||||
const apps = [
|
||||
{ id: 'web', name: 'Web App', subtitle: 'Browser Version', icon: 'fas fa-globe', platform: 'Web', isActive: true, url: 'https://securebit.chat/', color: 'green' },
|
||||
{ id: 'windows', name: 'Windows', subtitle: 'Desktop App', icon: 'fab fa-windows', platform: 'Desktop', isActive: false, url: 'https://securebit.chat/download/windows/SecureBit%20Chat%20Setup%204.1.222.exe', color: 'blue' },
|
||||
{ id: 'macos', name: 'macOS', subtitle: 'Desktop App', icon: 'fab fa-safari', platform: 'Desktop', isActive: false, url: '#', color: 'gray' },
|
||||
{ id: 'linux', name: 'Linux', subtitle: 'Desktop App', icon: 'fab fa-linux', platform: 'Desktop', isActive: false, url: '#', color: 'orange' },
|
||||
{ id: 'ios', name: 'iOS', subtitle: 'iPhone & iPad', icon: 'fab fa-apple', platform: 'Mobile', isActive: false, url: 'https://apps.apple.com/app/securebit-chat/', color: 'white' },
|
||||
{ id: 'android', name: 'Android', subtitle: 'Google Play', icon: 'fab fa-android', platform: 'Mobile', isActive: false, url: 'https://play.google.com/store/apps/details?id=com.securebit.chat', color: 'green' },
|
||||
{ id: 'chrome', name: 'Chrome', subtitle: 'Browser Extension', icon: 'fab fa-chrome', platform: 'Browser', isActive: false, url: '#', color: 'yellow' },
|
||||
{ id: 'edge', name: 'Edge', subtitle: 'Browser Extension', icon: 'fab fa-edge', platform: 'Browser', isActive: false, url: '#', color: 'blue' },
|
||||
{ id: 'opera', name: 'Opera', subtitle: 'Browser Extension', icon: 'fab fa-opera', platform: 'Browser', isActive: false, url: '#', color: 'red' },
|
||||
{ id: 'firefox', name: 'Firefox', subtitle: 'Browser Extension', icon: 'fab fa-firefox-browser', platform: 'Browser', isActive: false, url: '#', color: 'orange' },
|
||||
];
|
||||
|
||||
const handleDownload = (app) => {
|
||||
if (app.isActive) window.open(app.url, '_blank');
|
||||
};
|
||||
|
||||
const desktopApps = apps.filter(a => a.platform === 'Desktop' || a.platform === 'Web');
|
||||
const mobileApps = apps.filter(a => a.platform === 'Mobile');
|
||||
const browserApps = apps.filter(a => a.platform === 'Browser');
|
||||
|
||||
const cardSize = "w-28 h-28";
|
||||
|
||||
const colorClasses = {
|
||||
green: 'text-green-500',
|
||||
blue: 'text-blue-500',
|
||||
gray: 'text-gray-500',
|
||||
orange: 'text-orange-500',
|
||||
red: 'text-red-500',
|
||||
white: 'text-white',
|
||||
yellow: 'text-yellow-400',
|
||||
};
|
||||
|
||||
const renderAppCard = (app) => (
|
||||
React.createElement('div', {
|
||||
key: app.id,
|
||||
className: `group relative ${cardSize} rounded-2xl overflow-hidden card-minimal cursor-pointer`
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'bg-icon',
|
||||
className: `${app.icon} absolute text-[3rem] ${app.isActive ? colorClasses[app.color] : 'text-white/10'} top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 pointer-events-none transition-all duration-500 group-hover:scale-105`
|
||||
}),
|
||||
React.createElement('div', {
|
||||
key: 'overlay',
|
||||
className: "absolute inset-0 bg-black/30 backdrop-blur-md flex flex-col items-center justify-center text-center opacity-0 transition-opacity duration-300 group-hover:opacity-100"
|
||||
}, [
|
||||
React.createElement('h4', { key: 'name', className: `text-sm font-semibold text-primary mb-1` }, app.name),
|
||||
React.createElement('p', { key: 'subtitle', className: `text-xs text-secondary mb-2` }, app.subtitle),
|
||||
app.isActive ?
|
||||
React.createElement('button', {
|
||||
key: 'btn',
|
||||
onClick: () => handleDownload(app),
|
||||
className: `px-2 py-1 rounded-xl bg-emerald-500 text-black font-medium hover:bg-emerald-600 transition-colors text-xs`
|
||||
}, app.id === "web" ? "Launch" : "Download")
|
||||
:
|
||||
React.createElement('span', { key: 'coming', className: "text-gray-400 font-medium text-xs" }, "Coming Soon")
|
||||
])
|
||||
])
|
||||
);
|
||||
|
||||
return React.createElement('div', { className: "mt-20 px-6" }, [
|
||||
// Header
|
||||
React.createElement('div', { key: 'header', className: "text-center max-w-3xl mx-auto mb-12" }, [
|
||||
React.createElement('h3', { key: 'title', className: "text-3xl font-bold text-primary mb-3" }, 'Download SecureBit.chat'),
|
||||
React.createElement('p', { key: 'subtitle', className: "text-secondary text-lg mb-5" }, 'Stay secure on every device. Choose your platform and start chatting privately.')
|
||||
]),
|
||||
|
||||
// Desktop Apps
|
||||
React.createElement('div', { key: 'desktop-row', className: "hidden sm:flex justify-center flex-wrap gap-6 mb-6" },
|
||||
desktopApps.map(renderAppCard)
|
||||
),
|
||||
|
||||
// Mobile Apps
|
||||
React.createElement('div', { key: 'mobile-row', className: "flex justify-center gap-6 mb-6" },
|
||||
mobileApps.map(renderAppCard)
|
||||
),
|
||||
|
||||
// Browser Extensions
|
||||
React.createElement('div', { key: 'browser-row', className: "flex justify-center gap-6" },
|
||||
browserApps.map(renderAppCard)
|
||||
)
|
||||
]);
|
||||
};
|
||||
|
||||
window.DownloadApps = DownloadApps;
|
||||
423
src/components/ui/FileTransfer.jsx
Normal file
@@ -0,0 +1,423 @@
|
||||
// File Transfer Component for Chat Interface - Fixed Version
|
||||
const FileTransferComponent = ({ webrtcManager, isConnected }) => {
|
||||
const [dragOver, setDragOver] = React.useState(false);
|
||||
const [transfers, setTransfers] = React.useState({ sending: [], receiving: [] });
|
||||
const [readyFiles, setReadyFiles] = React.useState([]); // файлы, готовые к скачиванию
|
||||
const fileInputRef = React.useRef(null);
|
||||
|
||||
// Update transfers periodically
|
||||
React.useEffect(() => {
|
||||
if (!isConnected || !webrtcManager) return;
|
||||
|
||||
const updateTransfers = () => {
|
||||
const currentTransfers = webrtcManager.getFileTransfers();
|
||||
setTransfers(currentTransfers);
|
||||
};
|
||||
|
||||
const interval = setInterval(updateTransfers, 500);
|
||||
return () => clearInterval(interval);
|
||||
}, [isConnected, webrtcManager]);
|
||||
|
||||
// Setup file transfer callbacks - ИСПРАВЛЕНИЕ: НЕ отправляем промежуточные сообщения в чат
|
||||
React.useEffect(() => {
|
||||
if (!webrtcManager) return;
|
||||
|
||||
webrtcManager.setFileTransferCallbacks(
|
||||
// Progress callback - ТОЛЬКО обновляем UI, НЕ отправляем в чат
|
||||
(progress) => {
|
||||
// Обновляем только локальное состояние
|
||||
const currentTransfers = webrtcManager.getFileTransfers();
|
||||
setTransfers(currentTransfers);
|
||||
|
||||
// НЕ отправляем сообщения в чат!
|
||||
},
|
||||
|
||||
// File received callback - добавляем кнопку скачивания в UI
|
||||
(fileData) => {
|
||||
// Добавляем в список готовых к скачиванию
|
||||
setReadyFiles(prev => {
|
||||
// избегаем дублей по fileId
|
||||
if (prev.some(f => f.fileId === fileData.fileId)) return prev;
|
||||
return [...prev, {
|
||||
fileId: fileData.fileId,
|
||||
fileName: fileData.fileName,
|
||||
fileSize: fileData.fileSize,
|
||||
mimeType: fileData.mimeType,
|
||||
getBlob: fileData.getBlob,
|
||||
getObjectURL: fileData.getObjectURL,
|
||||
revokeObjectURL: fileData.revokeObjectURL
|
||||
}];
|
||||
});
|
||||
|
||||
// Обновляем список активных передач
|
||||
const currentTransfers = webrtcManager.getFileTransfers();
|
||||
setTransfers(currentTransfers);
|
||||
},
|
||||
|
||||
// Error callback
|
||||
(error) => {
|
||||
const currentTransfers = webrtcManager.getFileTransfers();
|
||||
setTransfers(currentTransfers);
|
||||
|
||||
// ИСПРАВЛЕНИЕ: НЕ дублируем сообщения об ошибках
|
||||
// Уведомления об ошибках уже отправляются в WebRTC менеджере
|
||||
}
|
||||
);
|
||||
}, [webrtcManager]);
|
||||
|
||||
const handleFileSelect = async (files) => {
|
||||
if (!isConnected || !webrtcManager) {
|
||||
alert('Соединение не установлено. Сначала установите соединение.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Дополнительная проверка состояния соединения
|
||||
if (!webrtcManager.isConnected() || !webrtcManager.isVerified) {
|
||||
alert('Соединение не готово для передачи файлов. Дождитесь завершения установки соединения.');
|
||||
return;
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
try {
|
||||
// КРИТИЧЕСКОЕ ИСПРАВЛЕНИЕ: Валидация файла перед отправкой
|
||||
const validation = webrtcManager.validateFile(file);
|
||||
if (!validation.isValid) {
|
||||
const errorMessage = validation.errors.join('. ');
|
||||
alert(`Файл ${file.name} не может быть отправлен: ${errorMessage}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
await webrtcManager.sendFile(file);
|
||||
} catch (error) {
|
||||
// Более мягкая обработка ошибок - не закрываем сессию
|
||||
|
||||
// Показываем пользователю ошибку, но не закрываем соединение
|
||||
if (error.message.includes('Connection not ready')) {
|
||||
alert(`Файл ${file.name} не может быть отправлен сейчас. Проверьте соединение и попробуйте снова.`);
|
||||
} else if (error.message.includes('File too large') || error.message.includes('exceeds maximum')) {
|
||||
alert(`Файл ${file.name} слишком большой: ${error.message}`);
|
||||
} else if (error.message.includes('Maximum concurrent transfers')) {
|
||||
alert(`Достигнут лимит одновременных передач. Дождитесь завершения текущих передач.`);
|
||||
} else if (error.message.includes('File type not allowed')) {
|
||||
alert(`Тип файла ${file.name} не поддерживается: ${error.message}`);
|
||||
} else {
|
||||
alert(`Ошибка отправки файла ${file.name}: ${error.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleDrop = (e) => {
|
||||
e.preventDefault();
|
||||
setDragOver(false);
|
||||
|
||||
const files = Array.from(e.dataTransfer.files);
|
||||
handleFileSelect(files);
|
||||
};
|
||||
|
||||
const handleDragOver = (e) => {
|
||||
e.preventDefault();
|
||||
setDragOver(true);
|
||||
};
|
||||
|
||||
const handleDragLeave = (e) => {
|
||||
e.preventDefault();
|
||||
setDragOver(false);
|
||||
};
|
||||
|
||||
const handleFileInputChange = (e) => {
|
||||
const files = Array.from(e.target.files);
|
||||
handleFileSelect(files);
|
||||
e.target.value = ''; // Reset input
|
||||
};
|
||||
|
||||
const formatFileSize = (bytes) => {
|
||||
if (bytes === 0) return '0 B';
|
||||
const k = 1024;
|
||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
const getStatusIcon = (status) => {
|
||||
switch (status) {
|
||||
case 'metadata_sent':
|
||||
case 'preparing':
|
||||
return 'fas fa-cog fa-spin';
|
||||
case 'transmitting':
|
||||
case 'receiving':
|
||||
return 'fas fa-exchange-alt fa-pulse';
|
||||
case 'assembling':
|
||||
return 'fas fa-puzzle-piece fa-pulse';
|
||||
case 'completed':
|
||||
return 'fas fa-check text-green-400';
|
||||
case 'failed':
|
||||
return 'fas fa-times text-red-400';
|
||||
default:
|
||||
return 'fas fa-circle';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusText = (status) => {
|
||||
switch (status) {
|
||||
case 'metadata_sent':
|
||||
return 'Подготовка...';
|
||||
case 'transmitting':
|
||||
return 'Отправка...';
|
||||
case 'receiving':
|
||||
return 'Получение...';
|
||||
case 'assembling':
|
||||
return 'Сборка файла...';
|
||||
case 'completed':
|
||||
return 'Завершено';
|
||||
case 'failed':
|
||||
return 'Ошибка';
|
||||
default:
|
||||
return status;
|
||||
}
|
||||
};
|
||||
|
||||
if (!isConnected) {
|
||||
return React.createElement('div', {
|
||||
className: "p-4 text-center text-muted"
|
||||
}, 'Передача файлов доступна только при установленном соединении');
|
||||
}
|
||||
|
||||
// Проверяем дополнительное состояние соединения
|
||||
const isConnectionReady = webrtcManager && webrtcManager.isConnected() && webrtcManager.isVerified;
|
||||
|
||||
if (!isConnectionReady) {
|
||||
return React.createElement('div', {
|
||||
className: "p-4 text-center text-yellow-600"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-exclamation-triangle mr-2'
|
||||
}),
|
||||
'Соединение устанавливается... Передача файлов будет доступна после завершения установки.'
|
||||
]);
|
||||
}
|
||||
|
||||
return React.createElement('div', {
|
||||
className: "file-transfer-component"
|
||||
}, [
|
||||
// File Drop Zone
|
||||
React.createElement('div', {
|
||||
key: 'drop-zone',
|
||||
className: `file-drop-zone ${dragOver ? 'drag-over' : ''}`,
|
||||
onDrop: handleDrop,
|
||||
onDragOver: handleDragOver,
|
||||
onDragLeave: handleDragLeave,
|
||||
onClick: () => fileInputRef.current?.click()
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'drop-content',
|
||||
className: "drop-content"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-cloud-upload-alt text-2xl mb-2 text-blue-400'
|
||||
}),
|
||||
React.createElement('p', {
|
||||
key: 'text',
|
||||
className: "text-primary font-medium"
|
||||
}, 'Drag files here or click to select'),
|
||||
React.createElement('p', {
|
||||
key: 'subtext',
|
||||
className: "text-muted text-sm"
|
||||
}, 'Maximum size: 100 MB per file')
|
||||
])
|
||||
]),
|
||||
|
||||
// Hidden file input
|
||||
React.createElement('input', {
|
||||
key: 'file-input',
|
||||
ref: fileInputRef,
|
||||
type: 'file',
|
||||
multiple: true,
|
||||
className: 'hidden',
|
||||
onChange: handleFileInputChange
|
||||
}),
|
||||
|
||||
// Active Transfers
|
||||
(transfers.sending.length > 0 || transfers.receiving.length > 0) && React.createElement('div', {
|
||||
key: 'transfers',
|
||||
className: "active-transfers mt-4"
|
||||
}, [
|
||||
React.createElement('h4', {
|
||||
key: 'title',
|
||||
className: "text-primary font-medium mb-3 flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-exchange-alt mr-2'
|
||||
}),
|
||||
'Передача файлов'
|
||||
]),
|
||||
|
||||
// Sending files
|
||||
...transfers.sending.map(transfer =>
|
||||
React.createElement('div', {
|
||||
key: `send-${transfer.fileId}`,
|
||||
className: "transfer-item bg-blue-500/10 border border-blue-500/20 rounded-lg p-3 mb-2"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'header',
|
||||
className: "flex items-center justify-between mb-2"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'info',
|
||||
className: "flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-upload text-blue-400 mr-2'
|
||||
}),
|
||||
React.createElement('span', {
|
||||
key: 'name',
|
||||
className: "text-primary font-medium text-sm"
|
||||
}, transfer.fileName),
|
||||
React.createElement('span', {
|
||||
key: 'size',
|
||||
className: "text-muted text-xs ml-2"
|
||||
}, formatFileSize(transfer.fileSize))
|
||||
]),
|
||||
React.createElement('button', {
|
||||
key: 'cancel',
|
||||
onClick: () => webrtcManager.cancelFileTransfer(transfer.fileId),
|
||||
className: "text-red-400 hover:text-red-300 text-xs"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-times'
|
||||
})
|
||||
])
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'progress',
|
||||
className: "progress-bar"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'fill',
|
||||
className: "progress-fill bg-blue-400",
|
||||
style: { width: `${transfer.progress}%` }
|
||||
}),
|
||||
React.createElement('div', {
|
||||
key: 'text',
|
||||
className: "progress-text text-xs flex items-center justify-between"
|
||||
}, [
|
||||
React.createElement('span', {
|
||||
key: 'status',
|
||||
className: "flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: `${getStatusIcon(transfer.status)} mr-1`
|
||||
}),
|
||||
getStatusText(transfer.status)
|
||||
]),
|
||||
React.createElement('span', {
|
||||
key: 'percent'
|
||||
}, `${transfer.progress.toFixed(1)}%`)
|
||||
])
|
||||
])
|
||||
])
|
||||
),
|
||||
|
||||
// Receiving files
|
||||
...transfers.receiving.map(transfer =>
|
||||
React.createElement('div', {
|
||||
key: `recv-${transfer.fileId}`,
|
||||
className: "transfer-item bg-green-500/10 border border-green-500/20 rounded-lg p-3 mb-2"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'header',
|
||||
className: "flex items-center justify-between mb-2"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'info',
|
||||
className: "flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: 'fas fa-download text-green-400 mr-2'
|
||||
}),
|
||||
React.createElement('span', {
|
||||
key: 'name',
|
||||
className: "text-primary font-medium text-sm"
|
||||
}, transfer.fileName),
|
||||
React.createElement('span', {
|
||||
key: 'size',
|
||||
className: "text-muted text-xs ml-2"
|
||||
}, formatFileSize(transfer.fileSize))
|
||||
]),
|
||||
React.createElement('div', { key: 'actions', className: 'flex items-center space-x-2' }, [
|
||||
(() => {
|
||||
const rf = readyFiles.find(f => f.fileId === transfer.fileId);
|
||||
if (!rf || transfer.status !== 'completed') return null;
|
||||
return React.createElement('button', {
|
||||
key: 'download',
|
||||
className: 'text-green-400 hover:text-green-300 text-xs flex items-center',
|
||||
onClick: async () => {
|
||||
try {
|
||||
const url = await rf.getObjectURL();
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = rf.fileName || 'file';
|
||||
a.click();
|
||||
rf.revokeObjectURL(url);
|
||||
} catch (e) {
|
||||
alert('Failed to start download: ' + e.message);
|
||||
}
|
||||
}
|
||||
}, [
|
||||
React.createElement('i', { key: 'i', className: 'fas fa-download mr-1' }),
|
||||
'Download'
|
||||
]);
|
||||
})(),
|
||||
React.createElement('button', {
|
||||
key: 'cancel',
|
||||
onClick: () => webrtcManager.cancelFileTransfer(transfer.fileId),
|
||||
className: "text-red-400 hover:text-red-300 text-xs"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-times'
|
||||
})
|
||||
])
|
||||
])
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'progress',
|
||||
className: "progress-bar"
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'fill',
|
||||
className: "progress-fill bg-green-400",
|
||||
style: { width: `${transfer.progress}%` }
|
||||
}),
|
||||
React.createElement('div', {
|
||||
key: 'text',
|
||||
className: "progress-text text-xs flex items-center justify-between"
|
||||
}, [
|
||||
React.createElement('span', {
|
||||
key: 'status',
|
||||
className: "flex items-center"
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
key: 'icon',
|
||||
className: `${getStatusIcon(transfer.status)} mr-1`
|
||||
}),
|
||||
getStatusText(transfer.status)
|
||||
]),
|
||||
React.createElement('span', {
|
||||
key: 'percent'
|
||||
}, `${transfer.progress.toFixed(1)}%`)
|
||||
])
|
||||
])
|
||||
])
|
||||
)
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
// Export
|
||||
window.FileTransferComponent = FileTransferComponent;
|
||||
708
src/components/ui/Header.jsx
Normal file
@@ -0,0 +1,708 @@
|
||||
const EnhancedMinimalHeader = ({
|
||||
status,
|
||||
fingerprint,
|
||||
verificationCode,
|
||||
onDisconnect,
|
||||
isConnected,
|
||||
securityLevel,
|
||||
sessionManager,
|
||||
sessionTimeLeft,
|
||||
webrtcManager
|
||||
}) => {
|
||||
const [currentTimeLeft, setCurrentTimeLeft] = React.useState(sessionTimeLeft || 0);
|
||||
const [hasActiveSession, setHasActiveSession] = React.useState(false);
|
||||
const [sessionType, setSessionType] = React.useState('unknown');
|
||||
const [realSecurityLevel, setRealSecurityLevel] = React.useState(null);
|
||||
const [lastSecurityUpdate, setLastSecurityUpdate] = React.useState(0);
|
||||
|
||||
// ============================================
|
||||
// FIXED SECURITY UPDATE LOGIC
|
||||
// ============================================
|
||||
|
||||
React.useEffect(() => {
|
||||
let isUpdating = false;
|
||||
let lastUpdateAttempt = 0;
|
||||
|
||||
const updateRealSecurityStatus = async () => {
|
||||
const now = Date.now();
|
||||
if (now - lastUpdateAttempt < 10000) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUpdating) {
|
||||
return;
|
||||
}
|
||||
|
||||
isUpdating = true;
|
||||
lastUpdateAttempt = now;
|
||||
|
||||
try {
|
||||
if (!webrtcManager || !isConnected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const activeWebrtcManager = webrtcManager;
|
||||
|
||||
let realSecurityData = null;
|
||||
|
||||
if (typeof activeWebrtcManager.getRealSecurityLevel === 'function') {
|
||||
realSecurityData = await activeWebrtcManager.getRealSecurityLevel();
|
||||
} else if (typeof activeWebrtcManager.calculateAndReportSecurityLevel === 'function') {
|
||||
realSecurityData = await activeWebrtcManager.calculateAndReportSecurityLevel();
|
||||
} else {
|
||||
realSecurityData = await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(activeWebrtcManager);
|
||||
}
|
||||
|
||||
if (realSecurityData && realSecurityData.isRealData !== false) {
|
||||
const currentScore = realSecurityLevel?.score || 0;
|
||||
const newScore = realSecurityData.score || 0;
|
||||
|
||||
if (currentScore !== newScore || !realSecurityLevel) {
|
||||
setRealSecurityLevel(realSecurityData);
|
||||
setLastSecurityUpdate(now);
|
||||
|
||||
} else if (window.DEBUG_MODE) {
|
||||
}
|
||||
} else {
|
||||
console.warn(' Security calculation returned invalid data');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error(' Error in real security calculation:', error);
|
||||
} finally {
|
||||
isUpdating = false;
|
||||
}
|
||||
};
|
||||
|
||||
if (isConnected) {
|
||||
updateRealSecurityStatus();
|
||||
|
||||
if (!realSecurityLevel || realSecurityLevel.score < 50) {
|
||||
const retryInterval = setInterval(() => {
|
||||
if (!realSecurityLevel || realSecurityLevel.score < 50) {
|
||||
updateRealSecurityStatus();
|
||||
} else {
|
||||
clearInterval(retryInterval);
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
setTimeout(() => clearInterval(retryInterval), 30000);
|
||||
}
|
||||
}
|
||||
|
||||
const interval = setInterval(updateRealSecurityStatus, 30000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [webrtcManager, isConnected]);
|
||||
|
||||
// ============================================
|
||||
// FIXED EVENT HANDLERS
|
||||
// ============================================
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleSecurityUpdate = (event) => {
|
||||
|
||||
setTimeout(() => {
|
||||
setLastSecurityUpdate(0);
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const handleRealSecurityCalculated = (event) => {
|
||||
|
||||
if (event.detail && event.detail.securityData) {
|
||||
setRealSecurityLevel(event.detail.securityData);
|
||||
setLastSecurityUpdate(Date.now());
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('security-level-updated', handleSecurityUpdate);
|
||||
document.addEventListener('real-security-calculated', handleRealSecurityCalculated);
|
||||
|
||||
window.forceHeaderSecurityUpdate = (webrtcManager) => {
|
||||
|
||||
if (webrtcManager && window.EnhancedSecureCryptoUtils) {
|
||||
window.EnhancedSecureCryptoUtils.calculateSecurityLevel(webrtcManager)
|
||||
.then(securityData => {
|
||||
if (securityData && securityData.isRealData !== false) {
|
||||
setRealSecurityLevel(securityData);
|
||||
setLastSecurityUpdate(Date.now());
|
||||
console.log('✅ Header security level force-updated');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('❌ Force update failed:', error);
|
||||
});
|
||||
} else {
|
||||
setLastSecurityUpdate(0);
|
||||
}
|
||||
};
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('security-level-updated', handleSecurityUpdate);
|
||||
document.removeEventListener('real-security-calculated', handleRealSecurityCalculated);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// ============================================
|
||||
// REST of the component logic
|
||||
// ============================================
|
||||
|
||||
React.useEffect(() => {
|
||||
// All security features are enabled by default - no session management needed
|
||||
setHasActiveSession(true);
|
||||
setCurrentTimeLeft(0);
|
||||
setSessionType('premium'); // All features enabled
|
||||
}, []);
|
||||
|
||||
React.useEffect(() => {
|
||||
// All security features are enabled by default
|
||||
setHasActiveSession(true);
|
||||
setCurrentTimeLeft(0);
|
||||
setSessionType('premium'); // All features enabled
|
||||
}, [sessionTimeLeft]);
|
||||
|
||||
React.useEffect(() => {
|
||||
const handleForceUpdate = (event) => {
|
||||
// All security features are enabled by default
|
||||
setHasActiveSession(true);
|
||||
setCurrentTimeLeft(0);
|
||||
setSessionType('premium'); // All features enabled
|
||||
};
|
||||
|
||||
// Connection cleanup handler (use existing event from module)
|
||||
const handleConnectionCleaned = () => {
|
||||
if (window.DEBUG_MODE) {
|
||||
console.log('🧹 Connection cleaned - clearing security data in header');
|
||||
}
|
||||
|
||||
setRealSecurityLevel(null);
|
||||
setLastSecurityUpdate(0);
|
||||
|
||||
setHasActiveSession(false);
|
||||
setCurrentTimeLeft(0);
|
||||
setSessionType('unknown');
|
||||
};
|
||||
|
||||
const handlePeerDisconnect = () => {
|
||||
if (window.DEBUG_MODE) {
|
||||
console.log('👋 Peer disconnect detected - clearing security data in header');
|
||||
}
|
||||
|
||||
setRealSecurityLevel(null);
|
||||
setLastSecurityUpdate(0);
|
||||
};
|
||||
|
||||
const handleDisconnected = () => {
|
||||
|
||||
setRealSecurityLevel(null);
|
||||
setLastSecurityUpdate(0);
|
||||
setHasActiveSession(false);
|
||||
setCurrentTimeLeft(0);
|
||||
setSessionType('unknown');
|
||||
};
|
||||
|
||||
document.addEventListener('force-header-update', handleForceUpdate);
|
||||
document.addEventListener('peer-disconnect', handlePeerDisconnect);
|
||||
document.addEventListener('connection-cleaned', handleConnectionCleaned);
|
||||
document.addEventListener('disconnected', handleDisconnected);
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('force-header-update', handleForceUpdate);
|
||||
document.removeEventListener('peer-disconnect', handlePeerDisconnect);
|
||||
document.removeEventListener('connection-cleaned', handleConnectionCleaned);
|
||||
document.removeEventListener('disconnected', handleDisconnected);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// ============================================
|
||||
// SECURITY INDICATOR CLICK HANDLER
|
||||
// ============================================
|
||||
|
||||
const handleSecurityClick = async (event) => {
|
||||
// Check if it's a right-click or Ctrl+click to disconnect
|
||||
if (event && (event.button === 2 || event.ctrlKey || event.metaKey)) {
|
||||
if (onDisconnect && typeof onDisconnect === 'function') {
|
||||
onDisconnect();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent default behavior
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
|
||||
// Run real security tests if webrtcManager is available
|
||||
let realTestResults = null;
|
||||
if (webrtcManager && window.EnhancedSecureCryptoUtils) {
|
||||
try {
|
||||
realTestResults = await window.EnhancedSecureCryptoUtils.calculateSecurityLevel(webrtcManager);
|
||||
console.log('✅ Real security tests completed:', realTestResults);
|
||||
} catch (error) {
|
||||
console.error('❌ Real security tests failed:', error);
|
||||
}
|
||||
} else {
|
||||
console.log('⚠️ Cannot run security tests:', {
|
||||
webrtcManager: !!webrtcManager,
|
||||
cryptoUtils: !!window.EnhancedSecureCryptoUtils
|
||||
});
|
||||
}
|
||||
|
||||
// If no real test results and no existing security level, show progress message
|
||||
if (!realTestResults && !realSecurityLevel) {
|
||||
alert('Security verification in progress...\nPlease wait for real-time cryptographic verification to complete.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Use real test results if available, otherwise fall back to current data
|
||||
let securityData = realTestResults || realSecurityLevel;
|
||||
|
||||
// If still no security data, create a basic fallback
|
||||
if (!securityData) {
|
||||
securityData = {
|
||||
level: 'UNKNOWN',
|
||||
score: 0,
|
||||
color: 'gray',
|
||||
verificationResults: {},
|
||||
timestamp: Date.now(),
|
||||
details: 'Security verification not available',
|
||||
isRealData: false,
|
||||
passedChecks: 0,
|
||||
totalChecks: 0,
|
||||
sessionType: 'unknown'
|
||||
};
|
||||
console.log('Using fallback security data:', securityData);
|
||||
}
|
||||
|
||||
// Detailed information about the REAL security check
|
||||
let message = `REAL-TIME SECURITY VERIFICATION\n\n`;
|
||||
message += `Security Level: ${securityData.level} (${securityData.score}%)\n`;
|
||||
message += `Session Type: ${securityData.sessionType || 'premium'}\n`;
|
||||
message += `Verification Time: ${new Date(securityData.timestamp).toLocaleTimeString()}\n`;
|
||||
message += `Data Source: ${securityData.isRealData ? 'Real Cryptographic Tests' : 'Simulated Data'}\n\n`;
|
||||
|
||||
if (securityData.verificationResults) {
|
||||
message += 'DETAILED CRYPTOGRAPHIC TESTS:\n';
|
||||
message += '=' + '='.repeat(40) + '\n';
|
||||
|
||||
const passedTests = Object.entries(securityData.verificationResults).filter(([key, result]) => result.passed);
|
||||
const failedTests = Object.entries(securityData.verificationResults).filter(([key, result]) => !result.passed);
|
||||
|
||||
if (passedTests.length > 0) {
|
||||
message += 'PASSED TESTS:\n';
|
||||
passedTests.forEach(([key, result]) => {
|
||||
const testName = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
|
||||
message += ` ${testName}: ${result.details || 'Test passed'}\n`;
|
||||
});
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
if (failedTests.length > 0) {
|
||||
message += 'FAILED/UNAVAILABLE TESTS:\n';
|
||||
failedTests.forEach(([key, result]) => {
|
||||
const testName = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase());
|
||||
message += ` ${testName}: ${result.details || 'Test failed or unavailable'}\n`;
|
||||
});
|
||||
message += '\n';
|
||||
}
|
||||
|
||||
message += `SUMMARY:\n`;
|
||||
message += `Passed: ${securityData.passedChecks}/${securityData.totalChecks} tests\n`;
|
||||
message += `Score: ${securityData.score}/${securityData.maxPossibleScore || 100} points\n\n`;
|
||||
}
|
||||
|
||||
// Real security features status
|
||||
message += `SECURITY FEATURES STATUS:\n`;
|
||||
message += '=' + '='.repeat(40) + '\n';
|
||||
|
||||
if (securityData.verificationResults) {
|
||||
const features = {
|
||||
'ECDSA Digital Signatures': securityData.verificationResults.verifyECDSASignatures?.passed || false,
|
||||
'ECDH Key Exchange': securityData.verificationResults.verifyECDHKeyExchange?.passed || false,
|
||||
'AES-GCM Encryption': securityData.verificationResults.verifyEncryption?.passed || false,
|
||||
'Message Integrity (HMAC)': securityData.verificationResults.verifyMessageIntegrity?.passed || false,
|
||||
'Perfect Forward Secrecy': securityData.verificationResults.verifyPerfectForwardSecrecy?.passed || false,
|
||||
'Replay Protection': securityData.verificationResults.verifyReplayProtection?.passed || false,
|
||||
'DTLS Fingerprint': securityData.verificationResults.verifyDTLSFingerprint?.passed || false,
|
||||
'SAS Verification': securityData.verificationResults.verifySASVerification?.passed || false,
|
||||
'Metadata Protection': securityData.verificationResults.verifyMetadataProtection?.passed || false,
|
||||
'Traffic Obfuscation': securityData.verificationResults.verifyTrafficObfuscation?.passed || false
|
||||
};
|
||||
|
||||
Object.entries(features).forEach(([feature, isEnabled]) => {
|
||||
message += `${isEnabled ? '✅' : '❌'} ${feature}\n`;
|
||||
});
|
||||
} else {
|
||||
// Fallback if no verification results
|
||||
message += `✅ ECDSA Digital Signatures\n`;
|
||||
message += `✅ ECDH Key Exchange\n`;
|
||||
message += `✅ AES-GCM Encryption\n`;
|
||||
message += `✅ Message Integrity (HMAC)\n`;
|
||||
message += `✅ Perfect Forward Secrecy\n`;
|
||||
message += `✅ Replay Protection\n`;
|
||||
message += `✅ DTLS Fingerprint\n`;
|
||||
message += `✅ SAS Verification\n`;
|
||||
message += `✅ Metadata Protection\n`;
|
||||
message += `✅ Traffic Obfuscation\n`;
|
||||
}
|
||||
|
||||
message += `\n${securityData.details || 'Real cryptographic verification completed'}`;
|
||||
|
||||
if (securityData.isRealData) {
|
||||
message += '\n\n✅ This is REAL-TIME verification using actual cryptographic functions.';
|
||||
} else {
|
||||
message += '\n\n⚠️ Warning: This data may be simulated. Connection may not be fully established.';
|
||||
}
|
||||
|
||||
// Show in a more user-friendly way
|
||||
const modal = document.createElement('div');
|
||||
modal.style.cssText = `
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0,0,0,0.8);
|
||||
z-index: 10000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-family: monospace;
|
||||
`;
|
||||
|
||||
const content = document.createElement('div');
|
||||
content.style.cssText = `
|
||||
background: #1a1a1a;
|
||||
color: #fff;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
overflow-y: auto;
|
||||
white-space: pre-line;
|
||||
border: 1px solid #333;
|
||||
`;
|
||||
|
||||
content.textContent = message;
|
||||
modal.appendChild(content);
|
||||
|
||||
// Close on click outside
|
||||
modal.addEventListener('click', (e) => {
|
||||
if (e.target === modal) {
|
||||
document.body.removeChild(modal);
|
||||
}
|
||||
});
|
||||
|
||||
// Close on Escape key
|
||||
const handleKeyDown = (e) => {
|
||||
if (e.key === 'Escape') {
|
||||
document.body.removeChild(modal);
|
||||
document.removeEventListener('keydown', handleKeyDown);
|
||||
}
|
||||
};
|
||||
document.addEventListener('keydown', handleKeyDown);
|
||||
|
||||
document.body.appendChild(modal);
|
||||
};
|
||||
|
||||
// ============================================
|
||||
// DISPLAY UTILITIES
|
||||
// ============================================
|
||||
|
||||
const getStatusConfig = () => {
|
||||
switch (status) {
|
||||
case 'connected':
|
||||
return {
|
||||
text: 'Connected',
|
||||
className: 'status-connected',
|
||||
badgeClass: 'bg-green-500/10 text-green-400 border-green-500/20'
|
||||
};
|
||||
case 'verifying':
|
||||
return {
|
||||
text: 'Verifying...',
|
||||
className: 'status-verifying',
|
||||
badgeClass: 'bg-purple-500/10 text-purple-400 border-purple-500/20'
|
||||
};
|
||||
case 'connecting':
|
||||
return {
|
||||
text: 'Connecting...',
|
||||
className: 'status-connecting',
|
||||
badgeClass: 'bg-blue-500/10 text-blue-400 border-blue-500/20'
|
||||
};
|
||||
case 'retrying':
|
||||
return {
|
||||
text: 'Retrying...',
|
||||
className: 'status-connecting',
|
||||
badgeClass: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20'
|
||||
};
|
||||
case 'failed':
|
||||
return {
|
||||
text: 'Error',
|
||||
className: 'status-failed',
|
||||
badgeClass: 'bg-red-500/10 text-red-400 border-red-500/20'
|
||||
};
|
||||
case 'reconnecting':
|
||||
return {
|
||||
text: 'Reconnecting...',
|
||||
className: 'status-connecting',
|
||||
badgeClass: 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20'
|
||||
};
|
||||
case 'peer_disconnected':
|
||||
return {
|
||||
text: 'Peer disconnected',
|
||||
className: 'status-failed',
|
||||
badgeClass: 'bg-orange-500/10 text-orange-400 border-orange-500/20'
|
||||
};
|
||||
default:
|
||||
return {
|
||||
text: 'Not connected',
|
||||
className: 'status-disconnected',
|
||||
badgeClass: 'bg-gray-500/10 text-gray-400 border-gray-500/20'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const config = getStatusConfig();
|
||||
const displaySecurityLevel = isConnected ? (realSecurityLevel || securityLevel) : null;
|
||||
|
||||
const shouldShowTimer = hasActiveSession && currentTimeLeft > 0 && window.SessionTimer;
|
||||
|
||||
// ============================================
|
||||
// DATA RELIABILITY INDICATOR
|
||||
// ============================================
|
||||
|
||||
const getSecurityIndicatorDetails = () => {
|
||||
if (!displaySecurityLevel) {
|
||||
return {
|
||||
tooltip: 'Security verification in progress...',
|
||||
isVerified: false,
|
||||
dataSource: 'loading'
|
||||
};
|
||||
}
|
||||
|
||||
const isRealData = displaySecurityLevel.isRealData !== false;
|
||||
const baseTooltip = `${displaySecurityLevel.level} (${displaySecurityLevel.score}%)`;
|
||||
|
||||
if (isRealData) {
|
||||
return {
|
||||
tooltip: `${baseTooltip} - Real-time verification ✅\nRight-click or Ctrl+click to disconnect`,
|
||||
isVerified: true,
|
||||
dataSource: 'real'
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
tooltip: `${baseTooltip} - Estimated (connection establishing...)\nRight-click or Ctrl+click to disconnect`,
|
||||
isVerified: false,
|
||||
dataSource: 'estimated'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const securityDetails = getSecurityIndicatorDetails();
|
||||
|
||||
// ============================================
|
||||
// ADDING global methods for debugging
|
||||
// ============================================
|
||||
|
||||
React.useEffect(() => {
|
||||
window.debugHeaderSecurity = () => {
|
||||
console.log('🔍 Header Security Debug:', {
|
||||
realSecurityLevel,
|
||||
lastSecurityUpdate,
|
||||
isConnected,
|
||||
webrtcManagerProp: !!webrtcManager,
|
||||
windowWebrtcManager: !!window.webrtcManager,
|
||||
cryptoUtils: !!window.EnhancedSecureCryptoUtils,
|
||||
displaySecurityLevel: displaySecurityLevel,
|
||||
securityDetails: securityDetails
|
||||
});
|
||||
};
|
||||
|
||||
return () => {
|
||||
delete window.debugHeaderSecurity;
|
||||
};
|
||||
}, [realSecurityLevel, lastSecurityUpdate, isConnected, webrtcManager, displaySecurityLevel, securityDetails]);
|
||||
|
||||
// ============================================
|
||||
// RENDER
|
||||
// ============================================
|
||||
|
||||
return React.createElement('header', {
|
||||
className: 'header-minimal sticky top-0 z-50'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'container',
|
||||
className: 'max-w-7xl mx-auto px-4 sm:px-6 lg:px-8'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'content',
|
||||
className: 'flex items-center justify-between h-16'
|
||||
}, [
|
||||
// Logo and Title
|
||||
React.createElement('div', {
|
||||
key: 'logo-section',
|
||||
className: 'flex items-center space-x-2 sm:space-x-3'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'logo',
|
||||
className: 'icon-container w-8 h-8 sm:w-10 sm:h-10'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-shield-halved accent-orange text-sm sm:text-base'
|
||||
})
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'title-section'
|
||||
}, [
|
||||
React.createElement('h1', {
|
||||
key: 'title',
|
||||
className: 'text-lg sm:text-xl font-semibold text-primary'
|
||||
}, 'SecureBit.chat'),
|
||||
React.createElement('p', {
|
||||
key: 'subtitle',
|
||||
className: 'text-xs sm:text-sm text-muted hidden sm:block'
|
||||
}, 'End-to-end freedom v4.3.120')
|
||||
])
|
||||
]),
|
||||
|
||||
// Status and Controls - Responsive
|
||||
React.createElement('div', {
|
||||
key: 'status-section',
|
||||
className: 'flex items-center space-x-2 sm:space-x-3'
|
||||
}, [
|
||||
// Session Timer - all features enabled by default
|
||||
shouldShowTimer && React.createElement(window.SessionTimer, {
|
||||
key: 'session-timer',
|
||||
timeLeft: currentTimeLeft,
|
||||
sessionType: sessionType,
|
||||
onDisconnect: onDisconnect
|
||||
}),
|
||||
|
||||
displaySecurityLevel && React.createElement('div', {
|
||||
key: 'security-level',
|
||||
className: 'hidden md:flex items-center space-x-2 cursor-pointer hover:opacity-80 transition-opacity duration-200',
|
||||
onClick: handleSecurityClick,
|
||||
onContextMenu: (e) => {
|
||||
e.preventDefault();
|
||||
if (onDisconnect && typeof onDisconnect === 'function') {
|
||||
onDisconnect();
|
||||
}
|
||||
},
|
||||
title: securityDetails.tooltip
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'security-icon',
|
||||
className: `w-6 h-6 rounded-full flex items-center justify-center relative ${
|
||||
displaySecurityLevel.color === 'green' ? 'bg-green-500/20' :
|
||||
displaySecurityLevel.color === 'orange' ? 'bg-orange-500/20' :
|
||||
displaySecurityLevel.color === 'yellow' ? 'bg-yellow-500/20' : 'bg-red-500/20'
|
||||
} ${securityDetails.isVerified ? '' : 'animate-pulse'}`
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: `fas fa-shield-alt text-xs ${
|
||||
displaySecurityLevel.color === 'green' ? 'text-green-400' :
|
||||
displaySecurityLevel.color === 'orange' ? 'text-orange-400' :
|
||||
displaySecurityLevel.color === 'yellow' ? 'text-yellow-400' : 'text-red-400'
|
||||
}`
|
||||
})
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'security-info',
|
||||
className: 'flex flex-col'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'security-level-text',
|
||||
className: 'text-xs font-medium text-primary flex items-center space-x-1'
|
||||
}, [
|
||||
React.createElement('span', {}, `${displaySecurityLevel.level} (${displaySecurityLevel.score}%)`)
|
||||
]),
|
||||
React.createElement('div', {
|
||||
key: 'security-details',
|
||||
className: 'text-xs text-muted mt-1 hidden lg:block'
|
||||
}, securityDetails.dataSource === 'real' ?
|
||||
`${displaySecurityLevel.passedChecks || 0}/${displaySecurityLevel.totalChecks || 0} tests` :
|
||||
(displaySecurityLevel.details || `Stage ${displaySecurityLevel.stage || 1}`)
|
||||
),
|
||||
React.createElement('div', {
|
||||
key: 'security-progress',
|
||||
className: 'w-16 h-1 bg-gray-600 rounded-full overflow-hidden'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'progress-bar',
|
||||
className: `h-full transition-all duration-500 ${
|
||||
displaySecurityLevel.color === 'green' ? 'bg-green-400' :
|
||||
displaySecurityLevel.color === 'orange' ? 'bg-orange-400' :
|
||||
displaySecurityLevel.color === 'yellow' ? 'bg-yellow-400' : 'bg-red-400'
|
||||
}`,
|
||||
style: { width: `${displaySecurityLevel.score}%` }
|
||||
})
|
||||
])
|
||||
])
|
||||
]),
|
||||
|
||||
// Mobile Security Indicator
|
||||
displaySecurityLevel && React.createElement('div', {
|
||||
key: 'mobile-security',
|
||||
className: 'md:hidden flex items-center'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'mobile-security-icon',
|
||||
className: `w-8 h-8 rounded-full flex items-center justify-center cursor-pointer hover:opacity-80 transition-opacity duration-200 relative ${
|
||||
displaySecurityLevel.color === 'green' ? 'bg-green-500/20' :
|
||||
displaySecurityLevel.color === 'orange' ? 'bg-orange-500/20' :
|
||||
displaySecurityLevel.color === 'yellow' ? 'bg-yellow-500/20' : 'bg-red-500/20'
|
||||
} ${securityDetails.isVerified ? '' : 'animate-pulse'}`,
|
||||
title: securityDetails.tooltip,
|
||||
onClick: handleSecurityClick,
|
||||
onContextMenu: (e) => {
|
||||
e.preventDefault();
|
||||
if (onDisconnect && typeof onDisconnect === 'function') {
|
||||
onDisconnect();
|
||||
}
|
||||
}
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: `fas fa-shield-alt text-sm ${
|
||||
displaySecurityLevel.color === 'green' ? 'text-green-400' :
|
||||
displaySecurityLevel.color === 'orange' ? 'text-orange-400' :
|
||||
displaySecurityLevel.color === 'yellow' ? 'text-yellow-400' : 'text-red-400'
|
||||
}`
|
||||
})
|
||||
])
|
||||
]),
|
||||
|
||||
// Status Badge
|
||||
React.createElement('div', {
|
||||
key: 'status-badge',
|
||||
className: `px-2 sm:px-3 py-1.5 rounded-lg border ${config.badgeClass} flex items-center space-x-1 sm:space-x-2`
|
||||
}, [
|
||||
React.createElement('span', {
|
||||
key: 'status-dot',
|
||||
className: `status-dot ${config.className}`
|
||||
}),
|
||||
React.createElement('span', {
|
||||
key: 'status-text',
|
||||
className: 'text-xs sm:text-sm font-medium'
|
||||
}, config.text),
|
||||
]),
|
||||
|
||||
// Disconnect Button
|
||||
isConnected && React.createElement('button', {
|
||||
key: 'disconnect-btn',
|
||||
onClick: onDisconnect,
|
||||
className: 'p-1.5 sm:px-3 sm:py-1.5 bg-red-500/10 hover:bg-red-500/20 text-red-400 border border-red-500/20 rounded-lg transition-all duration-200 text-sm'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-power-off sm:mr-2'
|
||||
}),
|
||||
React.createElement('span', {
|
||||
className: 'hidden sm:inline'
|
||||
}, 'Disconnect')
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
window.EnhancedMinimalHeader = EnhancedMinimalHeader;
|
||||
91
src/components/ui/PasswordModal.jsx
Normal file
@@ -0,0 +1,91 @@
|
||||
const React = window.React;
|
||||
|
||||
const PasswordModal = ({ isOpen, onClose, onSubmit, action, password, setPassword }) => {
|
||||
if (!isOpen) return null;
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
if (password.trim()) {
|
||||
onSubmit(password.trim());
|
||||
setPassword('');
|
||||
}
|
||||
};
|
||||
|
||||
const getActionText = () => {
|
||||
return action === 'offer' ? 'invitation' : 'response';
|
||||
};
|
||||
|
||||
return React.createElement('div', {
|
||||
className: 'fixed inset-0 bg-black/50 backdrop-blur-sm z-50 flex items-center justify-center p-4'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'modal',
|
||||
className: 'card-minimal rounded-xl p-6 max-w-md w-full border-purple-500/20'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'header',
|
||||
className: 'flex items-center mb-4'
|
||||
}, [
|
||||
React.createElement('div', {
|
||||
key: 'icon',
|
||||
className: 'w-10 h-10 bg-purple-500/10 border border-purple-500/20 rounded-lg flex items-center justify-center mr-3'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-key accent-purple'
|
||||
})
|
||||
]),
|
||||
React.createElement('h3', {
|
||||
key: 'title',
|
||||
className: 'text-lg font-medium text-primary'
|
||||
}, 'Password input')
|
||||
]),
|
||||
React.createElement('form', {
|
||||
key: 'form',
|
||||
onSubmit: handleSubmit,
|
||||
className: 'space-y-4'
|
||||
}, [
|
||||
React.createElement('p', {
|
||||
key: 'description',
|
||||
className: 'text-secondary text-sm'
|
||||
}, `Enter password for decryption ${getActionText()}:`),
|
||||
React.createElement('input', {
|
||||
key: 'password-input',
|
||||
type: 'password',
|
||||
value: password,
|
||||
onChange: (e) => setPassword(e.target.value),
|
||||
placeholder: 'Enter password...',
|
||||
className: 'w-full p-3 bg-gray-900/30 border border-gray-500/20 rounded-lg text-primary placeholder-gray-500 focus:border-purple-500/40 focus:outline-none transition-all',
|
||||
autoFocus: true
|
||||
}),
|
||||
React.createElement('div', {
|
||||
key: 'buttons',
|
||||
className: 'flex space-x-3'
|
||||
}, [
|
||||
React.createElement('button', {
|
||||
key: 'submit',
|
||||
type: 'submit',
|
||||
className: 'flex-1 btn-primary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-unlock-alt mr-2'
|
||||
}),
|
||||
'Decrypt'
|
||||
]),
|
||||
React.createElement('button', {
|
||||
key: 'cancel',
|
||||
type: 'button',
|
||||
onClick: onClose,
|
||||
className: 'flex-1 btn-secondary text-white py-3 px-4 rounded-lg font-medium transition-all duration-200'
|
||||
}, [
|
||||
React.createElement('i', {
|
||||
className: 'fas fa-times mr-2'
|
||||
}),
|
||||
'Cancel'
|
||||
])
|
||||
])
|
||||
])
|
||||
])
|
||||
]);
|
||||
};
|
||||
|
||||
window.PasswordModal = PasswordModal;
|
||||
432
src/components/ui/Roadmap.jsx
Normal file
@@ -0,0 +1,432 @@
|
||||
function Roadmap() {
|
||||
const [selectedPhase, setSelectedPhase] = React.useState(null);
|
||||
const phases = [
|
||||
{
|
||||
version: "v1.0",
|
||||
title: "Start of Development",
|
||||
status: "done",
|
||||
date: "Early 2025",
|
||||
description: "Idea, prototype, and infrastructure setup",
|
||||
features: [
|
||||
"Concept and requirements formation",
|
||||
"Stack selection: WebRTC, P2P, cryptography",
|
||||
"First messaging prototypes",
|
||||
"Repository creation and CI",
|
||||
"Basic encryption architecture",
|
||||
"UX/UI design"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v1.5",
|
||||
title: "Alpha Release",
|
||||
status: "done",
|
||||
date: "Spring 2025",
|
||||
description: "First public alpha: basic chat and key exchange",
|
||||
features: [
|
||||
"Basic P2P messaging via WebRTC",
|
||||
"Simple E2E encryption (demo scheme)",
|
||||
"Stable signaling and reconnection",
|
||||
"Minimal UX for testing",
|
||||
"Feedback collection from early testers"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v2.0",
|
||||
title: "Security Hardened",
|
||||
status: "done",
|
||||
date: "Summer 2025",
|
||||
description: "Security strengthening and stable branch release",
|
||||
features: [
|
||||
"ECDH/ECDSA implementation in production",
|
||||
"Perfect Forward Secrecy and key rotation",
|
||||
"Improved authentication checks",
|
||||
"File encryption and large payload transfers",
|
||||
"Audit of basic cryptoprocesses"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v3.0",
|
||||
title: "Scaling & Stability",
|
||||
status: "done",
|
||||
date: "Fall 2025",
|
||||
description: "Network scaling and stability improvements",
|
||||
features: [
|
||||
"Optimization of P2P connections and NAT traversal",
|
||||
"Reconnection mechanisms and message queues",
|
||||
"Reduced battery consumption on mobile",
|
||||
"Support for multi-device synchronization",
|
||||
"Monitoring and logging tools for developers"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v3.5",
|
||||
title: "Privacy-first Release",
|
||||
status: "done",
|
||||
date: "Winter 2025",
|
||||
description: "Focus on privacy: minimizing metadata",
|
||||
features: [
|
||||
"Metadata protection and fingerprint reduction",
|
||||
"Experiments with onion routing and DHT",
|
||||
"Options for anonymous connections",
|
||||
"Preparation for open code audit",
|
||||
"Improved user verification processes"
|
||||
]
|
||||
},
|
||||
|
||||
// current and future phases
|
||||
{
|
||||
version: "v4.3.120",
|
||||
title: "Enhanced Security Edition",
|
||||
status: "current",
|
||||
date: "Now",
|
||||
description: "Current version with ECDH + DTLS + SAS security, 18-layer military-grade cryptography and complete ASN.1 validation",
|
||||
features: [
|
||||
"ECDH + DTLS + SAS triple-layer security",
|
||||
"ECDH P-384 + AES-GCM 256-bit encryption",
|
||||
"DTLS fingerprint verification",
|
||||
"SAS (Short Authentication String) verification",
|
||||
"Perfect Forward Secrecy with key rotation",
|
||||
"Enhanced MITM attack prevention",
|
||||
"Complete ASN.1 DER validation",
|
||||
"OID and EC point verification",
|
||||
"SPKI structure validation",
|
||||
"P2P WebRTC architecture",
|
||||
"Metadata protection",
|
||||
"100% open source code"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v4.5",
|
||||
title: "Mobile & Desktop Edition",
|
||||
status: "development",
|
||||
date: "Q2 2025",
|
||||
description: "Native apps for all platforms",
|
||||
features: [
|
||||
"PWA app for mobile",
|
||||
"Electron app for desktop",
|
||||
"Real-time notifications",
|
||||
"Automatic reconnection",
|
||||
"Battery optimization",
|
||||
"Cross-device synchronization",
|
||||
"Improved UX/UI",
|
||||
"Support for files up to 100MB"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v5.0",
|
||||
title: "Quantum-Resistant Edition",
|
||||
status: "planned",
|
||||
date: "Q4 2025",
|
||||
description: "Protection against quantum computers",
|
||||
features: [
|
||||
"Post-quantum cryptography CRYSTALS-Kyber",
|
||||
"SPHINCS+ digital signatures",
|
||||
"Hybrid scheme: classic + PQ",
|
||||
"Quantum-safe key exchange",
|
||||
"Updated hashing algorithms",
|
||||
"Migration of existing sessions",
|
||||
"Compatibility with v4.x",
|
||||
"Quantum-resistant protocols"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v5.5",
|
||||
title: "Group Communications",
|
||||
status: "planned",
|
||||
date: "Q2 2026",
|
||||
description: "Group chats with preserved privacy",
|
||||
features: [
|
||||
"P2P group connections up to 8 participants",
|
||||
"Mesh networking for groups",
|
||||
"Signal Double Ratchet for groups",
|
||||
"Anonymous groups without metadata",
|
||||
"Ephemeral groups (disappear after session)",
|
||||
"Cryptographic group administration",
|
||||
"Group member auditing"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v6.0",
|
||||
title: "Decentralized Network",
|
||||
status: "research",
|
||||
date: "2027",
|
||||
description: "Fully decentralized network",
|
||||
features: [
|
||||
"LockBit node mesh network",
|
||||
"DHT for peer discovery",
|
||||
"Built-in onion routing",
|
||||
"Tokenomics and node incentives",
|
||||
"Governance via DAO",
|
||||
"Interoperability with other networks",
|
||||
"Cross-platform compatibility",
|
||||
"Self-healing network"
|
||||
]
|
||||
},
|
||||
{
|
||||
version: "v7.0",
|
||||
title: "AI Privacy Assistant",
|
||||
status: "research",
|
||||
date: "2028+",
|
||||
description: "AI for privacy and security",
|
||||
features: [
|
||||
"Local AI threat analysis",
|
||||
"Automatic MITM detection",
|
||||
"Adaptive cryptography",
|
||||
"Personalized security recommendations",
|
||||
"Zero-knowledge machine learning",
|
||||
"Private AI assistant",
|
||||
"Predictive security",
|
||||
"Autonomous attack protection"
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
const getStatusConfig = (status) => {
|
||||
switch (status) {
|
||||
case 'current':
|
||||
return {
|
||||
color: 'green',
|
||||
bgClass: 'bg-green-500/10 border-green-500/20',
|
||||
textClass: 'text-green-400',
|
||||
icon: 'fas fa-check-circle',
|
||||
label: 'Current Version'
|
||||
};
|
||||
case 'development':
|
||||
return {
|
||||
color: 'orange',
|
||||
bgClass: 'bg-orange-500/10 border-orange-500/20',
|
||||
textClass: 'text-orange-400',
|
||||
icon: 'fas fa-code',
|
||||
label: 'In Development'
|
||||
};
|
||||
case 'planned':
|
||||
return {
|
||||
color: 'blue',
|
||||
bgClass: 'bg-blue-500/10 border-blue-500/20',
|
||||
textClass: 'text-blue-400',
|
||||
icon: 'fas fa-calendar-alt',
|
||||
label: 'Planned'
|
||||
};
|
||||
case 'research':
|
||||
return {
|
||||
color: 'purple',
|
||||
bgClass: 'bg-purple-500/10 border-purple-500/20',
|
||||
textClass: 'text-purple-400',
|
||||
icon: 'fas fa-flask',
|
||||
label: 'Research'
|
||||
};
|
||||
case 'done':
|
||||
return {
|
||||
color: 'gray',
|
||||
bgClass: 'bg-gray-500/10 border-gray-500/20',
|
||||
textClass: 'text-gray-300',
|
||||
icon: 'fas fa-flag-checkered',
|
||||
label: 'Released'
|
||||
};
|
||||
default:
|
||||
return {
|
||||
color: 'gray',
|
||||
bgClass: 'bg-gray-500/10 border-gray-500/20',
|
||||
textClass: 'text-gray-400',
|
||||
icon: 'fas fa-question',
|
||||
label: 'Unknown'
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const togglePhaseDetail = (index) => {
|
||||
setSelectedPhase(selectedPhase === index ? null : index);
|
||||
};
|
||||
return (
|
||||
<div key="roadmap-section" className="mt-16 px-4 sm:px-0">
|
||||
<div key="section-header" className="text-center mb-12">
|
||||
<h3 key="title" className="text-2xl font-semibold text-primary mb-3">
|
||||
Development Roadmap
|
||||
</h3>
|
||||
<p key="subtitle" className="text-secondary max-w-2xl mx-auto mb-6">
|
||||
Evolution of SecureBit.chat : from initial development to quantum-resistant decentralized network with complete ASN.1 validation
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div key="roadmap-container" className="max-w-6xl mx-auto">
|
||||
<div key="timeline" className="relative">
|
||||
{/* The line has been removed */}
|
||||
|
||||
<div key="phases" className="space-y-8">
|
||||
{phases.map((phase, index) => {
|
||||
const statusConfig = getStatusConfig(phase.status);
|
||||
const isExpanded = selectedPhase === index;
|
||||
|
||||
return (
|
||||
<div key={`phase-${index}`} className="relative">
|
||||
{/* The dots are visible only on sm and larger screens */}
|
||||
|
||||
<button
|
||||
type="button"
|
||||
aria-expanded={isExpanded}
|
||||
onClick={() => togglePhaseDetail(index)}
|
||||
key={`phase-button-${index}`}
|
||||
className={`card-minimal rounded-xl p-4 text-left w-full transition-all duration-300 ${
|
||||
isExpanded
|
||||
? "ring-2 ring-" + statusConfig.color + "-500/30"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div
|
||||
key="phase-header"
|
||||
className="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-4 space-y-2 sm:space-y-0"
|
||||
>
|
||||
<div
|
||||
key="phase-info"
|
||||
className="flex flex-col sm:flex-row sm:items-center sm:space-x-4"
|
||||
>
|
||||
<div
|
||||
key="version-badge"
|
||||
className={`px-3 py-1 ${statusConfig.bgClass} border rounded-lg mb-2 sm:mb-0`}
|
||||
>
|
||||
<span
|
||||
key="version"
|
||||
className={`${statusConfig.textClass} font-bold text-sm`}
|
||||
>
|
||||
{phase.version}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div key="title-section">
|
||||
<h4
|
||||
key="title"
|
||||
className="text-lg font-semibold text-primary"
|
||||
>
|
||||
{phase.title}
|
||||